/* (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.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Logger;
import javax.xml.namespace.QName;
import net.opengis.wfs.AllSomeType;
import net.opengis.wfs.DeleteElementType;
import net.opengis.wfs.TransactionResponseType;
import net.opengis.wfs.TransactionType;
import org.eclipse.emf.ecore.EObject;
import org.geoserver.catalog.FeatureTypeInfo;
import org.geoserver.config.GeoServer;
import org.geoserver.wfs.request.Delete;
import org.geoserver.wfs.request.TransactionElement;
import org.geoserver.wfs.request.TransactionRequest;
import org.geoserver.wfs.request.TransactionResponse;
import org.geotools.data.DataStore;
import org.geotools.data.DataUtilities;
import org.geotools.data.Query;
import org.geotools.data.FeatureLockException;
import org.geotools.data.FeatureLocking;
import org.geotools.data.FeatureStore;
import org.geotools.data.FeatureWriter;
import org.geotools.data.simple.SimpleFeatureLocking;
import org.geotools.data.simple.SimpleFeatureStore;
import org.geotools.factory.CommonFactoryFinder;
import org.geotools.xml.EMFUtils;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.filter.Filter;
import org.opengis.filter.FilterFactory;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import com.vividsolutions.jts.geom.Envelope;
/**
* Processes standard Delete elements
*
* @author Andrea Aime - TOPP
*
*/
public class DeleteElementHandler extends AbstractTransactionElementHandler {
/**
* logger
*/
static Logger LOGGER = org.geotools.util.logging.Logging.getLogger("org.geoserver.wfs");
FilterFactory factory = CommonFactoryFinder.getFilterFactory(null);
public DeleteElementHandler(GeoServer gs) {
super(gs);
}
public Class getElementClass() {
return Delete.class;
}
/**
* @see org.geoserver.wfs.TransactionElementHandler#getTypeNames(org.eclipse.emf.ecore.EObject)
*/
public QName[] getTypeNames(TransactionElement element) throws WFSTransactionException {
return new QName[]{element.getTypeName()};
}
public void checkValidity(TransactionElement delete, Map featureTypeInfos)
throws WFSTransactionException {
if (!getInfo().getServiceLevel().getOps().contains(WFSInfo.Operation.TRANSACTION_DELETE)) {
throw new WFSException(delete, "Transaction Delete support is not enabled");
}
Filter f = delete.getFilter();
if ((f == null) || Filter.INCLUDE.equals(f)) {
throw new WFSTransactionException("Must specify filter for delete",
"MissingParameterValue");
}
}
public void execute(TransactionElement delete, TransactionRequest request, Map featureStores,
TransactionResponse response, TransactionListener listener) throws WFSTransactionException {
QName elementName = delete.getTypeName();
String handle = delete.getHandle();
long deleted = response.getTotalDeleted().longValue();
SimpleFeatureStore store = DataUtilities.simple((FeatureStore) featureStores.get(elementName));
if (store == null) {
throw new WFSException(request, "Could not locate FeatureStore for '" + elementName + "'");
}
String typeName = store.getSchema().getTypeName();
LOGGER.finer("Transaction Delete:" + delete);
try {
Filter filter = delete.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);
// notify listeners
TransactionEvent event = new TransactionEvent(TransactionEventType.PRE_DELETE, request,
elementName, store.getFeatures(filter));
event.setSource( Delete.WFS11.unadapt((Delete)delete));
listener.dataStoreChange( event );
// compute damaged area
Envelope damaged = store.getBounds(new Query(elementName.getLocalPart(), filter));
if (damaged == null) {
damaged = store.getFeatures(filter).getBounds();
}
if ((request.getLockId() != null) && store instanceof FeatureLocking
&& (request.isReleaseActionSome())) {
SimpleFeatureLocking locking;
locking = (SimpleFeatureLocking) store;
// TODO: Revisit Lock/Delete interaction in gt2
if (false) {
// REVISIT: This is bad - by releasing locks before
// we remove features we open ourselves up to the
// danger of someone else locking the features we
// are about to remove.
//
// We cannot do it the other way round, as the
// Features will not exist
//
// We cannot grab the fids offline using AUTO_COMMIT
// because we may have removed some of them earlier
// in the transaction
//
locking.unLockFeatures(filter);
store.removeFeatures(filter);
} else {
// This a bit better and what should be done, we
// will need to rework the gt2 locking api to work
// with fids or something
//
// The only other thing that would work
// would be to specify that FeatureLocking is
// required to remove locks when removing Features.
//
// While that sounds like a good idea, it
// would be extra work when doing release mode ALL.
//
DataStore data = (DataStore) store.getDataStore();
FeatureWriter<SimpleFeatureType, SimpleFeature> writer;
writer = data.getFeatureWriter(typeName, filter, store.getTransaction());
try {
while (writer.hasNext()) {
String fid = writer.next().getID();
Set featureIds = new HashSet();
featureIds.add(factory.featureId(fid));
locking.unLockFeatures(factory.id(featureIds));
writer.remove();
deleted++;
}
} finally {
writer.close();
}
store.removeFeatures(filter);
}
} else {
// We don't have to worry about locking right now
int deletedCount = store.getFeatures(filter).size();
if(deletedCount > 0)
deleted += deletedCount;
store.removeFeatures(filter);
}
} catch (IOException e) {
String msg = e.getMessage();
String eHandle = delete.getHandle();
String code = null;
//check case of feature lock exception and set appropriate exception
//code
if ( e instanceof FeatureLockException ) {
code = "MissingParameterValue";
}
throw new WFSTransactionException(msg, e, code, eHandle, handle);
}
// update deletion count
response.setTotalDeleted(BigInteger.valueOf(deleted));
}
}