KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > tapestry > vlib > ejb > impl > KeyAllocatorBean


1 // Copyright 2004 The Apache Software Foundation
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
// http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14

15 package org.apache.tapestry.vlib.ejb.impl;
16
17 import java.sql.Connection JavaDoc;
18 import java.sql.PreparedStatement JavaDoc;
19 import java.sql.ResultSet JavaDoc;
20 import java.sql.SQLException JavaDoc;
21 import java.util.LinkedList JavaDoc;
22
23 import javax.ejb.SessionBean JavaDoc;
24 import javax.ejb.SessionContext JavaDoc;
25 import javax.naming.Context JavaDoc;
26 import javax.naming.InitialContext JavaDoc;
27 import javax.naming.NamingException JavaDoc;
28 import javax.sql.DataSource JavaDoc;
29
30 import org.apache.tapestry.contrib.ejb.XEJBException;
31
32 /**
33  * Implementation of the {@link org.apache.tapestry.vlib.ejb.IKeyAllocator}
34  * stateless session bean.
35  *
36  * <p>We're cheating a little; they KeyAllocator does have
37  * state, it just doesn't get persisted ever. Since the
38  * operation on it is atomic ("gimme a key") it doesn't
39  * need to have conversational state with its clients.
40  *
41  * <p>The KeyAllocator records in the database the "next key
42  * to allocate". When it needs a key, it allocates a block
43  * of keys (by advancing the next key by a some number).
44  *
45  * <p>If the KeyAllocator instance is purged from the pool,
46  * then some number of keys that it has allocated will
47  * be lost. Big deal.
48  *
49  * @version $Id: KeyAllocatorBean.java,v 1.3 2004/02/19 17:38:07 hlship Exp $
50  * @author Howard Lewis Ship
51  *
52  **/

