Mercurial > dive4elements > http-client
diff src/main/java/org/dive4elements/artifacts/httpclient/http/HttpClientImpl.java @ 71:a857866d162f
Moved directories to org.dive4elements
author | Sascha L. Teichmann <teichmann@intevation.de> |
---|---|
date | Thu, 25 Apr 2013 11:14:14 +0200 |
parents | src/main/java/de/intevation/artifacts/httpclient/http/HttpClientImpl.java@874c25363dc9 |
children | 133281653904 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/org/dive4elements/artifacts/httpclient/http/HttpClientImpl.java Thu Apr 25 11:14:14 2013 +0200 @@ -0,0 +1,577 @@ +/* + * Copyright (c) 2010 by Intevation GmbH + * + * This program is free software under the LGPL (>=v2.1) + * Read the file LGPL.txt coming with the software for details + * or visit http://www.gnu.org/licenses/ if it does not exist. + */ +package de.intevation.artifacts.httpclient.http; + +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Logger; + +import org.restlet.Client; +import org.restlet.Request; +import org.restlet.Response; +import org.restlet.data.ClientInfo; +import org.restlet.data.Language; +import org.restlet.data.MediaType; +import org.restlet.data.Method; +import org.restlet.data.Preference; +import org.restlet.data.Protocol; +import org.restlet.data.Status; +import org.restlet.ext.xml.DomRepresentation; +import org.restlet.representation.Representation; + +import org.w3c.dom.Document; + +import de.intevation.artifacts.httpclient.exceptions.ConnectionException; +import de.intevation.artifacts.httpclient.http.response.DocumentResponseHandler; +import de.intevation.artifacts.httpclient.http.response.ResponseHandler; +import de.intevation.artifacts.httpclient.http.response.StreamResponseHandler; +import de.intevation.artifacts.httpclient.objects.Artifact; +import de.intevation.artifacts.httpclient.objects.ArtifactFactory; +import de.intevation.artifacts.httpclient.utils.ArtifactProtocolUtils; +import de.intevation.artifacts.httpclient.utils.ArtifactCreator; + + +/** + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class HttpClientImpl implements HttpClient { + + private static final Logger logger = Logger.getLogger(HttpClient.class); + + /** The URL part of the resource to list the existing users of the server.*/ + public static final String PATH_LIST_USERS = "/list-users"; + + /** The URL part of the resource to list the Collections owned by a specific + * user.*/ + public static final String PATH_USER_COLLECTIONS = "/list-collections"; + + /** The URL part og the resource to create a new user on the server.*/ + public static final String PATH_CREATE_USER = "/create-user"; + + /** The URL part og the resource to find an existing user on the server.*/ + public static final String PATH_FIND_USER = "/find-user"; + + /** The URL part of the resource to call a specific service.*/ + public static final String PATH_SERVICE = "/service"; + + /** The URL path of the resource to create new artifact collections.*/ + public static final String PATH_CREATE_COLLECTION = "/create-collection"; + + /** The URL path of the resource to work with an artifact collections.*/ + public static final String PATH_ACTION_COLLECTION = "/collection"; + + /** The URL path of the resource to work with an artifact collections.*/ + public static final String PATH_OUT_COLLECTION = "/collection"; + + private String serverUrl; + + private String localeString; + + private static final ThreadLocal<Client> CLIENT = + new ThreadLocal<Client>() { + @Override + protected Client initialValue() { + logger.debug("create new HTTP client"); + return new Client(Protocol.HTTP); + } + }; + + public HttpClientImpl(String serverUrl) { + this.serverUrl = serverUrl; + } + + + /** + * This constructor might be used to modify the request's locale manually. + * E.g. the localization should not be based on the configured browser + * locale, but site specific configuration - than you are able to set the + * locale in this constructor. + * + * @param serverUrl The url that is used for the request. + * @param localeString The string representation of the desired locale. + */ + public HttpClientImpl(String serverUrl, String localeString) { + this(serverUrl); + + this.localeString = localeString; + } + + + @Override + public ArtifactFactory[] getArtifactFactories() + throws ConnectionException + { + ResponseHandler handler = new DocumentResponseHandler(); + + try { + String url = serverUrl + "/factories"; + Document result = (Document) handler.handle(doGet(url)); + + return ArtifactProtocolUtils.extractArtifactFactories(result); + } + catch (IOException ioe) { + throw new ConnectionException( + "Connection to server failed. No Factories recieved."); + } + } + + + /** + * This method creates a new artifact in the artifact server and returns + * this artifact. The new artifact is created using <i>creator</i>. If no + * {@link ArtifactCreator} is given (null), an {@link Artifact} is returned. + * + * @param doc The CREATE document. + * @param creator The {@link ArtifactCreator} that is used to extract the + * new artifact from response document of the server. + * + * @return the new artifact. + */ + @Override + public Object create(Document doc, ArtifactCreator creator) + throws ConnectionException + { + ResponseHandler handler = new DocumentResponseHandler(); + + try { + String url = serverUrl + "/create"; + Document result = (Document) handler.handle(doPost(url, doc)); + + return creator == null + ? ArtifactProtocolUtils.extractArtifact(result) + : creator.create(result); + } + catch (IOException ioe) { + throw new ConnectionException( + "Connection to server failed. No Artifact created."); + } + } + + + @Override + public Object describe( + Artifact artifact, + Document doc, + ResponseHandler handler) + throws ConnectionException + { + try { + String url = serverUrl + "/artifact/" + artifact.getUuid(); + return handler.handle(doPost(url, doc)); + } + catch (IOException ioe) { + throw new ConnectionException( + "Connection to server failed: " + ioe.getMessage()); + } + } + + + @Override + public Object feed(Artifact artifact, Document doc, ResponseHandler handler) + throws ConnectionException + { + try { + String url = serverUrl + "/artifact/" + artifact.getUuid(); + Document result = (Document) handler.handle(doPost(url, doc)); + + return result; + } + catch (IOException ioe) { + throw new ConnectionException( + "Connection to server failed: " + ioe.getMessage()); + } + } + + + @Override + public Object advance(Artifact artifact, Document doc, ResponseHandler handler) + throws ConnectionException + { + try { + String url = serverUrl + "/artifact/" + artifact.getUuid(); + Document result = (Document) handler.handle(doPost(url, doc)); + + return result; + } + catch (IOException ioe) { + throw new ConnectionException( + "Connection to server failed: " + ioe.getMessage()); + } + } + + + @Override + public void out( + Artifact artifact, + Document doc, + String target, + OutputStream out) + throws ConnectionException + { + try { + String url = + serverUrl + + "/artifact/" + + artifact.getUuid() + + "/" + target; + + ResponseHandler handler = new StreamResponseHandler(); + + InputStream stream = (InputStream) handler.handle(doPost(url, doc)); + try { + byte[] b = new byte[4096]; + int i; + while ((i = stream.read(b)) >= 0) { + out.write(b, 0, i); + } + } + finally { + stream.close(); + } + } + catch (IOException ioe) { + throw new ConnectionException( + "Connection to server failed: " + ioe.getMessage()); + } + } + + + //============================== + // HTTP specific methods + //============================== + + private Response doPost(String url, Document body) throws IOException { + if (logger.isDebugEnabled()) { + logger.debug("Start HTTP-POST request to: " + url); + } + + Client client = getClient(); + Request request = prepareRequest(Method.POST, url); + + Representation representation = new DomRepresentation( + MediaType.APPLICATION_XML, + body); + + request.setEntity(representation); + Response response = client.handle(request); + + Status status = response.getStatus(); + if (status.getCode() != 200) { + logger.error("Response status: " + status.getCode()); + throw new IOException(status.getDescription()); + } + + return response; + } + + + private static Client getClient() { + return CLIENT.get(); + } + + + private Response doGet(String url) throws IOException { + if (logger.isDebugEnabled()) { + logger.debug("Start HTTP-POST request to: "+ url); + } + + Client client = getClient(); + Request request = prepareRequest(Method.GET, url); + + Response response = client.handle(request); + + Status status = response.getStatus(); + if (status.getCode() != 200) { + logger.error("Response status: " + status.getCode()); + throw new IOException(status.getDescription()); + } + + return response; + } + + + /** + * This method prepares the request object. + * + * @param method The HTTP method (GET,POST). + * @param url The URL used for the request. + * + * @return the request object. + */ + private Request prepareRequest(Method method, String url) { + Request request = new Request(method, url); + + ClientInfo info = request.getClientInfo(); + + setLocale(info); + + request.setClientInfo(info); + + return request; + } + + + /** + * This method is called to set the request's locale. + * + * @param info The ClientInfo that is used to provide request information. + */ + private void setLocale(ClientInfo info) { + if (localeString == null) { + return; + } + + List<Preference<Language>> accepted = + new ArrayList<Preference<Language>>(); + + Language lang = Language.valueOf(localeString); + + if (lang != null) { + if (logger.isDebugEnabled()) { + logger.debug( + "Set locale of the request object: " + lang.toString()); + } + + Preference<Language> pref = new Preference<Language>(); + pref.setMetadata(lang); + accepted.add(pref); + + info.setAcceptedLanguages(accepted); + } + } + + + //============================== + // Collection API + //============================== + + /** + * This method triggers the artifact servers resource to create a new + * artifact collection. + * + * @param create The CREATE document for the collection. + * @param ownerId The uuid of the creator. + * @param handler The handler that is used to create the result object. + * + * @return a result object created by <i>handler</i>. + */ + public Object createCollection( + Document create, + String ownerId, + ResponseHandler handler) + throws ConnectionException + { + String url = serverUrl + PATH_CREATE_COLLECTION + "/" + ownerId; + + try { + return handler.handle(doPost(url, create)); + } + catch (IOException ioe) { + throw new ConnectionException(ioe.getMessage(), ioe); + } + } + + + /** + * This method might be used to trigger a collection specific action. The + * action that is executed depends on the document <i>actionDoc</i>. + * + * @param actionDoc The document that describes the action to be executed. + * @param uuid The uuid of the collection. + * @param handler The handler that is used to create the result object. + * + * @return a result object created by <i>handler</i>. + */ + public Object doCollectionAction( + Document actionDoc, + String uuid, + ResponseHandler handler) + throws ConnectionException + { + String url = serverUrl + PATH_ACTION_COLLECTION + "/" + uuid; + + try { + return handler.handle(doPost(url, actionDoc)); + } + catch (IOException ioe) { + throw new ConnectionException(ioe.getMessage(), ioe); + } + } + + + /** + * This method triggers the out() operation of a Collection. The result of + * this operation is written to <i>out</i> directly - there is no return + * value. + * + * @param doc The request document for the out() operation. + * @param uuid The identifier of the Collection. + * @param type The name of the output type. + * @param out The OutputStream. + */ + public void collectionOut( + Document doc, + String uuid, + String type, + OutputStream out) + throws ConnectionException + { + try { + InputStream stream = collectionOut(doc, uuid, type); + + byte[] b = new byte[4096]; + try { + int i; + while ((i = stream.read(b)) >= 0) { + out.write(b, 0, i); + } + } + finally { + stream.close(); + } + } + catch (IOException ioe) { + throw new ConnectionException(ioe.getMessage(), ioe); + } + } + + + /** + * This method triggers the out() operation of a Collection. The result of + * this operation is returned as an InputStream. + * + * @param doc The request document for the out() operation. + * @param uuid The identifier of the Collection. + * @param type The name of the output type. + * + * @return an InputStream. + */ + public InputStream collectionOut( + Document doc, + String uuid, + String type) + throws ConnectionException + { + String url = serverUrl + PATH_OUT_COLLECTION + "/" + uuid + "/" + type; + + ResponseHandler handler = new StreamResponseHandler(); + + try { + return (InputStream) handler.handle(doPost(url, doc)); + } + catch (IOException ioe) { + throw new ConnectionException(ioe.getMessage(), ioe); + } + } + + + /******************************* + * Service API + *******************************/ + + public Document callService(String url, String service, Document input) + throws ConnectionException + { + DocumentResponseHandler handler = new DocumentResponseHandler(); + + return (Document) callService(url, service, input, handler); + } + + + public Object callService( + String url, + String service, + Document input, + ResponseHandler handler) + throws ConnectionException { + if (logger.isDebugEnabled()) { + logger.debug("Start service call to '" + service + "'"); + } + + try { + String serverUrl = url + PATH_SERVICE + "/" + service; + return handler.handle(doPost(serverUrl, input)); + } + catch (IOException ioe) { + throw new ConnectionException( + "Connection to server failed: " + ioe.getMessage()); + } + } + + + /******************************* + * Users API + *******************************/ + + public Document listUsers() + throws ConnectionException + { + ResponseHandler handler = new DocumentResponseHandler(); + String url = serverUrl + PATH_LIST_USERS; + + try { + return (Document) handler.handle(doGet(url)); + } + catch (IOException ioe) { + throw new ConnectionException(ioe.getMessage(), ioe); + } + } + + + public Document listUserCollections(String userid) + throws ConnectionException + { + ResponseHandler handler = new DocumentResponseHandler(); + + String url = serverUrl + PATH_USER_COLLECTIONS + "/" + userid; + + try { + return (Document) handler.handle(doGet(url)); + } + catch (IOException ioe) { + throw new ConnectionException(ioe.getMessage(), ioe); + } + } + + @Override + public Document createUser(Document doc) + throws ConnectionException { + ResponseHandler handler = new DocumentResponseHandler(); + + String url = this.serverUrl + PATH_CREATE_USER; + + try { + return (Document) handler.handle(doPost(url, doc)); + } + catch (IOException ioe) { + throw new ConnectionException( + "Connection to server failed: " + ioe.getMessage()); + } + } + + @Override + public Document findUser(Document doc) + throws ConnectionException { + ResponseHandler handler = new DocumentResponseHandler(); + + String url = this.serverUrl + PATH_FIND_USER; + + try { + return (Document) handler.handle(doPost(url, doc)); + } + catch (IOException ioe) { + throw new ConnectionException( + "Connection to server failed: " + ioe.getMessage()); + } + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8: