ingo@530: package de.intevation.flys.client.server;
ingo@530: 
ingo@905: import java.util.ArrayList;
ingo@905: import java.util.HashMap;
ingo@530: import java.util.List;
ingo@530: import java.util.Map;
ingo@804: import java.util.Set;
ingo@530: 
ingo@905: import javax.xml.xpath.XPathConstants;
ingo@905: 
ingo@530: import org.w3c.dom.Document;
ingo@530: import org.w3c.dom.Element;
ingo@905: import org.w3c.dom.NamedNodeMap;
ingo@905: import org.w3c.dom.Node;
ingo@905: import org.w3c.dom.NodeList;
ingo@530: 
ingo@1367: import org.apache.log4j.Logger;
ingo@1367: 
ingo@530: import de.intevation.artifacts.common.ArtifactNamespaceContext;
ingo@905: import de.intevation.artifacts.common.utils.ClientProtocolUtils;
ingo@530: import de.intevation.artifacts.common.utils.XMLUtils;
ingo@530: import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator;
ingo@530: 
ingo@905: import de.intevation.artifacts.httpclient.exceptions.ConnectionException;
ingo@905: import de.intevation.artifacts.httpclient.http.HttpClient;
ingo@905: import de.intevation.artifacts.httpclient.http.HttpClientImpl;
ingo@905: import de.intevation.artifacts.httpclient.http.response.DocumentResponseHandler;
ingo@905: 
ingo@905: import de.intevation.flys.client.shared.exceptions.ServerException;
ingo@905: import de.intevation.flys.client.shared.model.Artifact;
ingo@804: import de.intevation.flys.client.shared.model.AttributedTheme;
ingo@905: import de.intevation.flys.client.shared.model.ChartMode;
ingo@530: import de.intevation.flys.client.shared.model.Collection;
ingo@905: import de.intevation.flys.client.shared.model.CollectionItem;
ingo@905: import de.intevation.flys.client.shared.model.DefaultCollection;
ingo@905: import de.intevation.flys.client.shared.model.DefaultCollectionItem;
ingo@905: import de.intevation.flys.client.shared.model.DefaultFacet;
ingo@905: import de.intevation.flys.client.shared.model.ExportMode;
ingo@905: import de.intevation.flys.client.shared.model.Facet;
ingo@905: import de.intevation.flys.client.shared.model.MapMode;
ingo@530: import de.intevation.flys.client.shared.model.OutputMode;
raimund@2977: import de.intevation.flys.client.shared.model.OverviewMode;
ingo@905: import de.intevation.flys.client.shared.model.ReportMode;
ingo@809: import de.intevation.flys.client.shared.model.Recommendation;
ingo@530: import de.intevation.flys.client.shared.model.Theme;
ingo@530: import de.intevation.flys.client.shared.model.ThemeList;
raimund@1439: import de.intevation.flys.client.shared.model.Settings;
raimund@1439: import de.intevation.flys.client.shared.model.Property;
raimund@1439: import de.intevation.flys.client.shared.model.PropertyGroup;
raimund@1439: import de.intevation.flys.client.shared.model.PropertySetting;
raimund@1439: import de.intevation.flys.client.shared.model.StringProperty;
raimund@1464: import de.intevation.flys.client.shared.model.DoubleProperty;
raimund@1464: import de.intevation.flys.client.shared.model.IntegerProperty;
raimund@1464: import de.intevation.flys.client.shared.model.BooleanProperty;
raimund@1439: import de.intevation.flys.client.shared.model.OutputSettings;
ingo@530: 
raimund@1439: //temporary
ingo@530: 
ingo@530: /**
ingo@530:  * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
ingo@530:  */
ingo@530: public class CollectionHelper {
ingo@530: 
ingo@1367:     private static final Logger logger =
ingo@1367:         Logger.getLogger(CollectionHelper.class);
ingo@1367: 
ingo@905:     public static final String ERROR_ADD_ARTIFACT = "error_add_artifact";
ingo@905: 
felix@1332:     public static final String ERROR_REMOVE_ARTIFACT = "error_remove_artifact";
felix@1332: 
ingo@905:     public static final String XPATH_FACETS = "art:facets/art:facet";
ingo@905: 
ingo@905:     public static final String XPATH_LOADED_RECOMMENDATIONS =
ingo@905:         "/art:artifact-collection/art:attribute/art:loaded-recommendations/art:recommendation";
ingo@905: 
ingo@905: 
ingo@530:     public static Document createAttribute(Collection collection) {
ingo@1367:         logger.debug("CollectionHelper.createAttribute");
ingo@530: 
ingo@530:         Document doc = XMLUtils.newDocument();
ingo@530: 
ingo@530:         ElementCreator cr = new ElementCreator(
ingo@530:             doc,
ingo@530:             ArtifactNamespaceContext.NAMESPACE_URI,
ingo@530:             ArtifactNamespaceContext.NAMESPACE_PREFIX);
ingo@530: 
ingo@530:         Element attr = cr.create("attribute");
ingo@530: 
ingo@530:         doc.appendChild(attr);
ingo@530: 
ingo@530:         Map<String, OutputMode> tmpOuts = collection.getOutputModes();
ingo@530: 
ingo@530:         Element outs = createOutputElements(cr, collection, tmpOuts);
ingo@809:         Element recs = createRecommendationsElements(cr, collection);
ingo@530: 
ingo@530:         if (outs != null) {
ingo@530:             attr.appendChild(outs);
ingo@530:         }
ingo@530: 
ingo@809:         if (recs != null) {
ingo@809:             attr.appendChild(recs);
ingo@809:         }
ingo@809: 
ingo@530:         return doc;
ingo@530:     }
ingo@530: 
ingo@530: 
ingo@530:     /**
ingo@530:      * Creates a whole block with art:output nodes.
ingo@530:      *
ingo@530:      * @param cr The ElementCreator used to create new elements.
ingo@530:      * @param c  The collection.
ingo@530:      * @param modes The OutputModes that should be included.
ingo@530:      *
ingo@530:      * @return an element with output modes.
ingo@530:      */
ingo@530:     protected static Element createOutputElements(
ingo@530:         ElementCreator          cr,
ingo@530:         Collection              c,
ingo@530:         Map<String, OutputMode> mmodes)
ingo@530:     {
ingo@1367:         logger.debug("CollectionHelper.createOutputElements");
ingo@530: 
ingo@530:         java.util.Collection<OutputMode> modes = mmodes != null
ingo@530:             ? mmodes.values()
ingo@530:             : null;
ingo@530: 
ingo@530:         if (modes == null || modes.size() == 0) {
ingo@1367:             logger.debug("Collection has no modes: " + c.identifier());
ingo@530:             return null;
ingo@530:         }
ingo@530: 
ingo@530:         Element outs = cr.create("outputs");
ingo@530: 
ingo@530:         for (OutputMode mode: modes) {
ingo@530:             Element out = createOutputElement(cr, c, mode);
ingo@530: 
ingo@530:             if (out != null) {
ingo@530:                 outs.appendChild(out);
ingo@530:             }
ingo@530:         }
ingo@530: 
ingo@530:         return outs;
ingo@530:     }
ingo@530: 
ingo@530: 
ingo@530:     /**
ingo@530:      * Create a node art:output that further consist of art:theme nodes.
ingo@530:      *
ingo@530:      * @param cr The ElementCreator used to create new elements.
ingo@530:      * @param c  The collection.
ingo@530:      * @param mode The OutputMode.
ingo@530:      *
ingo@530:      * @return an element that represents an output mode with its themes.
ingo@530:      */
ingo@530:     protected static Element createOutputElement(
ingo@530:         ElementCreator cr,
ingo@530:         Collection     collection,
ingo@530:         OutputMode     mode)
ingo@530:     {
ingo@1367:         logger.debug("CollectionHelper.createOutputElement");
ingo@530: 
ingo@530:         Element out = cr.create("output");
ingo@530:         cr.addAttr(out, "name", mode.getName(), false);
ingo@530: 
ingo@530:         ThemeList themeList = collection.getThemeList(mode.getName());
ingo@530:         List<Theme> themes  = themeList != null ? themeList.getThemes() : null;
ingo@530: 
ingo@530:         if (themes == null || themes.size() == 0) {
ingo@1367:             logger.debug("No themes for output mode: " + mode.getName());
ingo@530:             return null;
ingo@530:         }
ingo@530: 
ingo@530:         for (Theme theme: themes) {
ingo@530:             Element t = createThemeElement(cr, collection, theme);
ingo@530: 
ingo@530:             if (t != null) {
ingo@530:                 out.appendChild(t);
ingo@530:             }
ingo@530:         }
ingo@530: 
raimund@1478:         Document doc = out.getOwnerDocument();
raimund@1478: 
raimund@1478:         ElementCreator settingscr = new ElementCreator(doc, "", "");
raimund@1478: 
raimund@1478:         Settings settings = collection.getSettings(mode.getName());
raimund@1478:         if (settings == null ||
raimund@1478:             settings.getCategories().size() == 0)
raimund@1478:         {
raimund@1478:             logger.debug("No settings for output mode: " + mode.getName());
raimund@1478:         }
raimund@2434:         else {
raimund@2434:             Element s = createSettingsElement(settingscr, collection, settings);
raimund@2434:             if (s != null) {
raimund@2434:                 out.appendChild(s);
raimund@2434:             }
raimund@1478:         }
raimund@1478:         logger.info(XMLUtils.toString(out));
ingo@530:         return out;
ingo@530:     }
ingo@530: 
ingo@530: 
ingo@530:     /**
ingo@530:      * Creates a theme node art:theme that represents a curve in a chart or map.
ingo@530:      *
ingo@530:      * @param cr The ElementCreator used to create new elements.
ingo@530:      * @param collection The collection.
ingo@530:      * @param theme The theme whose attributes should be written to an element.
ingo@530:      *
ingo@530:      * @return an element that contains the informtion of the given theme.
ingo@530:      */
ingo@530:     protected static Element createThemeElement(
ingo@530:         ElementCreator cr,
ingo@530:         Collection     collection,
ingo@530:         Theme          theme)
ingo@530:     {
ingo@530:         if (theme == null) {
ingo@530:             return null;
ingo@530:         }
ingo@530: 
ingo@804:         Element t = cr.create("facet");
ingo@530: 
ingo@804:         if (theme instanceof AttributedTheme) {
ingo@804:             AttributedTheme at = (AttributedTheme) theme;
ingo@804:             Set<String>   keys = at.getKeys();
ingo@804: 
ingo@804:             for (String key: keys) {
ingo@804:                 cr.addAttr(t, key, at.getAttr(key), true);
ingo@804:             }
ingo@804:         }
ingo@804:         else {
ingo@804:             cr.addAttr(t, "active", Integer.toString(theme.getActive()), true);
ingo@804:             cr.addAttr(t, "artifact", theme.getArtifact(), true);
ingo@804:             cr.addAttr(t, "facet", theme.getFacet(), true);
ingo@804:             cr.addAttr(t, "pos", Integer.toString(theme.getPosition()), true);
ingo@804:             cr.addAttr(t, "index", Integer.toString(theme.getIndex()), true);
ingo@804:             cr.addAttr(t, "description", theme.getDescription(), true);
ingo@1342:             cr.addAttr(t, "visible", Integer.toString(theme.getVisible()), true);
ingo@804:         }
ingo@530: 
ingo@530:         return t;
ingo@530:     }
ingo@809: 
ingo@809: 
ingo@809:     /**
ingo@809:      * Creates a whole block with art:loaded-recommendations nodes.
ingo@809:      *
ingo@809:      * @param cr The ElementCreator used to create new elements.
ingo@809:      * @param c  The collection.
ingo@809:      *
ingo@809:      * @return an element with loaded recommendations.
ingo@809:      */
ingo@809:     protected static Element createRecommendationsElements(
ingo@809:         ElementCreator cr,
ingo@809:         Collection     c)
ingo@809:     {
ingo@1367:         logger.debug("CollectionHelper.createRecommendationsElements");
ingo@809: 
ingo@809:         List<Recommendation> rs = c.getRecommendations();
ingo@809: 
ingo@809:         if (rs == null || rs.size() == 0) {
ingo@1367:             logger.debug("Collection did not load recommendations: " +
ingo@809:                 c.identifier());
ingo@809:             return null;
ingo@809:         }
ingo@809: 
ingo@809:         Element loaded = cr.create("loaded-recommendations");
ingo@809: 
ingo@809:         for (Recommendation r: rs) {
ingo@809:             Element recommendation = createRecommendationElement(cr, c, r);
ingo@809: 
ingo@809:             if (recommendation != null) {
ingo@809:                 loaded.appendChild(recommendation);
ingo@809:             }
ingo@809:         }
ingo@809: 
ingo@809:         return loaded;
ingo@809:     }
ingo@809: 
ingo@809: 
ingo@809:     /**
ingo@809:      * Create a node art:recommended.
ingo@809:      *
ingo@809:      * @param cr The ElementCreator used to create new elements.
ingo@809:      * @param c  The collection.
ingo@809:      * @param r  The Recommendation.
ingo@809:      *
ingo@809:      * @return an element that represents an output mode with its themes.
ingo@809:      */
ingo@809:     protected static Element createRecommendationElement(
ingo@809:         ElementCreator cr,
ingo@809:         Collection     c,
ingo@809:         Recommendation r)
ingo@809:     {
ingo@1367:         logger.debug("CollectionHelper.createRecommendationElement");
ingo@809: 
ingo@809:         Element recommendation = cr.create("recommendation");
ingo@809:         cr.addAttr(recommendation, "factory", r.getFactory(), true);
sascha@836:         cr.addAttr(recommendation, "ids", r.getIDs(), true);
ingo@809: 
ingo@809:         return recommendation;
ingo@809:     }
ingo@905: 
ingo@905: 
ingo@905:     /**
raimund@1478:      *
raimund@1478:      */
raimund@1478:     protected static Element createSettingsElement(
raimund@1478:         ElementCreator cr,
raimund@1478:         Collection c,
raimund@1478:         Settings s)
raimund@1478:     {
raimund@1478:         logger.debug("CollectionHelper.createSettingsElement");
raimund@1478:         Element settings = cr.create("settings");
raimund@1478: 
raimund@1478:         List<String> categories = s.getCategories();
raimund@1478: 
raimund@1478:         for (String category: categories) {
raimund@1478:             Element cat =cr.create(category);
raimund@1478:             settings.appendChild(cat);
raimund@1478:             List<Property> props = s.getSettings(category);
raimund@1478:             for (Property p: props) {
raimund@1478:                 if (p instanceof PropertyGroup) {
raimund@1478:                     Element prop = createPropertyGroupElement(cr,
raimund@1478:                                                               (PropertyGroup)p);
raimund@1478:                     cat.appendChild(prop);
raimund@1478:                 }
raimund@1478:                 else if (p instanceof PropertySetting) {
raimund@1478:                     Element prop = createPropertyElement (cr,
raimund@1478:                                                           (PropertySetting)p);
raimund@1478:                     cat.appendChild(prop);
raimund@1478:                 }
raimund@1478:             }
raimund@1478:         }
raimund@1478:         return settings;
raimund@1478:     }
raimund@1478: 
raimund@1478: 
raimund@1478:     /**
raimund@1478:      *
raimund@1478:      */
raimund@1478:     protected static Element createPropertyGroupElement(
raimund@1478:         ElementCreator cr,
raimund@1478:         PropertyGroup pg)
raimund@1478:     {
raimund@1478:         Element e = cr.create(pg.getName());
raimund@1478: 
raimund@1478:         List<Property> list = pg.getProperties();
raimund@1478:         for (Property p: list) {
raimund@1478:             Element pe = createPropertyElement(cr, (PropertySetting)p);
raimund@1478:             e.appendChild(pe);
raimund@1478:         }
raimund@1478:         return e;
raimund@1478:     }
raimund@1478: 
raimund@1478: 
raimund@1478:     /**
raimund@1478:      *
raimund@1478:      */
raimund@1478:     protected static Element createPropertyElement(
raimund@1478:         ElementCreator cr,
raimund@1478:         PropertySetting p)
raimund@1478:     {
raimund@1478:         Element e = cr.create(p.getName());
raimund@1478: 
raimund@1478:         if(p instanceof BooleanProperty) {
raimund@1478:             cr.addAttr(e, "type", "boolean", false);
raimund@1478:         }
raimund@1478:         else if(p instanceof DoubleProperty) {
raimund@1478:             cr.addAttr(e, "type", "double", false);
raimund@1478:         }
raimund@1478:         else if(p instanceof IntegerProperty) {
raimund@1478:             cr.addAttr(e, "type", "integer", false);
raimund@1478:         }
raimund@1478:         else if(p instanceof StringProperty) {
raimund@1478:             cr.addAttr(e, "type", "string", false);
raimund@1478:         }
raimund@1478: 
raimund@1507:         e.setTextContent(p.getValue().toString());
raimund@1478:         cr.addAttr(e, "display", p.getAttribute("display"), false);
raimund@1478:         return e;
raimund@1478:     }
raimund@1478: 
raimund@1478: 
raimund@1478:     /**
felix@1318:      * Take the DESCRIBE document of the Collections describe()
ingo@905:      * operation and extracts the information about the collection itself and
ingo@905:      * the collection items.
ingo@905:      *
ingo@905:      * @param description The DESCRIBE document of the Collections describe()
ingo@905:      * operation.
ingo@905:      *
ingo@905:      * @return a Collection with CollectionItems.
ingo@905:      */
ingo@905:     public static Collection parseCollection(Document description) {
ingo@1367:         logger.debug("AddArtifactServiceImpl.parseCollection");
ingo@905: 
ingo@905:         if (description == null) {
ingo@1367:             logger.warn("The DESCRIBE of the Collection is null!");
ingo@905:             return null;
ingo@905:         }
ingo@905: 
ingo@905:         String uuid = XMLUtils.xpathString(
ingo@905:             description,
ingo@905:             "art:artifact-collection/@art:uuid",
ingo@905:             ArtifactNamespaceContext.INSTANCE);
ingo@905: 
ingo@905:         String ttlStr = XMLUtils.xpathString(
ingo@905:             description,
ingo@905:             "art:artifact-collection/@art:ttl",
ingo@905:             ArtifactNamespaceContext.INSTANCE);
ingo@905: 
ingo@905:         String name = XMLUtils.xpathString(
ingo@905:             description,
ingo@905:             "art:artifact-collection/@art:name",
ingo@905:             ArtifactNamespaceContext.INSTANCE);
ingo@905: 
felix@1318:         if (uuid.length() == 0) {
ingo@1367:             logger.warn("Found an invalid (zero length uuid) Collection!");
felix@1318:             return null;
felix@1318:         }
felix@1318: 
felix@1318:         if (ttlStr.length() == 0) {
ingo@1367:             logger.warn("Found an invalid Collectioni (zero length ttl)!");
ingo@905:             return null;
ingo@905:         }
ingo@905: 
ingo@905: 
ingo@905:         long ttl = -1;
ingo@905:         try {
ingo@905:             ttl = Long.valueOf(ttlStr);
ingo@905:         }
ingo@905:         catch (NumberFormatException nfe) {
ingo@905:             // do nothing
ingo@905:         }
ingo@905: 
ingo@905:         List<Recommendation> recommended = parseRecommendations(description);
felix@1435:         Map<String, CollectionItem> collectionItems =
felix@1435:             new HashMap<String, CollectionItem>();
ingo@905: 
ingo@905:         name = (name != null && name.length() > 0) ? name : uuid;
ingo@905: 
felix@1435:         Collection c = new DefaultCollection(uuid, ttl, name, recommended);
ingo@905: 
ingo@905:         NodeList items = (NodeList) XMLUtils.xpath(
ingo@905:             description,
ingo@905:             "art:artifact-collection/art:artifacts/art:artifact",
ingo@905:             XPathConstants.NODESET,
ingo@905:             ArtifactNamespaceContext.INSTANCE);
ingo@905: 
ingo@905:         if (items == null || items.getLength() == 0) {
ingo@1367:             logger.debug("No collection item found for this collection.");
ingo@905: 
ingo@905:             return c;
ingo@905:         }
ingo@905: 
ingo@905:         int size = items.getLength();
ingo@905: 
ingo@905:         for (int i = 0; i < size; i++) {
ingo@905:             CollectionItem item = parseCollectionItem(
ingo@905:                 (Element)items.item(i),
ingo@905:                 i == 0);
ingo@905: 
ingo@905:             if (item != null) {
ingo@905:                 c.addItem(item);
felix@1435:                 collectionItems.put(item.identifier() ,item);
ingo@905:             }
ingo@905:         }
ingo@905: 
felix@1435:         Map<String, ThemeList> themeLists = parseThemeLists(description, collectionItems);
felix@1435:         c.setThemeLists(themeLists);
felix@1435: 
raimund@1464:         Map<String, Settings> outSettings = parseSettings(description);
raimund@1464:         c.setSettings(outSettings);
ingo@1367:         logger.debug(
ingo@905:             "Found " + c.getItemLength() + " collection items " +
ingo@905:             "for the Collection '" + c.identifier() + "'.");
ingo@905: 
ingo@905:         return c;
ingo@905:     }
ingo@905: 
ingo@905: 
felix@1435:     /**
felix@1435:      * @param collectionItems map to look up collection item mapping a themes
felix@1435:      *                        (artifact) uuid.
felix@1435:      */
felix@1435:     protected static Map<String, ThemeList> parseThemeLists(
felix@1435:         Document desc, Map<String, CollectionItem> collectionItems
felix@1435:     ) {
ingo@1367:         logger.debug("DescribeCollectionServiceImpl.parseThemeLists");
ingo@905: 
ingo@905:         NodeList lists = (NodeList) XMLUtils.xpath(
ingo@905:             desc,
ingo@905:             "/art:artifact-collection/art:attribute/art:outputs/art:output",
ingo@905:             XPathConstants.NODESET,
ingo@905:             ArtifactNamespaceContext.INSTANCE);
ingo@905: 
ingo@905:         int num = lists != null ? lists.getLength() : 0;
ingo@905: 
ingo@905:         Map<String, ThemeList> themeList = new HashMap<String, ThemeList>(num);
ingo@905: 
ingo@905:         String uri = ArtifactNamespaceContext.NAMESPACE_URI;
ingo@905: 
ingo@905:         for (int i = 0; i < num; i++) {
ingo@905:             Element node = (Element)lists.item(i);
ingo@905: 
ingo@905:             String outName = node.getAttribute("name");
ingo@905: 
ingo@905:             if (outName.length() > 0) {
felix@1435:                 ThemeList list = parseThemeList(node, collectionItems);
felix@1435: 
ingo@905:                 if (list.getThemeCount() > 0) {
ingo@905:                     themeList.put(outName, list);
ingo@905:                 }
ingo@905:             }
ingo@905:         }
ingo@905: 
ingo@905:         return themeList;
ingo@905:     }
ingo@905: 
ingo@905: 
felix@1435:     /**
felix@1435:      * @param collectionItems map to look up collection item mapping a themes
felix@1435:      *                        (artifact) uuid.
felix@1435:      */
felix@1435:     protected static ThemeList parseThemeList(
felix@1435:         Element node, Map<String, CollectionItem> collectionItems
felix@1435:     ) {
ingo@1367:         logger.debug("DescribeCollectionServiceImpl.parseThemeList");
ingo@905: 
ingo@905:         NodeList themes = node.getElementsByTagNameNS(
ingo@905:             ArtifactNamespaceContext.NAMESPACE_URI,
ingo@905:             "facet");
ingo@905: 
ingo@905:         int num = themes != null ? themes.getLength() : 0;
ingo@905: 
ingo@905:         List<Theme> themeList = new ArrayList<Theme>(num);
ingo@905: 
ingo@905:         for (int i = 0; i < num; i++) {
ingo@905:             Theme theme = parseTheme((Element)themes.item(i));
felix@1435:             theme.setCollectionItem(collectionItems.get(theme.getArtifact()));
ingo@905: 
ingo@905:             if (theme != null) {
ingo@905:                 themeList.add(theme);
ingo@905:             }
ingo@905:         }
ingo@905: 
ingo@905:         return new ThemeList(themeList);
ingo@905:     }
ingo@905: 
ingo@905: 
ingo@905:     protected static Theme parseTheme(Element ele) {
ingo@1367:         logger.debug("DescribeCollectionServiceImpl.parseTheme");
ingo@905: 
ingo@905:         String uri = ArtifactNamespaceContext.NAMESPACE_URI;
ingo@905: 
ingo@905:         NamedNodeMap attrMap = ele.getAttributes();
ingo@905:         int          attrNum = attrMap != null ? attrMap.getLength() : 0;
ingo@905: 
ingo@905:         AttributedTheme t = new AttributedTheme();
ingo@905: 
ingo@905:         for (int i = 0; i < attrNum; i++) {
ingo@905:             Node attr = attrMap.item(i);
ingo@905: 
ingo@905:             String prefix = attr.getPrefix();
ingo@905:             String name   = attr.getNodeName().replace(prefix + ":", "");
ingo@905:             String value  = attr.getNodeValue();
ingo@905: 
ingo@905:             t.addAttr(name, value);
ingo@905:         }
ingo@905: 
ingo@905:         return t;
ingo@905:     }
ingo@905: 
ingo@905: 
ingo@905:     /**
raimund@1439:      * Parse Settings elements.
raimund@1439:      *
raimund@1439:      * @param description The collection description.
raimund@1439:      *
raimund@1439:      * @return Map containing the settings.
raimund@1439:      */
raimund@1439:     protected static Map<String, Settings> parseSettings(Document description) {
raimund@1439:         logger.info("parseSettings");
raimund@1464: 
raimund@1464:         NodeList lists = (NodeList) XMLUtils.xpath(
raimund@1464:             description,
raimund@1464:             "/art:artifact-collection/art:attribute/art:outputs/art:output",
raimund@1464:             XPathConstants.NODESET,
raimund@1464:             ArtifactNamespaceContext.INSTANCE);
raimund@1464: 
raimund@1464:         int num = lists != null ? lists.getLength() : 0;
raimund@1464: 
raimund@1464:         Map<String, Settings> list = new HashMap<String, Settings>(num);
raimund@1464: 
raimund@1464:         String uri = ArtifactNamespaceContext.NAMESPACE_URI;
raimund@1464: 
raimund@1464:         for (int i = 0; i < num; i++) {
raimund@1464:             Element node = (Element)lists.item(i);
raimund@1464:             String outName = node.getAttribute("name");
raimund@1464:             Settings s = parseSettings(outName, node);
raimund@1464:             list.put(outName, s);
raimund@1464:         }
raimund@1439: 
raimund@1439:         return list;
raimund@1439:     }
raimund@1439: 
raimund@1439: 
raimund@1439:     /**
felix@3509:      * From a document, parse the settings for an output and create an
felix@3509:      * OutputSettings object.
raimund@1439:      */
raimund@1464:     protected static Settings parseSettings(String outName, Element node) {
raimund@1439:         OutputSettings set = new OutputSettings(outName);
raimund@1464: 
raimund@1464:         NodeList elements = node.getElementsByTagName("settings");
raimund@1464: 
raimund@1464:         if (elements.getLength() == 0 || elements.getLength() > 1) {
raimund@1464:             return set;
raimund@1464:         }
raimund@1464: 
raimund@1464:         Element settings = (Element)elements.item(0);
raimund@1464: 
felix@3509:         // Get the categories
raimund@1439:         NodeList catNodes = settings.getChildNodes();
raimund@1439:         for (int i = 0; i < catNodes.getLength(); i++) {
raimund@1439:             Element catNode = (Element)catNodes.item(i);
raimund@1439: 
raimund@1439:             // The category name
raimund@1439:             String category = catNode.getTagName();
raimund@1439: 
raimund@1439:             // list of properties or groups (groups have child nodes).
raimund@1439:             NodeList list = catNode.getChildNodes();
raimund@1439: 
raimund@1439:             // iterate through all properties or groups.
raimund@1464:             List<Property> props = new ArrayList<Property> ();
raimund@1439:             for (int j = 0; j < list.getLength(); j++) {
felix@3509:                 Property p;
raimund@1439:                 Element e = (Element)list.item(j);
raimund@1439:                 if (e.hasChildNodes() &&
raimund@1439:                     e.getFirstChild().getNodeType() != Node.TEXT_NODE) {
raimund@1439:                     p = parseSettingsGroup(e);
raimund@1439:                 }
raimund@1439:                 else {
raimund@1439:                     p = parseSetting(e);
raimund@1439:                 }
raimund@1439:                 props.add(p);
raimund@1439:             }
raimund@1439:             set.setSettings(category, props);
raimund@1439:         }
raimund@1439:         return set;
raimund@1439:     }
raimund@1439: 
raimund@1439: 
raimund@1439:     /**
raimund@1439:      *
raimund@1439:      */
raimund@1439:     protected static Property parseSettingsGroup(Element group) {
raimund@1439:         PropertyGroup p = new PropertyGroup();
raimund@1439:         p.setName(group.getTagName());
raimund@1439: 
raimund@1439:         NodeList list = group.getChildNodes();
raimund@1439:         ArrayList<Property> props = new ArrayList<Property>();
raimund@1439:         for (int i = 0; i < list.getLength(); i++) {
raimund@1439:             props.add(parseSetting((Element)list.item(i)));
raimund@1439:         }
raimund@1439:         p.setProperties(props);
raimund@1439:         return p;
raimund@1439:     }
raimund@1439: 
raimund@1439: 
raimund@1439:     /**
felix@3509:      * From a property element create a Property object.
raimund@1439:      */
raimund@1439:     protected static Property parseSetting(Element property){
raimund@1439:         NamedNodeMap attrMap = property.getAttributes();
raimund@1439:         int          attrNum = attrMap != null ? attrMap.getLength() : 0;
raimund@1439: 
raimund@1439:         Node type = attrMap.getNamedItem("type");
raimund@1439:         String t = type.getNodeValue();
raimund@1439:         PropertySetting ps = new PropertySetting();
raimund@1439: 
raimund@1439:         if(t.equals("string")) {
raimund@1439:             ps = new StringProperty();
raimund@1439:         }
raimund@1464:         else if (t.equals("integer")) {
raimund@1464:             ps = new IntegerProperty();
raimund@1464:         }
raimund@1464:         else if (t.equals("double")) {
raimund@1464:             ps = new DoubleProperty();
raimund@1464:         }
raimund@1464:         else if (t.equals("boolean")) {
raimund@1464:             ps = new BooleanProperty();
raimund@1464:         }
raimund@1439:         ps.setName(property.getTagName());
raimund@1439:         ps.setValue(property.getTextContent());
raimund@1439: 
raimund@1439:         for (int i = 0; i < attrNum; i++) {
raimund@1439:             Node attr = attrMap.item(i);
raimund@1439: 
raimund@1439:             String name   = attr.getNodeName();
raimund@1439:             String value  = attr.getNodeValue();
raimund@1439:             if(name.equals("type")) {
raimund@1439:                 continue;
raimund@1439:             }
raimund@1439:             ps.setAttribute(name, value);
raimund@1439:         }
raimund@1439:         return ps;
raimund@1439:     }
raimund@1439: 
raimund@1439: 
raimund@1439:     /**
ingo@905:      * This method extracts the CollectionItem from <i>node</i> with its output
ingo@905:      * modes. The output modes are parsed using the parseOutputModes() method.
ingo@905:      *
ingo@905:      * @param node A node that contains information about a CollectionItem.
ingo@905:      *
ingo@905:      * @return a CollectionItem.
ingo@905:      */
ingo@905:     protected static CollectionItem parseCollectionItem(
ingo@905:         Element node,
ingo@905:         boolean outs
ingo@905:     ) {
felix@3509:         logger.debug("CollectionHelper.parseCollectionItem");
ingo@905: 
ingo@905:         if (node == null) {
ingo@1367:             logger.debug("The node for parsing CollectionItem is null!");
ingo@905:             return null;
ingo@905:         }
ingo@905: 
ingo@905:         String uri = ArtifactNamespaceContext.NAMESPACE_URI;
ingo@905: 
ingo@905:         String uuid = node.getAttributeNS(uri, "uuid");
ingo@905:         String hash = node.getAttributeNS(uri, "hash");
ingo@905: 
ingo@905:         if (uuid == null || uuid.length() == 0) {
ingo@1367:             logger.warn("Found an invalid CollectionItem!");
ingo@905:             return null;
ingo@905:         }
ingo@905: 
ingo@905:         List<OutputMode> modes = new ArrayList<OutputMode>();
ingo@905: 
ingo@905:         if (outs) {
ingo@905:             NodeList outputmodes = node.getElementsByTagNameNS(
ingo@905:                 uri, "outputmodes");
ingo@905: 
ingo@905:             if (outputmodes.getLength() < 1) {
ingo@905:                 return null;
ingo@905:             }
ingo@905: 
ingo@905:             Element om = (Element)outputmodes.item(0);
ingo@905: 
ingo@905:             modes = parseOutputModes(om);
ingo@905:         }
ingo@905: 
felix@1435:         HashMap<String, String> dataItems = new HashMap<String, String>();
felix@1435: 
felix@1435:         NodeList dataItemNodes = node.getElementsByTagNameNS(
felix@1435:             uri, "data-items");
felix@1435: 
felix@1435:         Element di = (Element)dataItemNodes.item(0);
felix@1435:         dataItems = parseDataItems(di);
felix@1435: 
felix@1435:         return new DefaultCollectionItem(uuid, hash, modes, dataItems);
ingo@905:     }
ingo@905: 
ingo@905: 
ingo@905:     /**
ingo@905:      * This method extracts the OutputModes available for a specific
ingo@905:      * CollectionItem and returns them as list.
ingo@905:      *
ingo@905:      * @param node The root node of the outputmodes list.
ingo@905:      *
ingo@905:      * @return a list of OutputModes.
ingo@905:      */
ingo@905:     protected static List<OutputMode> parseOutputModes(Element node) {
ingo@1367:         logger.debug("AddArtifactServiceImpl.parseOutputModes");
ingo@905: 
ingo@905:         if (node == null) {
ingo@1367:             logger.debug("The node for parsing OutputModes is null!");
ingo@905:             return null;
ingo@905:         }
ingo@905: 
ingo@905:         String uri = ArtifactNamespaceContext.NAMESPACE_URI;
ingo@905: 
ingo@905:         NodeList list = node.getElementsByTagNameNS(uri, "output");
ingo@905: 
ingo@905:         int size = list.getLength();
ingo@905: 
ingo@905:         if (size == 0) {
ingo@1367:             logger.debug("No outputmode nodes found!");
ingo@905:             return null;
ingo@905:         }
ingo@905: 
ingo@905:         List<OutputMode> modes = new ArrayList<OutputMode>(size);
ingo@905: 
ingo@905:         for (int i = 0; i < size; i++) {
ingo@905:             Element tmp = (Element)list.item(i);
ingo@905: 
ingo@905:             String name = tmp.getAttributeNS(uri, "name");
ingo@905:             String desc = tmp.getAttributeNS(uri, "description");
ingo@905:             String mime = tmp.getAttributeNS(uri, "mime-type");
ingo@905:             String type = tmp.getAttributeNS(uri, "type");
ingo@905: 
ingo@905:             if (name.length() == 0) {
ingo@1367:                 logger.warn("Found an invalid output mode.");
ingo@905:                 continue;
ingo@905:             }
ingo@905: 
ingo@905:             OutputMode outmode = null;
ingo@905:             List<Facet> fs     = extractFacets(tmp);
ingo@905: 
ingo@905:             if (type.equals("export")) {
ingo@905:                 outmode = new ExportMode(name, desc, mime, fs);
ingo@905:             }
ingo@905:             else if (type.equals("report")) {
ingo@905:                 outmode = new ReportMode(name, desc, mime, fs);
ingo@905:             }
ingo@905:             else if (type.equals("chart")){
raimund@2977:                 outmode = new ChartMode(name, desc, mime, fs, type);
ingo@905:             }
ingo@905:             else if (type.equals("map")){
ingo@905:                 outmode = new MapMode(name, desc, mime, fs);
ingo@905:             }
raimund@2977:             else if (type.equals("overview")) {
raimund@2977:                 outmode = new OverviewMode(name, desc, mime, fs, type);
raimund@2977:             }
ingo@905:             else {
ingo@1367:                 logger.warn("Broken Output mode without type found.");
ingo@905:                 continue;
ingo@905:             }
ingo@905: 
ingo@905:             modes.add(outmode);
ingo@905:         }
ingo@905: 
ingo@905:         return modes;
ingo@905:     }
ingo@905: 
ingo@905: 
felix@1435:     /**
felix@1435:      * Create a Key/Value map for data nodes of artifact/collectionitem.
felix@1435:      */
felix@1435:     protected static HashMap<String, String> parseDataItems(Element node) {
felix@1435:         logger.debug("AddArtifactServiceImpl.parseDataItems");
felix@1435: 
felix@1435:         if (node == null) {
felix@1435:             logger.debug("The node for parsing DataItems is null!");
felix@1435:             return null;
felix@1435:         }
felix@1435: 
felix@1435:         String uri = ArtifactNamespaceContext.NAMESPACE_URI;
felix@1435: 
felix@1435:         NodeList list = node.getElementsByTagNameNS(uri, "data");
felix@1435: 
felix@1435:         int size = list.getLength();
felix@1435: 
felix@1435:         if (size == 0) {
felix@1435:             logger.debug("No static data-item nodes found!");
felix@1435:         }
felix@1435: 
felix@1435:         HashMap<String, String> data = new HashMap<String, String>(size*2);
felix@1435: 
felix@1435:         for (int i = 0; i < size; i++) {
felix@1435:             Element tmp = (Element)list.item(i);
felix@1435: 
felix@1435:             String key = tmp.getAttributeNS(uri, "name");
felix@1435: 
felix@1435:             if (key.length() == 0) {
felix@1435:                 logger.warn("Found an invalid data item mode.");
felix@1435:                 continue;
felix@1435:             }
felix@1435: 
felix@1435:             // XXX We are restricted on 1/1 key/values in the data map here.
felix@1435:             NodeList valueNodes = tmp.getElementsByTagName("art:item");
felix@1435: 
felix@1435:             Element item = (Element) valueNodes.item(0);
felix@1435:             String value = item.getAttributeNS(uri, "value");
felix@1435:             logger.debug("Found a data item " + key + " : " + value);
felix@1435: 
felix@1435:             data.put(key, value);
felix@1435:         }
felix@1435: 
felix@1435: 
felix@1435:         // Dynamic data.
felix@1435:         list = node.getElementsByTagNameNS(uri, "select");
felix@1435: 
felix@1435:         size = list.getLength();
felix@1435: 
felix@1435:         if (size == 0) {
felix@1435:             logger.debug("No dynamic data-item nodes found!");
felix@1435:         }
felix@1435: 
felix@1435:         for (int i = 0; i < size; i++) {
felix@1435:             Element tmp = (Element)list.item(i);
felix@1435: 
felix@1435:             String key = tmp.getAttributeNS(uri, "name");
felix@1435: 
felix@1435:             if (key.length() == 0) {
felix@1435:                 logger.warn("Found an invalid data item node (missing key).");
felix@1435:                 continue;
felix@1435:             }
felix@1435: 
felix@1435:             String value = tmp.getAttributeNS(uri, "defaultValue");
felix@1435: 
felix@1435:             if (value.length() == 0) {
felix@1435:                 logger.warn("Found an invalid data item node (missing value).");
felix@1435:                 continue;
felix@1435:             }
felix@1435: 
felix@1435:             logger.debug("Found a (dyn) data item " + key + " : " + value);
felix@1435: 
felix@1435:             data.put(key, value);
felix@1435:         }
felix@1435: 
felix@1435:         return data;
felix@1435:     }
felix@1435: 
ingo@905:     protected static List<Facet> extractFacets(Element outmode) {
ingo@1367:         logger.debug("DescribeCollectionServiceImpl - extractFacets()");
ingo@905: 
ingo@905:         NodeList facetList = (NodeList) XMLUtils.xpath(
ingo@905:             outmode,
ingo@905:             XPATH_FACETS,
ingo@905:             XPathConstants.NODESET,
ingo@905:             ArtifactNamespaceContext.INSTANCE);
ingo@905: 
ingo@905:         int num = facetList != null ? facetList.getLength() : 0;
ingo@905: 
ingo@905:         List<Facet> facets = new ArrayList<Facet>(num);
ingo@905: 
ingo@905:         String uri = ArtifactNamespaceContext.NAMESPACE_URI;
ingo@905: 
ingo@905:         for (int i = 0; i < num; i++) {
ingo@905:             Element facetEl = (Element) facetList.item(i);
ingo@905: 
ingo@905:             String name  = facetEl.getAttributeNS(uri, "name");
ingo@905:             String desc  = facetEl.getAttributeNS(uri, "description");
ingo@905:             String index = facetEl.getAttributeNS(uri, "index");
ingo@905: 
ingo@905:             if (name != null && name.length() > 0 && index != null) {
ingo@905:                 facets.add(new DefaultFacet(name, Integer.valueOf(index),desc));
ingo@905:             }
ingo@905:         }
ingo@905: 
ingo@905:         return facets;
ingo@905:     }
ingo@905: 
ingo@905: 
ingo@905:     public static List<Recommendation> parseRecommendations(Document doc) {
ingo@1367:         logger.debug("DescribeCollectionServiceImpl.parseRecommendations");
ingo@905: 
ingo@905:         NodeList list = (NodeList) XMLUtils.xpath(
ingo@905:             doc,
ingo@905:             XPATH_LOADED_RECOMMENDATIONS,
ingo@905:             XPathConstants.NODESET,
ingo@905:             ArtifactNamespaceContext.INSTANCE);
ingo@905: 
ingo@905:         int num = list != null ? list.getLength() : 0;
ingo@905: 
ingo@905:         List<Recommendation> recs = new ArrayList<Recommendation>(num);
ingo@905: 
ingo@905:         String uri = ArtifactNamespaceContext.NAMESPACE_URI;
ingo@905: 
ingo@905:         for (int i = 0; i < num; i++) {
ingo@905:             Element rec = (Element) list.item(i);
ingo@905: 
ingo@905:             String factory = rec.getAttributeNS(uri, "factory");
ingo@905:             String dbids   = rec.getAttributeNS(uri, "ids");
ingo@905: 
ingo@905:             if (factory != null && factory.length() > 0) {
ingo@905:                 recs.add(new Recommendation(factory, dbids));
ingo@905:             }
ingo@905:         }
ingo@905: 
ingo@905:         return recs;
ingo@905:     }
ingo@905: 
ingo@905: 
felix@1318:     /**
felix@1318:      * Add an artifact to a collection.
felix@1318:      * @param collection Collection to add artifact to.
felix@1318:      * @param artifact   Artifact to add to collection
felix@1318:      */
ingo@905:     public static Collection addArtifact(
ingo@905:         Collection collection,
ingo@905:         Artifact   artifact,
ingo@905:         String     url,
ingo@905:         String     locale)
ingo@905:     throws ServerException
ingo@905:     {
ingo@1367:         logger.debug("Collection.addArtifact");
ingo@905: 
ingo@905:         if (collection == null) {
ingo@1367:             logger.warn("The given Collection is null!");
ingo@905:             return null;
ingo@905:         }
ingo@905: 
ingo@905:         Document add = ClientProtocolUtils.newAddArtifactDocument(
ingo@905:             artifact.getUuid(), null);
ingo@905: 
ingo@905:         HttpClient client = new HttpClientImpl(url, locale);
ingo@905: 
ingo@905:         try {
ingo@1367:             logger.debug("Do HTTP request now.");
ingo@905: 
ingo@905:             Document response = (Document) client.doCollectionAction(
ingo@905:                 add, collection.identifier(), new DocumentResponseHandler());
ingo@905: 
ingo@1367:             logger.debug(
ingo@905:                 "Finished HTTP request successfully. Parse Collection now.");
ingo@905: 
ingo@905:             Collection c = CollectionHelper.parseCollection(response);
ingo@905: 
ingo@905:             if (c == null) {
ingo@905:                 throw new ServerException(ERROR_ADD_ARTIFACT);
ingo@905:             }
ingo@905: 
ingo@905:             return c;
ingo@905:         }
ingo@905:         catch (ConnectionException ce) {
ingo@1367:             logger.error(ce, ce);
ingo@905:         }
ingo@905:         catch (Exception e) {
ingo@1367:             logger.error(e, e);
ingo@905:         }
ingo@905: 
ingo@905:         throw new ServerException(ERROR_ADD_ARTIFACT);
ingo@905:     }
felix@1320: 
felix@1320: 
felix@1320:     /**
felix@1320:      * Remove an artifact from a collection.
felix@1320:      * @param collection Collection to remove artifact to.
felix@1320:      * @param artifact   Artifact to add to collection
felix@1320:      */
felix@1320:     public static Collection removeArtifact(
felix@1320:         Collection collection,
felix@1320:         String     artifactId,
felix@1320:         String     url,
felix@1320:         String     locale)
felix@1320:     throws ServerException
felix@1320:     {
ingo@1367:         logger.debug("Collection.removeArtifact");
felix@1320: 
felix@1320:         if (collection == null) {
ingo@1367:             logger.warn("The given Collection is null!");
felix@1320:             return null;
felix@1320:         }
felix@1320: 
felix@1320:         Document remove = ClientProtocolUtils.newRemoveArtifactDocument(
felix@1320:             artifactId);
felix@1320: 
felix@1320:         HttpClient client = new HttpClientImpl(url, locale);
felix@1320: 
felix@1320:         try {
ingo@1367:             logger.debug("Do HTTP request now.");
felix@1320: 
felix@1320:             Document response = (Document) client.doCollectionAction(
felix@1320:                 remove, collection.identifier(), new DocumentResponseHandler());
felix@1320: 
ingo@1367:             logger.debug(
felix@1320:                 "Finished HTTP request successfully. Parse Collection now.");
ingo@1367:             logger.debug(XMLUtils.toString(response));
felix@1320: 
felix@1320:             Collection c = CollectionHelper.parseCollection(response);
felix@1320: 
felix@1320:             if (c == null) {
felix@1332:                 throw new ServerException(ERROR_REMOVE_ARTIFACT);
felix@1320:             }
felix@1320: 
felix@1320:             return c;
felix@1320:         }
felix@1320:         catch (ConnectionException ce) {
ingo@1367:             logger.error(ce, ce);
felix@1320:         }
felix@1320:         catch (Exception e) {
ingo@1367:             logger.error(e, e);
felix@1320:         }
felix@1332:         throw new ServerException(ERROR_REMOVE_ARTIFACT);
felix@1320:     }
ingo@530: }
ingo@530: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :