/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.gemstone.gemfire.internal.cache;
import com.gemstone.gemfire.cache.*;
import com.gemstone.gemfire.internal.cache.locks.*;

import java.util.*;

/** TXLockRequest represents all the locks that need to be made
 * for a single transaction.
 *
 * 
 * @since GemFire 4.0
 * 
 */
public class TXLockRequest {
  private boolean localLockHeld;
  private TXLockId distLockId;
  private IdentityArrayList localLocks;  // of TXRegionLockRequest
  private ArrayList<TXRegionLockRequest> distLocks; // of TXRegionLockRequest
  private Set otherMembers;

  public TXLockRequest()
  {
    this.localLockHeld = false;
    this.distLockId = null;
    this.localLocks = null;
    this.distLocks = null;
    this.otherMembers = null;
  }
  void setOtherMembers(Set s) {
    this.otherMembers = s;
  }
  public void addLocalRequest(TXRegionLockRequest req) {
    if (this.localLocks == null) {
      this.localLocks = new IdentityArrayList();
    }
    this.localLocks.add(req);
  }
  public TXRegionLockRequest getRegionLockRequest(String regionFullPath) {
    if (this.localLocks == null || regionFullPath == null) {
      return null;
    }
    Iterator<TXRegionLockRequestImpl> it = this.localLocks.iterator();
    while (it.hasNext()) {
      TXRegionLockRequestImpl rlr = it.next();
      if (rlr.getRegionFullPath().equals(regionFullPath)) {
        return rlr;
      }
    }
    return null;
  }
  void addDistributedRequest(TXRegionLockRequest req) {
    if (this.distLocks == null) {
      this.distLocks = new ArrayList<TXRegionLockRequest>();
    }
    this.distLocks.add(req);
  }
  public void obtain() throws CommitConflictException {
    if (this.localLocks != null && !this.localLocks.isEmpty()) {
      txLocalLock(this.localLocks);
      this.localLockHeld = true;
    }
    if (this.distLocks != null && !this.distLocks.isEmpty()) {
      this.distLockId = TXLockService.createDTLS().txLock(this.distLocks,
                                                          this.otherMembers);
    }
  }
  /**
   * Release any local locks obtained by this request
   */
  public void releaseLocal() {
    if (this.localLockHeld) {
      txLocalRelease(this.localLocks);
      this.localLockHeld = false;
    }
  }
  /**
   * Release any distributed locks obtained by this request
   */
  public void releaseDistributed() {
    if (this.distLockId != null) {
      TXLockService txls = TXLockService.createDTLS();
      txls.release(this.distLockId);
      this.distLockId = null;
    }
  }

  public TXLockId getDistributedLockId() {
    return this.distLockId;
  }

  @Override
  public String toString() {
    StringBuilder sb = new StringBuilder();
    sb.append(getClass().getCanonicalName()).append("@").append(System.identityHashCode(this));
    sb.append(" RegionLockRequests:");
    if (this.localLocks != null) {
      Iterator it = this.localLocks.iterator();
      while (it.hasNext()) {
        TXRegionLockRequest rlr = (TXRegionLockRequest) it.next();
        sb.append(" TXRegionLockRequest:");
        sb.append(rlr.getRegionFullPath()).append(" keys:").append(rlr.getKeys());
      }
    }
    return sb.toString();
  }

  public void cleanup() {
    releaseLocal();
    releaseDistributed();
  }
  static private final TXReservationMgr resMgr = new TXReservationMgr(true);

  /**
   * @param localLocks is a list of TXRegionLockRequest instances
   */
  private static void txLocalLock(IdentityArrayList localLocks)
    throws CommitConflictException
  {
    resMgr.makeReservation(localLocks);
  }
  private static void txLocalRelease(IdentityArrayList localLocks) {
    resMgr.releaseReservation(localLocks);
  }
}

@@ -3154,24 +3154,38 @@
  != null) %7B%0A
+      try %7B%0A  
       TXLock
@@ -3233,16 +3233,18 @@
 ;%0A      
+  
 txls.rel
@@ -3266,16 +3266,302 @@
 ockId);%0A
+      %7D catch (IllegalStateException ignore) %7B%0A        //IllegalStateException: TXLockService cannot be created %0A        //until connected to distributed system%0A        //could be thrown if a jvm is disconnected from the ds, %0A        //and tries to createDTLS() during clean up%0A      %7D%0A
       th

Handle IllegalStateException when node is disconnecting from distributed system.