openrat-java-client

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

commit b96bfd688cd1cd603a1dccdee3cc3cb7d2c219e7
Author: dankert <devnull@localhost>
Date:   Fri, 30 Sep 2016 22:45:01 +0200

first version of the java api.

Diffstat:
.hgignore | 5+++++
src/de/openrat/client/CMSClient.java | 206+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/de/openrat/client/action/Action.java | 106+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/de/openrat/client/action/LoginAction.java | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/de/openrat/client/action/ProjectAction.java | 31+++++++++++++++++++++++++++++++
src/de/openrat/client/dto/CMSObject.java | 78++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/de/openrat/client/dto/Language.java | 6++++++
src/de/openrat/client/dto/Project.java | 6++++++
src/de/openrat/client/dto/Template.java | 6++++++
src/de/openrat/client/dto/User.java | 28++++++++++++++++++++++++++++
src/de/openrat/client/util/CMSConnection.java | 463+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/de/openrat/client/util/CMSControl.java | 6++++++
src/de/openrat/client/util/CMSError.java | 100+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/de/openrat/client/util/CMSException.java | 87+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/de/openrat/client/util/CMSNode.java | 72++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/de/openrat/client/util/CMSRequest.java | 333+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/de/openrat/client/util/CMSResponse.java | 185+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/de/openrat/client/util/CMSSession.java | 73+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/de/openrat/client/util/CookieStoreMap.java | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/de/openrat/client/util/HttpClient.java | 380+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/de/openrat/client/util/HttpHeaderMap.java | 70++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/de/openrat/client/util/HttpRequest.java | 123+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/de/openrat/client/util/HttpResponse.java | 113+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/de/openrat/client/util/HttpStatus.java | 56++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/de/openrat/client/util/Id.java | 49+++++++++++++++++++++++++++++++++++++++++++++++++
src/de/openrat/client/util/MapConverter.java | 42++++++++++++++++++++++++++++++++++++++++++
src/de/openrat/client/util/NumberUtils.java | 24++++++++++++++++++++++++
src/de/openrat/client/util/ParameterMap.java | 109+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
test/de/openrat/client/test/TestLogin.java | 43+++++++++++++++++++++++++++++++++++++++++++
29 files changed, 2922 insertions(+), 0 deletions(-)

