view gnv-artifacts/src/main/java/de/intevation/gnv/state/timeseries/TimeSeriesOutputState.java @ 442:52e031261eaa

Create a new 'gnv' section in config file. gnv-artifacts/trunk@490 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Tue, 29 Dec 2009 10:09:26 +0000
parents 8975de9d7483
children da21c256a0ba
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,
                    callContext
                );
            }
            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 =
                    (Collection<Result>) getChartResult(uuid, callContext);
                this.createCSV(outputStream, chartResult);
            } else if (outputMode.equalsIgnoreCase("statistics")) {
                log.debug("Statistics will be generated.");
                Statistics s = getStatisticsGenerator();
                Collection<Result> chartResult =
                    (Collection<Result>) getChartResult(uuid, callContext);
                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,
        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,
            (Collection) 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
        );

        /* XXX: @Ingo: What's this? Looks like dev test remains.
        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,
            (Collection) 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(
            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 :

http://dive4elements.wald.intevation.org