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