diff --git a/.hgignore b/.hgignore @@ -0,0 +1,5 @@ +syntax: glob +bin/* +.settings/* +.project +.classpath diff --git a/src/de/openrat/client/CMSClient.java b/src/de/openrat/client/CMSClient.java @@ -0,0 +1,206 @@ +/* +OpenRat Java-Client +Copyright (C) 2009 Jan Dankert + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this library; if not, write to the +Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, +Boston, MA 02110-1301, USA. + + */ +package de.openrat.client; + +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Locale; + +import de.openrat.client.action.LoginAction; +import de.openrat.client.util.CMSConnection; + +/** + * API-Request to the OpenRat Content Management System. <br> + * <br> + * The call to the CMS server is done via a (non-SSL) HTTP connection.<br> + * <br> + * Before a call you are able to set some key/value-pairs as parameters. After + * calling the CMS a DOM-document is returned, which contains the server + * response.<br> + * Example <br> + * + * <pre> + * CMSRequest request = new CMSRequest(&quot;your.openrat.example.com&quot;); + * // prints tracing information to stdout. + * request.trace = true; + * try + * { + * request.parameter.put(&quot;action&quot;, &quot;index&quot;); + * request.parameter.put(&quot;subaction&quot;, &quot;showlogin&quot;); // login page + * request.parameter.put(&quot;...&quot;, &quot;...&quot;); + * Document response = request.call(); + * // now traverse through the dom tree and get your information. + * } + * catch (IOException e) + * { + * // your error handling. + * } + * </pre> + * + * @author Jan Dankert + */ +public class CMSClient +{ + + public final static int SUPPORTED_API_VERSION = 2; + + final CMSConnection connection; + + /** + * Constructs a CMS-Connection to the specified server.<br> + * Server-Path is "/", Server-Port is 80. + * + * @param host + * hostname + */ + public CMSClient(String host) + { + + this.connection = new CMSConnection(host, 80, "/"); + } + + /** + * Constructs a CMS-Request to the specified server/path.<br> + * Server-Port is 80. + * + * @param host + * hostname + * @param path + * path + */ + public CMSClient(String host, String path) + { + + this.connection = new CMSConnection(host, 80, path); + + } + + /** + * Constructs a CMS-Request to the specified server/path/port. + * + * @param host + * hostname + * @param path + * path + * @param port + * port-number + */ + public CMSClient(String host, String path, int port) + { + + this.connection = new CMSConnection(host, port, path); + } + + public LoginAction getLoginAction() + { + return new LoginAction(connection); + } + + public void setLogWriter(PrintWriter logWriter) + { + this.connection.setLogWriter(logWriter); + } + + public CMSConnection getConnection() + { + return connection; + } + + /** + * Setting a HTTP-Proxy. + * + * @param host + * hostname + * @param port + * port + */ + public void setProxy(String host, int port) + { + + setProxy(host, port, null, null); + } + + /** + * Setting a HTTP-Proxy. + * + * @param host + * hostname + * @param port + * port + */ + public void setProxy(String host, int port, String user, String password) + { + + this.connection.setProxyHostname(host); + this.connection.setProxyPort(port); + this.connection.setProxyUser(user); + this.connection.setProxyPassword(password); + } + + public void setLocale(Locale locale) + { + connection.setLocale(locale); + } + + public void setTimeout(int timeout) + { + connection.setTimeout(timeout); + } + + public void setKeepAlive(boolean useKeepAlive) + { + connection.setKeepAlive(useKeepAlive); + } + + @Override + public String toString() + { + return super.toString() + ": " + String.valueOf(this.connection); + } + + public void close() + { + if (connection.getSocket() != null) + { + try + { + connection.getSocket().close(); + } + catch (IOException e) + { + ; + } + } + } + + /** + * {@inheritDoc} + * + * @see java.lang.Object#finalize() + */ + @Override + protected void finalize() throws Throwable + { + close(); + super.finalize(); + } + +} diff --git a/src/de/openrat/client/action/Action.java b/src/de/openrat/client/action/Action.java @@ -0,0 +1,106 @@ +package de.openrat.client.action; + +import java.io.IOException; + +import de.openrat.client.util.CMSConnection; +import de.openrat.client.util.CMSException; +import de.openrat.client.util.CMSRequest; +import de.openrat.client.util.CMSResponse; +import de.openrat.client.util.HttpRequest.HttpMethod; +import de.openrat.client.util.Id; +import de.openrat.client.util.ParameterMap; + +public abstract class Action +{ + + /** + * Parameter map. + */ + private ParameterMap parameter = new ParameterMap(); + private Id id; + + private CMSConnection connection; + private String action; + + /** + * Clear parameter values. + */ + public void clear() + { + + parameter.clear(); + } + + protected Action(CMSConnection connection, String action) + { + this.connection = connection; + this.action = action; + } + + /** + * Setting a parameter value. + * + * @param paramName + * name + * @param paramValue + * value + */ + protected void setParameter(String paramName, String paramValue) + { + + parameter.put(paramName, paramValue); + } + + /** + * Setting a parameter value. <strong>DO NOT url-encode your values</strong> + * as this is done automatically inside this method! + * + * @param paramName + * name + * @param paramValue + * value + */ + public void addParameter(String paramName, String paramValue) + { + + if (paramName == null || paramValue == null || "" == paramName) + throw new IllegalArgumentException("parameter name and value must have values"); + + parameter.put(paramName, paramValue); + } + + public void setId(Id id) + { + this.id = id; + } + + public CMSConnection getConnection() + { + return connection; + } + + protected CMSResponse execute(String method, HttpMethod httpMethod) throws CMSException + { + + final ParameterMap parameter = new ParameterMap(); + + parameter.put(connection.getParamActionName(), action); + parameter.put(connection.getParamMethodName(), method); + parameter.put("id", String.valueOf(id)); + parameter.putAll(this.parameter); + + CMSRequest request = new CMSRequest(this.connection); + request.setMethod(httpMethod); + request.getParameter().putAll(parameter); + + try + { + CMSResponse response = request.execute(); + return response; + } + catch (IOException e) + { + throw new CMSException(e); + } + } +} diff --git a/src/de/openrat/client/action/LoginAction.java b/src/de/openrat/client/action/LoginAction.java @@ -0,0 +1,57 @@ +package de.openrat.client.action; + +import javax.security.auth.login.LoginException; + +import de.openrat.client.dto.User; +import de.openrat.client.util.CMSConnection; +import de.openrat.client.util.CMSException; +import de.openrat.client.util.CMSResponse; +import de.openrat.client.util.HttpRequest.HttpMethod; + +/** + * This class is NOT threadsafe and should be used by one thread simultaneously. + * + * @author dankert + */ +public class LoginAction extends Action +{ + + public LoginAction(CMSConnection connection) + { + super(connection, "login"); + } + + public User login(String username, String password, String databaseId) throws LoginException + { + + execute("login", HttpMethod.GET); + + clear(); + setParameter("login_name", username); + setParameter("login_password", password); + setParameter("dbid", databaseId); + try + { + CMSResponse response = execute("login", HttpMethod.POST); + + User user = new User(); + return user; + } + catch (CMSException e) + { + if ("LOGIN_FAILED".equals(e.getStatus())) + // wrong credentials - throw checked exception + throw new LoginException(e.getLocalizedMessage()); + else + // otherwise it's a technical exception + throw e; + } + + } + + public void logout() + { + + execute("logout", HttpMethod.POST); + } +} diff --git a/src/de/openrat/client/action/ProjectAction.java b/src/de/openrat/client/action/ProjectAction.java @@ -0,0 +1,31 @@ +package de.openrat.client.action; + +import de.openrat.client.dto.Project; +import de.openrat.client.util.CMSConnection; +import de.openrat.client.util.CMSResponse; +import de.openrat.client.util.HttpRequest.HttpMethod; +import de.openrat.client.util.Id; + +/** + * This class is NOT threadsafe and should be used by one thread simultaneously. + * + * @author dankert + */ +public class ProjectAction extends Action +{ + + public ProjectAction(CMSConnection request) + { + super(request, "project"); + } + + public Project getInfo(Id id) + { + + CMSResponse response = execute("info", HttpMethod.GET); + // TODO + + return new Project(); + } + +} diff --git a/src/de/openrat/client/dto/CMSObject.java b/src/de/openrat/client/dto/CMSObject.java @@ -0,0 +1,78 @@ +package de.openrat.client.dto; + +import java.io.Serializable; + +import de.openrat.client.util.Id; + +public class CMSObject implements Serializable +{ + private static final long serialVersionUID = -7483013624561450027L; + + private Id id; + + /** + * Inhalt des Feldes <code>id</code>. + * + * @return id + */ + public Id getId() + { + return id; + } + + /** + * Setzt das Feld <code>id</code>. + * + * @param id + * id + */ + public void setId(Id id) + { + this.id = id; + } + + /** + * {@inheritDoc} + * + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() + { + final int prime = 31; + int result = 1; + result = prime * result + ((id == null) ? 0 : id.hashCode()); + return result; + } + + /** + * {@inheritDoc} + * + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) + { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + CMSObject other = (CMSObject) obj; + if (id == null) + { + if (other.id != null) + return false; + } + else if (!id.equals(other.id)) + return false; + return true; + } + + @Override + public String toString() + { + return super.toString() + ": Id " + id.longValue(); + } +} diff --git a/src/de/openrat/client/dto/Language.java b/src/de/openrat/client/dto/Language.java @@ -0,0 +1,6 @@ +package de.openrat.client.dto; + +public class Language extends CMSObject +{ + +} diff --git a/src/de/openrat/client/dto/Project.java b/src/de/openrat/client/dto/Project.java @@ -0,0 +1,6 @@ +package de.openrat.client.dto; + +public class Project extends CMSObject +{ + +} diff --git a/src/de/openrat/client/dto/Template.java b/src/de/openrat/client/dto/Template.java @@ -0,0 +1,6 @@ +package de.openrat.client.dto; + +public class Template extends CMSObject +{ + +} diff --git a/src/de/openrat/client/dto/User.java b/src/de/openrat/client/dto/User.java @@ -0,0 +1,28 @@ +package de.openrat.client.dto; + +public class User extends CMSObject +{ + private String name; + + /** + * Inhalt des Feldes <code>name</code>. + * + * @return name + */ + public String getName() + { + return name; + } + + /** + * Setzt das Feld <code>name</code>. + * + * @param name + * name + */ + public void setName(String name) + { + this.name = name; + } + +} diff --git a/src/de/openrat/client/util/CMSConnection.java b/src/de/openrat/client/util/CMSConnection.java @@ -0,0 +1,463 @@ +/* +OpenRat Java-Client +Copyright (C) 2009 Jan Dankert + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this library; if not, write to the +Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, +Boston, MA 02110-1301, USA. + + */ +package de.openrat.client.util; + +import java.io.PrintWriter; +import java.net.Socket; +import java.util.Locale; + +/** + * API-Request to the OpenRat Content Management System. <br> + * <br> + * The call to the CMS server is done via a (non-SSL) HTTP connection.<br> + * <br> + * Before a call you are able to set some key/value-pairs as parameters. After + * calling the CMS a DOM-document is returned, which contains the server + * response.<br> + * Example <br> + * + * <pre> + * CMSRequest request = new CMSRequest(&quot;your.openrat.example.com&quot;); + * // prints tracing information to stdout. + * request.trace = true; + * try + * { + * request.parameter.put(&quot;action&quot;, &quot;index&quot;); + * request.parameter.put(&quot;subaction&quot;, &quot;showlogin&quot;); // login page + * request.parameter.put(&quot;...&quot;, &quot;...&quot;); + * Document response = request.call(); + * // now traverse through the dom tree and get your information. + * } + * catch (IOException e) + * { + * // your error handling. + * } + * </pre> + * + * @author Jan Dankert + */ +public class CMSConnection +{ + + private String serverPath; + private String serverHost; + private int serverPort; + private boolean secure; + + private String proxyHostname; + private int proxyPort; + + private String proxyUser; + private String proxyPassword; + + private PrintWriter logWriter; + + private CookieStoreMap cookieStore = new CookieStoreMap(); + private String token = ""; + + private String paramActionName = "action"; + private String paramMethodName = "subaction"; + + private Locale locale = Locale.getDefault(); + private int timeout = 5000; + private boolean keepAlive; + private Socket socket; + + /** + * Inhalt des Feldes <code>socket</code>. + * + * @return socket + */ + public Socket getSocket() + { + return socket; + } + + /** + * Setzt das Feld <code>socket</code>. + * + * @param socket + * socket + */ + public void setSocket(Socket socket) + { + this.socket = socket; + } + + /** + * Inhalt des Feldes <code>timeout</code>. + * + * @return timeout + */ + public int getTimeout() + { + return timeout; + } + + /** + * Constructs a CMS-Request to the specified server/path/port. + * + * @param host + * hostname + * @param port + * port-number + * @param path + * path + */ + public CMSConnection(String host, int port, String path) + { + + super(); + this.serverHost = host; + this.serverPath = path; + this.serverPort = port; + + if (this.serverHost.startsWith("https://")) + { + secure = true; + if (port == 80) + { + this.serverPort = 443; + } + this.serverHost = this.serverHost.substring(8); + } + else if (this.serverHost.startsWith("http://")) + { + this.serverHost = this.serverHost.substring(7); + } + else if (port == 443) + { + secure = true; + } + } + + /** + * Inhalt des Feldes <code>serverPath</code>. + * + * @return serverPath + */ + public String getServerPath() + { + return serverPath; + } + + /** + * Setzt das Feld <code>serverPath</code>. + * + * @param serverPath + * serverPath + */ + public void setServerPath(String serverPath) + { + this.serverPath = serverPath; + } + + /** + * Inhalt des Feldes <code>serverHost</code>. + * + * @return serverHost + */ + public String getServerHost() + { + return serverHost; + } + + /** + * Setzt das Feld <code>serverHost</code>. + * + * @param serverHost + * serverHost + */ + public void setServerHost(String serverHost) + { + this.serverHost = serverHost; + } + + /** + * Inhalt des Feldes <code>serverPort</code>. + * + * @return serverPort + */ + public int getServerPort() + { + return serverPort; + } + + /** + * Setzt das Feld <code>serverPort</code>. + * + * @param serverPort + * serverPort + */ + public void setServerPort(int serverPort) + { + this.serverPort = serverPort; + } + + /** + * Inhalt des Feldes <code>proxyHostname</code>. + * + * @return proxyHostname + */ + public String getProxyHostname() + { + return proxyHostname; + } + + /** + * Setzt das Feld <code>proxyHostname</code>. + * + * @param proxyHostname + * proxyHostname + */ + public void setProxyHostname(String proxyHostname) + { + this.proxyHostname = proxyHostname; + } + + /** + * Inhalt des Feldes <code>proxyPort</code>. + * + * @return proxyPort + */ + public int getProxyPort() + { + return proxyPort; + } + + /** + * Setzt das Feld <code>proxyPort</code>. + * + * @param proxyPort + * proxyPort + */ + public void setProxyPort(int proxyPort) + { + this.proxyPort = proxyPort; + } + + /** + * Setzt das Feld <code>logWriter</code>. + * + * @param logWriter + * logWriter + */ + public void setLogWriter(PrintWriter logWriter) + { + this.logWriter = logWriter; + } + + /** + * Setzt das Feld <code>secure</code>. + * + * @param secure + * secure + */ + public void setSecure(boolean secure) + { + this.secure = secure; + } + + /** + * Setzt das Feld <code>proxyUser</code>. + * + * @param proxyUser + * proxyUser + */ + public void setProxyUser(String proxyUser) + { + this.proxyUser = proxyUser; + } + + /** + * Setzt das Feld <code>proxyPassword</code>. + * + * @param proxyPassword + * proxyPassword + */ + public void setProxyPassword(String proxyPassword) + { + this.proxyPassword = proxyPassword; + } + + /** + * Inhalt des Feldes <code>proxyUser</code>. + * + * @return proxyUser + */ + public String getProxyUser() + { + return proxyUser; + } + + /** + * Inhalt des Feldes <code>proxyPassword</code>. + * + * @return proxyPassword + */ + public String getProxyPassword() + { + return proxyPassword; + } + + public PrintWriter getLogWriter() + { + return logWriter; + } + + /** + * Inhalt des Feldes <code>cookieStore</code>. + * + * @return cookieStore + */ + public CookieStoreMap getCookieStore() + { + return cookieStore; + } + + /** + * Inhalt des Feldes <code>token</code>. + * + * @return token + */ + public String getToken() + { + return token; + } + + /** + * Setzt das Feld <code>token</code>. + * + * @param token + * token + */ + public void setToken(String token) + { + this.token = token; + } + + /** + * Inhalt des Feldes <code>secure</code>. + * + * @return secure + */ + public boolean isSecure() + { + return secure; + } + + /** + * Inhalt des Feldes <code>paramActionName</code>. + * + * @return paramActionName + */ + public String getParamActionName() + { + return paramActionName; + } + + /** + * Setzt das Feld <code>paramActionName</code>. + * + * @param paramActionName + * paramActionName + */ + public void setParamActionName(String paramActionName) + { + this.paramActionName = paramActionName; + } + + /** + * Inhalt des Feldes <code>paramMethodName</code>. + * + * @return paramMethodName + */ + public String getParamMethodName() + { + return paramMethodName; + } + + /** + * Setzt das Feld <code>paramMethodName</code>. + * + * @param paramMethodName + * paramMethodName + */ + public void setParamMethodName(String paramMethodName) + { + this.paramMethodName = paramMethodName; + } + + /** + * Inhalt des Feldes <code>locale</code>. + * + * @return locale + */ + public Locale getLocale() + { + return this.locale; + } + + /** + * Setzt das Feld <code>locale</code>. + * + * @param locale + * locale + */ + public void setLocale(Locale locale) + { + this.locale = locale; + } + + /** + * Setzt das Feld <code>timeout</code>. + * + * @param timeout + * timeout + */ + public void setTimeout(int timeout) + { + this.timeout = timeout; + } + + /** + * Setzt das Feld <code>keepAlive</code>. + * + * @param keepAlive + * keepAlive + */ + public void setKeepAlive(boolean keepAlive) + { + this.keepAlive = keepAlive; + } + + public boolean isKeepAlive() + { + return keepAlive; + } + + @Override + public String toString() + { + return super.toString() + ": " + serverHost + ":" + serverPort + serverPath; + + } +} diff --git a/src/de/openrat/client/util/CMSControl.java b/src/de/openrat/client/util/CMSControl.java @@ -0,0 +1,6 @@ +package de.openrat.client.util; + +public class CMSControl +{ + +} diff --git a/src/de/openrat/client/util/CMSError.java b/src/de/openrat/client/util/CMSError.java @@ -0,0 +1,100 @@ +package de.openrat.client.util; + +public class CMSError +{ + + public static enum CMSErrorStatus + { + NOTICE, WARN, ERROR; + } + + private CMSErrorStatus status; + private String type; + private String message; + private String reason; + + /** + * Inhalt des Feldes <code>status</code>. + * + * @return status + */ + public CMSErrorStatus getStatus() + { + return status; + } + + /** + * Setzt das Feld <code>status</code>. + * + * @param status + * status + */ + public void setStatus(CMSErrorStatus status) + { + this.status = status; + } + + /** + * Inhalt des Feldes <code>type</code>. + * + * @return type + */ + public String getType() + { + return type; + } + + /** + * Setzt das Feld <code>type</code>. + * + * @param type + * type + */ + public void setType(String type) + { + this.type = type; + } + + /** + * Inhalt des Feldes <code>message</code>. + * + * @return message + */ + public String getMessage() + { + return message; + } + + /** + * Setzt das Feld <code>message</code>. + * + * @param message + * message + */ + public void setMessage(String message) + { + this.message = message; + } + + /** + * Inhalt des Feldes <code>reason</code>. + * + * @return reason + */ + public String getReason() + { + return reason; + } + + /** + * Setzt das Feld <code>reason</code>. + * + * @param reason + * reason + */ + public void setReason(String reason) + { + this.reason = reason; + } + +} diff --git a/src/de/openrat/client/util/CMSException.java b/src/de/openrat/client/util/CMSException.java @@ -0,0 +1,87 @@ +package de.openrat.client.util; + +public class CMSException extends RuntimeException +{ + + private static final long serialVersionUID = 3734310284809339317L; + + private String message; + private String status; + private String description; + private String reason; + + public CMSException(String message, Throwable cause) + { + super(message, cause); + } + + public CMSException(String message, String status, String description, String reason, Throwable cause) + { + super(message, cause); + + this.message = message; + this.status = status; + this.description = description; + this.reason = reason; + } + + public CMSException(String message, String status, String description, String reason) + { + super(message); + + this.message = message; + this.status = status; + this.description = description; + this.reason = reason; + } + + public CMSException(String message) + { + super(message); + this.message = message; + } + + public CMSException(Throwable cause) + { + super(cause); + this.message = cause.getMessage(); + } + + /** + * Inhalt des Feldes <code>status</code>. + * + * @return status + */ + public String getStatus() + { + return status; + } + + /** + * Inhalt des Feldes <code>description</code>. + * + * @return description + */ + public String getDescription() + { + return description; + } + + /** + * Inhalt des Feldes <code>reason</code>. + * + * @return reason + */ + public String getReason() + { + return reason; + } + + @Override + public String getMessage() + { + String message = this.message + " - Status: " + this.status + ", Description: " + this.description + ", Reason: " + this.reason; + + return message; + } +} diff --git a/src/de/openrat/client/util/CMSNode.java b/src/de/openrat/client/util/CMSNode.java @@ -0,0 +1,72 @@ +package de.openrat.client.util; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class CMSNode +{ + + private static final CMSNode EMPTY_NODE = new CMSNode(null, null, null); + private String name; + private String value; + private Map<String, CMSNode> children; + + public CMSNode(String name, String value, Map<String, CMSNode> children) + { + super(); + this.name = name; + this.value = value; + this.children = children; + } + + public List<CMSNode> getChildren() + { + + if (children != null) + return new ArrayList<CMSNode>(children.values()); + else + return new ArrayList<CMSNode>(); + } + + public CMSNode getChild(String name) + { + + if (children == null) + return EMPTY_NODE; + + CMSNode node = children.get(name); + + if (node != null) + return node; + else + return EMPTY_NODE; + } + + public String getValue() + { + return value; + } + + public String getName() + { + return name; + } + + public boolean isEmpty() + { + return name == null; + } + + public boolean isNotEmpty() + { + return !isEmpty(); + } + + @Override + public String toString() + { + return this.getClass().getSimpleName() + ": " + getName() + "=" + getValue() + " children:" + children.size() + " " + + children.toString(); + } +} diff --git a/src/de/openrat/client/util/CMSRequest.java b/src/de/openrat/client/util/CMSRequest.java @@ -0,0 +1,333 @@ +/* +OpenRat Java-Client +Copyright (C) 2009 Jan Dankert + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this library; if not, write to the +Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, +Boston, MA 02110-1301, USA. + + */ +package de.openrat.client.util; + +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringReader; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.NoSuchElementException; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +import de.openrat.client.CMSClient; +import de.openrat.client.util.HttpRequest.HttpMethod; + +/** + * API-Request to the OpenRat Content Management System. <br> + * <br> + * The call to the CMS server is done via a (non-SSL) HTTP connection.<br> + * <br> + * Before a call you are able to set some key/value-pairs as parameters. After + * calling the CMS a DOM-document is returned, which contains the server + * response.<br> + * Example <br> + * + * <pre> + * CMSRequest request = new CMSRequest(&quot;your.openrat.example.com&quot;); + * // prints tracing information to stdout. + * request.trace = true; + * try + * { + * request.parameter.put(&quot;action&quot;, &quot;index&quot;); + * request.parameter.put(&quot;subaction&quot;, &quot;showlogin&quot;); // login page + * request.parameter.put(&quot;...&quot;, &quot;...&quot;); + * Document response = request.call(); + * // now traverse through the dom tree and get your information. + * } + * catch (IOException e) + * { + * // your error handling. + * } + * </pre> + * + * @author Jan Dankert + */ +public class CMSRequest +{ + + private ParameterMap parameter = new ParameterMap(); + + private PrintWriter logWriter; + + private HttpMethod method = HttpMethod.GET; + + private CMSConnection connection; + + /** + * Set the HTTP Method. Default is "GET". + * + * @param method + * HTTP-method + */ + public void setMethod(HttpMethod method) + { + + this.method = method; + } + + /** + * Constructs a CMS-Request to the specified server/path/port. + * + * @param host + * hostname + * @param path + * path + * @param port + * port-number + */ + public CMSRequest(CMSConnection connection) + { + + super(); + this.connection = connection; + this.logWriter = connection.getLogWriter(); + } + + /** + * Sends a request to the openrat-server and parses the response into a DOM + * tree document. + * + * @return server response as a DOM tree + * @throws IOException + * if server is unrechable or responds non-wellformed XML + */ + public CMSResponse execute() throws IOException + { + + parameter.put("token", connection.getToken()); + + HttpRequest httpRequest = new HttpRequest(); + httpRequest.setMethod(method); + + httpRequest.getRequestHeader().put("User-Agent", "Mozilla/5.0; compatible (OpenRat CMS java-client)"); + httpRequest.getRequestHeader().put("Accept", "application/xml"); + httpRequest.getRequestHeader().put("Accept-Charset", "utf-8"); + + final HttpClient httpClient = new HttpClient(connection); + httpClient.getParameter().putAll(parameter); + + HttpResponse httpResponse = httpClient.execute(httpRequest); + + final CMSNode rootNode; + try + { + // Try XML parsing + final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + final DocumentBuilder builder = factory.newDocumentBuilder(); + final Document document = builder.parse(new InputSource(new StringReader(httpResponse.getPayload()))); + rootNode = convertXMLNodeIntoCMSNode(document.getDocumentElement()); + } + catch (ParserConfigurationException e) + { + if (logWriter != null) + { + e.printStackTrace(logWriter); + } + throw new CMSException("XML-Parser-Configuration invalid", "", "", e.getMessage(), e); + } + catch (SAXException e) + { + throw new CMSException("Server did not return a valid XML-document: " + httpResponse.getPayload(), "" + + httpResponse.getHttpStatus().getStatusCode(), httpResponse.getHttpStatus().getServerMessage(), e.getMessage(), e); + } + + CMSResponse cmsResponse = createCMSResponse(httpResponse.getHttpStatus(), rootNode); + + cmsResponse.setHttpStatus(httpResponse.getHttpStatus().getStatusCode()); + connection.setToken(cmsResponse.getSession().getToken()); + return cmsResponse; + } + + /** + * Erzeugt aus + * + * @param httpStatus + * + * @param rootNode + * @return + */ + private CMSResponse createCMSResponse(HttpStatus httpStatus, final CMSNode rootNode) + { + + if (httpStatus.getStatusCode() == 204) + { + return null; // No content + } + + if (httpStatus.isServerError()) + { + if (rootNode.getName() == "error") + { + // Server reports an technical error. + String error = rootNode.getChild("error").getValue(); + String status = rootNode.getChild("status").getValue(); + String description = rootNode.getChild("description").getValue(); + String reason = rootNode.getChild("reason").getValue(); + + throw new CMSException(error, status, description, reason); + + } + else + { + throw new CMSException(httpStatus.getServerMessage(), "" + httpStatus.getStatusCode(), "", ""); + } + + } + + if (httpStatus.getStatusCode() == 200) + { + + if (rootNode.getName() == "server") + { + // Server reports an answer + + // Do we support the server api version? + int apiVersion = Integer.parseInt(rootNode.getChild("api").getValue()); + + if (apiVersion != CMSClient.SUPPORTED_API_VERSION) + { + // oh no, the server api is older or newer than our client + // api. + // there is nothing we can do. + throw new CMSException("Only API Version 2 is supported. The server is using API Version " + rootNode.getChild("api")); + } + + CMSResponse cmsResponse = new CMSResponse(); + + cmsResponse.setApi(apiVersion); + cmsResponse.setVersion(rootNode.getChild("version").getValue()); + + List<CMSError> errorList = new ArrayList<CMSError>(); + for (CMSNode errorNode : rootNode.getChild("errors").getChildren()) + { + CMSError error = new CMSError(); + errorList.add(error); + } + cmsResponse.setError(errorList.toArray(new CMSError[] {})); + + CMSControl control = new CMSControl(); + cmsResponse.setControl(control); + + CMSNode sessionNode = rootNode.getChild("session"); + CMSSession session = new CMSSession(); + session.setName(sessionNode.getChild("name").getValue()); + session.setId(sessionNode.getChild("id").getValue()); + session.setToken(sessionNode.getChild("token").getValue()); + cmsResponse.setSession(session); + + cmsResponse.setOutput(rootNode.getChild("outpout")); + + return cmsResponse; + } + else + { + // HTTP-Status 200 OK, but no XML-Element "server" found. + throw new CMSException(httpStatus.getServerMessage(), "" + httpStatus.getStatusCode(), "", "no SERVER element found"); + } + } + else + { + // Unknown HTTP Status + throw new CMSException(httpStatus.getServerMessage(), "" + httpStatus.getStatusCode(), "", "Unsupported HTTP Status"); + } + } + + public void setLogWriter(PrintWriter logWriter) + { + this.logWriter = logWriter; + } + + public static Iterable<Node> iterable(final NodeList n) + { + + return new Iterable<Node>() + { + + public Iterator<Node> iterator() + { + + return new Iterator<Node>() + { + + int index = 0; + + public boolean hasNext() + { + return index < n.getLength(); + } + + public Node next() + { + if (hasNext()) + { + return n.item(index++); + } + else + { + throw new NoSuchElementException(); + } + } + + public void remove() + { + throw new UnsupportedOperationException(); + } + }; + } + }; + } + + private static CMSNode convertXMLNodeIntoCMSNode(Node node) + { + + Map<String, CMSNode> children = new HashMap<String, CMSNode>(); + + for (Node nodex : iterable(node.getChildNodes())) + { + if (nodex.getNodeType() == Node.ELEMENT_NODE) + { + + CMSNode childNode = convertXMLNodeIntoCMSNode(nodex); + children.put(nodex.getNodeName(), childNode); + } + } + + return new CMSNode(node.getNodeName(), node.getTextContent(), children); + } + + public ParameterMap getParameter() + { + return parameter; + } +} diff --git a/src/de/openrat/client/util/CMSResponse.java b/src/de/openrat/client/util/CMSResponse.java @@ -0,0 +1,185 @@ +/* +OpenRat Java-Client +Copyright (C) 2009 Jan Dankert + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this library; if not, write to the +Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, +Boston, MA 02110-1301, USA. + + */ +package de.openrat.client.util; + + +/** + * @author Jan Dankert + */ +public class CMSResponse +{ + + private CMSError[] error; + private CMSNode output; + private CMSControl control; + private CMSSession session; + private int httpStatus; + + private int api; + private String version; + + /** + * Inhalt des Feldes <code>error</code>. + * + * @return error + */ + public CMSError[] getError() + { + return error; + } + + /** + * Setzt das Feld <code>error</code>. + * + * @param error + * error + */ + public void setError(CMSError[] error) + { + this.error = error; + } + + /** + * Inhalt des Feldes <code>output</code>. + * + * @return output + */ + public CMSNode getOutput() + { + return output; + } + + /** + * Setzt das Feld <code>output</code>. + * + * @param cmsNode + * output + */ + public void setOutput(CMSNode cmsNode) + { + this.output = cmsNode; + } + + /** + * Inhalt des Feldes <code>control</code>. + * + * @return control + */ + public CMSControl getControl() + { + return control; + } + + /** + * Setzt das Feld <code>control</code>. + * + * @param control + * control + */ + public void setControl(CMSControl control) + { + this.control = control; + } + + /** + * Inhalt des Feldes <code>api</code>. + * + * @return api + */ + public int getApi() + { + return api; + } + + /** + * Setzt das Feld <code>api</code>. + * + * @param api + * api + */ + public void setApi(int api) + { + this.api = api; + } + + /** + * Inhalt des Feldes <code>version</code>. + * + * @return version + */ + public String getVersion() + { + return version; + } + + /** + * Setzt das Feld <code>version</code>. + * + * @param version + * version + */ + public void setVersion(String version) + { + this.version = version; + } + + /** + * Inhalt des Feldes <code>session</code>. + * + * @return session + */ + public CMSSession getSession() + { + return session; + } + + /** + * Setzt das Feld <code>session</code>. + * + * @param session + * session + */ + public void setSession(CMSSession session) + { + this.session = session; + } + + /** + * Inhalt des Feldes <code>httpStatus</code>. + * + * @return httpStatus + */ + public int getHttpStatus() + { + return httpStatus; + } + + /** + * Setzt das Feld <code>httpStatus</code>. + * + * @param httpStatus + * httpStatus + */ + public void setHttpStatus(int httpStatus) + { + this.httpStatus = httpStatus; + } +} diff --git a/src/de/openrat/client/util/CMSSession.java b/src/de/openrat/client/util/CMSSession.java @@ -0,0 +1,73 @@ +package de.openrat.client.util; + +public class CMSSession +{ + + private String name; + private String id; + private String token; + + /** + * Inhalt des Feldes <code>name</code>. + * + * @return name + */ + public String getName() + { + return name; + } + + /** + * Setzt das Feld <code>name</code>. + * + * @param name + * name + */ + public void setName(String name) + { + this.name = name; + } + + /** + * Inhalt des Feldes <code>id</code>. + * + * @return id + */ + public String getId() + { + return id; + } + + /** + * Setzt das Feld <code>id</code>. + * + * @param id + * id + */ + public void setId(String id) + { + this.id = id; + } + + /** + * Inhalt des Feldes <code>token</code>. + * + * @return token + */ + public String getToken() + { + return token; + } + + /** + * Setzt das Feld <code>token</code>. + * + * @param token + * token + */ + public void setToken(String token) + { + this.token = token; + } + +} diff --git a/src/de/openrat/client/util/CookieStoreMap.java b/src/de/openrat/client/util/CookieStoreMap.java @@ -0,0 +1,65 @@ +package de.openrat.client.util; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +public class CookieStoreMap +{ + private Map<String, String> cookies = new HashMap<String, String>(); + + /** + * @return + * @see java.util.Map#size() + */ + public int size() + { + return cookies.size(); + } + + /** + * @param key + * @return + * @see java.util.Map#containsKey(java.lang.Object) + */ + public boolean containsKey(Object key) + { + return cookies.containsKey(key); + } + + /** + * @param key + * @return + * @see java.util.Map#get(java.lang.Object) + */ + public String get(Object key) + { + return cookies.get(key); + } + + /** + * @param key + * @param value + * @return + * @see java.util.Map#put(java.lang.Object, java.lang.Object) + */ + public String put(String key, String value) + { + return cookies.put(key, value); + } + + /** + * @return + * @see java.util.Map#values() + */ + public Collection<String> values() + { + return cookies.values(); + } + + public String getCookieRequestHeader() + { + + return new MapConverter(cookies).convertMapToString("=", "; ", false); + } +} diff --git a/src/de/openrat/client/util/HttpClient.java b/src/de/openrat/client/util/HttpClient.java @@ -0,0 +1,380 @@ +/* +OpenRat Java-Client +Copyright (C) 2009 Jan Dankert + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this library; if not, write to the +Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, +Boston, MA 02110-1301, USA. + + */ +package de.openrat.client.util; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.net.ConnectException; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.net.SocketAddress; + +import javax.net.SocketFactory; +import javax.net.ssl.SSLSocketFactory; +import javax.xml.bind.DatatypeConverter; + +import de.openrat.client.util.HttpRequest.HttpMethod; + +/** + * API-Request to the OpenRat Content Management System. <br> + * <br> + * The call to the CMS server is done via a (non-SSL) HTTP connection.<br> + * <br> + * Before a call you are able to set some key/value-pairs as parameters. After + * calling the CMS a DOM-document is returned, which contains the server + * response.<br> + * Example <br> + * + * <pre> + * CMSRequest request = new CMSRequest(&quot;your.openrat.example.com&quot;); + * // prints tracing information to stdout. + * request.trace = true; + * try + * { + * request.parameter.put(&quot;action&quot;, &quot;index&quot;); + * request.parameter.put(&quot;subaction&quot;, &quot;showlogin&quot;); // login page + * request.parameter.put(&quot;...&quot;, &quot;...&quot;); + * Document response = request.call(); + * // now traverse through the dom tree and get your information. + * } + * catch (IOException e) + * { + * // your error handling. + * } + * </pre> + * + * @author Jan Dankert + */ +public class HttpClient +{ + private static final String HTTP_VERSION = "HTTP/1.0"; + + private PrintWriter logWriter; + + private CMSConnection connection; + + private ParameterMap parameter = new ParameterMap(); + + /** + * Constructs a CMS-Request to the specified server/path/port. + * + * @param host + * hostname + * @param path + * path + * @param port + * port-number + */ + public HttpClient(CMSConnection connection) + { + + super(); + this.connection = connection; + this.logWriter = connection.getLogWriter(); + } + + /** + * Sends a request to the openrat-server and parses the response into a DOM + * tree document. + * + * @return server response as a DOM tree + * @throws IOException + * if server is unrechable or responds non-wellformed XML + */ + public HttpResponse execute(HttpRequest request) throws IOException + { + final Socket socket = this.createSocket(); + + try + { + + String httpUrl = this.connection.getServerPath(); + + final PrintWriter socketWriter = new PrintWriter(socket.getOutputStream(), true); + + if (connection.getProxyHostname() != null) + // See RFC 2616 Section 5.1.2 "Request-URI" + // "The absolute URI form is REQUIRED when the request is being made to a proxy" + httpUrl = "http://" + this.connection.getServerHost() + httpUrl; + + String queryString = parameter.toQueryString(); + if (HttpMethod.GET.equals(request.getMethod())) + httpUrl = httpUrl + "?" + queryString; + + // using HTTP/1.0 as this is supported by all HTTP-servers and + // proxys. + // We have no need for HTTP/1.1 at the moment. + String httpCommandLine = request.getMethod().name() + " " + httpUrl + " " + HTTP_VERSION + "\n"; + + socketWriter.write(httpCommandLine); + + HttpHeaderMap requestHeader = new HttpHeaderMap(); + + // Setting the HTTP Header + requestHeader.put("Host", this.connection.getServerHost()); + requestHeader.put("Accept-Language", connection.getLocale().getLanguage()); + requestHeader.put("User-Agent", "Mozilla/5.0; compatible (" + HttpClient.class.getName() + ")"); + + requestHeader.putAll(request.getRequestHeader()); + + String connectionStatus = connection.isKeepAlive() ? "keep-alive" : "close"; + requestHeader.put("Connection", connectionStatus); + + if (this.connection.getProxyUser() != null) + { + final String userPass = DatatypeConverter.printBase64Binary((connection.getProxyUser() + ":" + connection + .getProxyPassword()).getBytes()); + requestHeader.put("Proxy-Authorization", "Basic " + userPass); + } + + String cookieHeader = connection.getCookieStore().getCookieRequestHeader(); + + if (cookieHeader.length() > 0) + requestHeader.put("Cookie", cookieHeader); + + if (HttpMethod.POST.equals(request.getMethod())) + { + requestHeader.put("Content-Type", "application/x-www-form-urlencoded"); + requestHeader.put("Content-Length", "" + queryString.length()); + + } + + // write HTTP-request-headers to socket + socketWriter.write(requestHeader.toHttpHeaderString()); + // empty line after HTTP headers + socketWriter.write("\n"); + + if (this.logWriter != null) + { + logWriter.println("--- HTTP-Request ---"); + logWriter.println(httpCommandLine); + logWriter.println(requestHeader.toHttpHeaderString()); + } + + // POST-request have the payload in the body + if (HttpMethod.POST.equals(request.getMethod())) + { + + if (this.logWriter != null) + { + logWriter.println("\n" + queryString); + } + + socketWriter.write(queryString); + } + + socketWriter.flush(); + + // now waiting for the answer... + final BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream())); + + String readLine = bufferedReader.readLine(); + + if (readLine == null) + { + throw new CMSException("Server response is empty"); + } + + final String httpServerResponse = readLine.trim(); + final String httpStatusCode = httpServerResponse.substring(9, 12); + final String httpServerMessage = httpServerResponse.substring(13); + + if (this.logWriter != null) + { + + logWriter.println("--- HTTP-Response ---"); + logWriter.println(httpServerResponse); + } + + HttpHeaderMap responseHeader = new HttpHeaderMap(); + // Analyze the HTTP response headers + while (true) + { + String responseHeaderString = bufferedReader.readLine().trim(); + + if (responseHeaderString.equals("")) + break; + + int pos = responseHeaderString.indexOf(": "); + if (pos > 1) + { + String key = responseHeaderString.substring(0, pos); + String value = responseHeaderString.substring(pos + 2); + responseHeader.put(key, value); + } + else + { + throw new CMSException("Unknown HTTP response header:" + responseHeaderString); + } + + } + + if (this.logWriter != null) + logWriter.println(responseHeader.toHttpHeaderString()); + + if (responseHeader.containsKey("Set-Cookie")) + { + this.parseRawCookie(responseHeader.get("Set-Cookie")); + } + + StringBuffer responseString = new StringBuffer(); + // while (bufferedReader.ready()) + // { + // responseString.append(bufferedReader.readLine() + "\n"); + // } + + String buffer; + while ((buffer = bufferedReader.readLine()) != null) + { + responseString.append(buffer + "\n"); + } + + if (this.logWriter != null) + { + logWriter.println(); + logWriter.println(responseString + "\n\n\n"); + logWriter.flush(); + } + + final HttpResponse httpResponse = new HttpResponse(); + httpResponse.setPayload(responseString.toString()); + httpResponse.setHttpStatus(new HttpStatus(NumberUtils.toInt(httpStatusCode), httpServerMessage)); + + return httpResponse; + } + finally + { + // always close the socket because sockets are not endless resources + if (!connection.isKeepAlive()) + try + { + socket.close(); + } + catch (Exception e) + { + ; // we have done our very best to close the socket + } + } + } + + public Socket createSocket() throws IOException + { + + if (connection.getSocket() != null && connection.isKeepAlive()) + { + if (logWriter != null) + { + logWriter.println("Reusing socket: " + connection.getSocket().toString()); + } + + return connection.getSocket(); + } + + // When a client uses a proxy, it typically sends all requests to that + // proxy, instead + // of to the servers in the URLs. Requests to a proxy differ from normal + // requests in one + // way: in the first line, they use the complete URL of the resource + // being requested, + // instead of just the path. + + final boolean useProxy = connection.getProxyHostname() != null; + + SocketFactory socketFactory; + if (connection.isSecure()) + { + socketFactory = SSLSocketFactory.getDefault(); + } + else + { + socketFactory = SocketFactory.getDefault(); + } + + Socket socket = socketFactory.createSocket(); + + SocketAddress socketAddress; + if (useProxy) + { + socketAddress = new InetSocketAddress(connection.getProxyHostname(), connection.getProxyPort()); + } + else + { + socketAddress = new InetSocketAddress(connection.getServerHost(), connection.getServerPort()); + } + + if (logWriter != null) + { + logWriter.println("Creating Socket: " + socketAddress.toString()); + } + + socket.setKeepAlive(connection.isKeepAlive()); + socket.setReuseAddress(false); + + try + { + socket.connect(socketAddress, connection.getTimeout()); + } + catch (ConnectException e) + { + throw new CMSException("cannot connect to " + socketAddress.toString(), "", "", e.getMessage(), e); + } + + if (connection.isKeepAlive()) + { + connection.setSocket(socket); + } + + return socket; + } + + public void setLogWriter(PrintWriter logWriter) + { + this.logWriter = logWriter; + } + + private void parseRawCookie(String rawCookie) + { + + String[] rawCookieParams = rawCookie.split(";"); + String[] rawCookieNameAndValue = rawCookieParams[0].split("="); + + if (rawCookieNameAndValue.length != 2) + { + this.logWriter.println("Set-Cookie: " + rawCookie + " - Invalid cookie: missing name and value"); + } + + String cookieName = rawCookieNameAndValue[0].trim(); + String cookieValue = rawCookieNameAndValue[1].trim(); + + connection.getCookieStore().put(cookieName, cookieValue); + + // Ignoring all cookie attributes, because we are only storing the + // cookies for this session. + } + + public ParameterMap getParameter() + { + return parameter; + } + +} diff --git a/src/de/openrat/client/util/HttpHeaderMap.java b/src/de/openrat/client/util/HttpHeaderMap.java @@ -0,0 +1,70 @@ +package de.openrat.client.util; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +public class HttpHeaderMap +{ + private Map<String, String> header = new HashMap<String, String>(); + + /** + * @return + * @see java.util.Map#size() + */ + public int size() + { + return header.size(); + } + + /** + * @param key + * @return + * @see java.util.Map#containsKey(java.lang.Object) + */ + public boolean containsKey(Object key) + { + return header.containsKey(key); + } + + /** + * @param key + * @return + * @see java.util.Map#get(java.lang.Object) + */ + public String get(Object key) + { + return header.get(key); + } + + /** + * @param key + * @param value + * @return + * @see java.util.Map#put(java.lang.Object, java.lang.Object) + */ + public String put(String key, String value) + { + return header.put(key, value); + } + + /** + * @return + * @see java.util.Map#values() + */ + public Collection<String> values() + { + return header.values(); + } + + public String toHttpHeaderString() + { + + return new MapConverter(header).convertMapToString(": ", "\n", true); + } + + public void putAll(HttpHeaderMap requestHeader) + { + header.putAll(requestHeader.header); + } +} diff --git a/src/de/openrat/client/util/HttpRequest.java b/src/de/openrat/client/util/HttpRequest.java @@ -0,0 +1,123 @@ +/* +OpenRat Java-Client +Copyright (C) 2009 Jan Dankert + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this library; if not, write to the +Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, +Boston, MA 02110-1301, USA. + + */ +package de.openrat.client.util; + +/** + * API-Request to the OpenRat Content Management System. <br> + * <br> + * The call to the CMS server is done via a (non-SSL) HTTP connection.<br> + * <br> + * Before a call you are able to set some key/value-pairs as parameters. After + * calling the CMS a DOM-document is returned, which contains the server + * response.<br> + * Example <br> + * + * <pre> + * CMSRequest request = new CMSRequest(&quot;your.openrat.example.com&quot;); + * // prints tracing information to stdout. + * request.trace = true; + * try + * { + * request.parameter.put(&quot;action&quot;, &quot;index&quot;); + * request.parameter.put(&quot;subaction&quot;, &quot;showlogin&quot;); // login page + * request.parameter.put(&quot;...&quot;, &quot;...&quot;); + * Document response = request.call(); + * // now traverse through the dom tree and get your information. + * } + * catch (IOException e) + * { + * // your error handling. + * } + * </pre> + * + * @author Jan Dankert + */ +public class HttpRequest +{ + + public static enum HttpMethod + { + + GET, POST; + } + + private HttpHeaderMap requestHeader = new HttpHeaderMap(); + private String payload; + + /** + * HTTP-method, must be "GET" or "POST", default: "GET". + */ + private HttpMethod method = HttpMethod.GET; + + /** + * Set the HTTP Method. Default is "GET". + * + * @param method + * HTTP-method + */ + public void setMethod(HttpMethod method) + { + + this.method = method; + } + + /** + * Inhalt des Feldes <code>payload</code>. + * + * @return payload + */ + public String getPayload() + { + return payload; + } + + /** + * Setzt das Feld <code>payload</code>. + * + * @param payload + * payload + */ + public void setPayload(String payload) + { + this.payload = payload; + } + + /** + * Inhalt des Feldes <code>requestHeader</code>. + * + * @return requestHeader + */ + public HttpHeaderMap getRequestHeader() + { + return requestHeader; + } + + /** + * Inhalt des Feldes <code>method</code>. + * + * @return method + */ + public HttpMethod getMethod() + { + return method; + } + +} diff --git a/src/de/openrat/client/util/HttpResponse.java b/src/de/openrat/client/util/HttpResponse.java @@ -0,0 +1,113 @@ +/* +OpenRat Java-Client +Copyright (C) 2009 Jan Dankert + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this library; if not, write to the +Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, +Boston, MA 02110-1301, USA. + + */ +package de.openrat.client.util; + +/** + * API-Request to the OpenRat Content Management System. <br> + * <br> + * The call to the CMS server is done via a (non-SSL) HTTP connection.<br> + * <br> + * Before a call you are able to set some key/value-pairs as parameters. After + * calling the CMS a DOM-document is returned, which contains the server + * response.<br> + * Example <br> + * + * <pre> + * CMSRequest request = new CMSRequest(&quot;your.openrat.example.com&quot;); + * // prints tracing information to stdout. + * request.trace = true; + * try + * { + * request.parameter.put(&quot;action&quot;, &quot;index&quot;); + * request.parameter.put(&quot;subaction&quot;, &quot;showlogin&quot;); // login page + * request.parameter.put(&quot;...&quot;, &quot;...&quot;); + * Document response = request.call(); + * // now traverse through the dom tree and get your information. + * } + * catch (IOException e) + * { + * // your error handling. + * } + * </pre> + * + * @author Jan Dankert + */ +public class HttpResponse +{ + + private HttpHeaderMap responseHeader = new HttpHeaderMap(); + private String payload; + + private HttpStatus httpStatus; + + /** + * Inhalt des Feldes <code>payload</code>. + * + * @return payload + */ + public String getPayload() + { + return payload; + } + + /** + * Setzt das Feld <code>payload</code>. + * + * @param payload + * payload + */ + public void setPayload(String payload) + { + this.payload = payload; + } + + /** + * Inhalt des Feldes <code>responseHeader</code>. + * + * @return responseHeader + */ + public HttpHeaderMap getResponseHeader() + { + return responseHeader; + } + + /** + * Inhalt des Feldes <code>httpStatus</code>. + * + * @return httpStatus + */ + public HttpStatus getHttpStatus() + { + return httpStatus; + } + + /** + * Setzt das Feld <code>httpStatus</code>. + * + * @param httpStatus + * httpStatus + */ + public void setHttpStatus(HttpStatus httpStatus) + { + this.httpStatus = httpStatus; + } + +} diff --git a/src/de/openrat/client/util/HttpStatus.java b/src/de/openrat/client/util/HttpStatus.java @@ -0,0 +1,56 @@ +package de.openrat.client.util; + +public class HttpStatus +{ + + private int statusCode; + private String serverMessage; + + public HttpStatus(int statusCode, String serverMessage) + { + super(); + this.statusCode = statusCode; + this.serverMessage = serverMessage; + } + + public boolean isSuccess() + { + return statusCode / 100 == 2; + } + + public boolean isRedirect() + { + return statusCode / 100 == 3; + } + + public boolean isClientError() + { + return statusCode / 100 == 4; + } + + public boolean isServerError() + { + return statusCode / 100 == 5; + } + + /** + * Inhalt des Feldes <code>statusCode</code>. + * + * @return statusCode + */ + public int getStatusCode() + { + return statusCode; + } + + /** + * Inhalt des Feldes <code>serverMessage</code>. + * + * @return serverMessage + */ + public String getServerMessage() + { + return serverMessage; + } + +} diff --git a/src/de/openrat/client/util/Id.java b/src/de/openrat/client/util/Id.java @@ -0,0 +1,49 @@ +package de.openrat.client.util; + +public class Id extends Number +{ + + private static final long serialVersionUID = -1360182293567671578L; + + private final long value; + + Id(long id) + { + this.value = id; + } + + Id(int id) + { + this.value = (long) id; + } + + Id(short id) + { + this.value = (long) id; + } + + @Override + public int intValue() + { + return (int) value; + } + + @Override + public long longValue() + { + return value; + } + + @Override + public float floatValue() + { + throw new ArithmeticException("this id is never a float value"); + } + + @Override + public double doubleValue() + { + throw new ArithmeticException("this id is never a double value"); + } + +} diff --git a/src/de/openrat/client/util/MapConverter.java b/src/de/openrat/client/util/MapConverter.java @@ -0,0 +1,42 @@ +package de.openrat.client.util; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +public class MapConverter +{ + + private Map<String, String> map; + + public MapConverter(Map<String, String> map) + { + super(); + this.map = map; + } + + public String convertMapToString(String keyValueSeparator, String entrySeparator, boolean withLast) + { + + List<String> list = new ArrayList<String>(); + + for (Entry<String, String> entry : map.entrySet()) + { + list.add(entry.getKey() + keyValueSeparator + entry.getValue()); + } + + StringBuffer out = new StringBuffer(); + for (Iterator<String> i = list.iterator(); i.hasNext();) + { + out.append(i.next()); + if (withLast || i.hasNext()) + { + out.append(entrySeparator); + } + } + return out.toString(); + + } +} diff --git a/src/de/openrat/client/util/NumberUtils.java b/src/de/openrat/client/util/NumberUtils.java @@ -0,0 +1,24 @@ +package de.openrat.client.util; + +public class NumberUtils +{ + /** + * Null-safe and Exception-safe conversion from {@link String} to + * {@link Integer}. + * + * @param number + * Number + * @return int (0, if number is not a number) + */ + public static int toInt(String number) + { + try + { + return Integer.parseInt(number); + } + catch (NumberFormatException e) + { + return 0; + } + } +} diff --git a/src/de/openrat/client/util/ParameterMap.java b/src/de/openrat/client/util/ParameterMap.java @@ -0,0 +1,109 @@ +package de.openrat.client.util; + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +public class ParameterMap +{ + private Map<String, String> parameter = new HashMap<String, String>(); + + /** + * @return + * @see java.util.Map#size() + */ + public int size() + { + return parameter.size(); + } + + /** + * @param key + * @return + * @see java.util.Map#containsKey(java.lang.Object) + */ + public boolean containsKey(Object key) + { + return parameter.containsKey(key); + } + + /** + * @param key + * @return + * @see java.util.Map#get(java.lang.Object) + */ + public String get(Object key) + { + return parameter.get(key); + } + + /** + * @param key + * @param value + * @return + * @see java.util.Map#put(java.lang.Object, java.lang.Object) + */ + public String put(String key, String value) + { + value = urlEncode(value); + return parameter.put(key, value); + } + + /** + * @return + * @see java.util.Map#values() + */ + public Collection<String> values() + { + return parameter.values(); + } + + public String toQueryString() + { + + return new MapConverter(parameter).convertMapToString("=", "&", false); + } + + /** + * @param m + * @see java.util.Map#putAll(java.util.Map) + */ + public void putAll(ParameterMap other) + { + parameter.putAll(other.parameter); + } + + /** + * + * @see java.util.Map#clear() + */ + public void clear() + { + parameter.clear(); + } + + /** + * URL-Encoder. + * + * @param value + * @return url-encoded value + */ + private String urlEncode(String value) + { + + String CHARSET_UTF8 = "UTF-8"; + + try + { + return URLEncoder.encode(value, CHARSET_UTF8); + } + catch (UnsupportedEncodingException e) + { + // maybe... this would be strange + throw new IllegalStateException(CHARSET_UTF8 + " ist not supported by this VM"); + } + } + +} diff --git a/test/de/openrat/client/test/TestLogin.java b/test/de/openrat/client/test/TestLogin.java @@ -0,0 +1,43 @@ +package de.openrat.client.test; + +import static org.junit.Assert.fail; + +import java.io.PrintWriter; +import java.util.Locale; + +import javax.security.auth.login.LoginException; + +import org.junit.Test; + +import de.openrat.client.CMSClient; +import de.openrat.client.action.LoginAction; + +public class TestLogin +{ + + /** + * simple example for using the client. + */ + @Test + public void test() + { + + CMSClient client = new CMSClient("demo.openrat.de", "/latest-snapshot/openrat/dispatcher.php", 80); + client.setLogWriter(new PrintWriter(System.out, true)); +// client.setProxy("proxy.mycompany.exmaple", 8080, "user", "pass"); + client.setLocale(Locale.GERMAN); + client.setKeepAlive(false); + client.setTimeout(15000); + LoginAction loginAction = client.getLoginAction(); + + try + { + loginAction.login("admin", "admin", "db1"); + } + catch (LoginException e) + { + fail("Login failed" + e.getLocalizedMessage()); + } + } + +}