view gnv/src/main/java/de/intevation/gnv/artifactdatabase/client/DefaultArtifactDatabaseClient.java @ 12:4ebe57b170d3

Integration of moving through the Artifact-States and rendering the UI. gnv/trunk@91 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Tim Englich <tim.englich@intevation.de>
date Wed, 16 Sep 2009 07:44:26 +0000
parents 3cb753564552
children 2535158e2687
line wrap: on
line source
/**
 *
 */
package de.intevation.gnv.artifactdatabase.client;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.apache.log4j.Logger;
import org.restlet.Client;
import org.restlet.data.Method;
import org.restlet.data.Protocol;
import org.restlet.data.Request;
import org.restlet.data.Response;
import org.restlet.representation.Representation;
import org.restlet.representation.StringRepresentation;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import de.intevation.gnv.artifactdatabase.client.exception.ArtifactDatabaseClientException;
import de.intevation.gnv.artifactdatabase.objects.Artifact;
import de.intevation.gnv.artifactdatabase.objects.ArtifactDescription;
import de.intevation.gnv.artifactdatabase.objects.ArtifactFactory;
import de.intevation.gnv.artifactdatabase.objects.ArtifactObject;
import de.intevation.gnv.artifactdatabase.objects.InputParameter;
import de.intevation.gnv.util.XMLUtils;

/**
 * @author Tim Englich <tim.englich@intevation.de>
 *
 */
public class DefaultArtifactDatabaseClient implements ArtifactDatabaseClient {
    /**
     * The URI of the namespace of the artifacts.
     */
    public final static String NAMESPACE_URI = "http://www.intevation.de/2009/artifacts";
    
    /**
     * The XML prefix for the artifacts namespace.
     */
    public final static String NAMESPACE_PREFIX = "art";

    /**
     * the logger, used to log exceptions and additonaly information
     */
    private static Logger log = Logger.getLogger(DefaultArtifactDatabaseClient.class);
    
    // TODO Container for ArtifactDatabases should be used.
    private static Map<String, String> artifactDatabases = null;
    
    private static boolean initialized = false;
    
    /**
     * Constructor
     */
    public DefaultArtifactDatabaseClient() {
        super();
    }

    /**
     * @see de.intevation.gnv.artifactdatabase.client.ArtifactDatabaseClient#getArtifactFactories()
     */
    public Collection<ArtifactObject> getArtifactFactories() throws ArtifactDatabaseClientException {
        Collection<ArtifactObject> resultValues = null;
        if (!initialized){
            this.initialize();
        }
        try {
           XMLUtils xmlUtils = new XMLUtils();
            log.debug("DefaultArtifactDatabaseClient.getArtifactFactories");
            Iterator<String> it = artifactDatabases.values().iterator();
            while (it.hasNext()){
                String server = it.next();
                String url =  server+ "/factories";
                Document document = this.doGetRequest(url);
                if (resultValues == null){
                    resultValues = this.getArtifactFactories(document,server);
                }else{
                    resultValues.addAll(this.getArtifactFactories(document,server));
                }
            }
        } catch (IOException e) {
            log.error(e,e);
        }
        return resultValues;
    }

    private Collection<ArtifactObject>  getArtifactFactories(Document document, String server){
        XMLUtils xmlUtils = new XMLUtils();
        NodeList artifactFactories = xmlUtils.getNodeSetXPath(document, "/result/factories/factory");
        Collection<ArtifactObject> resultValues = new ArrayList<ArtifactObject>(artifactFactories.getLength());
        if (artifactFactories != null){
            for (int i = 0; i < artifactFactories.getLength(); i++){
                Node  artifactFactoryNode = artifactFactories.item(i);
                String name = xmlUtils.getStringXPath(artifactFactoryNode, "@name");
                String description = xmlUtils.getStringXPath(artifactFactoryNode, "@description");
                ArtifactFactory artifactFactory = new ArtifactFactory(name, description, server);
                resultValues.add(artifactFactory);
            }
        }
        return resultValues;
    }
    
    /**
     * @throws IOException
     */
    private Document doGetRequest(String requestUrl) throws IOException {
        XMLUtils xmlUtils = new XMLUtils();
        Client client = new Client(Protocol.HTTP);
        Response response = client.get(requestUrl);
        Representation output = response.getEntity();
        Document document = xmlUtils.readDocument(output.getStream());
        log.debug(xmlUtils.writeDocument2String(document));
        return document;
    }
    
    /**
     * @throws IOException
     */
    private InputStream doPostRequest(String requestUrl, Document requestBody) throws IOException {
        Client client = new Client(Protocol.HTTP);
        Request request = new Request(Method.POST, requestUrl);
        String documentBody = new XMLUtils().writeDocument2String(requestBody);
        Representation representation = new StringRepresentation(documentBody);
        request.setEntity(representation);
        Response response = client.handle(request);
        Representation output = response.getEntity();
        return output.getStream();
    }
    
    private synchronized void initialize(){
        if (!initialized){
            this.artifactDatabases = new HashMap<String, String>();
            this.artifactDatabases.put("test", "http://localhost:8181");            // TODO Read from Config
            initialized = true;
        }
        
    }

    /**
     * @see de.intevation.gnv.artifactdatabase.client.ArtifactDatabaseClient#createNewArtifact(de.intevation.gnv.artifactdatabase.objects.ArtifactObject)
     */
    public ArtifactObject createNewArtifact(ArtifactObject artifactFactory)
            throws ArtifactDatabaseClientException {
        
        try {
            Document request = this.createCreateRequestBody(artifactFactory.getId());
            Document result = doPostRequest(artifactFactory, request, "create");
            return this.getArtifact(result);
        } catch (IOException e) {
            log.error(e,e);
            throw new ArtifactDatabaseClientException(e);
        }
    }
    
    
    private ArtifactObject getArtifact(Document document){
        XMLUtils xmlUtils = new XMLUtils(); 
        String uuid = xmlUtils.getStringXPath(document, "/result/uuid/@value");
        String hash = xmlUtils.getStringXPath(document, "/result/hash/@value");
        log.info("NEW Artifact: "+uuid+" / "+hash);
        return new Artifact(uuid, hash);
    }
    
    
    
    
    private Document createCreateRequestBody(String artifactFactoryName){
        Document document = new XMLUtils().newDocument();
        Node rootNode  = this.createRootNode(document);
        Element typeNode = this.createArtifactElement(document, "type");
        typeNode.setAttribute("name", "create");
        rootNode.appendChild(typeNode);
             
        Element factoyNode = this.createArtifactElement(document, "factory");
        factoyNode.setAttribute("name", artifactFactoryName);
        rootNode.appendChild(factoyNode);
        
        return document;
    }
    
    private Element createRootNode(Document document){
        Element rootNode = this.createArtifactElement(document,"action");
        document.appendChild(rootNode);
        return rootNode;
    }
    
    /**
     * @param document
     * @return
     */
    private Element createArtifactElement(Document document, String name) {
        Element node = document.createElementNS(NAMESPACE_URI, name);
        node.setPrefix(NAMESPACE_PREFIX);
        return node;
    }

/**
 * @param artifactFactory
 * @param xmlUtils
 * @param request
 * @throws IOException
 */
private Document doPostRequest(ArtifactObject artifactFactory,
        Document request, String suburl) throws IOException {
    XMLUtils xmlUtils = new XMLUtils();
    String url = ((ArtifactFactory)artifactFactory).getDataBaseUrl();
    InputStream is = this.doPostRequest(url+"/"+suburl, request);
    Document result = xmlUtils.readDocument(is);
    // TODO: Fehleranalyse des Dokumentes
    log.debug(xmlUtils.writeDocument2String(result));
    return result;
}
    
    private Document createDescribeRequestBody(ArtifactObject currentArtifact){
        Document document = new XMLUtils().newDocument();
        Node rootNode  = this.createRootNode(document);
        Element typeNode = this.createArtifactElement(document, "type");
        typeNode.setAttribute("name", "describe");
        rootNode.appendChild(typeNode);
             
        Element uuidNode = this.createArtifactElement(document, "uuid");
        uuidNode.setAttribute("value", currentArtifact.getId());
        rootNode.appendChild(uuidNode);
        
        Element hashNode = this.createArtifactElement(document, "hash");
        hashNode.setAttribute("value", currentArtifact.getHash());
        rootNode.appendChild(hashNode);
        
        return document;
    }

    /**
     * @see de.intevation.gnv.artifactdatabase.client.ArtifactDatabaseClient#getCurrentStepDescription(de.intevation.gnv.artifactdatabase.objects.ArtifactFactory, de.intevation.gnv.artifactdatabase.objects.ArtifactObject)
     */
    public ArtifactDescription getCurrentStepDescription(ArtifactObject artifactFactory,
            ArtifactObject currentArtifact)
            throws ArtifactDatabaseClientException {
        try {
            
            Document request = this.createDescribeRequestBody(currentArtifact);
            String url = this.getArtifactUrl(artifactFactory, currentArtifact);
            Document result = this.doGetRequest(url);
            return this.readDescription(result,currentArtifact);
        } catch (IOException e) {
            log.error(e,e);
            throw new ArtifactDatabaseClientException(e);
        }
    }

    /**
     * @param artifactFactory
     * @param currentArtifact
     * @return
     */
    private String getArtifactUrl(ArtifactObject artifactFactory,
            ArtifactObject currentArtifact) {
        String url = ((ArtifactFactory)artifactFactory).getDataBaseUrl()+"/artifact/"+ currentArtifact.getId();
        return url;
    }
    
    private ArtifactDescription readDescription(Document document, ArtifactObject artifact) throws ArtifactDatabaseClientException{
        XMLUtils xmlUtils = new XMLUtils();
        if (artifact instanceof ArtifactDescription){
            ArtifactDescription ad = (ArtifactDescription)artifact;
            Node uiNode =  xmlUtils.getNodeXPath(document, "/result/ui");
//            uiNode = uiNode.getFirstChild();
            Node outputNode = xmlUtils.getNodeXPath(document, "/result/outputs");
            String currentState = xmlUtils.getStringXPath(document, "/result/state/@name");
            NodeList statesList = xmlUtils.getNodeSetXPath(document, "/result/reachable-states/state/@name");
            Collection<String> reachableStates = new ArrayList<String>(statesList.getLength());
            for (int i = 0; i < statesList.getLength(); i++){
                reachableStates.add(statesList.item(i).getNodeValue());
            }
            
            NodeList inputNodes = xmlUtils.getNodeSetXPath(document, "/result/model/input");
            if (inputNodes != null){
                Collection<String> inputParameter = new ArrayList<String>(inputNodes.getLength());
                for (int i = 0; i < inputNodes.getLength(); i++){
                    Node inputNode = inputNodes.item(i);
                    String name = xmlUtils.getStringXPath(inputNode, "@name");
                    inputParameter.add(name);
                }
                ad.setInputParameter(inputParameter);
            }
            
            ad.setCurrentOut(outputNode);
            ad.setCurrentUI(uiNode);
            ad.setCurrentState(currentState);
            ad.setReachableStates(reachableStates);
            return ad;
        }else{
            log.error("Artifact must be Instance of ArtifactDescription");
            throw new ArtifactDatabaseClientException("Artifact must be Instance of ArtifactDescription");
        }
       
        
    }

    /**
     * @see de.intevation.gnv.artifactdatabase.client.ArtifactDatabaseClient#doNextStep(de.intevation.gnv.artifactdatabase.objects.ArtifactObject, de.intevation.gnv.artifactdatabase.objects.ArtifactObject, java.lang.String, java.util.Collection)
     */
    public ArtifactDescription doNextStep(ArtifactObject artifactFactory,
            ArtifactObject currentArtifact, String target,
            Collection<InputParameter> inputParameter)
            throws ArtifactDatabaseClientException {
        
        try {
            // 1 Feed
            Document feedDocument = this.createFeedRequestBody(currentArtifact, inputParameter);
            String url = this.getArtifactUrl(artifactFactory, currentArtifact);
            InputStream feedResult = this.doPostRequest(url, feedDocument);
            // TODO feedResult auswerten und ggf. Fehler werfen.
            // 2 Advance
            Document advanceDocument = this.createAdvanceRequestBody(currentArtifact, target);
            log.debug(new XMLUtils().writeDocument2String(advanceDocument));
            InputStream advanceResult = this.doPostRequest(url, advanceDocument);
            // TODO feedResult auswerten und ggf. Fehler werfen.
            // 3 Descibe
            return this.getCurrentStepDescription(artifactFactory, currentArtifact);
        } catch (IOException e) {
            log.error(e,e);
            throw new ArtifactDatabaseClientException(e);
        }
    }
    
    private Document createFeedRequestBody(ArtifactObject currentArtifact, 
                                           Collection<InputParameter> inputParameter){
        Document document = new XMLUtils().newDocument();
        Node rootNode  = this.createRootNode(document);
        
        Element typeNode = this.createArtifactElement(document, "type");
        typeNode.setAttribute("name", "feed");
        rootNode.appendChild(typeNode);
             
        Element uuidNode = this.createArtifactElement(document, "uuid");
        uuidNode.setAttribute("value", currentArtifact.getId());
        rootNode.appendChild(uuidNode);
        
        Element hashNode = this.createArtifactElement(document, "hash");
        hashNode.setAttribute("value", currentArtifact.getHash());
        rootNode.appendChild(hashNode);
        
        Element dataNode = this.createArtifactElement(document, "data");
        rootNode.appendChild(dataNode);
        if (inputParameter != null){
            Iterator<InputParameter> it = inputParameter.iterator();
            while(it.hasNext()){
                InputParameter ip = it.next();
                String name = ip.getName();
                String[] values = ip.getValues();
                if (values != null){
                    for (int i = 0; i < values.length; i++){
                        String value = values[i];
                        Element inputNode = this.createArtifactElement(document, "input");
                        inputNode.setAttribute("name", name);
                        inputNode.setAttribute("value", value);
                        dataNode.appendChild(inputNode);
                    }
                }
            }
        }
        
        
        return document;
    }
    
    private Document createAdvanceRequestBody(ArtifactObject currentArtifact, String target){
            Document document = new XMLUtils().newDocument();
            Node rootNode  = this.createRootNode(document);
            
            Element typeNode = this.createArtifactElement(document, "type");
            typeNode.setAttribute("name", "advance");
            rootNode.appendChild(typeNode);
            
            Element uuidNode = this.createArtifactElement(document, "uuid");
            uuidNode.setAttribute("value", currentArtifact.getId());
            rootNode.appendChild(uuidNode);
            
            Element hashNode = this.createArtifactElement(document, "hash");
            hashNode.setAttribute("value", currentArtifact.getHash());
            rootNode.appendChild(hashNode);
            Element targetNode = this.createArtifactElement(document, "target");
            targetNode.setAttribute("name", target);
            rootNode.appendChild(targetNode);
            return document;
    }
}

http://dive4elements.wald.intevation.org