Package org.geoserver.wfs

Source Code of org.geoserver.wfs.UpdateElementHandler

/* Copyright (c) 2001 - 2007 TOPP - www.openplans.org. All rights reserved.
* This code is licensed under the GPL 2.0 license, availible at the root
* application directory.
*/
package org.geoserver.wfs;

import java.io.IOException;
import java.math.BigInteger;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.logging.Logger;

import javax.xml.namespace.QName;

import net.opengis.wfs.AllSomeType;
import net.opengis.wfs.PropertyType;
import net.opengis.wfs.TransactionResponseType;
import net.opengis.wfs.TransactionType;
import net.opengis.wfs.UpdateElementType;

import org.eclipse.emf.ecore.EObject;
import org.geoserver.catalog.FeatureTypeInfo;
import org.geoserver.config.GeoServer;
import org.geotools.data.FeatureLocking;
import org.geotools.data.FeatureStore;
import org.geotools.factory.CommonFactoryFinder;
import org.geotools.factory.GeoTools;
import org.geotools.feature.FeatureCollection;
import org.geotools.geometry.jts.GeometryCoordinateSequenceTransformer;
import org.geotools.geometry.jts.JTS;
import org.geotools.referencing.CRS;
import org.geotools.referencing.operation.projection.PointOutsideEnvelopeException;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.feature.type.AttributeDescriptor;
import org.opengis.feature.type.FeatureType;
import org.opengis.feature.type.GeometryDescriptor;
import org.opengis.feature.type.PropertyDescriptor;
import org.opengis.filter.Filter;
import org.opengis.filter.FilterFactory;
import org.opengis.filter.FilterFactory2;
import org.opengis.filter.Id;
import org.opengis.filter.expression.PropertyName;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.operation.MathTransform;

import com.vividsolutions.jts.geom.Geometry;


/**
* Processes standard update elements
*
* @author Andrea Aime - TOPP
*
*/
public class UpdateElementHandler implements TransactionElementHandler {
    /**
     * logger
     */
    static Logger LOGGER = org.geotools.util.logging.Logging.getLogger("org.geoserver.wfs");
    private WFSInfo wfs;

    public UpdateElementHandler(GeoServer gs) {
        this.wfs = gs.getService( WFSInfo.class );
    }

    public void checkValidity(EObject element, Map typeInfos)
        throws WFSTransactionException {
        // check inserts are enabled
        if (!wfs.getServiceLevel().getOps().contains(WFSInfo.Operation.TRANSACTION_UPDATE) ) {
            throw new WFSException("Transaction Update support is not enabled");
        }

        FilterFactory ff = CommonFactoryFinder.getFilterFactory( null );
       
        // check that all required properties have a specified value
        UpdateElementType update = (UpdateElementType) element;

        try {
            FeatureTypeInfo meta = (FeatureTypeInfo) typeInfos.values().iterator().next();
            FeatureType featureType = meta.getFeatureType();

            for (Iterator prop = update.getProperty().iterator(); prop.hasNext();) {
                PropertyType property = (PropertyType) prop.next();

                //check that valus that are non-nillable exist
                if (property.getValue() == null) {
                    String propertyName = property.getName().getLocalPart();
                    AttributeDescriptor attributeType = null;
                    PropertyDescriptor pd = featureType.getDescriptor(propertyName);
                    if(pd instanceof AttributeDescriptor) {
                        attributeType = (AttributeDescriptor) pd;
                    }
                    if ((attributeType != null) && (attributeType.getMinOccurs() > 0)) {
                        String msg = "Property '" + attributeType.getLocalName()
                            + "' is mandatory but no value specified.";
                        throw new WFSException(msg, "MissingParameterValue");
                    }
                }
               
                //check that property names are actually valid
                QName name = property.getName();
                PropertyName propertyName = null;
               
                if ( name.getPrefix() != null && !"".equals( name.getPrefix() )) {
                    propertyName = ff.property( name.getPrefix() + ":" + name.getLocalPart() );
                }
                else {
                    propertyName = ff.property( name.getLocalPart() );
                }
               
                if ( propertyName.evaluate( featureType ) == null ) {
                    String msg = "No such property: " + property.getName();
                    throw new WFSException( msg );
                }
            }
        } catch (IOException e) {
            throw new WFSTransactionException("Could not locate feature type information for "
                + update.getTypeName(), e, update.getHandle());
        }
    }

