Mercurial > dive4elements > gnv-client
view gnv-artifacts/src/main/java/de/intevation/gnv/state/timeseries/TimeSeriesOutputState.java @ 505:7ff916744f40
Solved issue152. Time intervals of timeseries axis are defined by JFreeChart automatically.
gnv-artifacts/trunk@588 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author | Ingo Weinzierl <ingo.weinzierl@intevation.de> |
---|---|
date | Wed, 20 Jan 2010 17:54:48 +0000 |
parents | fec85cd01497 |
children | a162793b6053 |
line wrap: on
line source
/** * */ package de.intevation.gnv.state.timeseries; import au.com.bytecode.opencsv.CSVWriter; import de.intevation.artifactdatabase.Config; import de.intevation.artifactdatabase.XMLUtils; import de.intevation.artifacts.ArtifactNamespaceContext; import de.intevation.artifacts.CallContext; import de.intevation.artifacts.CallMeta; import de.intevation.artifacts.PreferredLocale; import de.intevation.gnv.artifacts.context.GNVArtifactContext; import de.intevation.gnv.artifacts.ressource.RessourceFactory; import de.intevation.gnv.chart.Chart; import de.intevation.gnv.chart.ChartLabels; import de.intevation.gnv.chart.TimeSeriesChart; import de.intevation.gnv.chart.XMLChartTheme; import de.intevation.gnv.chart.exception.TechnicalChartException; import de.intevation.gnv.exports.ChartExportHelper; import de.intevation.gnv.exports.DefaultDataCollector; import de.intevation.gnv.exports.DefaultExport; import de.intevation.gnv.exports.DefaultProfile; import de.intevation.gnv.exports.Export.Profile; import de.intevation.gnv.exports.SimpleOdvDataCollector; import de.intevation.gnv.geobackend.base.Result; import de.intevation.gnv.state.InputData; import de.intevation.gnv.state.OutputStateBase; import de.intevation.gnv.state.describedata.KeyValueDescibeData; import de.intevation.gnv.state.describedata.NamedCollection; import de.intevation.gnv.state.exception.StateException; import de.intevation.gnv.statistics.Statistic; import de.intevation.gnv.statistics.StatisticSet; import de.intevation.gnv.statistics.Statistics; import de.intevation.gnv.statistics.TimeseriesStatistics; import de.intevation.gnv.statistics.exception.StatisticsException; import de.intevation.gnv.timeseries.gap.DefaultTimeGap; import de.intevation.gnv.timeseries.gap.TimeGap; import de.intevation.gnv.utils.ArtifactXMLUtilities; import java.io.File; import java.io.IOException; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Vector; import org.apache.log4j.Logger; import org.jfree.chart.ChartTheme; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; /** * @author Tim Englich (tim.englich@intevation.de) * @author Ingo Weinzierl (ingo.weinzierl@intevation.de) */ public class TimeSeriesOutputState extends OutputStateBase { protected static final boolean CACHE_CHART = Boolean.parseBoolean(System.getProperty("cache.chart", "false")); protected static final boolean PDF_FORMAT_LANDSCAPE = Boolean.parseBoolean(System.getProperty("export.pdf.landscape","true")); protected static final String[] IMG_EXPORT_FORMAT = { "PNG", "JPEG", "GIF" }; /** * The UID of this Class */ private static final long serialVersionUID = 4178407570503098858L; /** * the logger, used to log exceptions and additonaly information */ private static Logger log = Logger .getLogger(TimeSeriesOutputState.class); private static List<TimeGap> timeGapDefinitions = null; protected String domainLable = "chart.timeseries.title.xaxis"; protected String featureValuesName = "featureid"; protected String parameterValuesName = "parameterid"; protected String measuremenValueName = "measurementid"; protected String dateValueName = "dateid"; public static final String [] TIMESERIES_CSV_PROFILE_COLUMNS = { "XORDINATE", "YORDINATE", "GROUP1", "GROUP2", "GROUP3" }; public static final String [] TIMESERIES_TIMESERIES_CSV_COLUMN_LABEL = { "Date/Time", "Value", "ParameterID", "MeasurementID", "TimeseriesID" }; public static final String [] TIMESERIES_MESH_CSV_COLUMN_LABEL = { "Date/Time", "Value", "ParameterID", "FeatureID", "MeshID" }; public static final String [] TIMESERIES_ODV_PROFILE_NAMES = { "CRUISE", "STATION", "TYPE", "SHAPE", "BOTDEPTH", "DEPTH", "TIMEVALUE", "DATAVALUE", "PARAMETER" }; public static final String [] ODV_COLUMN_HEADER = { "Cruise", "Station", "Type", "Longitude [deegrees_east]", "Latitude [deegrees_north]", "Bot. Depth [m]", "Depth [m]", "Date/Time", "Value", "Parameterid" }; /** * Profile for exporting data to odv * TODO Change TIMESERIES_PROFILE_NAMES, which belong to CSV exports */ public static final Profile TIMESERIES_ODV_PROFILE = new DefaultProfile( ODV_COLUMN_HEADER, '\t', CSVWriter.NO_QUOTE_CHARACTER, CSVWriter.NO_ESCAPE_CHARACTER, "ODV", "ISO-8859-1"); /** * Constructor */ public TimeSeriesOutputState() { super(); } /** * @see de.intevation.gnv.transition.OutputTransition#out(java.lang.String, * java.util.Collection, java.io.OutputStream, java.lang.String, * de.intevation.artifacts.CallMeta) */ public void out( Document format, Collection<InputData> inputData, OutputStream outputStream, String uuid, CallContext callContext ) throws StateException { log.debug("TimeSeriesOutputTransition.out"); String outputMode = XMLUtils.xpathString( format, XPATH_OUTPUT_MODE, ArtifactNamespaceContext.INSTANCE); String mimeType = XMLUtils.xpathString( format, XPATH_MIME_TYPE, ArtifactNamespaceContext.INSTANCE); CallMeta callMeta = callContext.getMeta(); int chartWidth = 600; int chartHeight = 400; boolean sVisible = false; // lines are always visible. if lines should be configurable we need a // parameter in the user interface boolean lVisible = true; try { if (inputData != null) { Iterator<InputData> it = inputData.iterator(); while (it.hasNext()) { InputData ip = it.next(); String optionName = ip.getName().trim(); if (optionName.equals("width")) { chartWidth = Integer.parseInt(ip.getValue()); } else if (optionName.equals("height")) { chartHeight = Integer.parseInt(ip.getValue()); } else if (optionName.equals("points")) { sVisible = Boolean.parseBoolean(ip.getValue()); } } } } catch (NumberFormatException e) { log.error(e, e); throw new StateException(e); } try { if (outputMode.equalsIgnoreCase("chart")) { log.debug("Chart will be generated."); PreferredLocale[] locales = callMeta.getLanguages(); Locale[] serverLocales = RessourceFactory.getInstance().getLocales(); Locale locale = callMeta.getPreferredLocale(serverLocales); log.debug( "Best locale - regarding intersection of server and " + "browser locales - is " + locale.toString() ); Collection parameters = this.getCleanedParameters(uuid); Collection measurements = this.getMeasurements(uuid); Collection dates = this.getDates(uuid); ChartLabels chartLables = createChartLabels(locale, uuid); String exportFormat = getExportFormat(mimeType); this.createChart( outputStream, parameters, measurements, dates, chartLables, callContext, uuid, exportFormat, locale, chartWidth, chartHeight, lVisible, sVisible, callContext ); } else if (outputMode.equalsIgnoreCase("pdf")) { log.debug("Output mode == pdf"); Locale[] serverLocales = RessourceFactory.getInstance().getLocales(); Locale locale = callMeta.getPreferredLocale(serverLocales); log.debug( "Best locale - regarding intersection of server and " + "browser locales - is " + locale.toString() ); createPDF( outputStream, getCleanedParameters(uuid), getMeasurements(uuid), getDates(uuid), new ChartLabels( createChartTitle(locale, uuid), createChartSubtitle(locale, uuid), RessourceFactory.getInstance().getRessource( locale, domainLable, domainLable ) ), uuid, "A4", true, lVisible, sVisible, locale, callContext ); } else if (outputMode.equalsIgnoreCase("svg")) { log.debug("Output mode == svg"); Locale[] serverLocales = RessourceFactory.getInstance().getLocales(); Locale locale = callMeta.getPreferredLocale(serverLocales); log.debug( "Best locale - regarding intersection of server and " + "browser locales - is " + locale.toString() ); createSVG( outputStream, getCleanedParameters(uuid), getMeasurements(uuid), getDates(uuid), new ChartLabels( createChartTitle(locale, uuid), createChartSubtitle(locale, uuid), RessourceFactory.getInstance().getRessource( locale, domainLable, domainLable ) ), uuid, locale, chartWidth, chartHeight, lVisible, sVisible, callContext ); } else if (outputMode.equalsIgnoreCase("csv")) { log.debug("CSV-File will be generated."); Object result = getChartResult(uuid, callContext); if (result instanceof Collection) { this.createCSV( outputStream, (Collection<Result>)result); } } else if (outputMode.equalsIgnoreCase("statistics")) { log.debug("Statistics will be generated."); Collection<StatisticSet> statistics; Statistics s = getStatisticsGenerator(); Object result = getChartResult(uuid, callContext); if (result != null && s != null) { Collection<KeyValueDescibeData> parameters = getParameters(uuid); Collection<KeyValueDescibeData> measurements = getMeasurements(uuid); Collection<KeyValueDescibeData> dates = getDates(uuid); statistics = s.calculateStatistics( result, parameters, measurements, dates); } else { statistics = new ArrayList<StatisticSet>(); } Document doc = writeStatistics2XML(statistics); XMLUtils.toStream(doc, outputStream); } else if (outputMode.equalsIgnoreCase("odv")) { Collection<Result> odvResult = this.getODVResult(uuid); this.createODV(outputStream, odvResult); } } catch (IOException e) { log.error(e, e); throw new StateException(e); } catch (TechnicalChartException e) { log.error(e, e); throw new StateException(e); } catch (StatisticsException e) { log.error(e, e); throw new StateException(e); } } protected String getExportFormat(String mime) { for(int i = 0; i < IMG_EXPORT_FORMAT.length; i++) { if (mime.trim().toUpperCase().indexOf(IMG_EXPORT_FORMAT[i]) > 0) return IMG_EXPORT_FORMAT[i]; } // no format found relating to mimeType, default export as PNG return IMG_EXPORT_FORMAT[0]; } protected Collection getCleanedParameters(Collection parameters) { Iterator iter = parameters.iterator(); Collection parameter = new Vector(parameters); while (iter.hasNext()) { KeyValueDescibeData data = (KeyValueDescibeData)iter.next(); if (!data.isSelected()) parameter.remove(data); } return parameter; } protected Collection getCleanedParameters(String uuid) { return getCleanedParameters(getParameters(uuid)); } protected void createCSV(OutputStream out, Collection<Result> results) throws UnsupportedEncodingException, IOException, StateException { Iterator iter = results.iterator(); Result res = iter.hasNext() ? (Result) iter.next() : null; if (res == null) return; Profile profile = null; int dataid = res.getInteger("DATAID").intValue(); // on meshes if (dataid == 2) { profile = new DefaultProfile( TIMESERIES_MESH_CSV_COLUMN_LABEL, ',', '"', '"', "CSV", "ISO-8859-1"); } // on timeseries else { profile = new DefaultProfile( TIMESERIES_TIMESERIES_CSV_COLUMN_LABEL, ',', '"', '"', "CSV", "ISO-8859-1"); } DefaultExport export = new DefaultExport( new DefaultDataCollector(TIMESERIES_CSV_PROFILE_COLUMNS)); export.create(profile, out, results); } /** * TODO Result is not used at the moment. Change result with correct data. */ protected void createODV(OutputStream outputStream, Collection result) throws IOException, StateException { DefaultExport export = new DefaultExport(new SimpleOdvDataCollector( TIMESERIES_ODV_PROFILE_NAMES)); if (result == null) log.error("#################### RESULT == NULL #################"); export.create(TIMESERIES_ODV_PROFILE, outputStream, result); } /** * @return */ protected Statistics getStatisticsGenerator() { Statistics s = new TimeseriesStatistics(); return s; } protected Document writeStatistics2XML( Collection<StatisticSet> statistic) { ArtifactXMLUtilities xmlUtilities = new ArtifactXMLUtilities(); Document doc = XMLUtils.newDocument(); if (statistic != null) { Node statisticResults = xmlUtilities.createArtifactElement(doc, "statistics"); doc.appendChild(statisticResults); Iterator<StatisticSet> it = statistic.iterator(); while (it.hasNext()) { StatisticSet set = it.next(); Element setElement = xmlUtilities.createArtifactElement(doc, "statistic"); setElement.setAttribute("name", set.getName()); Iterator<Statistic> sit = set.getStatistics().iterator(); while (sit.hasNext()){ Statistic s = sit.next(); Element result = xmlUtilities.createArtifactElement(doc, "statistic-value"); result.setAttribute("name", s.getKey()); result.setAttribute("value", s.getStringValue()); setElement.appendChild(result); } statisticResults.appendChild(setElement); } } return doc; } protected String getSelectedFeatureName(String uuid) { Collection values = getCollection(featureValuesName, uuid); if (values != null) { Iterator it = values.iterator(); while (it.hasNext()) { KeyValueDescibeData data = (KeyValueDescibeData) it.next(); if (data.isSelected()) { return data.getValue(); } } } return null; } /** * @param outputStream * @param parameters * @param measurements * @param timeSeriesName * @param chartStyle * @param chartLables * @throws IOException * @throws TechnicalChartException */ protected void createChart( OutputStream outputStream, Collection parameters, Collection measurements, Collection dates, ChartLabels chartLables, CallContext context, String uuid, String exportFormat, Locale locale, int width, int height, boolean linesVisible, boolean shapesVisible, CallContext callContext ) throws IOException, TechnicalChartException { log.debug("Create chart."); Chart chart = getChart( chartLables, createStyle(context), parameters, measurements, dates, getChartResult(uuid, callContext), locale, // Locale uuid, linesVisible, shapesVisible, callContext ); if (chart == null) { log.error("Could not initialize chart."); return; } log.debug( "export chart as " + exportFormat + " in " + width + "x" + height ); ChartExportHelper.exportImage( outputStream, chart.generateChart(), exportFormat, width, height ); } protected void createPDF( OutputStream outputStream, Collection parameters, Collection measurements, Collection dates, ChartLabels chartLables, String uuid, String exportFormat, boolean landscape, boolean linesVisible, boolean shapesVisible, Locale locale, CallContext context ) { Chart chart = getChart( chartLables, createStyle(context), parameters, measurements, dates, getChartResult(uuid, context), locale, uuid, linesVisible, shapesVisible, context ); if (chart == null) { log.error("Could not initialize chart."); return; } ChartExportHelper.exportPDF( outputStream, chart.generateChart(), "A4", PDF_FORMAT_LANDSCAPE, 50F, 50F, 50F, 50F ); } protected void createSVG( OutputStream outputStream, Collection parameters, Collection measurements, Collection dates, ChartLabels chartLables, String uuid, Locale locale, int width, int height, boolean linesVisible, boolean shapesVisible, CallContext callContext ) { Chart chart = getChart( chartLables, createStyle(callContext), parameters, measurements, dates, getChartResult(uuid, callContext), locale, uuid, linesVisible, shapesVisible, callContext ); if (chart == null) { log.error("Could not initialize chart."); return; } ChartExportHelper.exportSVG( outputStream, chart.generateChart(), null, 600, 400 ); log.debug("svg export finished."); } protected Chart getChart( ChartLabels chartLables, ChartTheme theme, Collection parameters, Collection measurements, Collection dates, Object result, Locale locale, String uuid, boolean linesVisible, boolean shapesVisible, CallContext callContext ) { Chart chart = null; if (CACHE_CHART) { log.info("Try to get timeseries chart from cache."); chart = (Chart) getChartFromCache(uuid, callContext); } if (chart != null) return chart; log.info("Chart not in cache yet."); chart = new TimeSeriesChart( chartLables, theme, parameters, measurements, dates, (Collection)result, timeGapDefinitions, locale, linesVisible, shapesVisible ); chart.generateChart(); if (CACHE_CHART) { log.info("Put chart into cache."); purifyChart(chart, uuid); } return chart; } protected ChartTheme createStyle(CallContext callContext) { log.debug("Fetch chart theme from global context"); GNVArtifactContext context = (GNVArtifactContext) callContext.globalContext(); XMLChartTheme theme = (XMLChartTheme) context.get( GNVArtifactContext.CHART_TEMPLATE_KEY); return theme; } protected ChartLabels createChartLabels(Locale locale, String uuid) { return new ChartLabels( createChartTitle(locale, uuid), createChartSubtitle(locale, uuid), RessourceFactory.getInstance().getRessource( locale, domainLable, domainLable ) ); } protected String createChartTitle(Locale locale, String uuid) { return getFisName(locale); } protected String createChartSubtitle(Locale locale, String uuid) { return getSelectedFeatureName(uuid); } protected String getFisName(Locale locale) { String returnValue = ""; InputData input = inputData.get("fisname"); if (input != null) { String value = input.getValue(); returnValue = RessourceFactory.getInstance().getRessource( locale, value, value ); } return returnValue; } protected String getSelectedInputDataName(String uuid, String key) { Collection values = getCollection(key, uuid); if (values != null) { Iterator it = values.iterator(); while (it.hasNext()) { KeyValueDescibeData data = (KeyValueDescibeData) it.next(); if (data.isSelected()) { return data.getValue(); } } } return null; } protected Collection<KeyValueDescibeData> getParameters(String uuid) { return this.getCollection(parameterValuesName, uuid); } protected Collection<KeyValueDescibeData> getMeasurements(String uuid) { return this.getCollection(measuremenValueName, uuid); } protected Collection<KeyValueDescibeData> getDates(String uuid) { return this.getCollection(dateValueName,uuid); } @Override public void setup(Node configuration) { super.setup(configuration); String featureNameValue = Config.getStringXPath(configuration, "value-names/value-name[@name='feature']/@value"); if (featureNameValue != null) { this.featureValuesName = featureNameValue; } String parameterNameValue = Config.getStringXPath(configuration, "value-names/value-name[@name='parameter']/@value"); if (parameterNameValue != null) { this.parameterValuesName = parameterNameValue; } String measurementNameValue = Config.getStringXPath(configuration, "value-names/value-name[@name='measurement']/@value"); if (measurementNameValue != null) { this.measuremenValueName = measurementNameValue; } String dateNameValue = Config.getStringXPath(configuration, "value-names/value-name[@name='date']/@value"); if (dateNameValue != null) { this.dateValueName = dateNameValue; } if (timeGapDefinitions == null){ Element gapDefinition = (Element)Config.getNodeXPath(configuration, "time-gap-definition"); synchronized (this.getClass()) { if (gapDefinition != null){ String link = gapDefinition.getAttribute("xlink:href"); if (link != null ){ String absolutFileName = Config.replaceConfigDir(link); gapDefinition = (Element)new ArtifactXMLUtilities(). readConfiguration(absolutFileName); } NodeList gapDefinitions = Config.getNodeSetXPath(gapDefinition, "/time-gaps/time-gap"); if (gapDefinition != null){ timeGapDefinitions = new ArrayList<TimeGap>(gapDefinitions. getLength()); for (int i = 0; i < gapDefinitions.getLength(); i++){ Element gapNode = (Element)gapDefinitions.item(i); String unit = gapNode.getAttribute("unit"); int key = Integer.parseInt(gapNode.getAttribute("key")); int value = Integer.parseInt(gapNode.getAttribute("gap")); log.info("Add new Timegap: "+key+" "+value+" "+ unit); timeGapDefinitions.add(new DefaultTimeGap(unit, key, value)); } } } } } } /** * @param collectionName * @return */ protected Collection<KeyValueDescibeData> getCollection( String collectionName, String uuid) { Iterator<Object> it = this.getDescibeData(uuid).iterator(); while (it.hasNext()) { Object o = it.next(); if (o instanceof NamedCollection<?>) { NamedCollection<KeyValueDescibeData> nc = (NamedCollection<KeyValueDescibeData>) o; if (nc.getName().equals(collectionName)) { return nc; } } } return null; } } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :