org.kalypso.simulation.core.ant.GMLWeightingOperation.java Source code

Java tutorial

Introduction

Here is the source code for org.kalypso.simulation.core.ant.GMLWeightingOperation.java

Source

/*----------------    FILE HEADER KALYPSO ------------------------------------------
 *
 *  This file is part of kalypso.
 *  Copyright (C) 2004 by:
 * 
 *  Technical University Hamburg-Harburg (TUHH)
 *  Institute of River and coastal engineering
 *  Denickestrae 22
 *  21073 Hamburg, Germany
 *  http://www.tuhh.de/wb
 * 
 *  and
 *  
 *  Bjoernsen Consulting Engineers (BCE)
 *  Maria Trost 3
 *  56070 Koblenz, Germany
 *  http://www.bjoernsen.de
 * 
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 * 
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 * 
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 * 
 *  Contact:
 * 
 *  E-Mail:
 *  belger@bjoernsen.de
 *  schlienger@bjoernsen.de
 *  v.doemming@tuhh.de
 *   
 *  ---------------------------------------------------------------------------*/
package org.kalypso.simulation.core.ant;

import java.io.File;
import java.io.FileWriter;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
import java.net.URL;
import java.util.Date;
import java.util.List;
import java.util.logging.Level;

import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.namespace.NamespaceContext;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.tools.ant.BuildException;
import org.kalypso.commons.bind.JaxbUtilities;
import org.kalypso.contribs.java.net.IUrlResolver;
import org.kalypso.contribs.java.net.UrlResolverSingleton;
import org.kalypso.contribs.java.util.logging.ILogger;
import org.kalypso.contribs.java.util.logging.LoggerUtilities;
import org.kalypso.contribs.java.xml.XMLUtilities;
import org.kalypso.ogc.gml.serialize.GmlSerializer;
import org.kalypso.ogc.sensor.DateRange;
import org.kalypso.ogc.sensor.SensorException;
import org.kalypso.ogc.sensor.filter.FilterFactory;
import org.kalypso.ogc.sensor.zml.ZmlFactory;
import org.kalypso.zml.filters.AbstractFilterType;
import org.kalypso.zml.filters.InterpolationFilterType;
import org.kalypso.zml.filters.NOperationFilterType;
import org.kalypso.zml.filters.OperationFilterType;
import org.kalypso.zml.filters.ZmlFilterType;
import org.kalypso.zml.obslink.TimeseriesLinkType;
import org.kalypsodeegree.model.feature.Feature;
import org.kalypsodeegree.model.feature.FeatureList;
import org.kalypsodeegree.model.feature.GMLWorkspace;
import org.kalypsodeegree_impl.model.feature.gmlxpath.GMLXPath;
import org.kalypsodeegree_impl.model.feature.gmlxpath.GMLXPathException;
import org.kalypsodeegree_impl.model.feature.gmlxpath.GMLXPathUtilities;
import org.w3._1999.xlinkext.SimpleLinkType;
import org.xml.sax.InputSource;

/**
 * @author Gernot Belger
 */
public class GMLWeightingOperation {
    private final org.w3._1999.xlinkext.ObjectFactory m_linkFac = new org.w3._1999.xlinkext.ObjectFactory();

    private final IGMLWeightingData m_data;

    private final ILogger m_logger;

    private NamespaceContext m_namespaceContext;

    public GMLWeightingOperation(final IGMLWeightingData data, final ILogger logger) {
        m_data = data;
        m_logger = logger;
    }

    public void execute() throws Exception {
        final IUrlResolver urlResolver = UrlResolverSingleton.getDefault();
        // create needed factories
        final Marshaller marshaller = JaxbUtilities.createMarshaller(ZmlFactory.JC, true);

        // workspace for results
        final URL modelURL = m_data.getModelLocation();
        final GMLWorkspace resultWorkspace = CopyObservationMappingHelper.createMappingWorkspace(modelURL);

        // 1. load srcgml
        m_logger.log(Level.INFO, -1, "Lade Modell " + modelURL);
        final GMLWorkspace workspace = GmlSerializer.createGMLWorkspace(modelURL, null);
        m_namespaceContext = workspace.getNamespaceContext();

        // 2. locate features to process
        final GMLXPath targetFeaturePath = asPath(m_data.getTargetFeaturePath());
        final Feature[] targetFeatures = resolveFeatures(workspace.getRootFeature(), targetFeaturePath);
        if (targetFeatures == null)
            throw new BuildException("Kein(e) Ziel-Feature(s) gefunden fr FeaturePath: " + targetFeaturePath);

        final GMLXPath targetZMLPath = asPath(m_data.getTargetZMLProperty());
        final URL targetContext = m_data.getTargetContext();

        final GMLXPath sourceMember = asPath(m_data.getSourceMember());

        final GMLXPath weightPath = asPath(m_data.getWeightProperty());
        final GMLXPath offsetPath = asPath(m_data.getOffsetProperty());

        // loop all features
        for (final Feature targetFE : targetFeatures) {
            // 3. find target
            final TimeseriesLinkType targetLink = GMLXPathUtilities.query(targetZMLPath, targetFE);
            final String targetHref = targetLink.getHref();
            final URL targetURL = urlResolver.resolveURL(targetContext, targetHref);

            // 4. build n-operation filter
            final NOperationFilterType nOperationFilter = FilterFactory.OF_FILTER.createNOperationFilterType();
            nOperationFilter.setOperator("+"); //$NON-NLS-1$
            final List<JAXBElement<? extends AbstractFilterType>> filterList = nOperationFilter.getFilter();

            // 5. resolve weights

            final GMLXPath weightMember = asPath(m_data.getWeightMember());
            final Feature[] weightFEs = resolveFeatures(targetFE, weightMember);
            if (weightFEs == null)
                throw new BuildException("Kein(e) Gewichts-Feature(s) gefunden fr FeaturePath: " + weightMember);

            // 6. loop weights
            for (final Feature weightFE : weightFEs) {
                final double factor = getFactor(weightFE, weightPath);
                final double offset = getOffset(weightFE, offsetPath);

                // 7. resolve sources
                final Feature[] sourceFeatures = resolveFeatures(weightFE, sourceMember);
                if (sourceFeatures == null)
                    throw new BuildException("Kein(e) Quell-Feature(s) gefunden fr FeaturePath: " + sourceMember);

                final OperationFilterType offsetFilter = FilterFactory.OF_FILTER.createOperationFilterType();
                offsetFilter.setOperator("+"); //$NON-NLS-1$
                offsetFilter.setOperand(Double.toString(offset));

                final NOperationFilterType weightSumFilter = FilterFactory.OF_FILTER.createNOperationFilterType();
                weightSumFilter.setOperator("+"); //$NON-NLS-1$

                offsetFilter.setFilter(FilterFactory.OF_FILTER.createNOperationFilter(weightSumFilter));

                final List<JAXBElement<? extends AbstractFilterType>> offsetSummands = weightSumFilter.getFilter();

                addSourceSummands(weightFE, factor, sourceFeatures, offsetSummands);
                /* Empty NOperation filter is forbidden */
                // Bad warning message, can happen if all sub-elements are disabled
                if (offsetSummands.isEmpty()) {
                    // m_logger.log( Level.WARNING, LoggerUtilities.CODE_SHOW_DETAILS, "Leere Summe fr Feature: " +
                    // weightFE.getId() );
                } else
                    filterList.add(FilterFactory.OF_FILTER.createOperationFilter(offsetFilter));
            }

            /* Empty NOperation filter is forbidden */
            if (filterList.isEmpty()) {
                m_logger.log(Level.SEVERE, LoggerUtilities.CODE_SHOW_MSGBOX,
                        "Leere Summe fr Feature: " + targetFE.getId());
                return;
            }

            // 11. serialize filter to string
            final Writer writer = new StringWriter();
            marshaller.marshal(FilterFactory.OF_FILTER.createNOperationFilter(nOperationFilter), writer);
            writer.close();
            final String string = XMLUtilities.removeXMLHeader(writer.toString());
            final String filterInline = XMLUtilities.prepareInLine(string);

            // 12. add mapping to result workspace
            CopyObservationMappingHelper.addMapping(resultWorkspace, filterInline, targetURL.toExternalForm());
            m_logger.log(Level.INFO, -1, "Ziel-ZML " + targetURL);
        }

        // 14. do the mapping
        final Date sourceFrom = m_data.getSourceFrom();
        final Date sourceTo = m_data.getSourceTo();
        final Date targetFrom = m_data.getTargetFrom();
        final Date targetTo = m_data.getTargetTo();
        final Date forecastFrom = m_data.getForecastFrom();
        final Date forecastTo = m_data.getForecastTo();

        final DateRange measuredRange = DateRange.createDateRangeOrNull(sourceFrom, sourceTo);
        final DateRange keForecastRange = DateRange.createDateRangeOrNull(targetFrom, targetTo);
        final DateRange forecastMetadataRange = DateRange.createDateRangeOrNull(forecastFrom, forecastTo);

        CopyObservationMappingHelper.runMapping(resultWorkspace, modelURL, m_logger, true, measuredRange,
                keForecastRange, forecastMetadataRange);

        // 15. serialize result workspace to file
        final File targetMapping = m_data.getTargetMapping();
        if (targetMapping != null) {
            FileWriter writer = null;
            try {
                writer = new FileWriter(targetMapping);
                GmlSerializer.serializeWorkspace(writer, resultWorkspace);
                writer.close();
            } finally {
                IOUtils.closeQuietly(writer);
            }
        }
    }

