view gnv/src/main/java/de/intevation/gnv/artifactdatabase/client/DefaultArtifactDatabaseClient.java @ 34:25fdec8b4c69

Added Global Errorhandling to the GNV-Client gnv/trunk@170 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Tim Englich <tim.englich@intevation.de>
date Fri, 02 Oct 2009 08:38:57 +0000
parents 0f4362d75e9e
children 4405f31bbc30
line wrap: on
line source
/**
 *
 */
package de.intevation.gnv.artifactdatabase.client;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
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.ArtifactStatisticValue;
import de.intevation.gnv.artifactdatabase.objects.DefaultArtifactStatisticValue;
import de.intevation.gnv.artifactdatabase.objects.DefaultOutputMode;
import de.intevation.gnv.artifactdatabase.objects.DefaultOutputParameter;
import de.intevation.gnv.artifactdatabase.objects.InputParameter;
import de.intevation.gnv.artifactdatabase.objects.OutputMode;
import de.intevation.gnv.artifactdatabase.objects.OutputParameter;
import de.intevation.gnv.propertiesreader.PropertiesReader;
import de.intevation.gnv.propertiesreader.PropertiesReaderFactory;
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);
    
    /**
     * The Databases which could be used
     */
    private static Collection<String> artifactDatabases = null;
    
    /**
     * Is the Class initialized?
     */
    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 {
            log.debug("DefaultArtifactDatabaseClient.getArtifactFactories");
            Iterator<String> it = artifactDatabases.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, ArtifactDatabaseClientException {
        return this.doGetRequest(requestUrl, null);
    }
    
    /**
     * @throws IOException
     */
    private Document doGetRequest(String requestUrl, Document requestBody) throws IOException, ArtifactDatabaseClientException {
        XMLUtils xmlUtils = new XMLUtils();
        Representation output = doGetRequestInternal(requestUrl, requestBody);
        Document document = xmlUtils.readDocument(output.getStream());
        this.check4ExceptionReport(document);
        return document;
    }

    /**
     * @param requestUrl
     * @param requestBody
     * @return
     */
    private Representation doGetRequestInternal(String requestUrl,
            Document requestBody) {
        Client client = new Client(Protocol.HTTP);
        Request request = new Request(Method.GET, requestUrl);
        if (requestBody != null){
            String documentBody = new XMLUtils().writeDocument2String(requestBody);
            Representation representation = new StringRepresentation(documentBody);
            request.setEntity(representation);
        }
        Response response = client.handle(request);
        // TODO RESPONSESTATUS AUSWERTEN.
        Representation output = response.getEntity();
        return output;
    }
    
    /**
     * @throws IOException
     */
    private InputStream doPostRequest(String requestUrl, Document requestBody) throws IOException {
        log.debug("##################################################");
        log.debug(new XMLUtils().writeDocument2String(requestBody));
        log.debug("##################################################");
        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);
       // TODO RESPONSESTATUS AUSWERTEN.
        Representation output = response.getEntity();
        return output.getStream();
    }
    
    private synchronized void initialize(){
        if (!initialized){
            PropertiesReader pr = PropertiesReaderFactory.getInstance().getPropertiesReader();
            int count = Integer.parseInt(pr.getPropertieValue(ARTIFACTDATABASE_COUNT_ID, "0"));
            artifactDatabases = new ArrayList<String>(count);
            for (int i = 0; i < count ; i++){
                artifactDatabases.add(pr.getPropertieValue(ARTIFACTDATABASE_URL_ID+"."+(i+1), "N/N"));
            }
            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, ArtifactDatabaseClientException {
        XMLUtils xmlUtils = new XMLUtils();
        String url = ((ArtifactFactory)artifactFactory).getDataBaseUrl();
        InputStream is = this.doPostRequest(url+"/"+suburl, request);
        Document result = xmlUtils.readDocument(is);
        this.check4ExceptionReport(result);
        return result;
    }
    

    /**
     * @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 {
            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{
        // Check if there was an Error or Exception reported from the ArtifactDatabase
        this.check4ExceptionReport(document);
        XMLUtils xmlUtils = new XMLUtils();
        if (artifact instanceof ArtifactDescription){
            ArtifactDescription ad = (ArtifactDescription)artifact;
            Node uiNode =  xmlUtils.getNodeXPath(document, "/result/ui");
            Node outputNode = xmlUtils.getNodeXPath(document, "/result/outputs");
            
            Map<String, OutputMode> outputModes = null;
            if (outputNode != null){
                NodeList outputModesNodes = xmlUtils.getNodeSetXPath(outputNode, "output");
                if (outputModesNodes != null){
                    outputModes = new HashMap<String, OutputMode>(outputModesNodes.getLength());
                    for (int i = 0; i < outputModesNodes.getLength(); i++){
                        Node outputModeNode = outputModesNodes.item(i);
                        String name = xmlUtils.getStringXPath(outputModeNode, "@name");
                        String mimeType = xmlUtils.getStringXPath(outputModeNode, "@mime-type");
                        
                        NodeList parameterNodes = xmlUtils.getNodeSetXPath(outputModeNode, "parameter/parameter");
                        Collection<OutputParameter> parameter = null;
                        if (parameterNodes != null){
                            parameter = new ArrayList<OutputParameter>(parameterNodes.getLength());
                            for (int j = 0; j < parameterNodes.getLength(); j++){
                                Node outputParameterNode =  parameterNodes.item(j);
                                parameter.add(new DefaultOutputParameter(xmlUtils.getStringXPath(outputParameterNode,"@name"),xmlUtils.getStringXPath(outputParameterNode,"@value"),xmlUtils.getStringXPath(outputParameterNode,"@name"),xmlUtils.getStringXPath(outputParameterNode,"@type")));
                            }
                        }
                        outputModes.put(name,new DefaultOutputMode(name, mimeType, parameter));
                    }
                    
                }
            }
            
            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.setOutputModes(outputModes);
            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
            this.doFeed(artifactFactory, currentArtifact, inputParameter);
             // 2 Advance
            String url = this.getArtifactUrl(artifactFactory, currentArtifact);
            Document advanceDocument = this.createAdvanceRequestBody(currentArtifact, target);
            InputStream advanceResult = this.doPostRequest(url, advanceDocument);
            this.check4ExceptionReport(new XMLUtils().readDocument(advanceResult));
            // 3 Describe
            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);
        
        Node dataNode = this.createParameterNodes(inputParameter, document, "data");
        rootNode.appendChild(dataNode);
        
        return document;
    }

    /**
     * @param inputParameter
     * @param document
     * @param rootNode
     */
    private Node createParameterNodes(Collection<InputParameter> inputParameter, Document document, String nodeName) {
        Element dataNode = this.createArtifactElement(document, nodeName);
        
        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 dataNode;
    }
    
    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;
    }

    /**
     * @see de.intevation.gnv.artifactdatabase.client.ArtifactDatabaseClient#doOutput(de.intevation.gnv.artifactdatabase.objects.ArtifactObject, de.intevation.gnv.artifactdatabase.objects.ArtifactObject, java.io.OutputStream, java.lang.String, java.lang.String, java.util.Collection)
     */
    public void doOutput(ArtifactObject artifactFactory,
            ArtifactObject currentArtifact, OutputStream stream,
            String targetName, String mimeType,
            Collection<InputParameter> inputParameter)
            throws ArtifactDatabaseClientException {
        try {
            XMLUtils xmlUtils = new XMLUtils();
            Document requestBody = this.createOutRequestBody(currentArtifact, targetName, mimeType, inputParameter);
            
            String requestUrl = this.getArtifactUrl(artifactFactory, currentArtifact)+"/"+targetName;
            InputStream is = this.doPostRequest( requestUrl, requestBody);
            
            byte[] b = new byte[4096];
            int i = -1 ;
            while ((i = is.read(b)) > 0)
            {
                stream.write(b, 0, i);
            }
            } catch (IOException e) {
            log.error(e,e);
            throw new ArtifactDatabaseClientException(e);
        }
    }
    
    private Document createOutRequestBody(ArtifactObject currentArtifact, String target, String mimeType, Collection<InputParameter> inputParameter){
        Document document = new XMLUtils().newDocument();
        Node rootNode  = this.createRootNode(document);
        
        Element typeNode = this.createArtifactElement(document, "type");
        typeNode.setAttribute("name", "out");
        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 outNode = this.createArtifactElement(document, "out");
        outNode.setAttribute("name", target);
        rootNode.appendChild(outNode);
      
        Element mimeTypeNode = this.createArtifactElement(document, "out");
        mimeTypeNode.setAttribute("value", mimeType);
        outNode.appendChild(mimeTypeNode);
        
        Node parameterNode = this.createParameterNodes(inputParameter, document, "params");
        outNode.appendChild(parameterNode);
        
        return document;
}

    /**
     * @see de.intevation.gnv.artifactdatabase.client.ArtifactDatabaseClient#doFeed(de.intevation.gnv.artifactdatabase.objects.ArtifactObject, de.intevation.gnv.artifactdatabase.objects.ArtifactObject, java.util.Collection)
     */
    public void doFeed(ArtifactObject artifactFactory,
            ArtifactObject currentArtifact,
            Collection<InputParameter> inputParameter)
            throws ArtifactDatabaseClientException {
        
        try {
            Document feedDocument = this.createFeedRequestBody(currentArtifact, inputParameter);
            String url = this.getArtifactUrl(artifactFactory, currentArtifact);
            InputStream feedResult = this.doPostRequest(url, feedDocument);
            Document feedResultDocument = new XMLUtils().readDocument(feedResult);
            this.check4ExceptionReport(feedResultDocument);
        } catch (IOException e) {
            log.error(e,e);
            throw new ArtifactDatabaseClientException(e);
        }
    }
    
    private void check4ExceptionReport(Document document) throws ArtifactDatabaseClientException{
        
        String message = new XMLUtils().getStringXPath(document,"/exceptionreport/exception");
        if (message != null){
            throw new ArtifactDatabaseClientException(message);
        }
        
    }

    public Collection<ArtifactStatisticValue> calculateStatistics(
            ArtifactObject artifactFactory, ArtifactObject currentArtifact) throws ArtifactDatabaseClientException{
        log.debug("DefaultArtifactDatabaseClient.calculateStatistics") ;
        Collection<ArtifactStatisticValue> result;
        try {
            result = null;
            String targetName = "statistics";
            String requestUrl = this.getArtifactUrl(artifactFactory, currentArtifact)+"/"+targetName;
            Document requestBody = this.createOutRequestBody(currentArtifact, targetName, "text/xml", null);
            XMLUtils xmlUtils = new XMLUtils();
            InputStream is  = this.doPostRequest(requestUrl, requestBody);
            Document resultDocument = xmlUtils.readDocument(is);
            if (resultDocument != null){
                NodeList resultNodes = xmlUtils.getNodeSetXPath(resultDocument, "/statistic-values/statistic");
                if (resultNodes != null){
                    result = new ArrayList<ArtifactStatisticValue>(resultNodes.getLength());
                    for (int i = 0; i < resultNodes.getLength(); i++){
                        Node statisticNode = resultNodes.item(i);
                        String name = xmlUtils.getStringXPath(statisticNode, "@name");
                        String value = xmlUtils.getStringXPath(statisticNode, "@value");
                        result.add(new DefaultArtifactStatisticValue(name, value));
                    }
                }
            }
        } catch (IOException e) {
            log.error(e,e);
            throw new ArtifactDatabaseClientException(e); 
        }
        
        return result;
    }
}

http://dive4elements.wald.intevation.org