001: package org.geoserver.wfsv;
002:
003: import java.io.IOException;
004: import java.math.BigInteger;
005: import java.util.HashSet;
006: import java.util.Map;
007: import java.util.Set;
008:
009: import javax.xml.namespace.QName;
010:
011: import net.opengis.wfs.InsertedFeatureType;
012: import net.opengis.wfs.TransactionResponseType;
013: import net.opengis.wfs.TransactionType;
014: import net.opengis.wfs.WfsFactory;
015: import net.opengis.wfsv.RollbackType;
016:
017: import org.eclipse.emf.ecore.EObject;
018: import org.geoserver.wfs.TransactionElementHandler;
019: import org.geoserver.wfs.TransactionEvent;
020: import org.geoserver.wfs.TransactionEventType;
021: import org.geoserver.wfs.TransactionListener;
022: import org.geoserver.wfs.WFS;
023: import org.geoserver.wfs.WFSException;
024: import org.geoserver.wfs.WFSTransactionException;
025: import org.geotools.data.VersioningFeatureSource;
026: import org.geotools.data.VersioningFeatureStore;
027: import org.geotools.data.postgis.FeatureDiff;
028: import org.geotools.data.postgis.FeatureDiffReader;
029: import org.opengis.filter.Filter;
030: import org.opengis.filter.FilterFactory;
031: import org.vfny.geoserver.global.FeatureTypeInfo;
032:
033: /**
034: * Handles the extended rollback elements
035: *
036: * @author Andrea Aime - TOPP
037: */
038: public class RollbackElementHandler implements
039: TransactionElementHandler {
040:
041: private WFS wfs;
042:
043: private FilterFactory filterFactory;
044:
045: public RollbackElementHandler(WFS wfs, FilterFactory filterFactory) {
046: this .wfs = wfs;
047: this .filterFactory = filterFactory;
048: }
049:
050: public void checkValidity(EObject element, Map featureTypeInfos)
051: throws WFSTransactionException {
052: // let's check we can perfom inserts, updates and deletes
053: if ((wfs.getServiceLevel() & WFS.SERVICE_INSERT) == 0) {
054: throw new WFSException(
055: "Transaction INSERT support is not enabled "
056: + "(required for rollback)");
057: }
058:
059: if ((wfs.getServiceLevel() & WFS.SERVICE_UPDATE) == 0) {
060: throw new WFSException(
061: "Transaction UPDATE support is not enabled "
062: + "(required for rollback)");
063: }
064:
065: if ((wfs.getServiceLevel() & WFS.SERVICE_DELETE) == 0) {
066: throw new WFSException(
067: "Transaction DELETE support is not enabled "
068: + "(required for rollback)");
069: }
070:
071: // then, make sure we're hitting a versioning datastore
072: RollbackType rollback = (RollbackType) element;
073: FeatureTypeInfo info = (FeatureTypeInfo) featureTypeInfos
074: .get(rollback.getTypeName());
075:
076: try {
077: if (!(info.getFeatureSource() instanceof VersioningFeatureSource)) {
078: throw new WFSTransactionException(
079: "Cannot perform a rollback on "
080: + info.getTypeName()
081: + " since the backing data store is not versioning",
082: "", rollback.getHandle());
083: }
084: } catch (IOException e) {
085: throw new WFSTransactionException(
086: "Cannot get the feature source for feature type "
087: + info.getTypeName(), e, rollback
088: .getHandle());
089: }
090:
091: // TODO: we should check the user attribute, but for the moment
092: // we don't have an authentication subsystem
093: }
094:
095: public void execute(EObject element, TransactionType request,
096: Map featureStores, TransactionResponseType response,
097: TransactionListener listener)
098: throws WFSTransactionException {
099: RollbackType rollback = (RollbackType) element;
100: final QName layerName = rollback.getTypeName();
101: VersioningFeatureStore vstore = (VersioningFeatureStore) featureStores
102: .get(layerName);
103: long inserted = response.getTransactionSummary()
104: .getTotalInserted().longValue();
105: long updated = response.getTransactionSummary()
106: .getTotalUpdated().longValue();
107: long deleted = response.getTransactionSummary()
108: .getTotalDeleted().longValue();
109:
110: FeatureDiffReader reader = null;
111:
112: try {
113: // we use the difference to compute the number of inserted,
114: // updated and deleted features, but we can't use these to
115: // actually perform the rollback, since we would be unable to
116: // preserve the fids of the ones that were deleted and need to
117: // be re-inserted
118: Filter filter = (rollback.getFilter() != null) ? (Filter) rollback
119: .getFilter()
120: : Filter.INCLUDE;
121: String version = rollback.getToFeatureVersion();
122: String user = rollback.getUser();
123: String[] users = ((user != null) && !user.trim().equals("")) ? new String[] { user }
124: : null;
125: reader = vstore
126: .getDifferences(null, version, filter, users);
127:
128: Set insertedIds = new HashSet();
129: Set updatedIds = new HashSet();
130: Set deletedIds = new HashSet();
131: while (reader.hasNext()) {
132: FeatureDiff fd = reader.next();
133:
134: if (fd.getState() == FeatureDiff.INSERTED) {
135: inserted++;
136:
137: InsertedFeatureType insertedFeature = WfsFactory.eINSTANCE
138: .createInsertedFeatureType();
139: insertedFeature.setHandle(rollback.getHandle());
140: insertedFeature.getFeatureId().add(
141: filterFactory.featureId(fd.getID()));
142: response.getInsertResults().getFeature().add(
143: insertedFeature);
144: // accumulate fids for transaction event handling
145: insertedIds
146: .add(filterFactory.featureId(fd.getID()));
147: } else if (fd.getState() == FeatureDiff.UPDATED) {
148: updated++;
149: // accumulate fids for transaction event handling
150: updatedIds.add(filterFactory.featureId(fd.getID()));
151: } else if (fd.getState() == FeatureDiff.DELETED) {
152: deleted++;
153: // accumulate fids for transaction event handling
154: deletedIds.add(filterFactory.featureId(fd.getID()));
155: }
156: }
157:
158: // build filters
159: Filter insertedFilter = filterFactory.id(insertedIds);
160: Filter updatedFilter = filterFactory.id(updatedIds);
161: Filter deletedFilter = filterFactory.id(deletedIds);
162:
163: // notify pre-update and pre-delete
164: listener.dataStoreChange(new TransactionEvent(
165: TransactionEventType.PRE_UPDATE, layerName, vstore
166: .getFeatures(updatedFilter)));
167: listener.dataStoreChange(new TransactionEvent(
168: TransactionEventType.PRE_DELETE, layerName, vstore
169: .getFeatures(deletedFilter)));
170:
171: // now do the actual rollback
172: try {
173: vstore.rollback(version, (Filter) rollback.getFilter(),
174: users);
175: } catch (Exception e) {
176: throw new WFSTransactionException(
177: "Could not perform the rollback", e, rollback
178: .getHandle());
179: }
180:
181: // notify post update and post insert
182: listener.dataStoreChange(new TransactionEvent(
183: TransactionEventType.POST_INSERT, layerName, vstore
184: .getFeatures(insertedFilter)));
185: listener.dataStoreChange(new TransactionEvent(
186: TransactionEventType.POST_UPDATE, layerName, vstore
187: .getFeatures(updatedFilter)));
188:
189: // update summary information
190: response.getTransactionSummary().setTotalInserted(
191: BigInteger.valueOf(inserted));
192: response.getTransactionSummary().setTotalUpdated(
193: BigInteger.valueOf(updated));
194: response.getTransactionSummary().setTotalDeleted(
195: BigInteger.valueOf(deleted));
196: } catch (IOException e) {
197: throw new WFSTransactionException(
198: "Could not perform the rollback", e, rollback
199: .getHandle());
200: } finally {
201: if (reader != null) {
202: try {
203: reader.close();
204: } catch (IOException e) {
205: //
206: }
207: }
208: }
209: }
210:
211: public Class getElementClass() {
212: return RollbackType.class;
213: }
214:
215: public QName[] getTypeNames(EObject element)
216: throws WFSTransactionException {
217: RollbackType rollback = (RollbackType) element;
218:
219: return new QName[] { (QName) rollback.getTypeName() };
220: }
221: }
|