content: /**
   *  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 org.apache.aries.samples.ariestrader.persist.jdbc;
  
  import java.sql.Connection;
  import java.sql.PreparedStatement;
  import java.sql.ResultSet;
  import java.util.Collection;
  import java.util.HashMap;
  import java.util.Iterator;
  
  import org.apache.aries.samples.ariestrader.util.KeyBlock;
  import org.apache.aries.samples.ariestrader.util.Log;
  import org.apache.aries.samples.ariestrader.util.TradeConfig;
  
  public class KeySequenceDirect {
  
      private static HashMap keyMap = new HashMap();
  
      public static synchronized Integer getNextID(Connection conn, String keyName, boolean inSession, boolean inGlobalTxn)
          throws Exception {
          Integer nextID = null;
          // First verify we have allocated a block of keys
          // for this key name
          // Then verify the allocated block has not been depleted
          // allocate a new block if necessary
          if (keyMap.containsKey(keyName) == false)
              allocNewBlock(conn, keyName, inSession, inGlobalTxn);
          Collection block = (Collection) keyMap.get(keyName);
  
          Iterator ids = block.iterator();
          if (ids.hasNext() == false)
              ids = allocNewBlock(conn, keyName, inSession, inGlobalTxn).iterator();
          // get and return a new unique key
          nextID = (Integer) ids.next();
  
          if (Log.doTrace())
              Log.trace("KeySequenceDirect:getNextID inSession(" + inSession + ") - return new PK ID for Entity type: "
                  + keyName + " ID=" + nextID);
          return nextID;
      }
  
      private static Collection allocNewBlock(Connection conn, String keyName, boolean inSession, boolean inGlobalTxn)
          throws Exception {
          try {
              if (inGlobalTxn == false && !inSession)
                  conn.commit(); // commit any pending txns
              PreparedStatement stmt = conn.prepareStatement(getKeyForUpdateSQL);
              stmt.setString(1, keyName);
              ResultSet rs = stmt.executeQuery();
              if (!rs.next()) {
                  // No keys found for this name - create a new one
                  PreparedStatement stmt2 = conn.prepareStatement(createKeySQL);
                  int keyVal = 0;
                  stmt2.setString(1, keyName);
                  stmt2.setInt(2, keyVal);
                  stmt2.executeUpdate();
                  stmt2.close();
                  stmt.close();
                  stmt = conn.prepareStatement(getKeyForUpdateSQL);
                  stmt.setString(1, keyName);
                  rs = stmt.executeQuery();
                  rs.next();
              }
  
              int keyVal = rs.getInt("keyval");
  
              stmt.close();
  
              stmt = conn.prepareStatement(updateKeyValueSQL);
              stmt.setInt(1, keyVal + TradeConfig.KEYBLOCKSIZE);
              stmt.setString(2, keyName);
              stmt.executeUpdate();
              stmt.close();
  
              Collection block = new KeyBlock(keyVal, keyVal + TradeConfig.KEYBLOCKSIZE - 1);
              keyMap.put(keyName, block);
              if (inGlobalTxn == false && !inSession)
                  conn.commit();
              return block;
          } catch (Exception e) {
              String error =
                  "KeySequenceDirect:allocNewBlock - failure to allocate new block of keys for Entity type: " + keyName;
              Log.error(e, error);
              throw new Exception(error + e.toString());
          }
      }
  
      private static final String getKeyForUpdateSQL = "select * from keygenejb kg where kg.keyname = ?  for update";
  
      private static final String createKeySQL =
          "insert into keygenejb " + "( keyname, keyval ) " + "VALUES (  ?  ,  ? )";
  
      private static final String updateKeyValueSQL = "update keygenejb set keyval = ? " + "where keyname = ?";
  
  }
  