/* * Geotoolkit - An Open Source Java GIS Toolkit * http://www.geotoolkit.org * * (C) 2009, Geomatys * * 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; * version 2.1 of the License. * * 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. */ package org.geotoolkit.data.session; import com.vividsolutions.jts.geom.Geometry; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.logging.Level; import org.apache.sis.feature.FeatureExt; import org.geotoolkit.data.FeatureStore; import org.geotoolkit.data.FeatureIterator; import org.geotoolkit.data.memory.GenericModifyFeatureIterator; import org.geotoolkit.data.memory.WrapFeatureIterator; import org.geotoolkit.data.query.Query; import org.geotoolkit.data.query.QueryBuilder; import org.apache.sis.referencing.CRS; import org.apache.sis.storage.DataStoreException; import org.apache.sis.util.Utilities; import org.apache.sis.util.NullArgumentException; import org.opengis.feature.Feature; import org.opengis.feature.FeatureType; import org.opengis.util.GenericName; import org.opengis.filter.Id; import org.opengis.filter.identity.Identifier; import org.opengis.geometry.Envelope; import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.opengis.util.FactoryException; import org.apache.sis.internal.feature.AttributeConvention; import static org.apache.sis.util.ArgumentChecks.*; import org.geotoolkit.data.FeatureStoreRuntimeException; import org.geotoolkit.geometry.jts.JTS; import org.opengis.geometry.MismatchedDimensionException; import org.opengis.referencing.operation.MathTransform; import org.opengis.referencing.operation.TransformException; /** * Delta which modify a collection of features. * * @author Johann Sorel (Geomatys) * @module * @todo make this concurrent */ public class ModifyDelta extends AbstractDelta{ protected final Map<String,Object> values = new HashMap<>(); protected Id filter; public ModifyDelta(final Session session, final String typeName, final Id filter, final Map<String,?> values){ super(session,typeName); ensureNonNull("type name", typeName); if(filter == null){ throw new NullArgumentException("Filter can not be null. Did you mean Filter.INCLUDE ?"); } if(values == null || values.isEmpty()){ throw new IllegalArgumentException("Modified values can not be null or empty. A modify delta is useless in this case."); } this.filter = filter; this.values.putAll(values); } /** * {@inheritDoc } */ @Override public void update(Map<String, String> idUpdates) { if(idUpdates == null || idUpdates.isEmpty())return; final Set<Identifier> ids = filter.getIdentifiers(); final Set<Identifier> newIds = new HashSet<Identifier>(); for(final Identifier id : ids){ String newId = idUpdates.get(id.getID().toString()); if(newId != null){ //id has change newIds.add(FF.featureId(newId)); }else{ //this id did not change newIds.add(id); } } filter = FF.id(newIds); } /** * {@inheritDoc } */ @Override public Query modify(final Query query) { if(!query.getTypeName().equals(type)) return query; //we always include the modified features //they will be filtered at return time in the other modified methods //todo we should modify this query for count and envelope final QueryBuilder builder = new QueryBuilder(query); builder.setFilter(FF.or(builder.getFilter(),filter)); return builder.buildQuery(); } /** * {@inheritDoc } */ @Override public FeatureIterator modify(final Query query, final FeatureIterator reader) throws DataStoreException { final FeatureIterator wrap = new WrapFeatureIterator(reader) { @Override protected Feature modify(Feature feature) { if(!filter.evaluate(feature)){ return feature; } //modify the feature feature = GenericModifyFeatureIterator.apply(feature, values); try { final CoordinateReferenceSystem crs = query.getCoordinateSystemReproject(); //wrap reprojection ---------------------------------------------------- if(crs != null){ //check we have a geometry modification final FeatureType original = session.getFeatureStore().getFeatureType(feature.getType().getName().toString()); for(String desc : values.keySet()){ if (AttributeConvention.isGeometryAttribute(feature.getType().getProperty(desc))) { final CoordinateReferenceSystem originalCRS = FeatureExt.getCRS(original.getProperty(desc)); if(!Utilities.equalsIgnoreMetadata(originalCRS,crs)){ MathTransform trs = CRS.findOperation(originalCRS, crs, null).getMathTransform(); Object geom = feature.getPropertyValue(desc); if (geom instanceof Geometry) { try { geom = JTS.transform((Geometry) geom, trs); } catch (MismatchedDimensionException | TransformException ex) { throw new FeatureStoreRuntimeException(ex); } JTS.setCRS((Geometry) geom, crs); feature.setPropertyValue(desc, geom); } } } } } } catch (DataStoreException ex) { getLogger().log(Level.WARNING, null, ex); feature = null; } catch (FactoryException ex) { getLogger().log(Level.WARNING, null, ex); feature = null; } return feature; } }; return wrap; } /** * {@inheritDoc } */ @Override public long modify(final Query query, final long count) throws DataStoreException{ //todo must find a correct wayto alterate the count //the send request should be modified return count; } /** * {@inheritDoc } */ @Override public Envelope modify(final Query query, final Envelope env) throws DataStoreException { //todo must find a correct wayto alterate the envelope //the send request should be modified return env; } /** * {@inheritDoc } */ @Override public Map<String,String> commit(final FeatureStore store) throws DataStoreException { store.updateFeatures(type, filter, values); return null; } /** * {@inheritDoc } */ @Override public void dispose() { } }