ingo@0: /* ingo@0: * Copyright (c) 2010 by Intevation GmbH ingo@0: * ingo@0: * This program is free software under the LGPL (>=v2.1) ingo@0: * Read the file LGPL.txt coming with the software for details ingo@0: * or visit http://www.gnu.org/licenses/ if it does not exist. ingo@0: */ ingo@0: ingo@0: package de.intevation.artifacts.httpclient; ingo@0: ingo@0: import java.io.IOException; ingo@0: import java.io.File; ingo@0: import java.io.FileOutputStream; ingo@0: import java.io.OutputStream; ingo@0: ingo@0: import java.net.MalformedURLException; ingo@0: ingo@0: import java.util.Arrays; ingo@0: import java.util.ArrayList; ingo@0: import java.util.HashMap; ingo@0: import java.util.List; ingo@0: import java.util.Map; ingo@0: ingo@0: import javax.xml.xpath.XPathConstants; ingo@0: ingo@0: import org.w3c.dom.Document; ingo@0: import org.w3c.dom.Node; ingo@0: import org.w3c.dom.NodeList; ingo@0: ingo@0: import org.apache.log4j.Logger; ingo@0: import org.apache.log4j.PropertyConfigurator; ingo@0: ingo@1: import de.intevation.artifacts.httpclient.http.HttpClient; ingo@1: import de.intevation.artifacts.httpclient.http.HttpClientImpl; ingo@0: import de.intevation.artifacts.httpclient.http.response.DocumentResponseHandler; ingo@0: ingo@0: import de.intevation.artifacts.httpclient.exceptions.ConnectionException; ingo@0: import de.intevation.artifacts.httpclient.exceptions.NoSuchOptionException; ingo@0: import de.intevation.artifacts.httpclient.objects.Artifact; ingo@0: import de.intevation.artifacts.httpclient.utils.ArtifactProtocolUtils; ingo@0: import de.intevation.artifacts.httpclient.utils.Configuration; ingo@0: import de.intevation.artifacts.httpclient.utils.XFormNamespaceContext; ingo@0: import de.intevation.artifacts.httpclient.utils.XMLUtils; ingo@0: ingo@0: /** ingo@0: * @author Ingo Weinzierl ingo@0: */ ingo@0: public class ConsoleClient ingo@0: { ingo@0: /** ingo@0: * The logging is done via Log4j. To configure the logging ingo@0: * a file 'log4j.properties' is search in the configuration directory. ingo@0: */ ingo@0: public static final String LOG4J_PROPERTIES = "log4j.properties"; ingo@0: ingo@0: ingo@0: /** ingo@0: * The path of the configuration directory. ingo@0: */ ingo@0: public static final String CONFIG_PATH = System.getProperty("config.dir", ingo@0: "conf"); ingo@0: ingo@0: public static final String CONFIG = System.getProperty("config.file", ingo@0: "use_case1.conf"); ingo@0: ingo@0: ingo@0: public static final String XPATH_DYNAMIC = "/art:result/art:ui/art:dynamic"; ingo@0: ingo@0: /** ingo@0: * The logger used in this class. ingo@0: */ ingo@0: private static Logger logger; ingo@0: ingo@0: ingo@0: static { ingo@0: configureLogging(); ingo@0: ingo@0: logger = Logger.getLogger(ConsoleClient.class); ingo@0: } ingo@0: ingo@0: ingo@0: /** ingo@0: * Trys to load the Log4j configuration from ${config.dir}/log4j.properties. ingo@0: */ ingo@0: public static final void configureLogging() { ingo@0: File configDir = new File(CONFIG_PATH); ingo@0: File propFile = new File(configDir, LOG4J_PROPERTIES); ingo@0: ingo@0: if (propFile.isFile() && propFile.canRead()) { ingo@0: try { ingo@0: PropertyConfigurator.configure(propFile.toURI().toURL()); ingo@0: } ingo@0: catch (MalformedURLException mue) { ingo@0: mue.printStackTrace(System.err); ingo@0: } ingo@0: } ingo@0: } ingo@0: ingo@0: ingo@0: public static final Configuration readConfiguration() { ingo@0: File configDir = new File(CONFIG_PATH); ingo@0: File configFile = new File(configDir, CONFIG); ingo@0: ingo@0: logger.debug("Configuration file: " + configFile.getAbsolutePath()); ingo@0: ingo@0: if (configFile.isFile() && configFile.canRead()) { ingo@0: try { ingo@0: Configuration conf = new Configuration(configFile); ingo@0: conf.initialize(); ingo@0: ingo@0: return conf; ingo@0: } ingo@0: catch (IOException ioe) { ingo@0: logger.error("Error while reading configuration."); ingo@0: } ingo@0: } ingo@0: ingo@0: return null; ingo@0: } ingo@0: ingo@0: ingo@0: public static void main( String[] args ) ingo@0: { ingo@1: logger.info("Starting console client."); ingo@0: ingo@0: Configuration conf = readConfiguration(); ingo@0: ingo@0: String serverHost = (String) conf.getServerSettings("host"); ingo@0: String serverPort = (String) conf.getServerSettings("port"); ingo@1: HttpClient client = new HttpClientImpl(serverHost + ":" + serverPort); ingo@0: ingo@0: try { ingo@0: Document create = ArtifactProtocolUtils.createCreateDocument( ingo@0: (String) conf.getArtifactSettings("fis")); ingo@2: Artifact artifact = (Artifact) client.create(create, null); ingo@0: ingo@0: Map attr = new HashMap(); ingo@0: String product = (String) conf.getArtifactSettings("product"); ingo@0: String[] products = extractOptions(client, artifact, product); ingo@0: attr.put("product", products[0]); ingo@0: ingo@0: feedAndGo(client, artifact, attr, "timeSeries"); ingo@0: ingo@0: attr.clear(); ingo@0: String area = (String) conf.getArtifactSettings("areaid"); ingo@0: String[] areas = extractOptions(client, artifact, area); ingo@0: attr.put("areaid", areas[0]); ingo@0: feedAndGo(client, artifact, attr, "timeseries_without_geom"); ingo@0: ingo@0: attr.clear(); ingo@0: String feature = (String) conf.getArtifactSettings("featureid"); ingo@0: String[] features = extractOptions(client, artifact, feature); ingo@0: attr.put("featureid", features[0]); ingo@0: feedAndGo(client, artifact, attr, "timeseries_vector_scalar"); ingo@0: ingo@0: attr.clear(); ingo@0: String vector = (String) conf.getArtifactSettings("vectorscalar"); ingo@0: String[] vectors = extractOptions(client, artifact, vector); ingo@0: attr.put("vectorscalar", vectors[0]); ingo@0: feedAndGo(client, artifact, attr, "timeseries_parameter"); ingo@0: ingo@0: attr.clear(); ingo@0: String parameter = (String) conf.getArtifactSettings("parameterid"); ingo@0: String[] parameters = extractOptions(client, artifact, parameter); ingo@0: attr.put("parameterid", parameters); ingo@0: feedAndGo(client, artifact, attr, "timeseries_depth_height"); ingo@0: ingo@0: attr.clear(); ingo@0: String measure = (String) conf.getArtifactSettings("measurementid"); ingo@0: String[] measures = extractMeasurements(client, artifact, measure); ingo@0: attr.put("measurementid", measures); ingo@0: feedAndGo(client, artifact, attr, "timeseries_interval"); ingo@0: ingo@0: attr.clear(); ingo@0: String min = (String) conf.getArtifactSettings("minvalue"); ingo@0: String max = (String) conf.getArtifactSettings("maxvalue"); ingo@0: attr.put("minvalue", min); ingo@0: attr.put("maxvalue", max); ingo@0: feedAndGo(client, artifact, attr, "timeseries_calculate_results"); ingo@0: ingo@0: try { ingo@0: Map opts = new HashMap(); ingo@0: opts.put("mime-type", conf.getOutputSettings("mime-type")); ingo@0: opts.put("width", conf.getOutputSettings("width")); ingo@0: opts.put("height", conf.getOutputSettings("height")); ingo@0: opts.put("points", conf.getOutputSettings("points")); ingo@0: ingo@0: Document chart = ingo@0: ArtifactProtocolUtils.createChartDocument(artifact, opts); ingo@0: ingo@0: String dir = (String) conf.getOutputSettings("directory"); ingo@0: ingo@0: File outDir = new File(dir); ingo@0: File output = new File(outDir, "output.png"); ingo@0: OutputStream os = new FileOutputStream(output); ingo@0: ingo@0: client.out(artifact, chart, "chart", os); ingo@0: } ingo@0: catch (IOException ioe) { ingo@0: logger.error( ingo@0: "IO error while writing the output: " + ioe.getMessage()); ingo@0: } ingo@0: ingo@1: logger.debug("Finished console client."); ingo@0: } ingo@0: catch (ConnectionException ce) { ingo@0: logger.error(ce.getMessage()); ingo@0: } ingo@0: catch (NoSuchOptionException nsoe) { ingo@0: logger.error( ingo@0: "No such option found: " + nsoe.getMessage()); ingo@0: } ingo@0: } ingo@0: ingo@0: ingo@0: public static void feedAndGo( ingo@1: HttpClient client, ingo@0: Artifact artifact, ingo@0: Map attr, ingo@0: String target) ingo@0: throws ConnectionException ingo@0: { ingo@0: Document feed = ArtifactProtocolUtils.createFeedDocument(artifact, attr); ingo@0: client.feed(artifact, feed, new DocumentResponseHandler()); ingo@0: ingo@0: Document advance = ArtifactProtocolUtils.createAdvanceDocument( ingo@0: artifact, ingo@0: target); ingo@0: ingo@0: client.advance(artifact, advance, new DocumentResponseHandler()); ingo@0: } ingo@0: ingo@0: ingo@0: /** ingo@0: * XXX I think, this method should be implemented somewhere else to be able ingo@0: * to re-use this implementation. But this method needs more work to be more ingo@0: * abstract, so it needs to be reimplemented later, I think. ingo@0: */ ingo@0: public static String[] extractOptions( ingo@1: HttpClient client, ingo@0: Artifact artifact, ingo@0: String text) ingo@0: throws NoSuchOptionException, ConnectionException ingo@0: { ingo@0: Document describe = ArtifactProtocolUtils.createDescribeDocument( ingo@0: artifact, true); ingo@0: ingo@0: Document description = (Document) client.describe( ingo@0: artifact, describe, new DocumentResponseHandler()); ingo@0: ingo@0: List pieces = Arrays.asList(text.split(",")); ingo@0: List options = new ArrayList(pieces.size()); ingo@0: ingo@0: Node dynamic = XMLUtils.getNodeXPath(description, XPATH_DYNAMIC); ingo@0: ingo@0: // TODO We should handle these cases better!! ingo@0: NodeList items = (NodeList) XMLUtils.getXPath( ingo@0: dynamic, "xform:select1/xform:choices/xform:item", ingo@0: XPathConstants.NODESET, XFormNamespaceContext.INSTANCE); ingo@0: ingo@0: if (items == null || items.getLength() == 0) { ingo@0: items = (NodeList) XMLUtils.getXPath( ingo@0: dynamic, "xform:select/xform:choices/xform:item", ingo@0: XPathConstants.NODESET, XFormNamespaceContext.INSTANCE); ingo@0: } ingo@0: ingo@0: if (items == null || items.getLength() == 0) { ingo@0: items = (NodeList) XMLUtils.getXPath( ingo@0: dynamic, "xform:group/xform:select/xform:item", ingo@0: XPathConstants.NODESET, XFormNamespaceContext.INSTANCE); ingo@0: } ingo@0: ingo@0: ingo@0: for (int i = 0; i < items.getLength(); i++) { ingo@0: Node item = items.item(i); ingo@0: Node label = (Node) XMLUtils.getXPath( ingo@0: item, "xform:label", XPathConstants.NODE, ingo@0: XFormNamespaceContext.INSTANCE); ingo@0: ingo@0: Node value = (Node) XMLUtils.getXPath( ingo@0: item, "xform:value", XPathConstants.NODE, ingo@0: XFormNamespaceContext.INSTANCE); ingo@0: ingo@0: if (pieces.indexOf(label.getTextContent()) >= 0) ingo@0: options.add(value.getTextContent()); ingo@0: } ingo@0: ingo@0: if (options.isEmpty()) ingo@0: throw new NoSuchOptionException(text); ingo@0: ingo@0: return (String[]) options.toArray(new String[options.size()]); ingo@0: } ingo@0: ingo@0: ingo@0: /** ingo@0: * XXX This method extracts the measurement ids depending on the user ingo@0: * configuration from describe document. Currently, this is a special case ingo@0: * that should be handled the same way as all the other options in the ingo@0: * describe document. ingo@0: */ ingo@0: public static String[] extractMeasurements( ingo@1: HttpClient client, ingo@0: Artifact artifact, ingo@0: String text) ingo@0: throws NoSuchOptionException, ConnectionException ingo@0: { ingo@0: Document describe = ArtifactProtocolUtils.createDescribeDocument( ingo@0: artifact, true); ingo@0: ingo@0: Document description = (Document) client.describe( ingo@0: artifact, describe, new DocumentResponseHandler()); ingo@0: ingo@0: List pieces = Arrays.asList(text.split(",")); ingo@0: List options = new ArrayList(pieces.size()); ingo@0: ingo@0: Node dynamic = XMLUtils.getNodeXPath(description, XPATH_DYNAMIC); ingo@0: ingo@0: NodeList params = (NodeList) XMLUtils.getXPath( ingo@0: dynamic, "xform:group/xform:select", ingo@0: XPathConstants.NODESET, XFormNamespaceContext.INSTANCE); ingo@0: ingo@0: for (int i = 0; i < params.getLength(); i++) { ingo@0: Node param = params.item(i); ingo@0: ingo@0: NodeList items = (NodeList) XMLUtils.getXPath( ingo@0: param, "xform:item[@disabled='false']", XPathConstants.NODESET, ingo@0: XFormNamespaceContext.INSTANCE); ingo@0: ingo@0: for (int j = 0; j < items.getLength(); j++) { ingo@0: Node item = items.item(j); ingo@0: ingo@0: Node label = (Node) XMLUtils.getXPath( ingo@0: item, "xform:label", XPathConstants.NODE, ingo@0: XFormNamespaceContext.INSTANCE); ingo@0: ingo@0: if (pieces.indexOf(label.getTextContent()) < 0) { ingo@0: continue; ingo@0: } ingo@0: ingo@0: Node value = (Node) XMLUtils.getXPath( ingo@0: item, "xform:value", XPathConstants.NODE, ingo@0: XFormNamespaceContext.INSTANCE); ingo@0: ingo@0: options.add(value.getTextContent()); ingo@0: } ingo@0: } ingo@0: ingo@0: if (options.isEmpty()) ingo@0: throw new NoSuchOptionException(text); ingo@0: ingo@0: return (String[]) options.toArray(new String[options.size()]); ingo@0: } ingo@0: } ingo@0: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8: