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 }