53
54 public class KeyAllocatorBean implements SessionBean JavaDoc
55 {
56     private static final String JavaDoc PROPERTY_NAME = "next-key";
57
58     private SessionContext JavaDoc context;
59
60     /**
61      * List of Integer instances; these are keys
62      * acquired from the database.
63      *
64      **/

65
66     private LinkedList JavaDoc keys;
67
68     /**
69      * Number of keys to allocate from the database
70      * at a time. Set from the ENC property "blockSize".
71      *
72      **/

73
74     private int blockSize = 0;
75
76     /**
77      * Data source, retrieved from the ENC property
78      * "jdbc/dataSource".
79      *
80      **/

81
82     private DataSource JavaDoc dataSource;
83
84     /**
85      * Activates the bean. Gets the block size
86      * and DataSource from the environment.
87      *
88      **/

89
90     public void ejbCreate()
91     {
92         Context JavaDoc initial;
93         Context JavaDoc environment;
94         Integer JavaDoc blockSizeProperty;
95
96         try
97         {
98             initial = new InitialContext JavaDoc();
99             environment = (Context JavaDoc) initial.lookup("java:comp/env");
100         }
101         catch (NamingException JavaDoc ex)
102         {
103             throw new XEJBException("Could not lookup environment.", ex);
104         }
105
106         try
107         {
108             blockSizeProperty = (Integer JavaDoc) environment.lookup("blockSize");
109         }
110         catch (NamingException JavaDoc ex)
111         {
112             throw new XEJBException("Could not lookup blockSize property.", ex);
113         }
114
115         blockSize = blockSizeProperty.intValue();
116
117         try
118         {
119             dataSource = (DataSource JavaDoc) environment.lookup("jdbc/dataSource");
120         }
121         catch (NamingException JavaDoc ex)
122         {
123             throw new XEJBException("Could not lookup data source.", ex);
124         }
125
126         if (keys == null)
127             keys = new LinkedList JavaDoc();
128     }
129
130     /**
131      * Does nothing, not invoked in stateless session beans.
132      **/

133
134     public void ejbPassivate()
135     {
136     }
137
138     public void setSessionContext(SessionContext JavaDoc value)
139     {
140         context = value;
141     }
142
143     /**
144      * Does nothing, not invoked in stateless session beans.
145      *
146      **/

147
148     public void ejbActivate()
149     {
150     }
151
152     /**
153      * Does nothing. This is invoked when the bean moves from
154      * the method ready pool to the "does not exist" state.
155      * The EJB container will lost its reference to the
156      * bean, and the garbage collector will take it
157      * (including any keys it has cached from the database).
158      *
159      **/

160
161     public void ejbRemove()
162     {
163         // Does nothing.
164
}
165
166     /**
167      * Allocates a single key, going to the database
168      * only if it has no keys in its internal cache.
169      *
170      **/

171
172     public Integer JavaDoc allocateKey()
173     {
174         if (keys.isEmpty())
175             allocateBlock(1);
176
177         return (Integer JavaDoc) keys.removeFirst();
178     }
179
180     /**
181      * Allocates a block of keys, going to the database
182      * if there are insufficient keys in its internal
183      * cache.
184      *
185      **/

186
187     public Integer JavaDoc[] allocateKeys(int count)
188     {
189         Integer JavaDoc[] result;
190         int i;
191
192         if (keys.size() < count)
193             allocateBlock(count);
194
195         result = new Integer JavaDoc[count];
196
197         for (i = 0; i < count; i++)
198         {
199             result[i] = (Integer JavaDoc) keys.removeFirst();
200         }
201
202         return result;
203     }
204
205     /**
206      * Allocates a block of keys from the database.
207      * Allocates count keys, or the configured block size,
208      * whichever is greater.
209      *
210      * <p>It is assumed that this operation takes place
211      * within a transaction.
212      *
213      **/

214
215     protected void allocateBlock(int count)
216     {
217         Connection JavaDoc connection = null;
218         PreparedStatement JavaDoc statement = null;
219         ResultSet JavaDoc set = null;
220         int nextKey;
221         int allocationCount;
222         int i;
223
224         allocationCount = Math.max(count, blockSize);
225
226         try
227         {
228             connection = getConnection();
229
230             statement = connection.prepareStatement("select PROP_VALUE from PROP where NAME = ?");
231             statement.setString(1, PROPERTY_NAME);
232
233             set = statement.executeQuery();
234
235             // Advance to the first row.
236

237             set.next();
238
239             nextKey = set.getInt(1);
240
241             set.close();
242             set = null;
243
244             statement.close();
245             statement = null;
246
247             // Now, take those keys and advance nextKey
248

249             for (i = 0; i < allocationCount; i++)
250                 keys.add(new Integer JavaDoc(nextKey++));
251
252             // Update nextKey back to the database.
253

254             statement =
255                 connection.prepareStatement("update PROP\n" + "set PROP_VALUE = ?\n" + "where NAME = ?");
256             statement.setInt(1, nextKey);
257             statement.setString(2, PROPERTY_NAME);
258
259             statement.executeUpdate();
260         }
261         catch (SQLException JavaDoc ex)
262         {
263             ex.printStackTrace();
264
265             throw new XEJBException("Unable to allocate keys from the database.", ex);
266         }
267         finally
268         {
269             if (set != null)
270             {
271                 try
272                 {
273                     set.close();
274                 }
275                 catch (SQLException JavaDoc ex)
276                 {
277                 }
278             }
279
280             if (statement != null)
281             {
282                 try
283                 {
284                     statement.close();
285                 }
286                 catch (SQLException JavaDoc ex)
287                 {
288                 }
289             }
290
291             if (connection != null)
292             {
293                 try
294                 {
295                     connection.close();
296                 }
297                 catch (SQLException JavaDoc ex)
298                 {
299                 }
300             }
301         }
302
303     }
304
305     /**
306      * Gets a database connection from the pool.
307      *
308      * @throws EJBException if a {@link SQLException}
309      * is thrown.
310      *
311      **/

312
313     protected Connection JavaDoc getConnection()
314     {
315         try
316         {
317             return dataSource.getConnection();
318         }
319         catch (SQLException JavaDoc ex)
320         {
321             throw new XEJBException("Unable to get database connection from pool.", ex);
322         }
323     }
324 }
Popular Tags