001: //$Header: /deegreerepository/deegree/src/org/deegree/ogcwebservices/wfs/operation/transaction/Transaction.java,v 1.11 2007/02/07 15:01:51 poth Exp $
002: /*---------------- FILE HEADER ------------------------------------------
003:
004: This file is part of deegree.
005: Copyright (C) 2001-2008 by:
006: EXSE, Department of Geography, University of Bonn
007: http://www.giub.uni-bonn.de/deegree/
008: lat/lon GmbH
009: http://www.lat-lon.de
010:
011: This library is free software; you can redistribute it and/or
012: modify it under the terms of the GNU Lesser General Public
013: License as published by the Free Software Foundation; either
014: version 2.1 of the License, or (at your option) any later version.
015:
016: This library is distributed in the hope that it will be useful,
017: but WITHOUT ANY WARRANTY; without even the implied warranty of
018: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
019: Lesser General Public License for more details.
020:
021: You should have received a copy of the GNU Lesser General Public
022: License along with this library; if not, write to the Free Software
023: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
024:
025: Contact:
026:
027: Andreas Poth
028: lat/lon GmbH
029: Aennchenstraße 19
030: 53177 Bonn
031: Germany
032: E-Mail: poth@lat-lon.de
033:
034: Prof. Dr. Klaus Greve
035: Department of Geography
036: University of Bonn
037: Meckenheimer Allee 166
038: 53115 Bonn
039: Germany
040: E-Mail: greve@giub.uni-bonn.de
041:
042: ---------------------------------------------------------------------------*/
043: package org.deegree.ogcwebservices.wfs.operation.transaction;
044:
045: import java.util.ArrayList;
046: import java.util.HashSet;
047: import java.util.Iterator;
048: import java.util.List;
049: import java.util.Map;
050: import java.util.Set;
051:
052: import org.deegree.datatypes.QualifiedName;
053: import org.deegree.framework.log.ILogger;
054: import org.deegree.framework.log.LoggerFactory;
055: import org.deegree.framework.util.KVP2Map;
056: import org.deegree.ogcwebservices.InconsistentRequestException;
057: import org.deegree.ogcwebservices.InvalidParameterValueException;
058: import org.deegree.ogcwebservices.OGCWebServiceException;
059: import org.deegree.ogcwebservices.wfs.operation.AbstractWFSRequest;
060: import org.w3c.dom.Element;
061:
062: /**
063: * Represents a <code>Transaction</code> request to a web feature service.
064: * <p>
065: * A <code>Transaction</code> consists of a sequence of {@link Insert}, {@link Update},
066: * {@link Delete} and {@link Native} operations.
067: * <p>
068: * From the WFS Specification 1.1.0 OGC 04-094 (#12, Pg.63):
069: * <p>
070: * A <code>Transaction</code> request is used to describe data transformation operations that are
071: * to be applied to web accessible feature instances. When the transaction has been completed, a web
072: * feature service will generate an XML response document indicating the completion status of the
073: * transaction.
074: *
075: * @author <a href="mailto:schneider@lat-lon.de">Markus Schneider </a>
076: * @author last edited by: $Author: apoth $
077: *
078: * @version $Revision: 9348 $, $Date: 2007-12-27 08:59:14 -0800 (Thu, 27 Dec 2007) $
079: */
080: public class Transaction extends AbstractWFSRequest {
081:
082: private static final long serialVersionUID = 6904739857311368390L;
083:
084: private static final ILogger LOG = LoggerFactory
085: .getLogger(Transaction.class);
086:
087: private List<TransactionOperation> operations;
088:
089: // request version
090: private String version;
091:
092: // transaction ID
093: private String id;
094:
095: // LockID associated with the request
096: private String lockId;
097:
098: /**
099: * Specifies if ALL records should be released or if SOME records, indicating only those records
100: * which have been modified will be released. The default is ALL.
101: */
102: private RELEASE_ACTION releaseAction = RELEASE_ACTION.ALL;
103:
104: private TransactionDocument sourceDocument;
105:
106: /** Controls how locked features are treated when a transaction request is completed. */
107: public static enum RELEASE_ACTION {
108:
109: /**
110: * Indicates that the locks on all feature instances locked using the associated lockId
111: * should be released when the transaction completes, regardless of whether or not a
112: * particular feature instance in the locked set was actually operated upon.
113: */
114: ALL,
115:
116: /**
117: * Indicates that only the locks on feature instances modified by the transaction should be
118: * released. The other, unmodified, feature instances should remain locked using the same
119: * lockId so that subsequent transactions can operate on those feature instances. If an
120: * expiry period was specified, the expiry counter must be reset to zero after each
121: * transaction unless all feature instances in the locked set have been operated upon.
122: */
123: SOME
124: }
125:
126: /**
127: * Creates a new <code>Transaction</code> instance.
128: *
129: * @param version
130: * WFS version
131: * @param id
132: * Transaction id
133: * @param versionSpecificParameter
134: * @param lockID
135: * Lock Id
136: * @param operations
137: * List of operations to be carried out
138: * @param releaseAllFeatures
139: * @param sourceDocument
140: */
141: public Transaction(String id, String version,
142: Map<String, String> versionSpecificParameter,
143: String lockID, List<TransactionOperation> operations,
144: boolean releaseAllFeatures,
145: TransactionDocument sourceDocument) {
146: super (version, id, null, versionSpecificParameter);
147: this .id = id;
148: this .version = version;
149: this .lockId = lockID;
150: this .operations = operations;
151: if (!releaseAllFeatures) {
152: this .releaseAction = RELEASE_ACTION.SOME;
153: }
154: this .sourceDocument = sourceDocument;
155: }
156:
157: /**
158: * Returns the source document that was used to create this <code>Transaction</code> instance.
159: *
160: * @return the source document
161: */
162: public TransactionDocument getSourceDocument() {
163: return this .sourceDocument;
164: }
165:
166: /**
167: * Returns the {@link TransactionOperation}s that are contained in the transaction.
168: *
169: * @return the contained operations
170: */
171: public List<TransactionOperation> getOperations() {
172: return this .operations;
173: }
174:
175: /**
176: * Returns the lock identifier associated with this transaction.
177: *
178: * @return the lock identifier associated with this transaction if it exists, null otherwise
179: */
180: public String getLockId() {
181: return this .lockId;
182: }
183:
184: /**
185: * Returns the release action mode to be applied after the transaction finished successfully.
186: *
187: * @see RELEASE_ACTION
188: * @return the release action mode to be applied after the transaction finished successfully
189: */
190: public RELEASE_ACTION getReleaseAction() {
191: return this .releaseAction;
192: }
193:
194: /**
195: * Returns the names of the feature types that are affected by the transaction.
196: *
197: * @return the names of the affected feature types
198: */
199: public Set<QualifiedName> getAffectedFeatureTypes() {
200: Set<QualifiedName> featureTypeSet = new HashSet<QualifiedName>();
201:
202: Iterator<TransactionOperation> iter = this .operations
203: .iterator();
204: while (iter.hasNext()) {
205: TransactionOperation operation = iter.next();
206: featureTypeSet.addAll(operation.getAffectedFeatureTypes());
207: }
208: return featureTypeSet;
209: }
210:
211: /**
212: * Creates a <code>Transaction</code> request from a key-value-pair encoding of the parameters
213: * contained in the passed variable 'request'.
214: *
215: * @param id
216: * id of the request
217: * @param request
218: * key-value-pair encoded GetFeature request
219: * @return new created Transaction instance
220: * @throws InconsistentRequestException
221: * @throws InvalidParameterValueException
222: */
223: public static Transaction create(String id, String request)
224: throws InconsistentRequestException,
225: InvalidParameterValueException {
226:
227: Map<String, String> model = KVP2Map.toMap(request);
228: model.put("ID", id);
229:
230: return create(model);
231: }
232:
233: /**
234: * Creates a <code>Transaction</code> request from a key-value-pair encoding of the parameters
235: * contained in the given Map.
236: *
237: * @param model
238: * key-value-pair encoded Transaction request
239: * @return new Transaction instance
240: * @throws InconsistentRequestException
241: * @throws InvalidParameterValueException
242: */
243: public static Transaction create(Map<String, String> model)
244: throws InconsistentRequestException,
245: InvalidParameterValueException {
246:
247: Map<String, String> versionSpecificParameter = null;
248:
249: String id = model.get("ID");
250:
251: String version = checkVersionParameter(model);
252:
253: checkServiceParameter(model);
254:
255: String request = model.remove("REQUEST");
256: if (request == null) {
257: throw new InconsistentRequestException(
258: "Request parameter for a transaction request must be set.");
259: }
260:
261: String lockID = model.remove("LOCKID");
262:
263: String releaseAction = model.remove("RELEASEACTION");
264: boolean releaseAllFeatures = true;
265: if (releaseAction != null) {
266: if ("SOME".equals(releaseAction)) {
267: releaseAllFeatures = false;
268: } else if ("ALL".equals(releaseAction)) {
269: releaseAllFeatures = true;
270: } else {
271: throw new InvalidParameterValueException(
272: "releaseAction", releaseAction);
273: }
274: }
275:
276: QualifiedName[] typeNames = extractTypeNames(model);
277:
278: String featureIdParameter = model.remove("FEATUREID");
279: if (typeNames == null && featureIdParameter == null) {
280: throw new InconsistentRequestException(
281: "TypeName OR FeatureId parameter must be set.");
282: }
283:
284: // String[] featureIds = null;
285: // if ( featureIdParameter != null ) {
286: // // FEATUREID specified. Looking for featureId
287: // // declaration TYPENAME contained in featureId declaration (eg.
288: // // FEATUREID=InWaterA_1M.1013)
289: // featureIds = StringTools.toArray( featureIdParameter, ",", false );
290: // //typeNameSet = extractTypeNameFromFeatureId( featureIds, context, (HashSet) typeNameSet
291: // );
292: // }
293:
294: // Filters
295: // Map typeFilter = buildFilterMap( model, typeNames, featureIds, context );
296:
297: // // BBOX
298: // typeFilter = extractBBOXParameter( model, typeNames, typeFilter );
299: //
300: // if ( typeFilter == null || typeFilter.size() == 0 ) {
301: // for ( int i = 0; i < typeNames.length; i++ ) {
302: // typeFilter.put( typeNames[i], null );
303: // }
304: // }
305:
306: List<TransactionOperation> operations = extractOperations(
307: model, null);
308:
309: return new Transaction(id, version, versionSpecificParameter,
310: lockID, operations, releaseAllFeatures, null);
311: }
312:
313: /**
314: * Extracts the {@link TransactionOperation}s contained in the given kvp request.
315: *
316: * @param model
317: * @param typeFilter
318: * @param typeNames
319: * @return List
320: * @throws InconsistentRequestException
321: */
322: private static List<TransactionOperation> extractOperations(
323: Map model, Map typeFilter)
324: throws InconsistentRequestException {
325: List<TransactionOperation> operation = new ArrayList<TransactionOperation>();
326: String op = (String) model.remove("OPERATION");
327: if (op == null) {
328: throw new InconsistentRequestException(
329: "Operation parameter must be set");
330: }
331: if (op.equals("Delete")) {
332: List<Delete> deletes = Delete.create(typeFilter);
333: operation.addAll(deletes);
334: } else {
335: String msg = "Invalid OPERATION parameter '"
336: + op
337: + "'. KVP Transactions only support the 'Delete' operation.";
338: throw new InconsistentRequestException(msg);
339: }
340: return operation;
341: }
342:
343: /**
344: * Creates a <code>Transaction</code> instance from a document that contains the DOM
345: * representation of the request.
346: *
347: * @param id
348: * @param root
349: * element that contains the DOM representation of the request
350: * @return transaction instance
351: * @throws OGCWebServiceException
352: */
353: public static Transaction create(String id, Element root)
354: throws OGCWebServiceException {
355: TransactionDocument doc = new TransactionDocument();
356: doc.setRootElement(root);
357: Transaction request;
358: try {
359: request = doc.parse(id);
360: } catch (Exception e) {
361: LOG.logError(e.getMessage(), e);
362: throw new OGCWebServiceException("Transaction", e
363: .getMessage());
364: }
365: return request;
366: }
367:
368: @Override
369: public String toString() {
370: String ret = this .getClass().getName();
371: ret += "version: " + this .version + "\n";
372: ret += "id: " + this .id + "\n";
373: ret += "lockID: " + this .lockId + "\n";
374: ret += "operations: \n";
375: for (int i = 0; i < operations.size(); i++) {
376: ret += (i + ": " + operations.get(i) + "\n ");
377: }
378: ret += "releaseAllFeatures: " + this.releaseAction;
379: return ret;
380: }
381: }
|