teichmann@5861: /* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde teichmann@5861: * Software engineering by Intevation GmbH teichmann@5861: * teichmann@5861: * This file is Free Software under the GNU AGPL (>=v3) teichmann@5861: * and comes with ABSOLUTELY NO WARRANTY! Check out the teichmann@5861: * documentation coming with Dive4Elements River for details. teichmann@5861: */ teichmann@5861: teichmann@5835: package org.dive4elements.river.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: teichmann@5835: import org.dive4elements.artifacts.common.ArtifactNamespaceContext; teichmann@5835: import org.dive4elements.artifacts.common.utils.ClientProtocolUtils; teichmann@5835: import org.dive4elements.artifacts.common.utils.XMLUtils; teichmann@5835: import org.dive4elements.artifacts.common.utils.XMLUtils.ElementCreator; ingo@905: teichmann@5835: import org.dive4elements.artifacts.httpclient.exceptions.ConnectionException; teichmann@5835: import org.dive4elements.artifacts.httpclient.http.HttpClient; teichmann@5835: import org.dive4elements.artifacts.httpclient.http.HttpClientImpl; teichmann@5835: import org.dive4elements.artifacts.httpclient.http.response.DocumentResponseHandler; teichmann@5835: teichmann@5835: import org.dive4elements.river.client.shared.exceptions.ServerException; teichmann@5835: import org.dive4elements.river.client.shared.model.Artifact; teichmann@5835: import org.dive4elements.river.client.shared.model.AttributedTheme; teichmann@5835: import org.dive4elements.river.client.shared.model.ChartMode; teichmann@5835: import org.dive4elements.river.client.shared.model.Collection; teichmann@5835: import org.dive4elements.river.client.shared.model.CollectionItem; teichmann@5835: import org.dive4elements.river.client.shared.model.DefaultCollection; teichmann@5835: import org.dive4elements.river.client.shared.model.DefaultCollectionItem; teichmann@5835: import org.dive4elements.river.client.shared.model.DefaultFacet; teichmann@5835: import org.dive4elements.river.client.shared.model.ExportMode; teichmann@5835: import org.dive4elements.river.client.shared.model.Facet; teichmann@5835: import org.dive4elements.river.client.shared.model.MapMode; teichmann@5835: import org.dive4elements.river.client.shared.model.OutputMode; teichmann@5835: import org.dive4elements.river.client.shared.model.OverviewMode; teichmann@5835: import org.dive4elements.river.client.shared.model.ReportMode; teichmann@5835: import org.dive4elements.river.client.shared.model.Recommendation; teichmann@5835: import org.dive4elements.river.client.shared.model.Theme; teichmann@5835: import org.dive4elements.river.client.shared.model.ThemeList; teichmann@5835: import org.dive4elements.river.client.shared.model.Settings; teichmann@5835: import org.dive4elements.river.client.shared.model.Property; teichmann@5835: import org.dive4elements.river.client.shared.model.PropertyGroup; teichmann@5835: import org.dive4elements.river.client.shared.model.PropertySetting; teichmann@5835: import org.dive4elements.river.client.shared.model.StringProperty; teichmann@5835: import org.dive4elements.river.client.shared.model.DoubleProperty; teichmann@5835: import org.dive4elements.river.client.shared.model.IntegerProperty; teichmann@5835: import org.dive4elements.river.client.shared.model.BooleanProperty; teichmann@5835: import org.dive4elements.river.client.shared.model.OutputSettings; ingo@530: raimund@1439: //temporary ingo@530: ingo@530: /** ingo@530: * @author Ingo Weinzierl 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 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 mmodes) ingo@530: { ingo@1367: logger.debug("CollectionHelper.createOutputElements"); ingo@530: ingo@530: java.util.Collection 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 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 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 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 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 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 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) { bjoern@4663: logger.debug("CollectionHelper.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) { felix@4530: logger.warn("Found an invalid Collection (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 recommended = parseRecommendations(description); felix@1435: Map collectionItems = felix@1435: new HashMap(); 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 themeLists = parseThemeLists(description, collectionItems); felix@1435: c.setThemeLists(themeLists); felix@1435: raimund@1464: Map 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 parseThemeLists( felix@1435: Document desc, Map collectionItems felix@1435: ) { bjoern@4663: logger.debug("CollectionHelper.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 themeList = new HashMap(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 collectionItems felix@1435: ) { bjoern@4663: logger.debug("CollectionHelper.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 themeList = new ArrayList(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) { bjoern@4663: logger.debug("CollectionHelper.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 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 list = new HashMap(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 props = new ArrayList (); 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 props = new ArrayList(); 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 node 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 modes = new ArrayList(); 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 dataItems = new HashMap(); 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 parseOutputModes(Element node) { bjoern@4663: logger.debug("CollectionHelper.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 modes = new ArrayList(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 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 parseDataItems(Element node) { bjoern@4663: logger.debug("CollectionHelper.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 data = new HashMap(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 extractFacets(Element outmode) { bjoern@4663: logger.debug("CollectionHelper - 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 facets = new ArrayList(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 parseRecommendations(Document doc) { bjoern@4663: logger.debug("CollectionHelper.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 recs = new ArrayList(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: { bjoern@4663: logger.debug("CollectionHelper.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: { bjoern@4663: logger.debug("CollectionHelper.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 :