Mercurial > dive4elements > gnv-client
view gnv-artifacts/src/main/java/de/intevation/gnv/state/timeseries/TimeSeriesOutputState.java @ 416:04a242c67fe6
Added support of gap detection in horizontalcrossprofile charts.
gnv-artifacts/trunk@464 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author | Ingo Weinzierl <ingo.weinzierl@intevation.de> |
---|---|
date | Mon, 21 Dec 2009 13:49:49 +0000 |
parents | 6491000407dd |
children | bed9735adf84 |
line wrap: on
line source
/** * */ package de.intevation.gnv.state.timeseries; import java.io.IOException; import java.io.File; import java.io.OutputStream; import java.io.FileOutputStream; 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 javax.xml.transform.Transformer; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.TransformerFactoryConfigurationError; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.apache.log4j.Logger; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.jfree.chart.ChartTheme; import au.com.bytecode.opencsv.CSVWriter; import de.intevation.artifactdatabase.Config; import de.intevation.artifactdatabase.XMLUtils; import de.intevation.artifacts.CallMeta; import de.intevation.artifacts.CallContext; import de.intevation.artifacts.PreferredLocale; import de.intevation.gnv.artifacts.context.GNVArtifactContext; import de.intevation.gnv.artifacts.context.GNVArtifactContextFactory; 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.DefaultExport; import de.intevation.gnv.exports.DefaultDataCollector; import de.intevation.gnv.exports.SimpleOdvDataCollector; import de.intevation.gnv.exports.DefaultProfile; import de.intevation.gnv.exports.Export.Profile; 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; /** * @author Tim Englich <tim.englich@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 = Config.getStringXPath( format, "action/out/@name" ); String mimeType = Config.getStringXPath( format, "action/out/mime-type/@value" ); CallMeta callMeta = callContext.getMeta(); try { if (outputMode.equalsIgnoreCase("chart")) { log.debug("Chart will be generated."); int chartWidth = 600; int chartHeight = 400; try { if (inputData != null) { Iterator<InputData> it = inputData.iterator(); while (it.hasNext()) { InputData ip = it.next(); if (ip.getName().equalsIgnoreCase("width")) { chartWidth = Integer.parseInt(ip.getValue()); } else if (ip.getName().equalsIgnoreCase("height")) { chartHeight = Integer.parseInt(ip.getValue()); } } } } catch (NumberFormatException e) { log.error(e, e); throw new StateException(e); } 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 = new ChartLabels( createChartTitle(locale, uuid), createChartSubtitle(locale, uuid), RessourceFactory.getInstance().getRessource( locale, domainLable, domainLable ) ); String exportFormat = getExportFormat(mimeType); // TODO Remove this and parse input data boolean linesVisible = true; boolean shapesVisible = true; this.createChart( outputStream, parameters, measurements, dates, chartLables, callContext, uuid, exportFormat, locale, chartWidth, chartHeight, linesVisible, shapesVisible ); } else if (outputMode.equalsIgnoreCase("pdf")) { log.debug("Output mode == pdf"); Locale[] serverLocales = RessourceFactory.getInstance().getLocales(); Locale locale = callMeta.getPreferredLocale(serverLocales); // TODO Remove this and parse input data boolean linesVisible = true; boolean shapesVisible = true; 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, linesVisible, shapesVisible, locale, callContext ); } else if (outputMode.equalsIgnoreCase("svg")) { log.debug("Output mode == svg"); int width = 600; int height = 400; // TODO Remove this and parse input data boolean linesVisible = true; boolean shapesVisible = true; 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, width, height, linesVisible, shapesVisible, callContext ); } else if (outputMode.equalsIgnoreCase("csv")) { log.debug("CSV-File will be generated."); Collection<Result> chartResult = this.getChartResult(uuid); this.createCSV(outputStream, chartResult); } else if (outputMode.equalsIgnoreCase("statistics")) { log.debug("Statistics will be generated."); Statistics s = getStatisticsGenerator(); Collection<Result> chartResult = this.getChartResult(uuid); Collection<KeyValueDescibeData> parameters = this.getParameters(uuid); Collection<KeyValueDescibeData> measurements = this.getMeasurements(uuid); Collection<KeyValueDescibeData> dates = this.getDates(uuid); Collection<StatisticSet> statistics = s.calculateStatistics(chartResult, parameters, measurements, dates); Document doc = this.writeStatistics2XML(statistics); this.writeDocument2OutputStream(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 void writeDocument2OutputStream(Document document, OutputStream os) { try { TransformerFactory transformerFactory = TransformerFactory .newInstance(); Transformer transformer = transformerFactory.newTransformer(); DOMSource source = new DOMSource(document); StreamResult result = new StreamResult(os); transformer.transform(source, result); } catch (TransformerConfigurationException e) { log.error(e, e); } catch (TransformerFactoryConfigurationError e) { log.error(e, e); } catch (TransformerException e) { log.error(e, e); } } 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 ) throws IOException, TechnicalChartException { log.debug("Create chart."); Chart chart = getChart( chartLables, createStyle(context), parameters, measurements, dates, getChartResult(uuid), locale, // Locale uuid, linesVisible, shapesVisible ); 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), locale, uuid, linesVisible, shapesVisible ); if (chart == null) { log.error("Could not initialize chart."); return; } ChartExportHelper.exportPDF( outputStream, chart.generateChart(), "A4", PDF_FORMAT_LANDSCAPE, 50F, 50F, 50F, 50F ); try { OutputStream toFile = new FileOutputStream("/vol1/home/iweinzierl/tmp/test.svg"); ChartExportHelper.exportSVG( toFile, chart.generateChart(), null, 600, 400 ); toFile.flush(); toFile.close(); } catch(Exception e) { log.debug("ERROR WHLILE TEST."); } } 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), locale, uuid, linesVisible, shapesVisible ); 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, Collection result, Locale locale, String uuid, boolean linesVisible, boolean shapesVisible ) { Chart chart = null; if (CACHE_CHART) { log.info("Try to get timeseries chart from cache."); chart = (Chart) getChartFromCache(uuid); } if (chart != null) return chart; log.info("Chart not in cache yet."); chart = new TimeSeriesChart( chartLables, theme, parameters, measurements, dates, 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( GNVArtifactContextFactory.CHARTTEMPLATE ); return theme; } 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 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 :