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: aschmitz $
101 *
102 * @version $Revision: 24604 $, $Date: 2010-05-27 11:59:30 +0200 (Do, 27. Mai 2010) $
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 List<Exception> exceptions = new ArrayList<Exception>();
414
415 Iterator<TransactionOperation> iter = operations.iterator();
416 while ( iter.hasNext() ) {
417 TransactionOperation operation = iter.next();
418 String handle = operation.getHandle();
419 try {
420 if ( operation instanceof Insert ) {
421 List<FeatureId> insertedFIDs = performInsert( (Insert) operation );
422 inserts += insertedFIDs.size();
423
424 for ( FeatureId id : insertedFIDs ) {
425 InsertResults results = new InsertResults( handle, singletonList( id ) );
426 insertResults.add( results );
427 }
428 } else if ( operation instanceof Delete ) {
429 // the intended behavior is different between versions here, so in #performDelete the exception
430 // will be thrown now, and caught here if 1.1.0
431 if ( request.getVersion().equals( "1.0.0" ) ) {
432 deletes += performDelete( (Delete) operation );
433 } else {
434 try {
435 deletes += performDelete( (Delete) operation );
436 } catch ( MissingLockIdException e ) {
437 throw new MissingParameterValueException( "LockId", e.getMessage() );
438 }
439 }
440 } else if ( operation instanceof Update ) {
441 if ( request.getVersion().equals( "1.0.0" ) ) {
442 try {
443 updates += performUpdate( (Update) operation );
444 } catch ( MissingLockIdException e ) {
445 exceptions.add( e );
446 }
447 } else {
448 updates += performUpdate( (Update) operation );
449 }
450 } else if ( operation instanceof Native ) {
451 String msg = Messages.getMessage( "WFS_NATIVE_OPERATIONS_UNSUPPORTED" );
452 throw new OGCWebServiceException( this.getClass().getName(), msg );
453 } else {
454 String opType = operation.getClass().getName();
455 String msg = Messages.getMessage( "WFS_UNHANDLED_OPERATION_TYPE", opType );
456 throw new OGCWebServiceException( this.getClass().getName(), msg );
457 }
458 } catch ( DatastoreException e ) {
459 LOG.logError( e.getMessage(), e );
460 String msg = "A datastore exception occured during the processing of operation with handle '" + handle
461 + "': " + e.getMessage();
462 throw new InvalidParameterValueException( this.getClass().getName(), msg );
463 }
464 }
465 TransactionResponse response = new TransactionResponse( request, inserts, updates, deletes, insertResults,
466 exceptions );
467 return response;
468 }
469
470 /**
471 * Performs the given insert operation.
472 *
473 * @param insert
474 * insert operation to be performed
475 * @throws DatastoreException
476 */
477 private List<FeatureId> performInsert( Insert insert )
478 throws DatastoreException {
479
480 List<FeatureId> fids = new ArrayList<FeatureId>();
481 FeatureCollection fc = insert.getFeatures();
482
483 // clear reference to feature collection
484 // insert.setFeatureCollection( null );
485
486 if ( LOG.getLevel() == ILogger.LOG_DEBUG ) {
487 try {
488 GMLFeatureAdapter ada = new GMLFeatureAdapter( false );
489 GMLFeatureCollectionDocument doc = ada.export( fc );
490 LOG.logDebugXMLFile( "TransactionHandler_insert_merged", doc );
491 } catch ( Exception e ) {
492 LOG.logError( e.getMessage(), e );
493 }
494 }
495
496 Map<DatastoreTransaction, List<Feature>> taFeaturesMap = new HashMap<DatastoreTransaction, List<Feature>>();
497 FeatureIdAssigner fidAssigner = new FeatureIdAssigner( insert.getIdGen() );
498
499 // assign features to corresponding datastore transactions
500 for ( int i = 0; i < fc.size(); i++ ) {
501 Feature feature = fc.getFeature( i );
502 QualifiedName ftName = feature.getName();
503 DatastoreTransaction dsTa = this.taMap.get( ftName );
504 // reassign feature ids (if necessary)
505 fidAssigner.assignFID( feature, dsTa );
506 List<Feature> features = taFeaturesMap.get( dsTa );
507 if ( features == null ) {
508 features = new ArrayList<Feature>();
509 taFeaturesMap.put( dsTa, features );
510 }
511 features.add( feature );
512 }
513
514 // TODO remove this hack
515 fidAssigner.markStoredFeatures();
516
517 // clear reference to fidAssigner (implicitly to feature collection)
518 fidAssigner = null;
519
520 if ( LOG.getLevel() == ILogger.LOG_DEBUG ) {
521 try {
522 GMLFeatureAdapter ada = new GMLFeatureAdapter( false );
523 GMLFeatureCollectionDocument doc = ada.export( fc );
524 LOG.logDebugXMLFile( "TransactionHandler_insert_marked", doc );
525 } catch ( Exception e ) {
526 LOG.logError( e.getMessage(), e );
527 }
528 }
529
530 // clear reference to feature collection
531 fc = null;
532
533 for ( DatastoreTransaction ta : taFeaturesMap.keySet() ) {
534 List<Feature> features = taFeaturesMap.get( ta );
535 fids.addAll( ta.performInsert( features ) );
536 }
537 return fids;
538 }
539
540 /**
541 * Performs the given delete operation.
542 *
543 * @param delete
544 * delete operation to be performed
545 * @throws DatastoreException
546 */
547 private int performDelete( Delete delete )
548 throws DatastoreException {
549 QualifiedName ftName = delete.getTypeName();
550 MappedFeatureType ft = this.ftMap.get( ftName );
551 DatastoreTransaction dsTa = this.taMap.get( ftName );
552 int deleted = dsTa.performDelete( ft, delete.getFilter(), this.request.getLockId() );
553 return deleted;
554 }
555
556 /**
557 * Performs the given update operation.
558 * <p>
559 * Assigning of FIDs to replacement features is performed in the {@link DatastoreTransaction}.
560 *
561 * @param update
562 * update operation to be perform
563 * @throws DatastoreException
564 */
565 private int performUpdate( Update update )
566 throws DatastoreException {
567
568 QualifiedName ftName = update.getTypeName();
569 MappedFeatureType ft = this.ftMap.get( ftName );
570 DatastoreTransaction dsTa = this.taMap.get( ftName );
571 int updated = 0;
572 if ( update.getFeature() == null ) {
573 updated = dsTa.performUpdate( ft, update.getReplacementProperties(), update.getFilter(),
574 this.request.getLockId() );
575 } else {
576 updated = dsTa.performUpdate( ft, update.getFeature(), update.getFilter(), this.request.getLockId() );
577 }
578
579 // to work around API changes...
580 if ( dsTa instanceof SQLTransaction ) {
581 changedFIDs.addAll( ( (SQLTransaction) dsTa ).determineAffectedFIDs( ft, update.getFilter() ) );
582 }
583
584 return updated;
585 }
586
587 /**
588 * Acquires the necessary <code>DatastoreTransaction</code>s. For each participating <code>Datastore</code>, one
589 * transaction is needed.
590 * <p>
591 * Fills the <code>taMap</code> and <code>dsToTaMap</code> members of this class.
592 *
593 * @throws OGCWebServiceException
594 * if a feature type is unknown or a DatastoreTransaction could not be acquired
595 */
596 private void acquireDSTransactions()
597 throws OGCWebServiceException {
598 Set<QualifiedName> ftNames = this.request.getAffectedFeatureTypes();
599 for ( QualifiedName ftName : ftNames ) {
600 MappedFeatureType ft = this.ftMap.get( ftName );
601 if ( ft == null ) {
602 String msg = "FeatureType '" + ftName + "' is not known to the WFS.";
603 throw new OGCWebServiceException( this.getClass().getName(), msg );
604 }
605 Datastore ds = ft.getGMLSchema().getDatastore();
606 DatastoreTransaction dsTa = this.dsToTaMap.get( ds );
607 if ( dsTa == null ) {
608 try {
609 dsTa = ds.acquireTransaction();
610 } catch ( DatastoreException e ) {
611 LOG.logError( e.getMessage(), e );
612 String msg = "Could not acquire transaction for FeatureType '" + ftName + "'.";
613 throw new OGCWebServiceException( this.getClass().getName(), msg );
614 }
615 this.dsToTaMap.put( ds, dsTa );
616 }
617 this.taMap.put( ftName, dsTa );
618 }
619 }
620
621 /**
622 * Releases all acquired <code>DatastoreTransaction</code>s.
623 *
624 * @throws OGCWebServiceException
625 * if a DatastoreTransaction could not be released
626 */
627 private void releaseDSTransactions()
628 throws OGCWebServiceException {
629 String msg = "";
630 for ( DatastoreTransaction dsTa : this.dsToTaMap.values() ) {
631 LOG.logDebug( "Releasing DatastoreTransaction " + dsTa );
632 try {
633 dsTa.release();
634 } catch ( DatastoreException e ) {
635 LOG.logError( "Error releasing DatastoreTransaction: " + e.getMessage(), e );
636 msg += e.getMessage() + "\n";
637 }
638 }
639 if ( msg.length() != 0 ) {
640 msg = "Could not release one or more DatastoreTransactions: " + msg;
641 throw new OGCWebServiceException( this.getClass().getName(), msg );
642 }
643 }
644
645 /**
646 * Commits all pending <code>DatastoreTransaction</code>s.
647 *
648 * @throws OGCWebServiceException
649 * if a DatastoreException could not be committed
650 */
651 private void commitDSTransactions()
652 throws OGCWebServiceException {
653 String msg = "";
654 for ( DatastoreTransaction dsTa : this.dsToTaMap.values() ) {
655 LOG.logDebug( "Committing DatastoreTransaction " + dsTa );
656 try {
657 dsTa.commit();
658 } catch ( DatastoreException e ) {
659 LOG.logError( "Error committing DatastoreTransaction: " + e.getMessage(), e );
660 msg += e.getMessage() + "\n";
661 }
662 }
663 if ( msg.length() != 0 ) {
664 msg = "Could not commit one or more DatastoreTransactions: " + msg;
665 throw new OGCWebServiceException( this.getClass().getName(), msg );
666 }
667 }
668
669 /**
670 * Aborts all pending <code>DatastoreTransaction</code>s.
671 *
672 * @throws OGCWebServiceException
673 * if a DatastoreException could not be aborted
674 */
675 private void abortDSTransactions()
676 throws OGCWebServiceException {
677 String msg = "";
678 for ( DatastoreTransaction dsTa : this.dsToTaMap.values() ) {
679 LOG.logDebug( "Aborting DatastoreTransaction " + dsTa );
680 try {
681 dsTa.rollback();
682 } catch ( DatastoreException e ) {
683 LOG.logError( "Error aborting DatastoreTransaction: " + e.getMessage(), e );
684 msg += e.getMessage() + "\n";
685 }
686 }
687 if ( msg.length() != 0 ) {
688 msg = "Could not abort one or more DatastoreTransactions: " + msg;
689 throw new OGCWebServiceException( this.getClass().getName(), msg );
690 }
691 }
692 }