ingo@348: package de.intevation.flys.exports; ingo@348: ingo@348: import java.io.IOException; ingo@348: import java.io.OutputStream; ingo@1645: import java.util.Locale; 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@1645: import de.intevation.artifacts.CallMeta; ingo@1645: import de.intevation.artifacts.PreferredLocale; 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: sascha@1055: import de.intevation.flys.artifacts.WINFOArtifact; felix@1944: import de.intevation.artifactdatabase.state.ArtifactAndFacet; sascha@1055: ingo@408: import de.intevation.flys.artifacts.resources.Resources; ingo@1095: import de.intevation.flys.utils.FLYSUtils; 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: felix@1104: /** 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@1735: /** The default chart format, if no other height is set.*/ ingo@1735: public static final String DEFAULT_CHART_FORMAT = "png"; ingo@1735: 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@1735: public static final String XPATH_CHART_FORMAT = ingo@1735: "/art:action/art:attributes/art:format/@art:value"; ingo@1735: 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@1645: protected Locale getLocale() { ingo@1645: CallMeta meta = context.getMeta(); ingo@1645: PreferredLocale[] prefs = meta.getLanguages(); ingo@1645: ingo@1645: int len = prefs != null ? prefs.length : 0; ingo@1645: ingo@1645: Locale[] locales = new Locale[len]; ingo@1645: ingo@1645: for (int i = 0; i < len; i++) { ingo@1645: locales[i] = prefs[i].getLocale(); ingo@1645: } ingo@1645: ingo@1645: return meta.getPreferredLocale(locales); ingo@1645: } ingo@1645: ingo@1645: 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() { sascha@1055: WINFOArtifact flys = (WINFOArtifact) master; ingo@412: felix@1104: River river = FLYSUtils.getRiver(flys); felix@1104: return (river != null) ? river.getName() : ""; ingo@412: } ingo@412: ingo@412: ingo@412: protected double[] getRange() { sascha@1055: WINFOArtifact flys = (WINFOArtifact) master; ingo@412: ingo@1095: return FLYSUtils.getKmRange(flys); 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@1735: protected String getFormat() { ingo@1735: String format = (String) XMLUtils.xpath( ingo@1735: request, ingo@1735: XPATH_CHART_FORMAT, ingo@1735: XPathConstants.STRING, ingo@1735: ArtifactNamespaceContext.INSTANCE); ingo@1735: ingo@1735: return format == null || format.length() == 0 ingo@1735: ? DEFAULT_CHART_FORMAT ingo@1735: : format; ingo@1735: } ingo@1735: ingo@1735: felix@1944: /** felix@1944: * Get Range of Domain ("X"-) Axis from request. felix@1944: */ 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: 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: felix@1944: sascha@719: String uri = ArtifactNamespaceContext.NAMESPACE_URI; ingo@652: felix@1944: 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: felix@1944: return from > to felix@1944: ? new Range(to, from) felix@1944: : 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@1684: public abstract void doOut( felix@1944: ArtifactAndFacet bundle, ingo@1684: Document attr, ingo@1684: boolean visible); 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 :