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 }