    private void addSourceSummands(final Feature weightFE, final double factor, final Feature[] sourceFeatures,
            final List<JAXBElement<? extends AbstractFilterType>> offsetSummands)
            throws GMLXPathException, SensorException, JAXBException {
        final GMLXPath sourceZMLPath = asPath(m_data.getSourceZMLProperty());
        final GMLXPath sourceIsUsedPath = asPath(m_data.getSourceIsUsedProperty());
        final String sourceFilter = m_data.getSourceFilter();

        // 8. loop source features
        for (final Feature sourceFE : sourceFeatures) {
            if (sourceFE == null) {
                m_logger.log(Level.WARNING, -1, "Linked source feature missing in Feature: " + weightFE.getId());

                // IMPORTANT: just skips this weight; leads probably to wrong results
                continue;
            }

            // 9. resolve property that is source zml reference
            final TimeseriesLinkType zmlLink = GMLXPathUtilities.query(sourceZMLPath, sourceFE);
            final Boolean useThisSource;
            if (sourceIsUsedPath != null)
                useThisSource = GMLXPathUtilities.query(sourceIsUsedPath, sourceFE);
            else
                useThisSource = Boolean.TRUE;

            if (!useThisSource.booleanValue()) {
                m_logger.log(Level.INFO, LoggerUtilities.CODE_NONE, "Ignoriere: " + sourceFE.getId());
                continue;
            }

            if (zmlLink == null) {
                m_logger.log(Level.WARNING, LoggerUtilities.CODE_SHOW_DETAILS,
                        "Linked timeserie link missing in Feature: " + weightFE.getId()); //$NON-NLS-1$

                // IMPORTANT: just skips this weight; leads probably to wrong results
                continue;
            }

            // 10. build operation filter with parameters from gml
            final OperationFilterType filter = FilterFactory.OF_FILTER.createOperationFilterType();
            offsetSummands.add(FilterFactory.OF_FILTER.createOperationFilter(filter));
            filter.setOperator("*"); //$NON-NLS-1$
            filter.setOperand(Double.toString(factor));

            /* Innermost filter part */
            final ZmlFilterType zmlFilter = FilterFactory.OF_FILTER.createZmlFilterType();
            final SimpleLinkType simpleLink = m_linkFac.createSimpleLinkType();
            final String sourceHref = zmlLink.getHref();
            simpleLink.setHref(sourceHref);
            zmlFilter.setZml(simpleLink);

            if (sourceFilter != null) {
                final String strFilterXml = FilterFactory.getFilterPart(sourceFilter);

                final StringReader sr = new StringReader(strFilterXml);
                final Unmarshaller unmarshaller = ZmlFactory.JC.createUnmarshaller();
                final JAXBElement<?> filterElement = (JAXBElement<?>) unmarshaller.unmarshal(new InputSource(sr));
                if (filterElement == null
                        || !AbstractFilterType.class.isAssignableFrom(filterElement.getDeclaredType()))
                    throw new UnsupportedOperationException(
                            "Filter must start with an AbstractFilterType element."); //$NON-NLS-1$

                @SuppressWarnings("unchecked")
                final JAXBElement<AbstractFilterType> af = (JAXBElement<AbstractFilterType>) filterElement;
                filter.setFilter(af);

                // HACK
                final AbstractFilterType abstractFilter = af.getValue();
                if (abstractFilter instanceof InterpolationFilterType)
                    ((InterpolationFilterType) abstractFilter)
                            .setFilter(FilterFactory.OF_FILTER.createZmlFilter(zmlFilter));
                else
                    throw new UnsupportedOperationException(
                            "Only InterpolationFilter as source-filter supported at the moment."); //$NON-NLS-1$

                sr.close();
            } else
                filter.setFilter(FilterFactory.OF_FILTER.createZmlFilter(zmlFilter));
        }
    }

    private GMLXPath asPath(final String property) {
        if (StringUtils.isBlank(property))
            return null;

        return new GMLXPath(property, m_namespaceContext);
    }

    private Feature[] resolveFeatures(final Feature feature, final GMLXPath featurePath) throws GMLXPathException {
        if (featurePath == null)
            return new Feature[] { feature };

        final Object property = GMLXPathUtilities.query(featurePath, feature);
        if (property instanceof FeatureList)
            return ((FeatureList) property).toFeatures();

        if (property instanceof Feature)
            return new Feature[] { (Feature) property };

        if (property instanceof String) {
            final Feature resolvedFeature = feature.getWorkspace().getFeature((String) property);
            return new Feature[] { resolvedFeature };
        }

        return null;
    }

    private double getOffset(final Feature weightFE, final GMLXPath offsetPath) throws GMLXPathException {
        if (offsetPath == null)
            return 0.0;

        return resolveValueReference(weightFE, offsetPath, 0.0);
    }

    private double getFactor(final Feature weightFE, final GMLXPath weightPath) throws GMLXPathException {
        if (weightPath == null)
            return 1.0;

        return resolveValueReference(weightFE, weightPath, 1.0);
    }

    private double resolveValueReference(final Feature feature, final GMLXPath path, final double defaultValue)
            throws GMLXPathException {
        final Object valueOrReference = GMLXPathUtilities.query(path, feature);
        if (valueOrReference instanceof Number)
            return ((Number) valueOrReference).doubleValue();

        if (valueOrReference == null)
            return defaultValue;

        final String valuePath = valueOrReference.toString();
        if (StringUtils.isBlank(valuePath))
            return defaultValue;

        final GMLXPath valueXpath = new GMLXPath(valuePath, m_namespaceContext);

        return resolveValueReference(feature, valueXpath, defaultValue);
    }
}