ingo@348: package de.intevation.flys.exports; ingo@348: ingo@348: import java.io.IOException; ingo@348: import java.io.OutputStream; ingo@348: ingo@423: import javax.xml.xpath.XPathConstants; ingo@423: ingo@348: import org.apache.log4j.Logger; ingo@348: ingo@348: import org.w3c.dom.Document; sascha@719: import org.w3c.dom.Element; ingo@348: ingo@652: import org.jfree.data.Range; ingo@652: ingo@348: import de.intevation.artifacts.Artifact; ingo@412: import de.intevation.artifacts.CallContext; ingo@412: ingo@423: import de.intevation.artifacts.ArtifactNamespaceContext; ingo@423: import de.intevation.artifacts.common.utils.XMLUtils; ingo@423: ingo@695: import de.intevation.artifactdatabase.state.Facet; ingo@695: ingo@412: import de.intevation.flys.model.River; ingo@412: ingo@412: import de.intevation.flys.artifacts.FLYSArtifact; ingo@408: import de.intevation.flys.artifacts.resources.Resources; ingo@348: ingo@348: ingo@348: /** ingo@348: * The base class for chart creation. It should provide some basic things that ingo@348: * equal in all chart types. ingo@348: * ingo@348: * @author Ingo Weinzierl ingo@348: */ ingo@348: public abstract class ChartGenerator implements OutGenerator { ingo@348: ingo@348: private static Logger logger = Logger.getLogger(ChartGenerator.class); ingo@348: ingo@348: ingo@423: /** The default chart width, if no other width is set.*/ ingo@423: public static final int DEFAULT_CHART_WIDTH = 600; ingo@423: ingo@423: /** The default chart height, if no other height is set.*/ ingo@423: public static final int DEFAULT_CHART_HEIGHT = 400; ingo@423: ingo@423: /** The XPath that points to the chart size of the incoming request ingo@423: * document.*/ ingo@423: public static final String XPATH_CHART_SIZE = ingo@423: "/art:action/art:attributes/art:size"; ingo@423: ingo@652: public static final String XPATH_CHART_X_RANGE = ingo@652: "/art:action/art:attributes/art:xrange"; ingo@652: ingo@652: public static final String XPATH_CHART_Y_RANGE = ingo@652: "/art:action/art:attributes/art:yrange"; ingo@652: ingo@423: ingo@348: /** The document of the incoming out() request.*/ ingo@348: protected Document request; ingo@348: ingo@348: /** The output stream where the data should be written to.*/ ingo@348: protected OutputStream out; ingo@348: ingo@348: /** The CallContext object.*/ ingo@348: protected CallContext context; ingo@348: ingo@412: /** The artifact that is used to decorate the chart with meta information.*/ ingo@412: protected Artifact master; ingo@412: ingo@348: ingo@348: public void init(Document request, OutputStream out, CallContext context) { ingo@348: logger.debug("ChartGenerator.init"); ingo@348: ingo@348: this.request = request; ingo@348: this.out = out; ingo@348: this.context = context; ingo@348: } ingo@348: ingo@348: ingo@412: public void setMasterArtifact(Artifact master) { ingo@412: this.master = master; ingo@412: } ingo@412: ingo@412: ingo@408: protected String msg(String key, String def) { ingo@408: return Resources.getMsg(context.getMeta(), key, def); ingo@408: } ingo@408: ingo@408: ingo@412: protected String msg(String key, String def, Object[] args) { ingo@412: return Resources.getMsg(context.getMeta(), key, def, args); ingo@412: } ingo@412: ingo@412: ingo@412: protected String getRiverName() { ingo@412: FLYSArtifact flys = (FLYSArtifact) master; ingo@412: ingo@412: River river = flys.getRiver(); ingo@412: return river != null ? river.getName() : ""; ingo@412: } ingo@412: ingo@412: ingo@412: protected double[] getRange() { ingo@412: FLYSArtifact flys = (FLYSArtifact) master; ingo@412: ingo@412: return flys.getDistance(); ingo@412: } ingo@412: ingo@412: ingo@423: /** ingo@423: * Returns the size of a chart export as array which has been specified by ingo@423: * the incoming request document. ingo@423: * ingo@423: * @return the size of a chart as [width, height] or the result of ingo@423: * getDefaultSize() if no width or height are given in the request document. ingo@423: */ ingo@423: protected int[] getSize() { ingo@423: int[] size = new int[2]; ingo@423: sascha@719: Element sizeEl = (Element)XMLUtils.xpath( ingo@423: request, ingo@423: XPATH_CHART_SIZE, ingo@423: XPathConstants.NODE, ingo@423: ArtifactNamespaceContext.INSTANCE); ingo@423: ingo@423: if (sizeEl != null) { sascha@719: String uri = ArtifactNamespaceContext.NAMESPACE_URI; ingo@423: sascha@719: String w = sizeEl.getAttributeNS(uri, "width"); sascha@719: String h = sizeEl.getAttributeNS(uri, "height"); ingo@423: sascha@719: if (w.length() > 0 && h.length() > 0) { ingo@423: try { ingo@423: size[0] = Integer.parseInt(w); ingo@423: size[1] = Integer.parseInt(h); ingo@423: } ingo@423: catch (NumberFormatException nfe) { ingo@423: logger.warn("Wrong values for chart width/height."); ingo@423: } ingo@423: } ingo@423: } ingo@423: ingo@423: return size[0] > 0 && size[1] > 0 ? size : getDefaultSize(); ingo@423: } ingo@423: ingo@423: ingo@652: protected Range getDomainAxisRange() { sascha@719: Element xrange = (Element)XMLUtils.xpath( ingo@652: request, ingo@652: XPATH_CHART_X_RANGE, ingo@652: XPathConstants.NODE, ingo@652: ArtifactNamespaceContext.INSTANCE); ingo@652: ingo@652: if (xrange == null) { ingo@652: return null; ingo@652: } ingo@652: sascha@719: String uri = ArtifactNamespaceContext.NAMESPACE_URI; ingo@652: sascha@719: String lower = xrange.getAttributeNS(uri, "from"); sascha@719: String upper = xrange.getAttributeNS(uri, "to"); ingo@652: ingo@652: logger.debug("FOUND X RANGE: " + lower + " -> " + upper); ingo@652: sascha@719: if (lower.length() > 0 && upper.length() > 0) { ingo@652: try { ingo@652: double from = Double.parseDouble(lower); ingo@652: double to = Double.parseDouble(upper); ingo@652: ingo@652: if (from == 0 && to == 0) { ingo@652: logger.debug("No range specified. Lower and upper X == 0"); ingo@652: return null; ingo@652: } ingo@652: ingo@652: if (from > to) { ingo@652: double tmp = to; ingo@652: to = from; ingo@652: from = tmp; ingo@652: } ingo@652: ingo@652: return new Range(from, to); ingo@652: } ingo@652: catch (NumberFormatException nfe) { ingo@652: logger.warn("Wrong values for domain axis range."); ingo@652: } ingo@652: } ingo@652: ingo@652: return null; ingo@652: } ingo@652: ingo@652: ingo@652: protected Range getValueAxisRange() { sascha@719: Element yrange = (Element)XMLUtils.xpath( ingo@652: request, ingo@652: XPATH_CHART_Y_RANGE, ingo@652: XPathConstants.NODE, ingo@652: ArtifactNamespaceContext.INSTANCE); ingo@652: ingo@652: if (yrange == null) { ingo@652: return null; ingo@652: } ingo@652: sascha@719: String uri = ArtifactNamespaceContext.NAMESPACE_URI; ingo@652: sascha@719: String lower = yrange.getAttributeNS(uri, "from"); sascha@719: String upper = yrange.getAttributeNS(uri, "to"); ingo@652: sascha@719: if (lower.length() > 0 && upper.length() > 0) { ingo@652: try { ingo@652: double from = Double.parseDouble(lower); ingo@652: double to = Double.parseDouble(upper); ingo@652: ingo@652: if (from == 0 && to == 0) { ingo@652: logger.debug("No range specified. Lower and upper Y == 0"); ingo@652: return null; ingo@652: } ingo@652: ingo@652: if (from > to) { ingo@652: double tmp = to; ingo@652: to = from; ingo@652: from = tmp; ingo@652: } ingo@652: ingo@652: return new Range(from, to); ingo@652: } ingo@652: catch (NumberFormatException nfe) { ingo@652: logger.warn("Wrong values for value axis range."); ingo@652: } ingo@652: } ingo@652: ingo@652: return null; ingo@652: } ingo@652: ingo@652: ingo@423: /** ingo@423: * Returns the default size of a chart export as array. ingo@423: * ingo@423: * @return the default size of a chart as [width, height]. ingo@423: */ ingo@423: protected int[] getDefaultSize() { ingo@423: return new int[] { DEFAULT_CHART_WIDTH, DEFAULT_CHART_HEIGHT }; ingo@423: } ingo@423: ingo@423: ingo@695: public abstract void doOut(Artifact artifact, Facet facet, Document attr); ingo@348: ingo@348: public abstract void generate() throws IOException; ingo@348: } ingo@348: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :