ingo@464: package de.intevation.gnv.artifacts.fis;
ingo@464: 
ingo@464: import java.io.IOException;
ingo@464: import java.io.OutputStream;
ingo@464: import java.util.ArrayList;
ingo@464: import java.util.Collection;
ingo@464: import java.util.HashMap;
ingo@464: import java.util.Iterator;
ingo@464: import javax.xml.xpath.XPathConstants;
ingo@464: 
ingo@464: import org.apache.log4j.Logger;
ingo@464: import org.w3c.dom.Document;
ingo@464: import org.w3c.dom.Element;
ingo@464: import org.w3c.dom.Node;
ingo@464: import org.w3c.dom.NodeList;
ingo@464: 
ingo@464: import de.intevation.artifactdatabase.DefaultArtifact;
ingo@464: import de.intevation.artifactdatabase.ProxyArtifact;
ingo@464: import de.intevation.artifactdatabase.XMLUtils;
ingo@464: import de.intevation.artifacts.Artifact;
ingo@464: import de.intevation.artifacts.ArtifactFactory;
ingo@464: import de.intevation.artifacts.ArtifactNamespaceContext;
ingo@464: import de.intevation.artifacts.CallContext;
ingo@464: import de.intevation.artifacts.CallMeta;
ingo@464: import de.intevation.gnv.artifacts.GNVArtifactBase;
ingo@464: import de.intevation.gnv.artifacts.context.GNVArtifactContext;
ingo@464: import de.intevation.gnv.artifacts.fis.product.DefaultProduct;
ingo@464: import de.intevation.gnv.artifacts.fis.product.Product;
ingo@464: import de.intevation.gnv.artifacts.ressource.RessourceFactory;
ingo@464: import de.intevation.gnv.state.DefaultInputData;
ingo@464: import de.intevation.gnv.state.InputData;
ingo@464: import de.intevation.gnv.utils.ArtifactFactoryUtilities;
ingo@464: 
ingo@464: 
ingo@464: /**
ingo@464:  * @author Ingo Weinzierl <ingo.weinzierl@intevation.de>
ingo@464:  */
ingo@464: public class FISSelectArtifact extends DefaultArtifact {
ingo@464: 
ingo@464:     public static final String XPATH_IDENTIFIER_REPLACE = "IDENTIFIER";
ingo@464: 
ingo@464:     public static final String XPATH_ARTIFACT_CONFIGURATION =
ingo@464:         "/artifact-database/artifacts/artifact[@name='"
ingo@464:         + XPATH_IDENTIFIER_REPLACE + "']";
ingo@464: 
ingo@464:     public static final String XPATH_UUID = "art:action/art:uuid/@value";
ingo@464: 
ingo@464:     public static final String XPATH_HASH = "art:action/art:hash/@value";
ingo@464: 
ingo@464:     public static final String XPATH_INPUT_DATA_VALUE =
ingo@464:         "art:action/art:data/art:input[@name='product']/@value";
ingo@464: 
ingo@464:     /**
ingo@464:      * this xpath is related to the config.xml document which doesn't have any
ingo@464:      * prefixes yet
ingo@464:      */
ingo@464:     public static final String XPATH_PRODUCTS = "products/product";
ingo@464: 
ingo@464:     /**
ingo@464:      * this xpath is related to the config.xml document which doesn't have any
ingo@464:      * prefixes yet
ingo@464:      */
ingo@464:     public static final String XPATH_PRODUCT_PARAMETER = "parameters/parameter";
ingo@464: 
ingo@464:     public static final String XFORM_URL    = "http://www.w3.org/2002/xforms";
ingo@464:     public static final String XFORM_PREFIX = "xform";
ingo@464: 
ingo@464:     private static Logger log = Logger.getLogger(FISSelectArtifact.class);
ingo@464: 
ingo@464:     private HashMap  products;
ingo@464:     private Product  current;
ingo@464:     private Artifact artifact;
ingo@464:     private String   name;
ingo@464: 
ingo@464:     public FISSelectArtifact() {
ingo@464:         super();
ingo@464:     }
ingo@464: 
ingo@464: 
ingo@464:     @Override
ingo@464:     public void setup(
ingo@464:         String          identifier,
ingo@464:         ArtifactFactory factory,
ingo@464:         Object          context
ingo@464:     ) {
ingo@464:         log.debug("setup()");
ingo@464:         super.setup(identifier, factory, context);
ingo@464:         this.name = factory.getName();
ingo@464: 
ingo@464:         if (context instanceof GNVArtifactContext) {
ingo@464:             GNVArtifactContext gnvContext   = (GNVArtifactContext) context;
ingo@464:             Document           doc          = gnvContext.getConfig();
ingo@464:             Node               artifactNode = getConfigurationFragment(doc);
ingo@464: 
ingo@464:             NodeList products = (NodeList) XMLUtils.xpath(
ingo@464:                 artifactNode, XPATH_PRODUCTS, XPathConstants.NODESET);
ingo@464: 
ingo@464:             if (products != null) {
ingo@464:                 this.products = new HashMap(products.getLength());
ingo@464: 
ingo@464:                 for (int i = 0; i < products.getLength(); i++) {
ingo@464:                     Element  productNode    = (Element)products.item(i);
ingo@464:                     String   productName    = productNode.getAttribute("name");
ingo@464:                     NodeList parameterNodes = (NodeList) XMLUtils.xpath(
ingo@464:                         productNode,
ingo@464:                         XPATH_PRODUCT_PARAMETER,
ingo@464:                         XPathConstants.NODESET
ingo@464:                     );
ingo@464: 
ingo@464:                     Collection<InputData> parameter = null;
ingo@464:                     if (parameterNodes != null) {
ingo@464:                         parameter = new ArrayList(parameterNodes.getLength());
ingo@464: 
ingo@464:                         for (int j = 0; j < parameterNodes.getLength(); j++) {
ingo@464:                             Element parameterNode = (Element)parameterNodes.item(j);
ingo@464:                             String name  = parameterNode.getAttribute("name");
ingo@464:                             String value = parameterNode.getAttribute("value");
ingo@464:                             parameter.add(new DefaultInputData(name, value));
ingo@464:                         }
ingo@464:                     }
ingo@464:                     Node artifactFactoryNode = (Node) XMLUtils.xpath(
ingo@464:                         productNode, "artifact-factory", XPathConstants.NODE
ingo@464:                     );
ingo@464: 
ingo@464:                     ArtifactFactory artifactFactory =
ingo@464:                         new ArtifactFactoryUtilities().createArtitfactFactor(
ingo@464:                             doc, artifactFactoryNode
ingo@464:                         );
ingo@464: 
ingo@464:                     this.products.put(productName, new DefaultProduct(
ingo@464:                         productName, parameter, artifactFactory)
ingo@464:                     );
ingo@464:                 }
ingo@464:             }
ingo@464:         }
ingo@464:     }
ingo@464: 
ingo@464: 
ingo@464:     @Override
ingo@464:     public Document feed(Document target, CallContext context) {
ingo@464:         log.debug("FISSelectArtifact.feed()");
ingo@464: 
ingo@464:         if (artifact == null) {
ingo@464:             Document document    = XMLUtils.newDocument();
ingo@464:             String   productName = XMLUtils.xpathString(
ingo@464:                 target,
ingo@464:                 XPATH_INPUT_DATA_VALUE,
ingo@464:                 ArtifactNamespaceContext.INSTANCE
ingo@464:             );
ingo@464: 
ingo@464:             current = (Product) products.get(productName);
ingo@464: 
ingo@464:             String reportNode = null;
ingo@464:             String resultNode = null;
ingo@464:             String msg        = null;
ingo@464: 
ingo@464:             if (current != null) {
ingo@464:                 reportNode = "result";
ingo@464:                 resultNode = "success";
ingo@464:                 msg        = "Feed was successfully. New Artifact created.";
ingo@464:             }
ingo@464:             else {
ingo@464:                 reportNode = "exceptionreport";
ingo@464:                 resultNode = "exception";
ingo@464:                 msg        = "Product does not exist.";
ingo@464:             }
ingo@464: 
ingo@464:             XMLUtils.ElementCreator creator = new XMLUtils.ElementCreator(
ingo@464:                 document,
ingo@464:                 ArtifactNamespaceContext.NAMESPACE_URI,
ingo@464:                 ArtifactNamespaceContext.NAMESPACE_PREFIX
ingo@464:             );
ingo@464: 
ingo@464:             Element report  = creator.create(reportNode);
ingo@464:             Element success = creator.create(resultNode);
ingo@464:             success.setTextContent(msg);
ingo@464:             report.appendChild(success);
ingo@464:             document.appendChild(report);
ingo@464: 
ingo@464:             return document;
ingo@464:         }
ingo@464:         else {
ingo@464:             return artifact.feed(target, context);
ingo@464:         }
ingo@464:     }
ingo@464: 
ingo@464: 
ingo@464:     @Override
ingo@464:     public Document advance(Document target, CallContext context) {
ingo@464:         log.debug("FISSelectArtifact.advance()");
ingo@464: 
ingo@464:         if (artifact != null) {
ingo@464:             Document result = artifact.advance(target, context);
ingo@464:             context.putContextValue(ProxyArtifact.REPLACE_PROXY, artifact);
ingo@464:             return result;
ingo@464:         }
ingo@464: 
ingo@464:         Document result = XMLUtils.newDocument();
ingo@464:         if (current == null) {
ingo@464:             // artifact needs to be feeded first
ingo@464:             String msg = "Artifact is not configured properly. Call 'feed' fist.";
ingo@464:             log.error(msg);
ingo@464: 
ingo@464:             XMLUtils.ElementCreator creator = new XMLUtils.ElementCreator(
ingo@464:                 result,
ingo@464:                 ArtifactNamespaceContext.NAMESPACE_URI,
ingo@464:                 ArtifactNamespaceContext.NAMESPACE_PREFIX
ingo@464:             );
ingo@464: 
ingo@464:             Element report = creator.create("exceptionreport");
ingo@464:             Element exception = creator.create("exception");
ingo@464:             exception.setTextContent(msg);
ingo@464:             report.appendChild(exception);
ingo@464:             result.appendChild(report);
ingo@464: 
ingo@464:             return result;
ingo@464:         }
ingo@464: 
ingo@464:         String uuid = XMLUtils.xpathString(
ingo@464:             target, XPATH_UUID, ArtifactNamespaceContext.INSTANCE
ingo@464:         );
ingo@464: 
ingo@464:         String hash = XMLUtils.xpathString(
ingo@464:             target, XPATH_HASH, ArtifactNamespaceContext.INSTANCE
ingo@464:         );
ingo@464: 
ingo@464:         artifact = current.getArtifactFactory().createArtifact(
ingo@464:             uuid, context
ingo@464:         );
ingo@464: 
ingo@464:         Document feedDocument = feedDocument(uuid, hash);
ingo@464:         artifact.feed(feedDocument(uuid, hash), context);
ingo@464: 
ingo@464:         result = ((GNVArtifactBase) artifact).initialize(context);
ingo@464:         if (artifact instanceof GNVArtifactBase) {
ingo@464:             ((GNVArtifactBase) artifact).setProduct(current);
ingo@464:         }
ingo@464:         context.putContextValue(ProxyArtifact.REPLACE_PROXY, artifact);
ingo@464:         return result;
ingo@464:     }
ingo@464: 
ingo@464: 
ingo@464:     @Override
ingo@464:     public Document describe(Document data, CallContext context) {
ingo@464:         log.debug("FISSelectArtifact.describe()");
ingo@464: 
ingo@464:         // create root node
ingo@464:         Document document               = XMLUtils.newDocument();
ingo@464:         XMLUtils.ElementCreator creator = new XMLUtils.ElementCreator(
ingo@464:             document,
ingo@464:             ArtifactNamespaceContext.NAMESPACE_URI,
ingo@464:             ArtifactNamespaceContext.NAMESPACE_PREFIX
ingo@464:         );
ingo@464: 
ingo@464:         Element rootNode = creator.create("result");
ingo@464:         Element typeNode = creator.create("type");
ingo@464:         creator.addAttr(typeNode, "name", "describe");
ingo@464:         rootNode.appendChild(typeNode);
ingo@464: 
ingo@464:         Element uuidNode = creator.create("uuid");
ingo@464:         creator.addAttr(uuidNode, "value", super.identifier);
ingo@464:         rootNode.appendChild(uuidNode);
ingo@464: 
ingo@464:         Element hashNode = creator.create("hash");
ingo@464:         creator.addAttr(hashNode, "value", hash());
ingo@464:         rootNode.appendChild(hashNode);
ingo@464: 
ingo@464:         // create output node
ingo@464:         Element out = creator.create("outputs");
ingo@464:         rootNode.appendChild(out);
ingo@464: 
ingo@464:         // create current state
ingo@464:         Element state = creator.create("state");
ingo@464:         creator.addAttr(state, "name", "choose-product");
ingo@464:         creator.addAttr(state, "description", "Auswahl des Produktes.");
ingo@464:         rootNode.appendChild(state);
ingo@464: 
ingo@464:         // create reachable states
ingo@464:         Element rStates = creator.create("reachable-states");
ingo@464:         appendProducts(document, rStates, context);
ingo@464:         rootNode.appendChild(rStates);
ingo@464: 
ingo@464:         // create model
ingo@464:         Element model = creator.create("model");
ingo@464:         Element input = creator.create("input");
ingo@464:         creator.addAttr(input, "name", "product");
ingo@464:         creator.addAttr(input, "type", "String");
ingo@464:         model.appendChild(input);
ingo@464:         rootNode.appendChild(model);
ingo@464: 
ingo@464:         // create ui
ingo@464:         Element ui      = creator.create("ui");
ingo@464:         Element dynamic = creator.create("dynamic");
ingo@464:         appendSelectProducts(document, dynamic, context.getMeta());
ingo@464:         ui.appendChild(dynamic);
ingo@464:         rootNode.appendChild(ui);
ingo@464: 
ingo@464:         document.appendChild(rootNode);
ingo@464:         return document;
ingo@464:     }
ingo@464: 
ingo@464: 
ingo@464:     @Override
ingo@464:     public void out(Document document, OutputStream out, CallContext context)
ingo@464:     throws IOException
ingo@464:     {
ingo@464:         log.debug("FISSelectArtifact.out()");
ingo@464:         if (artifact != null) {
ingo@464:             artifact.out(document, out, context);
ingo@464:         }
ingo@464:     }
ingo@464: 
ingo@464: 
ingo@464:     protected void appendProducts(
ingo@464:         Document document,
ingo@464:         Node     parent,
ingo@464:         Object   context
ingo@464:     ) {
ingo@464:         Iterator iter = products.values().iterator();
ingo@464: 
ingo@464:         XMLUtils.ElementCreator creator = new XMLUtils.ElementCreator(
ingo@464:             document,
ingo@464:             ArtifactNamespaceContext.NAMESPACE_URI,
ingo@464:             ArtifactNamespaceContext.NAMESPACE_PREFIX
ingo@464:         );
ingo@464: 
ingo@464:         while(iter.hasNext()) {
ingo@464:             Product prod = (Product) iter.next();
ingo@464:             String  name = prod.getName();
ingo@464: 
ingo@464:             Element current = creator.create("state");
ingo@464:             creator.addAttr(current, "name", name);
ingo@464:             creator.addAttr(current, "description", name);
ingo@464:             parent.appendChild(current);
ingo@464:         }
ingo@464:     }
ingo@464: 
ingo@464: 
ingo@464:     protected void appendSelectProducts(
ingo@464:         Document document,
ingo@464:         Node     node,
ingo@464:         CallMeta callMeta
ingo@464:     ) {
ingo@464:         RessourceFactory ressource = RessourceFactory.getInstance();
ingo@464: 
ingo@464:         XMLUtils.ElementCreator creator = new XMLUtils.ElementCreator(
ingo@464:             document,
ingo@464:             XFORM_URL,
ingo@464:             XFORM_PREFIX
ingo@464:         );
ingo@464: 
ingo@464:         String  selectboxName = "product";
ingo@464:         Element selectNode    = creator.create("select1");
ingo@464:         creator.addAttr(selectNode, "ref", selectboxName);
ingo@464: 
ingo@464:         Element lableNode = creator.create("label");
ingo@464:         lableNode.setTextContent(ressource.getRessource(callMeta.getLanguages(),
ingo@464:                 selectboxName,
ingo@464:                 selectboxName
ingo@464:             )
ingo@464:         );
ingo@464: 
ingo@464:         Element choiceNode = creator.create("choices");
ingo@464:         selectNode.appendChild(lableNode);
ingo@464:         selectNode.appendChild(choiceNode);
ingo@464: 
ingo@464:         Iterator it = products.values().iterator();
ingo@464:         while (it.hasNext()) {
ingo@464:             Product p               = (Product) it.next();
ingo@464:             Element itemNode        = creator.create("item");
ingo@464:             Element choiceLableNode = creator.create("label");
ingo@464:             choiceLableNode.setTextContent(ressource.getRessource(
ingo@464:                 callMeta.getLanguages(),
ingo@464:                 p.getName(),
ingo@464:                 p.getName()
ingo@464:             ));
ingo@464:             itemNode.appendChild(choiceLableNode);
ingo@464: 
ingo@464:             Element choiceValueNode = creator.create("value");
ingo@464:             choiceValueNode.setTextContent(p.getName());
ingo@464:             itemNode.appendChild(choiceValueNode);
ingo@464:             choiceNode.appendChild(itemNode);
ingo@464:         }
ingo@464: 
ingo@464:         node.appendChild(selectNode);
ingo@464:     }
ingo@464: 
ingo@464: 
ingo@464:     protected Node getConfigurationFragment(Document document) {
ingo@464:         String xpathQuery = XPATH_ARTIFACT_CONFIGURATION.replaceAll(
ingo@464:             XPATH_IDENTIFIER_REPLACE, name
ingo@464:         );
ingo@464: 
ingo@464:         return (Node) XMLUtils.xpath(document, xpathQuery, XPathConstants.NODE);
ingo@464:     }
ingo@464: 
ingo@464: 
ingo@464:     protected Document feedDocument(String uuid, String hash) {
ingo@464:         Document document = XMLUtils.newDocument();
ingo@464: 
ingo@464:         XMLUtils.ElementCreator creator = new XMLUtils.ElementCreator(
ingo@464:             document,
ingo@464:             ArtifactNamespaceContext.NAMESPACE_URI,
ingo@464:             ArtifactNamespaceContext.NAMESPACE_PREFIX
ingo@464:         );
ingo@464:         Element  rootNode = creator.create("action");
ingo@464: 
ingo@464:         Element typeNode = creator.create("type");
ingo@464:         creator.addAttr(typeNode, "name", "feed");
ingo@464:         rootNode.appendChild(typeNode);
ingo@464: 
ingo@464:         Element uuidNode = creator.create("uuid");
ingo@464:         creator.addAttr(uuidNode, "value", uuid);
ingo@464:         rootNode.appendChild(uuidNode);
ingo@464: 
ingo@464:         Element hashNode = creator.create("hash");
ingo@464:         creator.addAttr(hashNode, "value", hash);
ingo@464:         rootNode.appendChild(hashNode);
ingo@464: 
ingo@464:         Element dataNode = creator.create("data");
ingo@464:         rootNode.appendChild(dataNode);
ingo@464: 
ingo@464:         Collection<InputData> parameter = this.current.getParameter();
ingo@464:         if (parameter != null) {
ingo@464:             Iterator<InputData> parameterIt = parameter.iterator();
ingo@464: 
ingo@464:             while (parameterIt.hasNext()) {
ingo@464:                 InputData inputData = parameterIt.next();
ingo@464: 
ingo@464:                 Element inputNode = creator.create("input");
ingo@464:                 creator.addAttr(inputNode, "name", inputData.getName());
ingo@464:                 creator.addAttr(inputNode, "value", inputData.getValue());
ingo@464:                 dataNode.appendChild(inputNode);
ingo@464:             }
ingo@464:         }
ingo@464:         document.appendChild(rootNode);
ingo@464:         return document;
ingo@464:     }
ingo@464: }
ingo@464: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8: