001    /**
002     *  Licensed to the Apache Software Foundation (ASF) under one or more
003     *  contributor license agreements.  See the NOTICE file distributed with
004     *  this work for additional information regarding copyright ownership.
005     *  The ASF licenses this file to You under the Apache License, Version 2.0
006     *  (the "License"); you may not use this file except in compliance with
007     *  the License.  You may obtain a copy of the License at
008     *
009     *     http://www.apache.org/licenses/LICENSE-2.0
010     *
011     *  Unless required by applicable law or agreed to in writing, software
012     *  distributed under the License is distributed on an "AS IS" BASIS,
013     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     *  See the License for the specific language governing permissions and
015     *  limitations under the License.
016     */
017    package org.apache.geronimo.samples.daytrader.direct;
018    
019    import java.util.Collection;
020    import java.util.Iterator;
021    import java.util.HashMap;
022    
023    import java.sql.Connection;
024    import java.sql.PreparedStatement;
025    import java.sql.ResultSet;
026    
027    import org.apache.geronimo.samples.daytrader.util.*;
028    
029    import org.apache.geronimo.samples.daytrader.*;
030    
031    public class KeySequenceDirect {
032    
033            private static HashMap keyMap = new HashMap();
034    
035        public static synchronized Integer getNextID(Connection conn, String keyName, boolean inSession, boolean inGlobalTxn)
036            throws Exception
037        {
038                    Integer nextID = null;
039                    // First verify we have allocated a block of keys 
040                    // for this key name
041                    // Then verify the allocated block has not been depleted
042                    // allocate a new block if necessary
043                    if ( keyMap.containsKey(keyName) == false)
044                            allocNewBlock(conn, keyName, inSession, inGlobalTxn);
045                    Collection block =      (Collection) keyMap.get(keyName);
046                    
047                    Iterator ids = block.iterator();
048                    if ( ids.hasNext() == false )
049                            ids = allocNewBlock(conn, keyName, inSession, inGlobalTxn).iterator();
050                    //get and return a new unique key
051                    nextID = (Integer) ids.next();
052    
053                    if (Log.doTrace()) Log.trace("KeySequenceDirect:getNextID inSession(" + inSession + ") - return new PK ID for Entity type: " + keyName + " ID=" + nextID);
054                    return nextID;
055            }
056    
057            private static Collection allocNewBlock(Connection conn, String keyName, boolean inSession, boolean inGlobalTxn)  
058            throws Exception
059            {
060                    try 
061                    {
062                            if (inGlobalTxn == false && !inSession) conn.commit();  // commit any pending txns
063                            PreparedStatement stmt = conn.prepareStatement(getKeyForUpdateSQL);
064                            stmt.setString(1, keyName);
065                            ResultSet rs = stmt.executeQuery();
066                            if (!rs.next()) 
067                            {
068                                    // No keys found for this name - create a new one
069                                    PreparedStatement stmt2 = conn.prepareStatement(createKeySQL);
070                                    int keyVal = 0;
071                                    stmt2.setString(1, keyName);
072                                    stmt2.setInt(2, keyVal);                                
073                                    int rowCount = stmt2.executeUpdate();
074                                    stmt2.close();
075                                    stmt.close();
076                                    stmt = conn.prepareStatement(getKeyForUpdateSQL);                               
077                                    stmt.setString(1, keyName);                             
078                                    rs = stmt.executeQuery();
079                                    rs.next();              
080                            }
081                            
082                            int keyVal = rs.getInt("keyval");
083                            
084                            stmt.close();
085                            
086                            stmt = conn.prepareStatement(updateKeyValueSQL);
087                            stmt.setInt(1, keyVal+TradeConfig.KEYBLOCKSIZE);
088                            stmt.setString(2, keyName);                     
089                            int rowCount = stmt.executeUpdate();
090                            stmt.close();
091    
092                            Collection block = new KeyBlock(keyVal, keyVal+TradeConfig.KEYBLOCKSIZE-1);
093                            keyMap.put(keyName, block);
094                            if (inGlobalTxn == false && !inSession) conn.commit();
095                            return block;                   
096                    }
097                    catch (Exception e)
098                    {
099                            String error = "KeySequenceDirect:allocNewBlock - failure to allocate new block of keys for Entity type: "+ keyName;
100                            Log.error(e, error);
101                            throw new Exception(error + e.toString());
102                    }
103            }
104            
105            private static final String getKeyForUpdateSQL  = 
106                    "select * from keygenejb kg where kg.keyname = ?  for update";
107            
108            private static final String createKeySQL =
109                    "insert into keygenejb " +
110                    "( keyname, keyval ) " +
111                    "VALUES (  ?  ,  ? )";
112                    
113            private static final String updateKeyValueSQL = 
114                    "update keygenejb set keyval = ? " +
115                    "where keyname = ?";
116                    
117    }
118