001 //$Header: /deegreerepository/deegree/src/org/deegree/ogcwebservices/wfs/TransactionHandler.java,v 1.69 2007/03/14 14:41:43 mschneider 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
044 package org.deegree.ogcwebservices.wfs;
045
046 import java.util.ArrayList;
047 import java.util.HashMap;
048 import java.util.Iterator;
049 import java.util.List;
050 import java.util.Map;
051 import java.util.Set;
052
053 import org.deegree.datatypes.QualifiedName;
054 import org.deegree.framework.log.ILogger;
055 import org.deegree.framework.log.LoggerFactory;
056 import org.deegree.i18n.Messages;
057 import org.deegree.io.datastore.Datastore;
058 import org.deegree.io.datastore.DatastoreException;
059 import org.deegree.io.datastore.DatastoreTransaction;
060 import org.deegree.io.datastore.FeatureId;
061 import org.deegree.io.datastore.LockManager;
062 import org.deegree.io.datastore.PropertyPathResolver;
063 import org.deegree.io.datastore.idgenerator.FeatureIdAssigner;
064 import org.deegree.io.datastore.schema.MappedFeaturePropertyType;
065 import org.deegree.io.datastore.schema.MappedFeatureType;
066 import org.deegree.io.datastore.schema.MappedGMLSchema;
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.OGCWebServiceException;
078 import org.deegree.ogcwebservices.wfs.operation.transaction.Delete;
079 import org.deegree.ogcwebservices.wfs.operation.transaction.Insert;
080 import org.deegree.ogcwebservices.wfs.operation.transaction.InsertResults;
081 import org.deegree.ogcwebservices.wfs.operation.transaction.Native;
082 import org.deegree.ogcwebservices.wfs.operation.transaction.Transaction;
083 import org.deegree.ogcwebservices.wfs.operation.transaction.TransactionOperation;
084 import org.deegree.ogcwebservices.wfs.operation.transaction.TransactionResponse;
085 import org.deegree.ogcwebservices.wfs.operation.transaction.Update;
086 import org.deegree.ogcwebservices.wfs.operation.transaction.Insert.ID_GEN;
087 import org.deegree.ogcwebservices.wfs.operation.transaction.Transaction.RELEASE_ACTION;
088
089 /**
090 * Handler for transaction requests to the {@link WFService}.
091 * <p>
092 * If the used backend does not support atomic transactions, it is possible that one part fails
093 * while another works well. Depending on definitions made in the OGC WFS 1.1.0 specification in
094 * this case it is possible that even if a sub part of the request fails no exception will be
095 * thrown. In this case the result objects contains informations on the parts of the request that
096 * 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: apoth $
101 *
102 * @version $Revision: 9345 $, $Date: 2007-12-27 17:22:25 +0100 (Do, 27 Dez 2007) $
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 /**
121 * Creates a new <code>TransactionHandler</code> instance.
122 *
123 * @param service
124 * @param request
125 */
126 TransactionHandler( WFService service, Transaction request ) {
127 this.service = service;
128 this.request = request;
129 this.ftMap = service.getMappedFeatureTypes();
130 }
131
132 /**
133 * Performs the associated transaction.
134 *
135 * @return transaction response
136 * @throws OGCWebServiceException
137 * if an error occured
138 */
139 TransactionResponse handleRequest()
140 throws OGCWebServiceException {
141
142 validate( this.request );
143
144 TransactionResponse response = null;
145
146 acquireDSTransactions();
147
148 try {
149 try {
150 response = performOperations();
151 } catch ( OGCWebServiceException e ) {
152 abortDSTransactions();
153 throw e;
154 }
155 commitDSTransactions();
156 if ( request.getLockId() != null && request.getReleaseAction() == RELEASE_ACTION.ALL ) {
157 try {
158 LockManager.getInstance().releaseLock( request.getLockId() );
159 } catch ( DatastoreException e ) {
160 LOG.logInfo( e.getMessage() );
161 }
162 }
163 } finally {
164 releaseDSTransactions();
165 }
166
167 return response;
168 }
169
170 /**
171 * Validates the feature instances in the given transaction against the WFS' application
172 * schemas.
173 * <p>
174 * The feature instances are assigned the corresponding <code>MappedFeatureType</code> in the
175 * process.
176 *
177 * @param request
178 * @throws OGCWebServiceException
179 */
180 private void validate( Transaction request )
181 throws OGCWebServiceException {
182
183 List<TransactionOperation> operations = request.getOperations();
184
185 Iterator<TransactionOperation> iter = operations.iterator();
186 while ( iter.hasNext() ) {
187 TransactionOperation operation = iter.next();
188 if ( operation instanceof Insert ) {
189 validateInsert( (Insert) operation );
190 } else if ( operation instanceof Delete ) {
191 validateDelete( (Delete) operation );
192 } else if ( operation instanceof Update ) {
193 validateUpdate( (Update) operation );
194 } else if ( operation instanceof Native ) {
195 // nothing to do
196 } else {
197 String msg = "Internal error. Unhandled transaction operation type '" + operation.getClass().getName()
198 + "'.";
199 throw new OGCWebServiceException( this.getClass().getName(), msg );
200 }
201 }
202 }
203
204 /**
205 * Validates all feature instances in the given insert operation against the WFS' application
206 * schemas.
207 * <p>
208 * The feature instances are assigned the corresponding <code>MappedFeatureType</code> in the
209 * process.
210 *
211 * @param operation
212 * @throws OGCWebServiceException
213 */
214 @SuppressWarnings("unchecked")
215 private void validateInsert( Insert operation )
216 throws OGCWebServiceException {
217 FeatureCollection fc = operation.getFeatures();
218 if ( LOG.getLevel() == ILogger.LOG_DEBUG ) {
219 try {
220 GMLFeatureAdapter ada = new GMLFeatureAdapter( false );
221 GMLFeatureCollectionDocument doc = ada.export( fc );
222 LOG.logDebugXMLFile( "TransactionHandler_insert_incoming", doc );
223 } catch ( Exception e ) {
224 LOG.logError( e.getMessage(), e );
225 }
226 }
227 Validator validator = new Validator( (Map) this.service.getMappedFeatureTypes() );
228 for ( int i = 0; i < fc.size(); i++ ) {
229 validator.validate( fc.getFeature( i ) );
230 }
231 }
232
233 /**
234 * Validates all feature instances in the given insert operation against the WFS' application
235 * schemas.
236 * <p>
237 * The feature instances are assigned the corresponding <code>MappedFeatureType</code> in the
238 * process.
239 *
240 * @param operation
241 * @throws OGCWebServiceException
242 */
243 private void validateDelete( Delete operation )
244 throws OGCWebServiceException {
245 QualifiedName ftName = operation.getTypeName();
246 MappedFeatureType ft = this.ftMap.get( ftName );
247 if ( ft == null ) {
248 String msg = Messages.getMessage( "WFS_DELETE_FEATURE_TYPE_UNKNOWN", ftName );
249 throw new OGCWebServiceException( this.getClass().getName(), msg );
250 }
251 if ( ft.isAbstract() ) {
252 String msg = Messages.getMessage( "WFS_DELETE_FEATURE_TYPE_ABSTRACT", ftName );
253 throw new OGCWebServiceException( this.getClass().getName(), msg );
254 }
255 }
256
257 /**
258 * Validates any feature instance in the given update operation against the WFS' application
259 * schemas.
260 * <p>
261 * Feature instances are assigned the corresponding <code>MappedFeatureType</code> in the
262 * process, property names are normalized and their values are parsed into the respective
263 * objects.
264 *
265 * @param operation
266 * update operation
267 * @throws OGCWebServiceException
268 */
269 @SuppressWarnings("unchecked")
270 private void validateUpdate( Update operation )
271 throws OGCWebServiceException {
272
273 QualifiedName ftName = operation.getTypeName();
274 MappedFeatureType ft = this.ftMap.get( ftName );
275 if ( ft == null ) {
276 String msg = Messages.getMessage( "WFS_UPDATE_FEATURE_TYPE_UNKNOWN", ftName );
277 throw new OGCWebServiceException( this.getClass().getName(), msg );
278 }
279
280 Feature feature = operation.getFeature();
281 if ( feature != null ) {
282 Validator validator = new Validator( (Map) this.service.getMappedFeatureTypes() );
283 validator.validate( feature );
284 } else {
285 validateProperties( ft, operation );
286 }
287 }
288
289 /**
290 * Validates the properties and their replacement values that are specified in the given
291 * <code>Update</code> operation.
292 * <p>
293 * Property names are normalized and their values are parsed into the respective objects.
294 *
295 * @param ft
296 * feature type
297 * @param operation
298 * update operation
299 * @throws OGCWebServiceException
300 */
301 private void validateProperties( MappedFeatureType ft, Update operation )
302 throws OGCWebServiceException {
303
304 Map<PropertyPath, FeatureProperty> replacementProps = operation.getReplacementProperties();
305 Map<PropertyPath, FeatureProperty> normalizedProps = new HashMap<PropertyPath, FeatureProperty>();
306
307 for ( PropertyPath path : replacementProps.keySet() ) {
308 FeatureProperty property = replacementProps.get( path );
309 path = PropertyPathResolver.normalizePropertyPath( ft, null, path );
310 validateProperty( ft, path, property );
311 normalizedProps.put( path, property );
312 }
313
314 // remove all mappings and add normalized ones
315 replacementProps.clear();
316 for ( PropertyPath path : normalizedProps.keySet() ) {
317 replacementProps.put( path, normalizedProps.get( path ) );
318 }
319 }
320
321 /**
322 * Validates the property name and it's replacement value.
323 * <p>
324 * Values are parsed into the respective objects.
325 *
326 * @param ft
327 * feature type
328 * @param path
329 * property name
330 * @param replacementProperty
331 * replacement property value (as XML node)
332 * @throws OGCWebServiceException
333 */
334 private void validateProperty( MappedFeatureType ft, PropertyPath path, FeatureProperty replacementProperty )
335 throws OGCWebServiceException {
336
337 for ( int i = 0; i < path.getSteps(); i += 2 ) {
338 // check if feature step is valid
339 PropertyPathStep ftStep = path.getStep( i );
340 FeatureType stepFt = this.ftMap.get( ftStep.getPropertyName() );
341 if ( stepFt == null ) {
342 String msg = Messages.getMessage( "WFS_UPDATE_FEATURE_STEP_UNKNOWN", path, stepFt.getName() );
343 throw new OGCWebServiceException( this.getClass().getName(), msg );
344 }
345 MappedGMLSchema schema = ft.getGMLSchema();
346 if ( !schema.isValidSubstitution( ft, stepFt ) ) {
347 String msg = Messages.getMessage( "WFS_UPDATE_FEATURE_STEP_INVALID", path, stepFt.getName(),
348 ft.getName() );
349 throw new OGCWebServiceException( this.getClass().getName(), msg );
350 }
351
352 // check if property step is valid
353 PropertyPathStep propertyStep = path.getStep( i + 1 );
354 QualifiedName propertyName = propertyStep.getPropertyName();
355 PropertyType pt = ft.getProperty( propertyName );
356 if ( pt == null ) {
357 String msg = Messages.getMessage( "WFS_UPDATE_PROPERTY_STEP_UNKNOWN", path, propertyName, ft.getName() );
358 throw new OGCWebServiceException( this.getClass().getName(), msg );
359 }
360 if ( i + 2 == path.getSteps() ) {
361 if ( replacementProperty.getValue() == null && pt.getMinOccurs() > 0 ) {
362 String msg = Messages.getMessage( "WFS_UPDATE_PROPERTY_NULL_INVALID", path, pt.getMinOccurs() );
363 throw new OGCWebServiceException( this.getClass().getName(), msg );
364 }
365 if ( replacementProperty.getValue() instanceof Feature ) {
366 Validator validator = new Validator( (Map) this.service.getMappedFeatureTypes() );
367 validator.validate( (Feature) replacementProperty.getValue() );
368 }
369 } else {
370 if ( !( pt instanceof MappedFeaturePropertyType ) ) {
371 String msg = Messages.getMessage( "WFS_UPDATE_NOT_FEATURE_PROPERTY", path, propertyName );
372 throw new OGCWebServiceException( this.getClass().getName(), msg );
373 }
374 MappedFeaturePropertyType fpt = (MappedFeaturePropertyType) pt;
375 ft = fpt.getFeatureTypeReference().getFeatureType();
376 }
377 }
378 }
379
380 /**
381 * Performs the operations contained in the transaction.
382 *
383 * @throws OGCWebServiceException
384 */
385 private TransactionResponse performOperations()
386 throws OGCWebServiceException {
387
388 int inserts = 0;
389 int deletes = 0;
390 int updates = 0;
391
392 List<InsertResults> insertResults = new ArrayList<InsertResults>();
393 List<TransactionOperation> operations = request.getOperations();
394
395 Iterator<TransactionOperation> iter = operations.iterator();
396 while ( iter.hasNext() ) {
397 TransactionOperation operation = iter.next();
398 String handle = operation.getHandle();
399 try {
400 if ( operation instanceof Insert ) {
401 List<FeatureId> insertedFIDs = performInsert( (Insert) operation );
402 InsertResults results = new InsertResults( handle, insertedFIDs );
403 insertResults.add( results );
404 inserts += insertedFIDs.size();
405 } else if ( operation instanceof Delete ) {
406 deletes += performDelete( (Delete) operation );
407 } else if ( operation instanceof Update ) {
408 updates += performUpdate( (Update) operation );
409 } else if ( operation instanceof Native ) {
410 String msg = Messages.getMessage( "WFS_NATIVE_OPERATIONS_UNSUPPORTED" );
411 throw new OGCWebServiceException( this.getClass().getName(), msg );
412 } else {
413 String opType = operation.getClass().getName();
414 String msg = Messages.getMessage( "WFS_UNHANDLED_OPERATION_TYPE", opType );
415 throw new OGCWebServiceException( this.getClass().getName(), msg );
416 }
417 } catch ( DatastoreException e ) {
418 LOG.logError( e.getMessage(), e );
419 String msg = "A datastore exception occured during the processing of operation with handle '" + handle
420 + "': " + e.getMessage();
421 throw new OGCWebServiceException( this.getClass().getName(), msg );
422 }
423 }
424 TransactionResponse response = new TransactionResponse( request, inserts, updates, deletes, insertResults );
425 return response;
426 }
427
428 /**
429 * Performs the given insert operation.
430 *
431 * @param insert
432 * insert operation to be performed
433 * @throws DatastoreException
434 */
435 private List<FeatureId> performInsert( Insert insert )
436 throws DatastoreException {
437
438 List<FeatureId> fids = new ArrayList<FeatureId>();
439 FeatureCollection fc = insert.getFeatures();
440
441 // merge all equal and anonymous features (without fid)
442 FeatureDisambiguator merger = new FeatureDisambiguator( fc );
443 if ( insert.getIdGen() == ID_GEN.USE_EXISTING ) {
444 if ( merger.checkForAnonymousFeatures() ) {
445 String msg = Messages.getMessage( "WFS_INSERT_USE_EXISTING_AND_NO_FID" );
446 throw new DatastoreException( msg );
447 }
448 }
449 fc = merger.mergeFeatures();
450
451 if ( LOG.getLevel() == ILogger.LOG_DEBUG ) {
452 try {
453 GMLFeatureAdapter ada = new GMLFeatureAdapter( false );
454 GMLFeatureCollectionDocument doc = ada.export( fc );
455 LOG.logDebugXMLFile( "TransactionHandler_insert_merged", doc );
456 } catch ( Exception e ) {
457 LOG.logError( e.getMessage(), e );
458 }
459 }
460
461 Map<DatastoreTransaction, List<Feature>> taFeaturesMap = new HashMap<DatastoreTransaction, List<Feature>>();
462 FeatureIdAssigner fidAssigner = new FeatureIdAssigner( insert.getIdGen() );
463
464 // assign features to corresponding datastore transactions
465 for ( int i = 0; i < fc.size(); i++ ) {
466 Feature feature = fc.getFeature( i );
467 QualifiedName ftName = feature.getName();
468 DatastoreTransaction dsTa = this.taMap.get( ftName );
469 // reassign feature ids (if necessary)
470 fidAssigner.assignFID( feature, dsTa );
471 List<Feature> features = taFeaturesMap.get( dsTa );
472 if ( features == null ) {
473 features = new ArrayList<Feature>();
474 taFeaturesMap.put( dsTa, features );
475 }
476 features.add( feature );
477 }
478
479 // TODO remove this hack
480 fidAssigner.markStoredFeatures();
481
482 if ( LOG.getLevel() == ILogger.LOG_DEBUG ) {
483 try {
484 GMLFeatureAdapter ada = new GMLFeatureAdapter( false );
485 GMLFeatureCollectionDocument doc = ada.export( fc );
486 LOG.logDebugXMLFile( "TransactionHandler_insert_marked", doc );
487 } catch ( Exception e ) {
488 LOG.logError( e.getMessage(), e );
489 }
490 }
491
492 Iterator<DatastoreTransaction> taIter = taFeaturesMap.keySet().iterator();
493 while ( taIter.hasNext() ) {
494 DatastoreTransaction ta = taIter.next();
495 List<Feature> features = taFeaturesMap.get( ta );
496 fids.addAll( ta.performInsert( features ) );
497 }
498 return fids;
499 }
500
501 /**
502 * Performs the given delete operation.
503 *
504 * @param delete
505 * delete operation to be performed
506 * @throws DatastoreException
507 */
508 private int performDelete( Delete delete )
509 throws DatastoreException {
510
511 QualifiedName ftName = delete.getTypeName();
512 MappedFeatureType ft = this.ftMap.get( ftName );
513 DatastoreTransaction dsTa = this.taMap.get( ftName );
514 int deleted = dsTa.performDelete( ft, delete.getFilter(), this.request.getLockId() );
515 return deleted;
516 }
517
518 /**
519 * Performs the given update operation.
520 * <p>
521 * Assigning of FIDs to replacment features is performed in the {@link DatastoreTransaction}.
522 *
523 * @param update
524 * update operation to be perform
525 * @throws DatastoreException
526 */
527 private int performUpdate( Update update )
528 throws DatastoreException {
529
530 QualifiedName ftName = update.getTypeName();
531 MappedFeatureType ft = this.ftMap.get( ftName );
532 DatastoreTransaction dsTa = this.taMap.get( ftName );
533 int updated = 0;
534 if ( update.getFeature() == null ) {
535 updated = dsTa.performUpdate( ft, update.getReplacementProperties(), update.getFilter(),
536 this.request.getLockId() );
537 } else {
538 updated = dsTa.performUpdate( ft, update.getFeature(), update.getFilter(), this.request.getLockId() );
539 }
540 return updated;
541 }
542
543 /**
544 * Acquires the necessary <code>DatastoreTransaction</code>s. For each participating
545 * <code>Datastore</code>, one transaction is needed.
546 * <p>
547 * Fills the <code>taMap</code> and <code>dsToTaMap</code> members of this class.
548 *
549 * @throws OGCWebServiceException
550 * if a feature type is unknown or a DatastoreTransaction could not be acquired
551 */
552 private void acquireDSTransactions()
553 throws OGCWebServiceException {
554 Set<QualifiedName> ftNames = this.request.getAffectedFeatureTypes();
555 for ( QualifiedName ftName : ftNames ) {
556 MappedFeatureType ft = this.ftMap.get( ftName );
557 if ( ft == null ) {
558 String msg = "FeatureType '" + ftName + "' is not known to the WFS.";
559 throw new OGCWebServiceException( this.getClass().getName(), msg );
560 }
561 Datastore ds = ft.getGMLSchema().getDatastore();
562 DatastoreTransaction dsTa = this.dsToTaMap.get( ds );
563 if ( dsTa == null ) {
564 try {
565 dsTa = ds.acquireTransaction();
566 } catch ( DatastoreException e ) {
567 LOG.logError( e.getMessage(), e );
568 String msg = "Could not acquire transaction for FeatureType '" + ftName + "'.";
569 throw new OGCWebServiceException( this.getClass().getName(), msg );
570 }
571 this.dsToTaMap.put( ds, dsTa );
572 }
573 this.taMap.put( ftName, dsTa );
574 }
575 }
576
577 /**
578 * Releases all acquired <code>DatastoreTransaction</code>s.
579 *
580 * @throws OGCWebServiceException
581 * if a DatastoreTransaction could not be released
582 */
583 private void releaseDSTransactions()
584 throws OGCWebServiceException {
585 String msg = "";
586 for ( DatastoreTransaction dsTa : this.dsToTaMap.values() ) {
587 LOG.logDebug( "Releasing DatastoreTransaction " + dsTa );
588 try {
589 dsTa.release();
590 } catch ( DatastoreException e ) {
591 LOG.logError( "Error releasing DatastoreTransaction: " + e.getMessage(), e );
592 msg += e.getMessage() + "\n";
593 }
594 }
595 if ( msg.length() != 0 ) {
596 msg = "Could not release one or more DatastoreTransactions: " + msg;
597 throw new OGCWebServiceException( this.getClass().getName(), msg );
598 }
599 }
600
601 /**
602 * Commits all pending <code>DatastoreTransaction</code>s.
603 *
604 * @throws OGCWebServiceException
605 * if a DatastoreException could not be committed
606 */
607 private void commitDSTransactions()
608 throws OGCWebServiceException {
609 String msg = "";
610 for ( DatastoreTransaction dsTa : this.dsToTaMap.values() ) {
611 LOG.logDebug( "Committing DatastoreTransaction " + dsTa );
612 try {
613 dsTa.commit();
614 } catch ( DatastoreException e ) {
615 LOG.logError( "Error committing DatastoreTransaction: " + e.getMessage(), e );
616 msg += e.getMessage() + "\n";
617 }
618 }
619 if ( msg.length() != 0 ) {
620 msg = "Could not commit one or more DatastoreTransactions: " + msg;
621 throw new OGCWebServiceException( this.getClass().getName(), msg );
622 }
623 }
624
625 /**
626 * Aborts all pending <code>DatastoreTransaction</code>s.
627 *
628 * @throws OGCWebServiceException
629 * if a DatastoreException could not be aborted
630 */
631 private void abortDSTransactions()
632 throws OGCWebServiceException {
633 String msg = "";
634 for ( DatastoreTransaction dsTa : this.dsToTaMap.values() ) {
635 LOG.logDebug( "Aborting DatastoreTransaction " + dsTa );
636 try {
637 dsTa.rollback();
638 } catch ( DatastoreException e ) {
639 LOG.logError( "Error aborting DatastoreTransaction: " + e.getMessage(), e );
640 msg += e.getMessage() + "\n";
641 }
642 }
643 if ( msg.length() != 0 ) {
644 msg = "Could not abort one or more DatastoreTransactions: " + msg;
645 throw new OGCWebServiceException( this.getClass().getName(), msg );
646 }
647 }
648 }