001: /* Copyright (c) 2001 - 2007 TOPP - www.openplans.org. All rights reserved.
002: * This code is licensed under the GPL 2.0 license, availible at the root
003: * application directory.
004: */
005: package org.geoserver.wfs;
006:
007: import net.opengis.wfs.InsertElementType;
008: import net.opengis.wfs.InsertedFeatureType;
009: import net.opengis.wfs.TransactionResponseType;
010: import net.opengis.wfs.TransactionType;
011: import net.opengis.wfs.WfsFactory;
012: import org.eclipse.emf.ecore.EObject;
013: import org.geoserver.feature.ReprojectingFeatureCollection;
014: import org.geotools.data.FeatureStore;
015: import org.geotools.feature.AttributeType;
016: import org.geotools.feature.DefaultFeatureCollection;
017: import org.geotools.feature.Feature;
018: import org.geotools.feature.FeatureCollection;
019: import org.geotools.feature.FeatureIterator;
020: import org.geotools.feature.FeatureType;
021: import org.geotools.feature.GeometryAttributeType;
022: import org.geotools.geometry.jts.JTS;
023: import org.geotools.referencing.operation.projection.PointOutsideEnvelopeException;
024: import org.opengis.filter.Filter;
025: import org.opengis.filter.FilterFactory;
026: import org.opengis.referencing.crs.CoordinateReferenceSystem;
027:
028: import com.vividsolutions.jts.geom.Geometry;
029:
030: import java.math.BigInteger;
031: import java.util.ArrayList;
032: import java.util.HashMap;
033: import java.util.HashSet;
034: import java.util.Iterator;
035: import java.util.LinkedList;
036: import java.util.List;
037: import java.util.Map;
038: import java.util.Set;
039: import java.util.logging.Logger;
040: import javax.xml.namespace.QName;
041:
042: /**
043: * Handler for the insert element
044: *
045: * @author Andrea Aime - TOPP
046: *
047: */
048: public class InsertElementHandler implements TransactionElementHandler {
049: /**
050: * logger
051: */
052: static Logger LOGGER = org.geotools.util.logging.Logging
053: .getLogger("org.geoserver.wfs");
054: private WFS wfs;
055: private FilterFactory filterFactory;
056:
057: public InsertElementHandler(WFS wfs, FilterFactory filterFactory) {
058: this .wfs = wfs;
059: this .filterFactory = filterFactory;
060: }
061:
062: public void checkValidity(EObject element, Map featureTypeInfos)
063: throws WFSTransactionException {
064: if ((wfs.getServiceLevel() & WFS.SERVICE_INSERT) == 0) {
065: throw new WFSException(
066: "Transaction INSERT support is not enabled");
067: }
068: }
069:
070: public void execute(EObject element, TransactionType request,
071: Map featureStores, TransactionResponseType response,
072: TransactionListener listener)
073: throws WFSTransactionException {
074: LOGGER.finer("Transasction Insert:" + element);
075:
076: InsertElementType insert = (InsertElementType) element;
077: long inserted = response.getTransactionSummary()
078: .getTotalInserted().longValue();
079:
080: try {
081: // group features by their schema
082: HashMap /* <FeatureType,FeatureCollection> */schema2features = new HashMap();
083:
084: for (Iterator f = insert.getFeature().iterator(); f
085: .hasNext();) {
086: Feature feature = (Feature) f.next();
087: FeatureType schema = feature.getFeatureType();
088: FeatureCollection collection = (FeatureCollection) schema2features
089: .get(schema);
090:
091: if (collection == null) {
092: collection = new DefaultFeatureCollection(null,
093: schema);
094: schema2features.put(schema, collection);
095: }
096:
097: collection.add(feature);
098: }
099:
100: // JD: change from set fo list because if inserting
101: // features into different feature stores, they could very well
102: // get given the same id
103: // JD: change from list to map so that the map can later be
104: // processed and we can report the fids back in the same order
105: // as they were supplied
106: HashMap schema2fids = new HashMap();
107:
108: for (Iterator c = schema2features.values().iterator(); c
109: .hasNext();) {
110: FeatureCollection collection = (FeatureCollection) c
111: .next();
112: FeatureType schema = collection.getSchema();
113:
114: QName elementName = new QName(schema.getNamespace()
115: .toString(), schema.getTypeName());
116: FeatureStore store = (FeatureStore) featureStores
117: .get(elementName);
118:
119: if (store == null) {
120: throw new WFSException(
121: "Could not locate FeatureStore for '"
122: + elementName + "'");
123: }
124:
125: if (collection != null) {
126: // if we really need to, make sure we are inserting coordinates that do
127: // match the CRS area of validity
128: if (wfs.getCiteConformanceHacks()) {
129: checkFeatureCoordinatesRange(collection);
130: }
131:
132: // reprojection
133: final GeometryAttributeType defaultGeometry = store
134: .getSchema().getDefaultGeometry();
135: if (defaultGeometry != null) {
136: CoordinateReferenceSystem target = defaultGeometry
137: .getCoordinateSystem();
138: if (target != null) {
139: collection = new ReprojectingFeatureCollection(
140: collection, target);
141: }
142: }
143:
144: // Need to use the namespace here for the
145: // lookup, due to our weird
146: // prefixed internal typenames. see
147: // http://jira.codehaus.org/secure/ViewIssue.jspa?key=GEOS-143
148:
149: // Once we get our datastores making features
150: // with the correct namespaces
151: // we can do something like this:
152: // FeatureTypeInfo typeInfo =
153: // catalog.getFeatureTypeInfo(schema.getTypeName(),
154: // schema.getNamespace());
155: // until then (when geos-144 is resolved) we're
156: // stuck with:
157: // QName qName = (QName) typeNames.get( i );
158: // FeatureTypeInfo typeInfo =
159: // catalog.featureType( qName.getPrefix(),
160: // qName.getLocalPart() );
161:
162: // this is possible with the insert hack above.
163: LOGGER
164: .finer("Use featureValidation to check contents of insert");
165:
166: // featureValidation(
167: // typeInfo.getDataStore().getId(), schema,
168: // collection );
169: List fids = (List) schema2fids.get(schema
170: .getTypeName());
171:
172: if (fids == null) {
173: fids = new LinkedList();
174: schema2fids.put(schema.getTypeName(), fids);
175: }
176:
177: listener.dataStoreChange(new TransactionEvent(
178: TransactionEventType.PRE_INSERT,
179: elementName, collection));
180: fids.addAll(store.addFeatures(collection));
181: }
182: }
183:
184: // report back fids, we need to keep the same order the
185: // fids were reported in the original feature collection
186: InsertedFeatureType insertedFeature = null;
187:
188: for (Iterator f = insert.getFeature().iterator(); f
189: .hasNext();) {
190: Feature feature = (Feature) f.next();
191: FeatureType schema = feature.getFeatureType();
192:
193: // get the next fid
194: LinkedList fids = (LinkedList) schema2fids.get(schema
195: .getTypeName());
196: String fid = (String) fids.removeFirst();
197:
198: insertedFeature = WfsFactory.eINSTANCE
199: .createInsertedFeatureType();
200: insertedFeature.setHandle(insert.getHandle());
201: insertedFeature.getFeatureId().add(
202: filterFactory.featureId(fid));
203:
204: response.getInsertResults().getFeature().add(
205: insertedFeature);
206: }
207:
208: // update the insert counter
209: inserted += insert.getFeature().size();
210: } catch (Exception e) {
211: String msg = "Error performing insert";
212: throw new WFSTransactionException(msg, e, insert
213: .getHandle());
214: }
215:
216: // update transaction summary
217: response.getTransactionSummary().setTotalInserted(
218: BigInteger.valueOf(inserted));
219: }
220:
221: /**
222: * Checks that all features coordinates are within the expected coordinate range
223: * @param collection
224: * @throws PointOutsideEnvelopeException
225: */
226: void checkFeatureCoordinatesRange(FeatureCollection collection)
227: throws PointOutsideEnvelopeException {
228: AttributeType[] types = collection.getSchema()
229: .getAttributeTypes();
230: FeatureIterator fi = collection.features();
231: try {
232: while (fi.hasNext()) {
233: Feature f = fi.next();
234: for (int i = 0; i < types.length; i++) {
235: if (types[i] instanceof GeometryAttributeType) {
236: GeometryAttributeType gat = (GeometryAttributeType) types[i];
237: if (gat.getCoordinateSystem() != null) {
238: Geometry geom = (Geometry) f
239: .getAttribute(i);
240: if (geom != null)
241: JTS.checkCoordinatesRange(geom, gat
242: .getCoordinateSystem());
243: }
244: }
245: }
246: }
247: } finally {
248: fi.close();
249: }
250: }
251:
252: public Class getElementClass() {
253: return InsertElementType.class;
254: }
255:
256: public QName[] getTypeNames(EObject element)
257: throws WFSTransactionException {
258: InsertElementType insert = (InsertElementType) element;
259: List typeNames = new ArrayList();
260:
261: if (!insert.getFeature().isEmpty()) {
262: for (Iterator f = insert.getFeature().iterator(); f
263: .hasNext();) {
264: Feature feature = (Feature) f.next();
265:
266: String name = feature.getFeatureType().getTypeName();
267: String namespaceURI = null;
268:
269: if (feature.getFeatureType().getNamespace() != null) {
270: namespaceURI = feature.getFeatureType()
271: .getNamespace().toString();
272: }
273:
274: typeNames.add(new QName(namespaceURI, name));
275: }
276: } else {
277: LOGGER
278: .finer("Insert was empty - does not need a FeatuerSoruce");
279: }
280:
281: return (QName[]) typeNames.toArray(new QName[typeNames.size()]);
282: }
283: }
|