view gnv/src/main/java/de/intevation/gnv/artifactdatabase/client/DefaultArtifactDatabaseClient.java @ 47:f35b7d7a04d6

Read the Status-Code from the Response and throw an Exception which Message will be visualized in the GUI. gnv/issue18 gnv/trunk@189 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Tim Englich <tim.englich@intevation.de>
date Tue, 06 Oct 2009 10:18:57 +0000
parents 23a4f196d7d6
children d6b82c585f1f
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 java.util.List;
import java.util.Locale;

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.data.Preference;
import org.restlet.data.Language;
import org.restlet.data.ClientInfo;

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;

    /**
     * Request locale
     */
    private Locale locale;


    /**
     * Constructor
     */
    public DefaultArtifactDatabaseClient() {
        
    }

    /**
     * @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);
            throw new ArtifactDatabaseClientException(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;
    }

    protected Request initialize(Request request) {
        return initialize(request, locale);
    }

    protected Request initialize(Request request, Locale locale) {
        if (locale != null) {
            ClientInfo clientInfo = request.getClientInfo();
            String lang = locale.getLanguage();
            Language language = new Language(lang);
            List<Preference<Language>> acceptedLanguages =
                new ArrayList<Preference<Language>>(2);
            acceptedLanguages.add(new Preference(language,     1.0f));
            acceptedLanguages.add(new Preference(Language.ALL, 0.5f));
            clientInfo.setAcceptedLanguages(acceptedLanguages);
        }
        return request;
    }

    /**
     * @param requestUrl
     * @param requestBody
     * @return
     */
    private Representation doGetRequestInternal(String requestUrl,
                                                Document requestBody) throws IOException {
        Client client = new Client(Protocol.HTTP);
        Request request = initialize(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);
        if (response.getStatus().getCode() != 200){
            throw new IOException(response.getStatus().getDescription());
        }
        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 = initialize(new Request(Method.POST, requestUrl));
        String documentBody = new XMLUtils().writeDocument2String(requestBody);
        Representation representation = new StringRepresentation(documentBody);
        request.setEntity(representation);
        Response response = client.handle(request);
        if (response.getStatus().getCode() != 200){
            throw new IOException(response.getStatus().getDescription());
        }
        // 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;
    }

    public void setLocale(Locale locale) {
        this.locale = locale;
    }
}

http://dive4elements.wald.intevation.org