    public void execute(EObject element, TransactionType request, Map featureStores,
        TransactionResponseType response, TransactionListener listener)
        throws WFSTransactionException {
        UpdateElementType update = (UpdateElementType) element;
        final QName elementName = update.getTypeName();
        String handle = update.getHandle();
        long updated = response.getTransactionSummary().getTotalUpdated().longValue();

        FeatureStore<SimpleFeatureType, SimpleFeature> store;
        store = (FeatureStore<SimpleFeatureType, SimpleFeature>) featureStores.get(elementName);

        if (store == null) {
            throw new WFSException("Could not locate FeatureStore for '" + elementName + "'");
        }

        LOGGER.finer("Transaction Update:" + element);

        try {
            Filter filter = (Filter) update.getFilter();
           
           
            // make sure all geometric elements in the filter have a crs, and that the filter
            // is reprojected to store's native crs as well
            CoordinateReferenceSystem declaredCRS = WFSReprojectionUtil.getDeclaredCrs(
                    store.getSchema(), request.getVersion());
            filter = WFSReprojectionUtil.normalizeFilterCRS(filter, store.getSchema(), declaredCRS);


            AttributeDescriptor[] types = new AttributeDescriptor[update.getProperty().size()];
            Object[] values = new Object[update.getProperty().size()];

            for (int j = 0; j < update.getProperty().size(); j++) {
                PropertyType property = (PropertyType) update.getProperty().get(j);
                types[j] = store.getSchema().getDescriptor(property.getName().getLocalPart());
                values[j] = property.getValue();
               
                // if geometry, it may be necessary to reproject it to the native CRS before
                // update
                if (values[j] instanceof Geometry ) {
                    Geometry geometry = (Geometry) values[j];
                   
                    // get the source crs, check the geometry itself first. If not set, assume
                    // the default one
                    CoordinateReferenceSystem source = null;
                    if ( geometry.getUserData() instanceof CoordinateReferenceSystem ) {
                        source = (CoordinateReferenceSystem) geometry.getUserData();
                    } else {
                        geometry.setUserData(declaredCRS);
                        source = declaredCRS;
                    }
                   
                    // see if the geometry has a CRS other than the default one
                    CoordinateReferenceSystem target = null;
                    if (types[j] instanceof GeometryDescriptor) {
                        target = ((GeometryDescriptor)types[j]).getCoordinateReferenceSystem();
                    }
                   
                    if(wfs.isCiteCompliant())
                        JTS.checkCoordinatesRange(geometry, source != null ? source : target);
                   
                    //if we have a source and target and they are not equal, do
                    // the reprojection, otherwise just update the value as is
                    if ( source != null && target != null && !CRS.equalsIgnoreMetadata(source, target)) {
                        try {
                            //TODO: this code should be shared with the code
                            // from ReprojectingFeatureCollection --JD
                            MathTransform tx = CRS.findMathTransform(source, target, true);
                            GeometryCoordinateSequenceTransformer gtx =
                                new GeometryCoordinateSequenceTransformer();
                            gtx.setMathTransform(tx);
                           
                            values[j] = gtx.transform(geometry);   
                        }
                        catch( Exception e ) {
                            String msg = "Failed to reproject geometry:" + e.getLocalizedMessage();
                            throw new WFSTransactionException( msg, e );
                        }
                    }
                   
                }
            }

            // Pass through data to collect fids and damaged
            // region
            // for validation
            //
            Set fids = new HashSet();
            LOGGER.finer("Preprocess to remember modification as a set of fids");
           
            FeatureCollection<SimpleFeatureType, SimpleFeature> features = store.getFeatures(filter);
            TransactionEvent event = new TransactionEvent(TransactionEventType.PRE_UPDATE, elementName, features);
            event.setSource( update );
           
            listener.dataStoreChange( event );

            Iterator preprocess = features.iterator();

            try {
                while (preprocess.hasNext()) {
                    SimpleFeature feature = (SimpleFeature) preprocess.next();
                    fids.add(feature.getID());
                }
            } catch (NoSuchElementException e) {
                throw new WFSException("Could not aquire FeatureIDs", e);
            } finally {
                features.close(preprocess);
            }

            try {
                if (types.length == 1) {
                    store.modifyFeatures(types[0], values[0], filter);
                } else {
                    store.modifyFeatures(types, values, filter);
                }
            }
            catch( Exception e) {
                //JD: this is a bit hacky but some of the wfs cite tests require
                // that the 'InvalidParameterValue' code be set on exceptions in
                // cases where a "bad" value is being suppliedin an update, so
                // we always set to that code
                throw new WFSTransactionException( "update error", e, "InvalidParameterValue");
               
            }
            finally {
                // make sure we unlock
                if ((request.getLockId() != null) && store instanceof FeatureLocking
                        && (request.getReleaseAction() == AllSomeType.SOME_LITERAL)) {
                    FeatureLocking<SimpleFeatureType, SimpleFeature> locking;
                    locking = (FeatureLocking<SimpleFeatureType, SimpleFeature>) store;
                    locking.unLockFeatures(filter);
                }
            }

            // Post process - gather the same features after the update, and 
            if (!fids.isEmpty()) {
                LOGGER.finer("Post process update for boundary update and featureValidation");

                Set featureIds = new HashSet();

                FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2(GeoTools.getDefaultHints());
                for (Iterator f = fids.iterator(); f.hasNext();) {
                    featureIds.add(ff.featureId((String) f.next()));
                }

                Id modified = ff.id(featureIds);

                FeatureCollection<SimpleFeatureType, SimpleFeature> changed = store.getFeatures(modified);
                listener.dataStoreChange(new TransactionEvent(TransactionEventType.POST_UPDATE,
                        elementName, changed));
            }

            // update the update counter
            updated += fids.size();
        } catch (IOException ioException) {
            // JD: changing from throwing service exception to
            // adding action that failed
            throw new WFSTransactionException(ioException, null, handle);
        } catch(PointOutsideEnvelopeException poe) {
            throw new WFSTransactionException(poe, null, handle);
        }

        // update transaction summary
        response.getTransactionSummary().setTotalUpdated(BigInteger.valueOf(updated));
    }

    public Class getElementClass() {
        return UpdateElementType.class;
    }

    public QName[] getTypeNames(EObject element) throws WFSTransactionException {
        return new QName[] { ((UpdateElementType) element).getTypeName() };
    }
}
TOP

Related Classes of org.geoserver.wfs.UpdateElementHandler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.