Package org.geoserver.wfs

Source Code of org.geoserver.wfs.UpdateElementHandler

/* (c) 2014 Open Source Geospatial Foundation - all rights reserved
* (c) 2001 - 2013 OpenPlans
* This code is licensed under the GPL 2.0 license, available 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.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.logging.Logger;

import javax.xml.namespace.QName;

import org.geoserver.catalog.FeatureTypeInfo;
import org.geoserver.config.GeoServer;
import org.geoserver.wfs.request.Property;
import org.geoserver.wfs.request.TransactionElement;
import org.geoserver.wfs.request.TransactionRequest;
import org.geoserver.wfs.request.TransactionResponse;
import org.geoserver.wfs.request.Update;
import org.geotools.data.DataUtilities;
import org.geotools.data.FeatureLocking;
import org.geotools.data.FeatureStore;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.data.simple.SimpleFeatureIterator;
import org.geotools.data.simple.SimpleFeatureLocking;
import org.geotools.data.simple.SimpleFeatureStore;
import org.geotools.factory.CommonFactoryFinder;
import org.geotools.factory.GeoTools;
import org.geotools.feature.FeatureIterator;
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.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.filter.identity.FeatureId;
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 extends AbstractTransactionElementHandler {
    /**
     * logger
     */
    static Logger LOGGER = org.geotools.util.logging.Logging.getLogger("org.geoserver.wfs");
   
    public UpdateElementHandler(GeoServer gs) {
        super(gs);
    }

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

        Update update = (Update) element;
        FilterFactory ff = CommonFactoryFinder.getFilterFactory( null );
       
        try {
            FeatureTypeInfo meta = typeInfos.values().iterator().next();
            FeatureType featureType = meta.getFeatureType();

            List<Property> props = update.getUpdateProperties();
            for (Iterator<Property> prop = props.iterator(); prop.hasNext();) {
                Property property = 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(element, 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: " + name;
                    throw new WFSException(element, msg );
                }
            }
        } catch (IOException e) {
            throw new WFSTransactionException("Could not locate feature type information for " +
                update.getTypeName(), e, update.getHandle());
        }
    }

    public void execute(TransactionElement element, TransactionRequest request,
       @SuppressWarnings("rawtypes") Map<QName, FeatureStore> featureStores,
       TransactionResponse response, TransactionListener listener) throws WFSTransactionException {
       
        Update update = (Update) element;
        final QName elementName = update.getTypeName();
        String handle = update.getHandle();
       
        long updated = response.getTotalUpdated().longValue();

        SimpleFeatureStore store = DataUtilities.simple((FeatureStore) featureStores.get(elementName));

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

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

        try {
            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());
            if(filter != null) {
                filter = WFSReprojectionUtil.normalizeFilterCRS(filter, store.getSchema(), declaredCRS);
            } else {
                filter = Filter.INCLUDE;
            }

            List<Property> properties = update.getUpdateProperties();
            AttributeDescriptor[] types = new AttributeDescriptor[properties.size()];
            String[] names = new String[properties.size()];
            Object[] values = new Object[properties.size()];

            for (int j = 0; j < properties.size(); j++) {
                Property property = properties.get(j);
                QName propertyName = property.getName();
                types[j] = store.getSchema().getDescriptor(propertyName.getLocalPart());
               
                names[j] = propertyName.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(getInfo().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<FeatureId> fids = new HashSet<FeatureId>();
            LOGGER.finer("Preprocess to remember modification as a set of fids");
           
            SimpleFeatureCollection features = store.getFeatures(filter);
            TransactionEvent event = new TransactionEvent(TransactionEventType.PRE_UPDATE, request,
                    elementName, features);
            event.setSource(Update.WFS11.unadapt(update));
           
            listener.dataStoreChange( event );

            FeatureIterator preprocess = features.features();

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

            try {
                store.modifyFeatures(names, 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.getMessage(), e, "InvalidParameterValue");
               
            }
            finally {
                // make sure we unlock
                if ((request.getLockId() != null) && store instanceof FeatureLocking
                        && (request.isReleaseActionSome())) {
                    SimpleFeatureLocking locking;
                    locking = (SimpleFeatureLocking) 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<FeatureId> featureIds = new HashSet<FeatureId>();

                FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2(GeoTools.getDefaultHints());
                for (Iterator<FeatureId> f = fids.iterator(); f.hasNext();) {
                    // create new FeatureIds without any possible version information in order to
                    // query for the latest version
                    featureIds.add(ff.featureId(f.next().getID()));
                }

                Id modified = ff.id(featureIds);

                SimpleFeatureCollection changed = store.getFeatures(modified);
               
                // grab final ids. Not using fetureIds as they may contain different version
                // information after the update
                Set<FeatureId> changedIds = new HashSet<FeatureId>();
                SimpleFeatureIterator iterator = changed.features();
                try{
                    while(iterator.hasNext()){
                        changedIds.add(iterator.next().getIdentifier());
                    }
                }finally{
                    iterator.close();
                }
                response.addUpdatedFeatures(handle, changedIds);

                listener.dataStoreChange(new TransactionEvent(TransactionEventType.POST_UPDATE,
                        request, elementName, changed, Update.WFS11.unadapt(update)));
               
            }

            // 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.setTotalUpdated(BigInteger.valueOf(updated));
    }

    /**
     * @see org.geoserver.wfs.TransactionElementHandler#getElementClass()
     */
    public Class getElementClass() {
        return Update.class;
    }

    /**
     * @see org.geoserver.wfs.TransactionElementHandler#getTypeNames(org.eclipse.emf.ecore.EObject)
     */
    public QName[] getTypeNames(TransactionElement element) throws WFSTransactionException {
        return new QName[] { 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.