001 //$Header: /deegreerepository/deegree/src/org/deegree/ogcwebservices/wfs/TransactionHandler.java,v 1.69 2007/03/14 14:41:43 mschneider Exp $
002 /*----------------------------------------------------------------------------
003 This file is part of deegree, http://deegree.org/
004 Copyright (C) 2001-2009 by:
005 Department of Geography, University of Bonn
006 and
007 lat/lon GmbH
008
009 This library is free software; you can redistribute it and/or modify it under
010 the terms of the GNU Lesser General Public License as published by the Free
011 Software Foundation; either version 2.1 of the License, or (at your option)
012 any later version.
013 This library is distributed in the hope that it will be useful, but WITHOUT
014 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
015 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
016 details.
017 You should have received a copy of the GNU Lesser General Public License
018 along with this library; if not, write to the Free Software Foundation, Inc.,
019 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
020
021 Contact information:
022
023 lat/lon GmbH
024 Aennchenstr. 19, 53177 Bonn
025 Germany
026 http://lat-lon.de/
027
028 Department of Geography, University of Bonn
029 Prof. Dr. Klaus Greve
030 Postfach 1147, 53001 Bonn
031 Germany
032 http://www.geographie.uni-bonn.de/deegree/
033
034 e-mail: info@deegree.org
035 ----------------------------------------------------------------------------*/
036
037 package org.deegree.ogcwebservices.wfs;
038
039 import static java.util.Collections.singletonList;
040 import static org.deegree.ogcwebservices.wfs.operation.transaction.Transaction.RELEASE_ACTION.ALL;
041 import static org.deegree.ogcwebservices.wfs.operation.transaction.Transaction.RELEASE_ACTION.SOME;
042
043 import java.util.ArrayList;
044 import java.util.HashMap;
045 import java.util.Iterator;
046 import java.util.List;
047 import java.util.Map;
048 import java.util.Set;
049 import java.util.TreeSet;
050
051 import org.deegree.datatypes.QualifiedName;
052 import org.deegree.framework.log.ILogger;
053 import org.deegree.framework.log.LoggerFactory;
054 import org.deegree.i18n.Messages;
055 import org.deegree.io.datastore.Datastore;
056 import org.deegree.io.datastore.DatastoreException;
057 import org.deegree.io.datastore.DatastoreTransaction;
058 import org.deegree.io.datastore.FeatureId;
059 import org.deegree.io.datastore.LockManager;
060 import org.deegree.io.datastore.MissingLockIdException;
061 import org.deegree.io.datastore.PropertyPathResolver;
062 import org.deegree.io.datastore.idgenerator.FeatureIdAssigner;
063 import org.deegree.io.datastore.schema.MappedFeaturePropertyType;
064 import org.deegree.io.datastore.schema.MappedFeatureType;
065 import org.deegree.io.datastore.schema.MappedGMLSchema;
066 import org.deegree.io.datastore.sql.transaction.SQLTransaction;
067 import org.deegree.model.feature.Feature;
068 import org.deegree.model.feature.FeatureCollection;
069 import org.deegree.model.feature.FeatureProperty;
070 import org.deegree.model.feature.GMLFeatureAdapter;
071 import org.deegree.model.feature.GMLFeatureCollectionDocument;
072 import org.deegree.model.feature.Validator;
073 import org.deegree.model.feature.schema.FeatureType;
074 import org.deegree.model.feature.schema.PropertyType;
075 import org.deegree.ogcbase.PropertyPath;
076 import org.deegree.ogcbase.PropertyPathStep;
077 import org.deegree.ogcwebservices.InvalidParameterValueException;
078 import org.deegree.ogcwebservices.MissingParameterValueException;
079 import org.deegree.ogcwebservices.OGCWebServiceException;
080 import org.deegree.ogcwebservices.wfs.operation.transaction.Delete;
081 import org.deegree.ogcwebservices.wfs.operation.transaction.Insert;
082 import org.deegree.ogcwebservices.wfs.operation.transaction.InsertResults;
083 import org.deegree.ogcwebservices.wfs.operation.transaction.Native;
084 import org.deegree.ogcwebservices.wfs.operation.transaction.Transaction;
085 import org.deegree.ogcwebservices.wfs.operation.transaction.TransactionOperation;
086 import org.deegree.ogcwebservices.wfs.operation.transaction.TransactionResponse;
087 import org.deegree.ogcwebservices.wfs.operation.transaction.Update;
088 import org.deegree.ogcwebservices.wfs.operation.transaction.Insert.ID_GEN;
089
090 /**
091 * Handler for transaction requests to the {@link WFService}.
092 * <p>
093 * If the used backend does not support atomic transactions, it is possible that one part fails while another works
094 * well. Depending on definitions made in the OGC WFS 1.1.0 specification in this case it is possible that even if a sub
095 * part of the request fails no exception will be thrown. In this case the result objects contains informations on the
096 * parts of the request that worked and that did not.
097 *
098 * @author <a href="mailto:schneider@lat-lon.de">Markus Schneider </a>
099 * @author <a href="mailto:deshmukh@lat-lon.de">Anup Deshmukh </a>
100 * @author last edited by: $Author: mschneider $
101 *
102 * @version $Revision: 18544 $, $Date: 2009-07-20 16:14:38 +0200 (Mo, 20. Jul 2009) $
103 */
104 class TransactionHandler {
105
106 private static final ILogger LOG = LoggerFactory.getLogger( TransactionHandler.class );
107
108 private WFService service;
109
110 private Transaction request;
111
112 private Map<QualifiedName, MappedFeatureType> ftMap;
113
114 // filled by #acquireDSTransactions()
115 private Map<QualifiedName, DatastoreTransaction> taMap = new HashMap<QualifiedName, DatastoreTransaction>();
116
117 // filled by #acquireDSTransactions()
118 private Map<Datastore, DatastoreTransaction> dsToTaMap = new HashMap<Datastore, DatastoreTransaction>();
119
120 private Set<FeatureId> changedFIDs = new TreeSet<FeatureId>();
121
122 /**
123 * Creates a new <code>TransactionHandler</code> instance.
124 *
125 * @param service
126 * @param request
127 */
128 TransactionHandler( WFService service, Transaction request ) {
129 this.service = service;
130 this.request = request;
131 this.ftMap = service.getMappedFeatureTypes();
132 }
133
134 /**
135 * Performs the associated transaction.
136 *
137 * @return transaction response
138 * @throws OGCWebServiceException
139 * if an error occurred
140 */
141 synchronized TransactionResponse handleRequest()
142 throws OGCWebServiceException {
143
144 changedFIDs.clear();
145
146 validate( this.request );
147
148 TransactionResponse response = null;
149
150 acquireDSTransactions();
151
152 try {
153 try {
154 response = performOperations();
155 } catch ( OGCWebServiceException e ) {
156 abortDSTransactions();
157 throw e;
158 }
159 commitDSTransactions();
160 if ( request.getLockId() != null && request.getReleaseAction() == ALL ) {
161 try {
162 LockManager.getInstance().releaseLock( request.getLockId() );
163 } catch ( DatastoreException e ) {
164 throw new InvalidParameterValueException( e.getMessage() );
165 }
166 }
167 if ( request.getLockId() != null && request.getReleaseAction() == SOME ) {
168 try {
169 LockManager.getInstance().releaseLockPartly( request.getLockId(), changedFIDs );
170 } catch ( DatastoreException e ) {
171 throw new InvalidParameterValueException( e.getMessage() );
172 }
173 }
174 } finally {
175 releaseDSTransactions();
176 }
177
178 return response;
179 }
180
181 /**
182 * Validates the feature instances in the given transaction against the WFS' application schemas.
183 * <p>
184 * The feature instances are assigned the corresponding <code>MappedFeatureType</code> in the process.
185 *
186 * @param request
187 * @throws OGCWebServiceException
188 */
189 private void validate( Transaction request )
190 throws OGCWebServiceException {
191
192 List<TransactionOperation> operations = request.getOperations();
193
194 Iterator<TransactionOperation> iter = operations.iterator();
195 while ( iter.hasNext() ) {
196 TransactionOperation operation = iter.next();
197 if ( operation instanceof Insert ) {
198 try {
199 validateInsert( (Insert) operation );
200 } catch ( DatastoreException e ) {
201 throw new OGCWebServiceException( this.getClass().getName(), e.getMessage() );
202 }
203 } else if ( operation instanceof Delete ) {
204 validateDelete( (Delete) operation );
205 } else if ( operation instanceof Update ) {
206 validateUpdate( (Update) operation );
207 } else if ( operation instanceof Native ) {
208 // nothing to do
209 } else {
210 String msg = "Internal error. Unhandled transaction operation type '" + operation.getClass().getName()
211 + "'.";
212 throw new OGCWebServiceException( this.getClass().getName(), msg );
213 }
214 }
215 }
216
217 /**
218 * Validates all feature instances in the given insert operation against the WFS' application schemas.
219 * <p>
220 * The feature instances are assigned the corresponding <code>MappedFeatureType</code> in the process and are
221 * disambiguated, so every feature has a unique feature id afterwards.
222 *
223 * @param operation
224 * @throws OGCWebServiceException
225 * @throws DatastoreException
226 */
227 @SuppressWarnings("unchecked")
228 private void validateInsert( Insert operation )
229 throws OGCWebServiceException, DatastoreException {
230 FeatureCollection fc = operation.getFeatures();
231 if ( LOG.getLevel() == ILogger.LOG_DEBUG ) {
232 try {
233 GMLFeatureAdapter ada = new GMLFeatureAdapter( false );
234 GMLFeatureCollectionDocument doc = ada.export( fc );
235 LOG.logDebugXMLFile( "TransactionHandler_insert_incoming", doc );
236 } catch ( Exception e ) {
237 LOG.logError( e.getMessage(), e );
238 }
239 }
240 Validator validator = new Validator( (Map) this.service.getMappedFeatureTypes() );
241 for ( int i = 0; i < fc.size(); i++ ) {
242 validator.validate( fc.getFeature( i ) );
243 }
244
245 // merge all equal and anonymous features (without fid)
246 FeatureDisambiguator merger = new FeatureDisambiguator( fc );
247 if ( operation.getIdGen() == ID_GEN.USE_EXISTING ) {
248 if ( merger.checkForAnonymousFeatures() ) {
249 String msg = Messages.getMessage( "WFS_INSERT_USE_EXISTING_AND_NO_FID" );
250 throw new DatastoreException( msg );
251 }
252 }
253 fc = merger.mergeFeatures();
254 }
255
256 /**
257 * Validates all feature instances in the given insert operation against the WFS' application schemas.
258 * <p>
259 * The feature instances are assigned the corresponding <code>MappedFeatureType</code> in the process.
260 *
261 * @param operation
262 * @throws OGCWebServiceException
263 */
264 private void validateDelete( Delete operation )
265 throws OGCWebServiceException {
266 QualifiedName ftName = operation.getTypeName();
267 MappedFeatureType ft = this.ftMap.get( ftName );
268 if ( ft == null ) {
269 String msg = Messages.getMessage( "WFS_DELETE_FEATURE_TYPE_UNKNOWN", ftName );
270 throw new OGCWebServiceException( this.getClass().getName(), msg );
271 }
272 if ( ft.isAbstract() ) {
273 String msg = Messages.getMessage( "WFS_DELETE_FEATURE_TYPE_ABSTRACT", ftName );
274 throw new OGCWebServiceException( this.getClass().getName(), msg );
275 }
276 }
277
278 /**
279 * Validates any feature instance in the given update operation against the WFS' application schemas.
280 * <p>
281 * Feature instances are assigned the corresponding <code>MappedFeatureType</code> in the process, property names
282 * are normalized and their values are parsed into the respective objects.
283 *
284 * @param operation
285 * update operation
286 * @throws OGCWebServiceException
287 */
288 @SuppressWarnings("unchecked")
289 private void validateUpdate( Update operation )
290 throws OGCWebServiceException {
291
292 QualifiedName ftName = operation.getTypeName();
293 MappedFeatureType ft = this.ftMap.get( ftName );
294 if ( ft == null ) {
295 String msg = Messages.getMessage( "WFS_UPDATE_FEATURE_TYPE_UNKNOWN", ftName );
296 throw new OGCWebServiceException( this.getClass().getName(), msg );
297 }
298
299 Feature feature = operation.getFeature();
300 if ( feature != null ) {
301 Validator validator = new Validator( (Map) this.service.getMappedFeatureTypes() );
302 validator.validate( feature );
303 } else {
304 validateProperties( ft, operation );
305 }
306 }
307
308 /**
309 * Validates the properties and their replacement values that are specified in the given <code>Update</code>
310 * operation.
311 * <p>
312 * Property names are normalized and their values are parsed into the respective objects.
313 *
314 * @param ft
315 * feature type
316 * @param operation
317 * update operation
318 * @throws OGCWebServiceException
319 */
320 private void validateProperties( MappedFeatureType ft, Update operation )
321 throws OGCWebServiceException {
322
323 Map<PropertyPath, FeatureProperty> replacementProps = operation.getReplacementProperties();
324 Map<PropertyPath, FeatureProperty> normalizedProps = new HashMap<PropertyPath, FeatureProperty>();
325
326 for ( PropertyPath path : replacementProps.keySet() ) {
327 FeatureProperty property = replacementProps.get( path );
328 path = PropertyPathResolver.normalizePropertyPath( ft, null, path );
329 validateProperty( ft, path, property );
330 normalizedProps.put( path, property );
331 }
332
333 // remove all mappings and add normalized ones
334 replacementProps.clear();
335 for ( PropertyPath path : normalizedProps.keySet() ) {
336 replacementProps.put( path, normalizedProps.get( path ) );
337 }
338 }
339
340 /**
341 * Validates the property name and it's replacement value.
342 * <p>
343 * Values are parsed into the respective objects.
344 *
345 * @param ft
346 * feature type
347 * @param path
348 * property name
349 * @param replacementProperty
350 * replacement property value (as XML node)
351 * @throws OGCWebServiceException
352 */
353 private void validateProperty( MappedFeatureType ft, PropertyPath path, FeatureProperty replacementProperty )
354 throws OGCWebServiceException {
355
356 for ( int i = 0; i < path.getSteps(); i += 2 ) {
357 // check if feature step is valid
358 PropertyPathStep ftStep = path.getStep( i );
359 FeatureType stepFt = this.ftMap.get( ftStep.getPropertyName() );
360 if ( stepFt == null ) {
361 String msg = Messages.getMessage( "WFS_UPDATE_FEATURE_STEP_UNKNOWN", path, "unknown" );
362 throw new OGCWebServiceException( this.getClass().getName(), msg );
363 }
364 MappedGMLSchema schema = ft.getGMLSchema();
365 if ( !schema.isValidSubstitution( ft, stepFt ) ) {
366 String msg = Messages.getMessage( "WFS_UPDATE_FEATURE_STEP_INVALID", path, stepFt.getName(),
367 ft.getName() );
368 throw new OGCWebServiceException( this.getClass().getName(), msg );
369 }
370
371 // check if property step is valid
372 PropertyPathStep propertyStep = path.getStep( i + 1 );
373 QualifiedName propertyName = propertyStep.getPropertyName();
374 PropertyType pt = ft.getProperty( propertyName );
375 if ( pt == null ) {
376 String msg = Messages.getMessage( "WFS_UPDATE_PROPERTY_STEP_UNKNOWN", path, propertyName, ft.getName() );
377 throw new OGCWebServiceException( this.getClass().getName(), msg );
378 }
379 if ( i + 2 == path.getSteps() ) {
380 if ( replacementProperty.getValue() == null && pt.getMinOccurs() > 0 ) {
381 String msg = Messages.getMessage( "WFS_UPDATE_PROPERTY_NULL_INVALID", path, pt.getMinOccurs() );
382 throw new InvalidParameterValueException( this.getClass().getName(), msg );
383 }
384 if ( replacementProperty.getValue() instanceof Feature ) {
385 Validator validator = new Validator( (Map) this.service.getMappedFeatureTypes() );
386 validator.validate( (Feature) replacementProperty.getValue() );
387 }
388 } else {
389 if ( !( pt instanceof MappedFeaturePropertyType ) ) {
390 String msg = Messages.getMessage( "WFS_UPDATE_NOT_FEATURE_PROPERTY", path, propertyName );
391 throw new OGCWebServiceException( this.getClass().getName(), msg );
392 }
393 MappedFeaturePropertyType fpt = (MappedFeaturePropertyType) pt;
394 ft = fpt.getFeatureTypeReference().getFeatureType();
395 }
396 }
397 }
398
399 /**
400 * Performs the operations contained in the transaction.
401 *
402 * @throws OGCWebServiceException
403 */
404 private TransactionResponse performOperations()
405 throws OGCWebServiceException {
406
407 int inserts = 0;
408 int deletes = 0;
409 int updates = 0;
410
411 List<InsertResults> insertResults = new ArrayList<InsertResults>();
412 List<TransactionOperation> operations = request.getOperations();
413
414 Iterator<TransactionOperation> iter = operations.iterator();
415 while ( iter.hasNext() ) {
416 TransactionOperation operation = iter.next();
417 String handle = operation.getHandle();
418 try {
419 if ( operation instanceof Insert ) {
420 List<FeatureId> insertedFIDs = performInsert( (Insert) operation );
421 inserts += insertedFIDs.size();
422
423 for ( FeatureId id : insertedFIDs ) {
424 InsertResults results = new InsertResults( handle, singletonList( id ) );
425 insertResults.add( results );
426 }
427 } else if ( operation instanceof Delete ) {
428 // the intended behavior is different between versions here, so in #performDelete the exception
429 // will be thrown now, and caught here if 1.1.0
430 if ( request.getVersion().equals( "1.0.0" ) ) {
431 deletes += performDelete( (Delete) operation );
432 } else {
433 try {
434 deletes += performDelete( (Delete) operation );
435 } catch ( MissingLockIdException e ) {
436 throw new MissingParameterValueException( "LockId", e.getMessage() );
437 }
438 }
439 } else if ( operation instanceof Update ) {
440 updates += performUpdate( (Update) operation );
441 } else if ( operation instanceof Native ) {
442 String msg = Messages.getMessage( "WFS_NATIVE_OPERATIONS_UNSUPPORTED" );
443 throw new OGCWebServiceException( this.getClass().getName(), msg );
444 } else {
445 String opType = operation.getClass().getName();
446 String msg = Messages.getMessage( "WFS_UNHANDLED_OPERATION_TYPE", opType );
447 throw new OGCWebServiceException( this.getClass().getName(), msg );
448 }
449 } catch ( DatastoreException e ) {
450 LOG.logError( e.getMessage(), e );
451 String msg = "A datastore exception occured during the processing of operation with handle '" + handle
452 + "': " + e.getMessage();
453 throw new InvalidParameterValueException( this.getClass().getName(), msg );
454 }
455 }
456 TransactionResponse response = new TransactionResponse( request, inserts, updates, deletes, insertResults );
457 return response;
458 }
459
460 /**
461 * Performs the given insert operation.
462 *
463 * @param insert
464 * insert operation to be performed
465 * @throws DatastoreException
466 */
467 private List<FeatureId> performInsert( Insert insert )
468 throws DatastoreException {
469
470 List<FeatureId> fids = new ArrayList<FeatureId>();
471 FeatureCollection fc = insert.getFeatures();
472
473 // clear reference to feature collection
474 // insert.setFeatureCollection( null );
475
476 if ( LOG.getLevel() == ILogger.LOG_DEBUG ) {
477 try {
478 GMLFeatureAdapter ada = new GMLFeatureAdapter( false );
479 GMLFeatureCollectionDocument doc = ada.export( fc );
480 LOG.logDebugXMLFile( "TransactionHandler_insert_merged", doc );
481 } catch ( Exception e ) {
482 LOG.logError( e.getMessage(), e );
483 }
484 }
485
486 Map<DatastoreTransaction, List<Feature>> taFeaturesMap = new HashMap<DatastoreTransaction, List<Feature>>();
487 FeatureIdAssigner fidAssigner = new FeatureIdAssigner( insert.getIdGen() );
488
489 // assign features to corresponding datastore transactions
490 for ( int i = 0; i < fc.size(); i++ ) {
491 Feature feature = fc.getFeature( i );
492 QualifiedName ftName = feature.getName();
493 DatastoreTransaction dsTa = this.taMap.get( ftName );
494 // reassign feature ids (if necessary)
495 fidAssigner.assignFID( feature, dsTa );
496 List<Feature> features = taFeaturesMap.get( dsTa );
497 if ( features == null ) {
498 features = new ArrayList<Feature>();
499 taFeaturesMap.put( dsTa, features );
500 }
501 features.add( feature );
502 }
503
504 // TODO remove this hack
505 fidAssigner.markStoredFeatures();
506
507 // clear reference to fidAssigner (implicitly to feature collection)
508 fidAssigner = null;
509
510 if ( LOG.getLevel() == ILogger.LOG_DEBUG ) {
511 try {
512 GMLFeatureAdapter ada = new GMLFeatureAdapter( false );
513 GMLFeatureCollectionDocument doc = ada.export( fc );
514 LOG.logDebugXMLFile( "TransactionHandler_insert_marked", doc );
515 } catch ( Exception e ) {
516 LOG.logError( e.getMessage(), e );
517 }
518 }
519
520 // clear reference to feature collection
521 fc = null;
522
523 for ( DatastoreTransaction ta : taFeaturesMap.keySet() ) {
524 List<Feature> features = taFeaturesMap.get( ta );
525 fids.addAll( ta.performInsert( features ) );
526 }
527 return fids;
528 }
529
530 /**
531 * Performs the given delete operation.
532 *
533 * @param delete
534 * delete operation to be performed
535 * @throws DatastoreException
536 */
537 private int performDelete( Delete delete )
538 throws DatastoreException {
539 QualifiedName ftName = delete.getTypeName();
540 MappedFeatureType ft = this.ftMap.get( ftName );
541 DatastoreTransaction dsTa = this.taMap.get( ftName );
542 int deleted = dsTa.performDelete( ft, delete.getFilter(), this.request.getLockId() );
543 return deleted;
544 }
545
546 /**
547 * Performs the given update operation.
548 * <p>
549 * Assigning of FIDs to replacement features is performed in the {@link DatastoreTransaction}.
550 *
551 * @param update
552 * update operation to be perform
553 * @throws DatastoreException
554 */
555 private int performUpdate( Update update )
556 throws DatastoreException {
557
558 QualifiedName ftName = update.getTypeName();
559 MappedFeatureType ft = this.ftMap.get( ftName );
560 DatastoreTransaction dsTa = this.taMap.get( ftName );
561 int updated = 0;
562 if ( update.getFeature() == null ) {
563 updated = dsTa.performUpdate( ft, update.getReplacementProperties(), update.getFilter(),
564 this.request.getLockId() );
565 } else {
566 updated = dsTa.performUpdate( ft, update.getFeature(), update.getFilter(), this.request.getLockId() );
567 }
568
569 // to work around API changes...
570 if ( dsTa instanceof SQLTransaction ) {
571 changedFIDs.addAll( ( (SQLTransaction) dsTa ).determineAffectedFIDs( ft, update.getFilter() ) );
572 }
573
574 return updated;
575 }
576
577 /**
578 * Acquires the necessary <code>DatastoreTransaction</code>s. For each participating <code>Datastore</code>, one
579 * transaction is needed.
580 * <p>
581 * Fills the <code>taMap</code> and <code>dsToTaMap</code> members of this class.
582 *
583 * @throws OGCWebServiceException
584 * if a feature type is unknown or a DatastoreTransaction could not be acquired
585 */
586 private void acquireDSTransactions()
587 throws OGCWebServiceException {
588 Set<QualifiedName> ftNames = this.request.getAffectedFeatureTypes();
589 for ( QualifiedName ftName : ftNames ) {
590 MappedFeatureType ft = this.ftMap.get( ftName );
591 if ( ft == null ) {
592 String msg = "FeatureType '" + ftName + "' is not known to the WFS.";
593 throw new OGCWebServiceException( this.getClass().getName(), msg );
594 }
595 Datastore ds = ft.getGMLSchema().getDatastore();
596 DatastoreTransaction dsTa = this.dsToTaMap.get( ds );
597 if ( dsTa == null ) {
598 try {
599 dsTa = ds.acquireTransaction();
600 } catch ( DatastoreException e ) {
601 LOG.logError( e.getMessage(), e );
602 String msg = "Could not acquire transaction for FeatureType '" + ftName + "'.";
603 throw new OGCWebServiceException( this.getClass().getName(), msg );
604 }
605 this.dsToTaMap.put( ds, dsTa );
606 }
607 this.taMap.put( ftName, dsTa );
608 }
609 }
610
611 /**
612 * Releases all acquired <code>DatastoreTransaction</code>s.
613 *
614 * @throws OGCWebServiceException
615 * if a DatastoreTransaction could not be released
616 */
617 private void releaseDSTransactions()
618 throws OGCWebServiceException {
619 String msg = "";
620 for ( DatastoreTransaction dsTa : this.dsToTaMap.values() ) {
621 LOG.logDebug( "Releasing DatastoreTransaction " + dsTa );
622 try {
623 dsTa.release();
624 } catch ( DatastoreException e ) {
625 LOG.logError( "Error releasing DatastoreTransaction: " + e.getMessage(), e );
626 msg += e.getMessage() + "\n";
627 }
628 }
629 if ( msg.length() != 0 ) {
630 msg = "Could not release one or more DatastoreTransactions: " + msg;
631 throw new OGCWebServiceException( this.getClass().getName(), msg );
632 }
633 }
634
635 /**
636 * Commits all pending <code>DatastoreTransaction</code>s.
637 *
638 * @throws OGCWebServiceException
639 * if a DatastoreException could not be committed
640 */
641 private void commitDSTransactions()
642 throws OGCWebServiceException {
643 String msg = "";
644 for ( DatastoreTransaction dsTa : this.dsToTaMap.values() ) {
645 LOG.logDebug( "Committing DatastoreTransaction " + dsTa );
646 try {
647 dsTa.commit();
648 } catch ( DatastoreException e ) {
649 LOG.logError( "Error committing DatastoreTransaction: " + e.getMessage(), e );
650 msg += e.getMessage() + "\n";
651 }
652 }
653 if ( msg.length() != 0 ) {
654 msg = "Could not commit one or more DatastoreTransactions: " + msg;
655 throw new OGCWebServiceException( this.getClass().getName(), msg );
656 }
657 }
658
659 /**
660 * Aborts all pending <code>DatastoreTransaction</code>s.
661 *
662 * @throws OGCWebServiceException
663 * if a DatastoreException could not be aborted
664 */
665 private void abortDSTransactions()
666 throws OGCWebServiceException {
667 String msg = "";
668 for ( DatastoreTransaction dsTa : this.dsToTaMap.values() ) {
669 LOG.logDebug( "Aborting DatastoreTransaction " + dsTa );
670 try {
671 dsTa.rollback();
672 } catch ( DatastoreException e ) {
673 LOG.logError( "Error aborting DatastoreTransaction: " + e.getMessage(), e );
674 msg += e.getMessage() + "\n";
675 }
676 }
677 if ( msg.length() != 0 ) {
678 msg = "Could not abort one or more DatastoreTransactions: " + msg;
679 throw new OGCWebServiceException( this.getClass().getName(), msg );
680 }
681 }
682 }