changeset 905:478a571f1f94

Refactored server code - HTTP related code moved to ArtifactsHelper and CollectionHelper which makes us able to combine Artifact and Collection protocol stuff in a single RPC service. flys-client/trunk@2757 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Ingo Weinzierl <ingo.weinzierl@intevation.de>
date Thu, 15 Sep 2011 12:55:36 +0000
parents 1e08a5b0add9
children 39acba4b5f0b
files flys-client/ChangeLog flys-client/src/main/java/de/intevation/flys/client/client/services/LoadArtifactService.java flys-client/src/main/java/de/intevation/flys/client/client/services/LoadArtifactServiceAsync.java flys-client/src/main/java/de/intevation/flys/client/server/AddArtifactServiceImpl.java flys-client/src/main/java/de/intevation/flys/client/server/ArtifactHelper.java flys-client/src/main/java/de/intevation/flys/client/server/ArtifactServiceImpl.java flys-client/src/main/java/de/intevation/flys/client/server/CollectionHelper.java flys-client/src/main/java/de/intevation/flys/client/server/DescribeCollectionServiceImpl.java flys-client/src/main/java/de/intevation/flys/client/server/LoadArtifactServiceImpl.java flys-client/src/main/webapp/WEB-INF/web.xml
diffstat 10 files changed, 678 insertions(+), 479 deletions(-) [+]
line wrap: on
line diff
--- a/flys-client/ChangeLog	Thu Sep 15 08:39:07 2011 +0000
+++ b/flys-client/ChangeLog	Thu Sep 15 12:55:36 2011 +0000
@@ -1,3 +1,34 @@
+2011-09-15  Ingo Weinzierl <ingo@intevation.de>
+
+	Refactored the HTTP related code for Collections and Artifacts out to helper
+	classes. This makes us able to combine several Artifact and Collection
+	protocol specific things in new Services. The first one which uses this
+	combination is the LoadArtifactService where a new Artifact is created and
+	finally added to a Collection.
+
+	* src/main/java/de/intevation/flys/client/server/LoadArtifactServiceImpl.java,
+	  src/main/java/de/intevation/flys/client/client/services/LoadArtifactServiceAsync.java,
+	  src/main/java/de/intevation/flys/client/client/services/LoadArtifactService.java:
+	  New service to create a new Artifact (with a given factory and a
+	  recommendation) and add it directly to a specified Collection.
+
+	* src/main/java/de/intevation/flys/client/server/DescribeCollectionServiceImpl.java,
+	  src/main/java/de/intevation/flys/client/server/AddArtifactServiceImpl.java:
+	  Removed HTTP related code - the CollectionHelper should do all this.
+
+	* src/main/java/de/intevation/flys/client/server/ArtifactServiceImpl.java:
+	  Removed HTTP related code - the ArtifactHelper should do all this.
+
+	* src/main/java/de/intevation/flys/client/server/CollectionHelper.java:
+	  Added HTTP related methods from DescribeCollectionServiceImpl and
+	  AddArtifactServiceImpl.
+
+	* src/main/java/de/intevation/flys/client/server/ArtifactHelper.java: New.
+	  This helper class should handle all the HTTP stuff for working with
+	  Artifacts.
+
+	* src/main/webapp/WEB-INF/web.xml: Registered the new LoadArtifactService.
+
 2011-09-15  Raimund Renkert <raimund.renkert@intevation.de>
 
 	Issue194
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/services/LoadArtifactService.java	Thu Sep 15 12:55:36 2011 +0000
@@ -0,0 +1,23 @@
+package de.intevation.flys.client.client.services;
+
+import com.google.gwt.user.client.rpc.RemoteService;
+import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;
+
+import de.intevation.flys.client.shared.exceptions.ServerException;
+import de.intevation.flys.client.shared.model.Artifact;
+import de.intevation.flys.client.shared.model.Collection;
+import de.intevation.flys.client.shared.model.Recommendation;
+
+
+@RemoteServiceRelativePath("load-artifact")
+public interface LoadArtifactService extends RemoteService {
+
+    Artifact load(
+        Collection     parent,
+        Recommendation recom,
+        String         factory,
+        String         url,
+        String         locale)
+    throws ServerException;
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/services/LoadArtifactServiceAsync.java	Thu Sep 15 12:55:36 2011 +0000
@@ -0,0 +1,23 @@
+package de.intevation.flys.client.client.services;
+
+import com.google.gwt.user.client.rpc.AsyncCallback;
+
+import de.intevation.flys.client.shared.model.Artifact;
+import de.intevation.flys.client.shared.model.Collection;
+import de.intevation.flys.client.shared.model.Recommendation;
+
+
+/**
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public interface LoadArtifactServiceAsync {
+
+    public void load(
+        Collection     parent,
+        Recommendation recom,
+        String         factory,
+        String         url,
+        String         locale,
+        AsyncCallback<Artifact> callback);
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-client/src/main/java/de/intevation/flys/client/server/AddArtifactServiceImpl.java	Thu Sep 15 08:39:07 2011 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/server/AddArtifactServiceImpl.java	Thu Sep 15 12:55:36 2011 +0000
@@ -1,14 +1,5 @@
 package de.intevation.flys.client.server;
 
-import org.w3c.dom.Document;
-
-import de.intevation.artifacts.common.utils.ClientProtocolUtils;
-
-import de.intevation.artifacts.httpclient.exceptions.ConnectionException;
-import de.intevation.artifacts.httpclient.http.HttpClient;
-import de.intevation.artifacts.httpclient.http.HttpClientImpl;
-import de.intevation.artifacts.httpclient.http.response.DocumentResponseHandler;
-
 import de.intevation.flys.client.shared.exceptions.ServerException;
 import de.intevation.flys.client.shared.model.Artifact;
 import de.intevation.flys.client.shared.model.Collection;
@@ -22,8 +13,6 @@
 extends      DescribeCollectionServiceImpl
 implements   AddArtifactService
 {
-    public static final String ERROR_ADD_ARTIFACT = "error_add_artifact";
-
     public Collection add(
         Collection collection,
         Artifact   artifact,
@@ -33,28 +22,7 @@
     {
         System.out.println("AddArtifactServiceImpl.add");
 
-        Document add = ClientProtocolUtils.newAddArtifactDocument(
-            artifact.getUuid(), null);
-
-        HttpClient client = new HttpClientImpl(url, locale);
-
-        try {
-            Document response = (Document) client.doCollectionAction(
-                add, collection.identifier(), new DocumentResponseHandler());
-
-            Collection c = parseCollection(response);
-
-            if (c == null) {
-                throw new ServerException(ERROR_ADD_ARTIFACT);
-            }
-
-            return c;
-        }
-        catch (ConnectionException ce) {
-            System.err.println(ce.getLocalizedMessage());
-        }
-
-        throw new ServerException(ERROR_ADD_ARTIFACT);
+        return CollectionHelper.addArtifact(collection, artifact, url, locale);
     }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/server/ArtifactHelper.java	Thu Sep 15 12:55:36 2011 +0000
@@ -0,0 +1,100 @@
+package de.intevation.flys.client.server;
+
+import org.w3c.dom.Document;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import de.intevation.artifacts.common.utils.ClientProtocolUtils;
+import de.intevation.artifacts.common.utils.CreationFilter;
+
+import de.intevation.artifacts.httpclient.exceptions.ConnectionException;
+import de.intevation.artifacts.httpclient.http.HttpClient;
+import de.intevation.artifacts.httpclient.http.HttpClientImpl;
+
+import de.intevation.flys.client.shared.exceptions.ServerException;
+import de.intevation.flys.client.shared.model.Artifact;
+
+import de.intevation.flys.client.shared.model.Recommendation;
+
+
+/**
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class ArtifactHelper {
+
+    /** The error message key that is thrown if an error occured while artifact
+     * creation.*/
+    public static final String ERROR_CREATE_ARTIFACT = "error_create_artifact";
+
+
+    private ArtifactHelper() {
+    }
+
+
+    public static Artifact createArtifact(
+        String         serverUrl,
+        String         locale,
+        String         factory,
+        Recommendation recommendation)
+    throws ServerException
+    {
+        System.out.println("ArtifactHelper.create");
+
+        String         uuid;
+        String         ids;
+        CreationFilter filter;
+
+        if (recommendation != null) {
+            uuid   = recommendation.getMasterArtifact();
+            ids    = recommendation.getIDs();
+            filter = convertFilter(recommendation.getFilter());
+        }
+        else {
+            uuid   = null;
+            ids    = null;
+            filter = null;
+        }
+
+        Document create = ClientProtocolUtils.newCreateDocument(
+            factory, uuid, ids, filter);
+
+        HttpClient client = new HttpClientImpl(serverUrl, locale);
+
+        try {
+            return (Artifact) client.create(create, new FLYSArtifactCreator());
+        }
+        catch (ConnectionException ce) {
+            System.err.println(ce.getLocalizedMessage());
+        }
+
+        throw new ServerException(ERROR_CREATE_ARTIFACT);
+    }
+
+
+    public static CreationFilter convertFilter(Recommendation.Filter filter) {
+
+        if (filter == null) {
+            return null;
+        }
+
+        CreationFilter cf = new CreationFilter();
+
+        Map<String, List<Recommendation.Facet>> outs = filter.getOuts();
+
+        for (Map.Entry<String, List<Recommendation.Facet>> entry:
+            outs.entrySet()) {
+            List<Recommendation.Facet> rfs = entry.getValue();
+            List<CreationFilter.Facet> cfs =
+                new ArrayList<CreationFilter.Facet>(rfs.size());
+            for (Recommendation.Facet rf: rfs) {
+                cfs.add(new CreationFilter.Facet(rf.getName(), rf.getIndex()));
+            }
+            cf.add(entry.getKey(), cfs);
+        }
+
+        return cf;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-client/src/main/java/de/intevation/flys/client/server/ArtifactServiceImpl.java	Thu Sep 15 08:39:07 2011 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/server/ArtifactServiceImpl.java	Thu Sep 15 12:55:36 2011 +0000
@@ -1,20 +1,7 @@
 package de.intevation.flys.client.server;
 
-import org.w3c.dom.Document;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
 import com.google.gwt.user.server.rpc.RemoteServiceServlet;
 
-import de.intevation.artifacts.common.utils.ClientProtocolUtils;
-import de.intevation.artifacts.common.utils.CreationFilter;
-
-import de.intevation.artifacts.httpclient.exceptions.ConnectionException;
-import de.intevation.artifacts.httpclient.http.HttpClient;
-import de.intevation.artifacts.httpclient.http.HttpClientImpl;
-
 import de.intevation.flys.client.shared.exceptions.ServerException;
 import de.intevation.flys.client.shared.model.Artifact;
 import de.intevation.flys.client.client.services.ArtifactService;
@@ -31,73 +18,27 @@
 extends      RemoteServiceServlet
 implements   ArtifactService
 {
-    /** The error message key that is thrown if an error occured while artifact
-     * creation.*/
-    public static final String ERROR_CREATE_ARTIFACT = "error_create_artifact";
-
-
+    /**
+     * Creates new Artifacts based on a given Recommendation and factory.
+     * <b>Note, that all the work is done in ArtifactHelper!</b>
+     *
+     * @param serverUrl The URL of the ArtifactServer.
+     * @param locale The locale used for HTTP request.
+     * @param factory The factory that is used to create the new Artifact.
+     *
+     * @return a new Artifact.
+     */
     public Artifact create(
         String         serverUrl,
         String         locale,
         String         factory,
-        Recommendation recommendation
+        Recommendation recom
     )
     throws ServerException
     {
         System.out.println("ArtifactServiceImpl.create");
 
-        String         uuid;
-        String         ids;
-        CreationFilter filter;
-
-        if (recommendation != null) {
-            uuid   = recommendation.getMasterArtifact();
-            ids    = recommendation.getIDs();
-            filter = convertFilter(recommendation.getFilter());
-        }
-        else {
-            uuid   = null;
-            ids    = null;
-            filter = null;
-        }
-
-        Document create = ClientProtocolUtils.newCreateDocument(
-            factory, uuid, ids, filter);
-
-        HttpClient client = new HttpClientImpl(serverUrl, locale);
-
-        try {
-            return (Artifact) client.create(create, new FLYSArtifactCreator());
-        }
-        catch (ConnectionException ce) {
-            System.err.println(ce.getLocalizedMessage());
-        }
-
-        throw new ServerException(ERROR_CREATE_ARTIFACT);
-    }
-
-    public static CreationFilter convertFilter(Recommendation.Filter filter) {
-
-        if (filter == null) {
-            return null;
-        }
-
-        CreationFilter cf = new CreationFilter();
-
-        Map<String, List<Recommendation.Facet>> outs = filter.getOuts();
-
-        for (Map.Entry<String, List<Recommendation.Facet>> entry:
-            outs.entrySet()) {
-            List<Recommendation.Facet> rfs = entry.getValue();
-            List<CreationFilter.Facet> cfs =
-                new ArrayList<CreationFilter.Facet>(rfs.size());
-            for (Recommendation.Facet rf: rfs) {
-                cfs.add(new CreationFilter.Facet(rf.getName(), rf.getIndex()));
-            }
-            cf.add(entry.getKey(), cfs);
-        }
-
-        return cf;
+        return ArtifactHelper.createArtifact(serverUrl, locale, factory, recom);
     }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-client/src/main/java/de/intevation/flys/client/server/CollectionHelper.java	Thu Sep 15 08:39:07 2011 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/server/CollectionHelper.java	Thu Sep 15 12:55:36 2011 +0000
@@ -1,19 +1,43 @@
 package de.intevation.flys.client.server;
 
+import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
+import javax.xml.xpath.XPathConstants;
+
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
 
 import de.intevation.artifacts.common.ArtifactNamespaceContext;
+import de.intevation.artifacts.common.utils.ClientProtocolUtils;
 import de.intevation.artifacts.common.utils.XMLUtils;
 import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator;
 
+import de.intevation.artifacts.httpclient.exceptions.ConnectionException;
+import de.intevation.artifacts.httpclient.http.HttpClient;
+import de.intevation.artifacts.httpclient.http.HttpClientImpl;
+import de.intevation.artifacts.httpclient.http.response.DocumentResponseHandler;
+
+import de.intevation.flys.client.shared.exceptions.ServerException;
+import de.intevation.flys.client.shared.model.Artifact;
 import de.intevation.flys.client.shared.model.AttributedTheme;
+import de.intevation.flys.client.shared.model.ChartMode;
 import de.intevation.flys.client.shared.model.Collection;
+import de.intevation.flys.client.shared.model.CollectionItem;
+import de.intevation.flys.client.shared.model.DefaultCollection;
+import de.intevation.flys.client.shared.model.DefaultCollectionItem;
+import de.intevation.flys.client.shared.model.DefaultFacet;
+import de.intevation.flys.client.shared.model.ExportMode;
+import de.intevation.flys.client.shared.model.Facet;
+import de.intevation.flys.client.shared.model.MapMode;
 import de.intevation.flys.client.shared.model.OutputMode;
+import de.intevation.flys.client.shared.model.ReportMode;
 import de.intevation.flys.client.shared.model.Recommendation;
 import de.intevation.flys.client.shared.model.Theme;
 import de.intevation.flys.client.shared.model.ThemeList;
@@ -24,6 +48,14 @@
  */
 public class CollectionHelper {
 
+    public static final String ERROR_ADD_ARTIFACT = "error_add_artifact";
+
+    public static final String XPATH_FACETS = "art:facets/art:facet";
+
+    public static final String XPATH_LOADED_RECOMMENDATIONS =
+        "/art:artifact-collection/art:attribute/art:loaded-recommendations/art:recommendation";
+
+
     public static Document createAttribute(Collection collection) {
         System.out.println("CollectionHelper.createAttribute");
 
@@ -232,5 +264,397 @@
 
         return recommendation;
     }
+
+
+    /**
+     * This method takes the DESCRIBE document of the Collections describe()
+     * operation and extracts the information about the collection itself and
+     * the collection items.
+     *
+     * @param description The DESCRIBE document of the Collections describe()
+     * operation.
+     *
+     * @return a Collection with CollectionItems.
+     */
+    public static Collection parseCollection(Document description) {
+        System.out.println("AddArtifactServiceImpl.parseCollection");
+
+        if (description == null) {
+            System.err.println("The DESCRIBE of the Collection is null!");
+            return null;
+        }
+
+        String uuid = XMLUtils.xpathString(
+            description,
+            "art:artifact-collection/@art:uuid",
+            ArtifactNamespaceContext.INSTANCE);
+
+        String ttlStr = XMLUtils.xpathString(
+            description,
+            "art:artifact-collection/@art:ttl",
+            ArtifactNamespaceContext.INSTANCE);
+
+        String name = XMLUtils.xpathString(
+            description,
+            "art:artifact-collection/@art:name",
+            ArtifactNamespaceContext.INSTANCE);
+
+        if (uuid.length() == 0 || ttlStr.length() == 0) {
+            System.err.println("Found an invalid Collection!");
+            return null;
+        }
+
+
+        long ttl = -1;
+        try {
+            ttl = Long.valueOf(ttlStr);
+        }
+        catch (NumberFormatException nfe) {
+            // do nothing
+        }
+
+        Map<String, ThemeList> themeList = parseThemeLists(description);
+        List<Recommendation> recommended = parseRecommendations(description);
+
+        name = (name != null && name.length() > 0) ? name : uuid;
+
+        Collection c = !themeList.isEmpty()
+            ? new DefaultCollection(uuid, ttl, name, recommended, themeList)
+            : new DefaultCollection(uuid, ttl, name, recommended);
+
+        NodeList items = (NodeList) XMLUtils.xpath(
+            description,
+            "art:artifact-collection/art:artifacts/art:artifact",
+            XPathConstants.NODESET,
+            ArtifactNamespaceContext.INSTANCE);
+
+        if (items == null || items.getLength() == 0) {
+            System.out.println("No collection item found for this collection.");
+
+            return c;
+        }
+
+        int size = items.getLength();
+
+        for (int i = 0; i < size; i++) {
+            CollectionItem item = parseCollectionItem(
+                (Element)items.item(i),
+                i == 0);
+
+            if (item != null) {
+                c.addItem(item);
+            }
+        }
+
+        System.out.println(
+            "Found " + c.getItemLength() + " collection items " +
+            "for the Collection '" + c.identifier() + "'.");
+
+        return c;
+    }
+
+
+    protected static Map<String, ThemeList> parseThemeLists(Document desc) {
+        System.out.println("DescribeCollectionServiceImpl.parseThemeLists");
+
+        NodeList lists = (NodeList) XMLUtils.xpath(
+            desc,
+            "/art:artifact-collection/art:attribute/art:outputs/art:output",
+            XPathConstants.NODESET,
+            ArtifactNamespaceContext.INSTANCE);
+
+        int num = lists != null ? lists.getLength() : 0;
+
+        Map<String, ThemeList> themeList = new HashMap<String, ThemeList>(num);
+
+        String uri = ArtifactNamespaceContext.NAMESPACE_URI;
+
+        for (int i = 0; i < num; i++) {
+            Element node = (Element)lists.item(i);
+
+            String outName = node.getAttribute("name");
+
+            if (outName.length() > 0) {
+                ThemeList list = parseThemeList(node);
+                if (list.getThemeCount() > 0) {
+                    themeList.put(outName, list);
+                }
+            }
+        }
+
+        return themeList;
+    }
+
+
+    protected static ThemeList parseThemeList(Element node) {
+        System.out.println("DescribeCollectionServiceImpl.parseThemeList");
+
+        NodeList themes = node.getElementsByTagNameNS(
+            ArtifactNamespaceContext.NAMESPACE_URI,
+            "facet");
+
+        int num = themes != null ? themes.getLength() : 0;
+
+        List<Theme> themeList = new ArrayList<Theme>(num);
+
+        for (int i = 0; i < num; i++) {
+            Theme theme = parseTheme((Element)themes.item(i));
+
+            if (theme != null) {
+                themeList.add(theme);
+            }
+        }
+
+        return new ThemeList(themeList);
+    }
+
+
+    protected static Theme parseTheme(Element ele) {
+        System.out.println("DescribeCollectionServiceImpl.parseTheme");
+
+        String uri = ArtifactNamespaceContext.NAMESPACE_URI;
+
+        NamedNodeMap attrMap = ele.getAttributes();
+        int          attrNum = attrMap != null ? attrMap.getLength() : 0;
+
+        AttributedTheme t = new AttributedTheme();
+
+        for (int i = 0; i < attrNum; i++) {
+            Node attr = attrMap.item(i);
+
+            String prefix = attr.getPrefix();
+            String name   = attr.getNodeName().replace(prefix + ":", "");
+            String value  = attr.getNodeValue();
+
+            t.addAttr(name, value);
+        }
+
+        return t;
+    }
+
+
+    /**
+     * This method extracts the CollectionItem from <i>node</i> with its output
+     * modes. The output modes are parsed using the parseOutputModes() method.
+     *
+     * @param node A node that contains information about a CollectionItem.
+     *
+     * @return a CollectionItem.
+     */
+    protected static CollectionItem parseCollectionItem(
+        Element node,
+        boolean outs
+    ) {
+        System.out.println("AddArtifactServiceImpl.parseCollectionItem");
+
+        if (node == null) {
+            System.err.println("The node for parsing CollectionItem is null!");
+            return null;
+        }
+
+        String uri = ArtifactNamespaceContext.NAMESPACE_URI;
+
+        String uuid = node.getAttributeNS(uri, "uuid");
+        String hash = node.getAttributeNS(uri, "hash");
+
+        if (uuid == null || uuid.length() == 0) {
+            System.err.println("Found an invalid CollectionItem!");
+            return null;
+        }
+
+        List<OutputMode> modes = new ArrayList<OutputMode>();
+
+        if (outs) {
+            NodeList outputmodes = node.getElementsByTagNameNS(
+                uri, "outputmodes");
+
+            if (outputmodes.getLength() < 1) {
+                return null;
+            }
+
+            Element om = (Element)outputmodes.item(0);
+
+            modes = parseOutputModes(om);
+        }
+
+        return new DefaultCollectionItem(uuid, hash, modes);
+    }
+
+
+    /**
+     * This method extracts the OutputModes available for a specific
+     * CollectionItem and returns them as list.
+     *
+     * @param node The root node of the outputmodes list.
+     *
+     * @return a list of OutputModes.
+     */
+    protected static List<OutputMode> parseOutputModes(Element node) {
+        System.out.println("AddArtifactServiceImpl.parseOutputModes");
+
+        if (node == null) {
+            System.err.println("The node for parsing OutputModes is null!");
+            return null;
+        }
+
+        String uri = ArtifactNamespaceContext.NAMESPACE_URI;
+
+        NodeList list = node.getElementsByTagNameNS(uri, "output");
+
+        int size = list.getLength();
+
+        if (size == 0) {
+            System.err.println("No outputmode nodes found!");
+            return null;
+        }
+
+        List<OutputMode> modes = new ArrayList<OutputMode>(size);
+
+        for (int i = 0; i < size; i++) {
+            Element tmp = (Element)list.item(i);
+
+            String name = tmp.getAttributeNS(uri, "name");
+            String desc = tmp.getAttributeNS(uri, "description");
+            String mime = tmp.getAttributeNS(uri, "mime-type");
+            String type = tmp.getAttributeNS(uri, "type");
+
+            if (name.length() == 0) {
+                System.err.println("Found an invalid output mode.");
+                continue;
+            }
+
+            OutputMode outmode = null;
+            List<Facet> fs     = extractFacets(tmp);
+
+            if (type.equals("export")) {
+                outmode = new ExportMode(name, desc, mime, fs);
+            }
+            else if (type.equals("report")) {
+                outmode = new ReportMode(name, desc, mime, fs);
+            }
+            else if (type.equals("chart")){
+                outmode = new ChartMode(name, desc, mime, fs);
+            }
+            else if (type.equals("map")){
+                outmode = new MapMode(name, desc, mime, fs);
+            }
+            else {
+                System.err.println("Broken Output mode without type found.");
+                continue;
+            }
+
+            modes.add(outmode);
+        }
+
+        return modes;
+    }
+
+
+    protected static List<Facet> extractFacets(Element outmode) {
+        System.out.println("DescribeCollectionServiceImpl - extractFacets()");
+
+        NodeList facetList = (NodeList) XMLUtils.xpath(
+            outmode,
+            XPATH_FACETS,
+            XPathConstants.NODESET,
+            ArtifactNamespaceContext.INSTANCE);
+
+        int num = facetList != null ? facetList.getLength() : 0;
+
+        List<Facet> facets = new ArrayList<Facet>(num);
+
+        String uri = ArtifactNamespaceContext.NAMESPACE_URI;
+
+        for (int i = 0; i < num; i++) {
+            Element facetEl = (Element) facetList.item(i);
+
+            String name  = facetEl.getAttributeNS(uri, "name");
+            String desc  = facetEl.getAttributeNS(uri, "description");
+            String index = facetEl.getAttributeNS(uri, "index");
+
+            if (name != null && name.length() > 0 && index != null) {
+                facets.add(new DefaultFacet(name, Integer.valueOf(index),desc));
+            }
+        }
+
+        return facets;
+    }
+
+
+    public static List<Recommendation> parseRecommendations(Document doc) {
+        System.out.println("DescribeCollectionServiceImpl.parseRecommendations");
+
+        NodeList list = (NodeList) XMLUtils.xpath(
+            doc,
+            XPATH_LOADED_RECOMMENDATIONS,
+            XPathConstants.NODESET,
+            ArtifactNamespaceContext.INSTANCE);
+
+        int num = list != null ? list.getLength() : 0;
+
+        List<Recommendation> recs = new ArrayList<Recommendation>(num);
+
+        String uri = ArtifactNamespaceContext.NAMESPACE_URI;
+
+        for (int i = 0; i < num; i++) {
+            Element rec = (Element) list.item(i);
+
+            String factory = rec.getAttributeNS(uri, "factory");
+            String dbids   = rec.getAttributeNS(uri, "ids");
+
+            if (factory != null && factory.length() > 0) {
+                recs.add(new Recommendation(factory, dbids));
+            }
+        }
+
+        return recs;
+    }
+
+
+    public static Collection addArtifact(
+        Collection collection,
+        Artifact   artifact,
+        String     url,
+        String     locale)
+    throws ServerException
+    {
+        System.out.println("Collection.addArtifact");
+
+        if (collection == null) {
+            System.err.println("The given Collection is null!");
+            return null;
+        }
+
+        Document add = ClientProtocolUtils.newAddArtifactDocument(
+            artifact.getUuid(), null);
+
+        HttpClient client = new HttpClientImpl(url, locale);
+
+        try {
+            System.out.println("Do HTTP request now.");
+
+            Document response = (Document) client.doCollectionAction(
+                add, collection.identifier(), new DocumentResponseHandler());
+
+            System.out.println(
+                "Finished HTTP request successfully. Parse Collection now.");
+
+            Collection c = CollectionHelper.parseCollection(response);
+
+            if (c == null) {
+                throw new ServerException(ERROR_ADD_ARTIFACT);
+            }
+
+            return c;
+        }
+        catch (ConnectionException ce) {
+            System.err.println(ce.getLocalizedMessage());
+        }
+        catch (Exception e) {
+            e.printStackTrace();
+        }
+
+        throw new ServerException(ERROR_ADD_ARTIFACT);
+    }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-client/src/main/java/de/intevation/flys/client/server/DescribeCollectionServiceImpl.java	Thu Sep 15 08:39:07 2011 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/server/DescribeCollectionServiceImpl.java	Thu Sep 15 12:55:36 2011 +0000
@@ -1,23 +1,10 @@
 package de.intevation.flys.client.server;
 
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import javax.xml.xpath.XPathConstants;
-
 import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.NamedNodeMap;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
 
 import com.google.gwt.user.server.rpc.RemoteServiceServlet;
 
-import de.intevation.artifacts.common.ArtifactNamespaceContext;
 import de.intevation.artifacts.common.utils.ClientProtocolUtils;
-import de.intevation.artifacts.common.utils.XMLUtils;
 
 import de.intevation.artifacts.httpclient.exceptions.ConnectionException;
 import de.intevation.artifacts.httpclient.http.HttpClient;
@@ -25,21 +12,8 @@
 import de.intevation.artifacts.httpclient.http.response.DocumentResponseHandler;
 
 import de.intevation.flys.client.shared.exceptions.ServerException;
-import de.intevation.flys.client.shared.model.AttributedTheme;
 import de.intevation.flys.client.shared.model.Collection;
-import de.intevation.flys.client.shared.model.CollectionItem;
-import de.intevation.flys.client.shared.model.DefaultCollection;
-import de.intevation.flys.client.shared.model.DefaultCollectionItem;
-import de.intevation.flys.client.shared.model.DefaultFacet;
-import de.intevation.flys.client.shared.model.ChartMode;
-import de.intevation.flys.client.shared.model.ExportMode;
-import de.intevation.flys.client.shared.model.MapMode;
-import de.intevation.flys.client.shared.model.ReportMode;
-import de.intevation.flys.client.shared.model.Facet;
-import de.intevation.flys.client.shared.model.OutputMode;
-import de.intevation.flys.client.shared.model.Recommendation;
-import de.intevation.flys.client.shared.model.Theme;
-import de.intevation.flys.client.shared.model.ThemeList;
+
 import de.intevation.flys.client.client.services.DescribeCollectionService;
 
 
@@ -59,11 +33,6 @@
     public static final String ERROR_DESCRIBE_COLLECTION =
         "error_describe_collection";
 
-    public static final String XPATH_FACETS = "art:facets/art:facet";
-
-    public static final String XPATH_LOADED_RECOMMENDATIONS =
-        "/art:artifact-collection/art:attribute/art:loaded-recommendations/art:recommendation";
-
 
     public Collection describe(String uuid, String serverUrl, String locale)
     throws ServerException
@@ -79,7 +48,7 @@
             Document response = (Document) client.doCollectionAction(
                 describe, uuid, new DocumentResponseHandler());
 
-            Collection c = parseCollection(response);
+            Collection c = CollectionHelper.parseCollection(response);
 
             if (c == null) {
                 throw new ServerException(ERROR_DESCRIBE_COLLECTION);
@@ -95,347 +64,5 @@
 
         throw new ServerException(ERROR_DESCRIBE_COLLECTION);
     }
-
-
-    /**
-     * This method takes the DESCRIBE document of the Collections describe()
-     * operation and extracts the information about the collection itself and
-     * the collection items.
-     *
-     * @param description The DESCRIBE document of the Collections describe()
-     * operation.
-     *
-     * @return a Collection with CollectionItems.
-     */
-    protected Collection parseCollection(Document description) {
-        System.out.println("AddArtifactServiceImpl.parseCollection");
-
-        if (description == null) {
-            System.err.println("The DESCRIBE of the Collection is null!");
-            return null;
-        }
-
-        String uuid = XMLUtils.xpathString(
-            description,
-            "art:artifact-collection/@art:uuid",
-            ArtifactNamespaceContext.INSTANCE);
-
-        String ttlStr = XMLUtils.xpathString(
-            description,
-            "art:artifact-collection/@art:ttl",
-            ArtifactNamespaceContext.INSTANCE);
-
-        String name = XMLUtils.xpathString(
-            description,
-            "art:artifact-collection/@art:name",
-            ArtifactNamespaceContext.INSTANCE);
-
-        if (uuid.length() == 0 || ttlStr.length() == 0) {
-            System.err.println("Found an invalid Collection!");
-            return null;
-        }
-
-
-        long ttl = -1;
-        try {
-            ttl = Long.valueOf(ttlStr);
-        }
-        catch (NumberFormatException nfe) {
-            // do nothing
-        }
-
-        Map<String, ThemeList> themeList = parseThemeLists(description);
-        List<Recommendation> recommended = parseRecommendations(description);
-
-        name = (name != null && name.length() > 0) ? name : uuid;
-
-        Collection c = !themeList.isEmpty()
-            ? new DefaultCollection(uuid, ttl, name, recommended, themeList)
-            : new DefaultCollection(uuid, ttl, name, recommended);
-
-        NodeList items = (NodeList) XMLUtils.xpath(
-            description,
-            "art:artifact-collection/art:artifacts/art:artifact",
-            XPathConstants.NODESET,
-            ArtifactNamespaceContext.INSTANCE);
-
-        if (items == null || items.getLength() == 0) {
-            System.out.println("No collection item found for this collection.");
-
-            return c;
-        }
-
-        int size = items.getLength();
-
-        for (int i = 0; i < size; i++) {
-            CollectionItem item = parseCollectionItem(
-                (Element)items.item(i),
-                i == 0);
-
-            if (item != null) {
-                c.addItem(item);
-            }
-        }
-
-        System.out.println(
-            "Found " + c.getItemLength() + " collection items " +
-            "for the Collection '" + c.identifier() + "'.");
-
-        return c;
-    }
-
-
-    protected Map<String, ThemeList> parseThemeLists(Document description) {
-        System.out.println("DescribeCollectionServiceImpl.parseThemeLists");
-
-        NodeList lists = (NodeList) XMLUtils.xpath(
-            description,
-            "/art:artifact-collection/art:attribute/art:outputs/art:output",
-            XPathConstants.NODESET,
-            ArtifactNamespaceContext.INSTANCE);
-
-        int num = lists != null ? lists.getLength() : 0;
-
-        Map<String, ThemeList> themeList = new HashMap<String, ThemeList>(num);
-
-        String uri = ArtifactNamespaceContext.NAMESPACE_URI;
-
-        for (int i = 0; i < num; i++) {
-            Element node = (Element)lists.item(i);
-
-            String outName = node.getAttribute("name");
-
-            if (outName.length() > 0) {
-                ThemeList list = parseThemeList(node);
-                if (list.getThemeCount() > 0) {
-                    themeList.put(outName, list);
-                }
-            }
-        }
-
-        return themeList;
-    }
-
-
-    protected ThemeList parseThemeList(Element node) {
-        System.out.println("DescribeCollectionServiceImpl.parseThemeList");
-
-        NodeList themes = node.getElementsByTagNameNS(
-            ArtifactNamespaceContext.NAMESPACE_URI,
-            "facet");
-
-        int num = themes != null ? themes.getLength() : 0;
-
-        List<Theme> themeList = new ArrayList<Theme>(num);
-
-        for (int i = 0; i < num; i++) {
-            Theme theme = parseTheme((Element)themes.item(i));
-
-            if (theme != null) {
-                themeList.add(theme);
-            }
-        }
-
-        return new ThemeList(themeList);
-    }
-
-
-    protected Theme parseTheme(Element ele) {
-        System.out.println("DescribeCollectionServiceImpl.parseTheme");
-
-        String uri = ArtifactNamespaceContext.NAMESPACE_URI;
-
-        NamedNodeMap attrMap = ele.getAttributes();
-        int          attrNum = attrMap != null ? attrMap.getLength() : 0;
-
-        AttributedTheme t = new AttributedTheme();
-
-        for (int i = 0; i < attrNum; i++) {
-            Node attr = attrMap.item(i);
-
-            String prefix = attr.getPrefix();
-            String name   = attr.getNodeName().replace(prefix + ":", "");
-            String value  = attr.getNodeValue();
-
-            t.addAttr(name, value);
-        }
-
-        return t;
-    }
-
-
-    /**
-     * This method extracts the CollectionItem from <i>node</i> with its output
-     * modes. The output modes are parsed using the parseOutputModes() method.
-     *
-     * @param node A node that contains information about a CollectionItem.
-     *
-     * @return a CollectionItem.
-     */
-    protected CollectionItem parseCollectionItem(Element node, boolean outs) {
-        System.out.println("AddArtifactServiceImpl.parseCollectionItem");
-
-        if (node == null) {
-            System.err.println("The node for parsing CollectionItem is null!");
-            return null;
-        }
-
-        String uri = ArtifactNamespaceContext.NAMESPACE_URI;
-
-        String uuid = node.getAttributeNS(uri, "uuid");
-        String hash = node.getAttributeNS(uri, "hash");
-
-        if (uuid == null || uuid.length() == 0) {
-            System.err.println("Found an invalid CollectionItem!");
-            return null;
-        }
-
-        List<OutputMode> modes = new ArrayList<OutputMode>();
-
-        if (outs) {
-            NodeList outputmodes = node.getElementsByTagNameNS(
-                uri, "outputmodes");
-
-            if (outputmodes.getLength() < 1) {
-                return null;
-            }
-
-            Element om = (Element)outputmodes.item(0);
-
-            modes = parseOutputModes(om);
-        }
-
-        return new DefaultCollectionItem(uuid, hash, modes);
-    }
-
-
-    /**
-     * This method extracts the OutputModes available for a specific
-     * CollectionItem and returns them as list.
-     *
-     * @param node The root node of the outputmodes list.
-     *
-     * @return a list of OutputModes.
-     */
-    protected List<OutputMode> parseOutputModes(Element node) {
-        System.out.println("AddArtifactServiceImpl.parseOutputModes");
-
-        if (node == null) {
-            System.err.println("The node for parsing OutputModes is null!");
-            return null;
-        }
-
-        String uri = ArtifactNamespaceContext.NAMESPACE_URI;
-
-        NodeList list = node.getElementsByTagNameNS(uri, "output");
-
-        int size = list.getLength();
-
-        if (size == 0) {
-            System.err.println("No outputmode nodes found!");
-            return null;
-        }
-
-        List<OutputMode> modes = new ArrayList<OutputMode>(size);
-
-        for (int i = 0; i < size; i++) {
-            Element tmp = (Element)list.item(i);
-
-            String name = tmp.getAttributeNS(uri, "name");
-            String desc = tmp.getAttributeNS(uri, "description");
-            String mime = tmp.getAttributeNS(uri, "mime-type");
-            String type = tmp.getAttributeNS(uri, "type");
-
-            if (name.length() == 0) {
-                System.err.println("Found an invalid output mode.");
-                continue;
-            }
-
-            OutputMode outmode = null;
-            List<Facet> fs     = extractFacets(tmp);
-
-            if (type.equals("export")) {
-                outmode = new ExportMode(name, desc, mime, fs);
-            }
-            else if (type.equals("report")) {
-                outmode = new ReportMode(name, desc, mime, fs);
-            }
-            else if (type.equals("chart")){
-                outmode = new ChartMode(name, desc, mime, fs);
-            }
-            else if (type.equals("map")){
-                outmode = new MapMode(name, desc, mime, fs);
-            }
-            else {
-                System.err.println("Broken Output mode without type found.");
-                continue;
-            }
-
-            modes.add(outmode);
-        }
-
-        return modes;
-    }
-
-
-    protected static List<Facet> extractFacets(Element outmode) {
-        System.out.println("DescribeCollectionServiceImpl - extractFacets()");
-
-        NodeList facetList = (NodeList) XMLUtils.xpath(
-            outmode,
-            XPATH_FACETS,
-            XPathConstants.NODESET,
-            ArtifactNamespaceContext.INSTANCE);
-
-        int num = facetList != null ? facetList.getLength() : 0;
-
-        List<Facet> facets = new ArrayList<Facet>(num);
-
-        String uri = ArtifactNamespaceContext.NAMESPACE_URI;
-
-        for (int i = 0; i < num; i++) {
-            Element facetEl = (Element) facetList.item(i);
-
-            String name  = facetEl.getAttributeNS(uri, "name");
-            String desc  = facetEl.getAttributeNS(uri, "description");
-            String index = facetEl.getAttributeNS(uri, "index");
-
-            if (name != null && name.length() > 0 && index != null) {
-                facets.add(new DefaultFacet(name, Integer.valueOf(index),desc));
-            }
-        }
-
-        return facets;
-    }
-
-
-    public static List<Recommendation> parseRecommendations(Document doc) {
-        System.out.println("DescribeCollectionServiceImpl.parseRecommendations");
-
-        NodeList list = (NodeList) XMLUtils.xpath(
-            doc,
-            XPATH_LOADED_RECOMMENDATIONS,
-            XPathConstants.NODESET,
-            ArtifactNamespaceContext.INSTANCE);
-
-        int num = list != null ? list.getLength() : 0;
-
-        List<Recommendation> recs = new ArrayList<Recommendation>(num);
-
-        String uri = ArtifactNamespaceContext.NAMESPACE_URI;
-
-        for (int i = 0; i < num; i++) {
-            Element rec = (Element) list.item(i);
-
-            String factory = rec.getAttributeNS(uri, "factory");
-            String dbids   = rec.getAttributeNS(uri, "ids");
-
-            if (factory != null && factory.length() > 0) {
-                recs.add(new Recommendation(factory, dbids));
-            }
-        }
-
-        return recs;
-    }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/server/LoadArtifactServiceImpl.java	Thu Sep 15 12:55:36 2011 +0000
@@ -0,0 +1,52 @@
+package de.intevation.flys.client.server;
+
+import de.intevation.flys.client.shared.exceptions.ServerException;
+import de.intevation.flys.client.shared.model.Artifact;
+import de.intevation.flys.client.shared.model.Collection;
+import de.intevation.flys.client.shared.model.Recommendation;
+
+import de.intevation.flys.client.client.services.LoadArtifactService;
+
+/**
+ * This service creates a new Artifact based on a given Recommendation and puts
+ * this new artifact into a specified Collection.
+ *
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class LoadArtifactServiceImpl
+extends      ArtifactServiceImpl
+implements   LoadArtifactService
+{
+    public static final String ERROR_LOAD_ARTIFACT = "error_load_artifact";
+
+    public Artifact load(
+        Collection     parent,
+        Recommendation recom,
+        String         factory,
+        String         url,
+        String         locale
+    )
+    throws ServerException {
+        System.out.println(
+            "LoadArtifactServiceImpl.load: " + recom.getMasterArtifact());
+
+        // 1) Clone the Artifact specified in >>recom<<
+        Artifact clone = ArtifactHelper.createArtifact(
+            url, locale, factory, recom);
+
+        if (clone != null) {
+            System.out.println("Successfully create Artifact Clone. Add now!");
+            Collection c = CollectionHelper.addArtifact(
+                parent, clone, url, locale);
+
+            if (c != null) {
+                System.out.println("Successfully added Clone to Collection.");
+
+                return clone;
+            }
+        }
+
+        throw new ServerException(ERROR_LOAD_ARTIFACT);
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-client/src/main/webapp/WEB-INF/web.xml	Thu Sep 15 08:39:07 2011 +0000
+++ b/flys-client/src/main/webapp/WEB-INF/web.xml	Thu Sep 15 12:55:36 2011 +0000
@@ -98,6 +98,16 @@
   </servlet-mapping>
 
   <servlet>
+    <servlet-name>load-artifact</servlet-name>
+    <servlet-class>de.intevation.flys.client.server.LoadArtifactServiceImpl</servlet-class>
+  </servlet>
+  
+  <servlet-mapping>
+    <servlet-name>load-artifact</servlet-name>
+    <url-pattern>/flys/load-artifact</url-pattern>
+  </servlet-mapping>
+
+  <servlet>
     <servlet-name>describe-collection</servlet-name>
     <servlet-class>de.intevation.flys.client.server.DescribeCollectionServiceImpl</servlet-class>
   </servlet>

http://dive4elements.wald.intevation.org