KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > uitags > tagutil > ScopedIdGenerator


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

18 package net.sf.uitags.tagutil;
19
20 import java.io.Serializable JavaDoc;
21 import java.util.HashMap JavaDoc;
22
23 import javax.servlet.jsp.PageContext JavaDoc;
24
25 /**
26  * Generates a <code>long</code> value which is guaranteed to be unique for a
27  * given combination of key and scope. This is useful when a counter
28  * is needed for assigning unique names to generated HTML/JavaScript
29  * entities.
30  *
31  * @author jonni
32  * @version $Id: ScopedIdGenerator.java,v 1.3 2006/07/23 07:18:27 hgani Exp $
33  */

34 public final class ScopedIdGenerator {
35   /**
36    * Non-instantiable by client.
37    */

38   private ScopedIdGenerator() {
39     super();
40   }
41
42   /**
43    * Generates a unique <code>long</code> value for a given combination
44    * of key and scope only if the <i>groupId</i> is unique. Otherwise,
45    * the previously generated value that corresponds to that particular
46    * <i>groupId</i> is returned. A <code>null</code> <i>groupId</i> means
47    * that the ID is not grouped,
48    *
49    * @param scope the scope of the ID
50    * @param key the key (aka name) of the ID
51    * @param pageContext provides access to the different scopes
52    * @param groupId the group ID
53    * @return a unique ID value
54    * @throws IllegalArgumentException if <code>scope</code> value is illegal
55    * @throws NullPointerException if <code>key</code> is <code>null</code>
56    * @throws IllegalStateException if trying to access a non-existant
57    * session
58    */

59   public static long nextId(
60       int scope, String JavaDoc key, PageContext JavaDoc pageContext, String JavaDoc groupId) {
61     // Check the arguments
62
if (scope != PageContext.PAGE_SCOPE &&
63         scope != PageContext.REQUEST_SCOPE &&
64         scope != PageContext.SESSION_SCOPE &&
65         scope != PageContext.APPLICATION_SCOPE) {
66       throw new IllegalArgumentException JavaDoc(
67           "Scope value must be one of the constants declared in PageContext.");
68     }
69     if (key == null) {
70       throw new NullPointerException JavaDoc("key can't be null.");
71     }
72
73     // If scope is page or request, there's no possibility of concurrent
74
// access, simply call the worker method.
75
if (scope == PageContext.PAGE_SCOPE || scope == PageContext.REQUEST_SCOPE) {
76       return nextIdVal(scope, key, pageContext, groupId);
77     }
78     // If scope if session or application, value may be accessed concurrently,
79
// use synchronization.
80
else {
81       synchronized (ScopedIdGenerator.class) {
82         return nextIdVal(scope, key, pageContext, groupId);
83       }
84     }
85   }
86
87   /**
88    * Generates a <code>long</code> value which is guaranteed to be unique for a
89    * given combination of key and scope.
90    *
91    * @param scope the scope of the ID
92    * @param key the key (aka name) of the ID
93    * @param pageContext provides access to the different scopes
94    * @return a unique ID value
95    * @throws IllegalArgumentException if <code>scope</code> value is illegal
96    * @throws NullPointerException if <code>key</code> is <code>null</code>
97    * @throws IllegalStateException if trying to access a non-existant
98    * session
99    */

100   public static long nextId(int scope, String JavaDoc key, PageContext JavaDoc pageContext) {
101     return nextId(scope, key, pageContext, null);
102   }
103
104   /**
105    * The worker method that does the actual work of ID generation. It doesn't
106    * support multi-threading; the caller has to synchronize the method call
107    * when appropriate.
108    * <p>
109    * A <code>null</code> <i>groupId</i> means that the ID is not grouped,
110    * therefore the returned ID will always be unique. When <i>groupId</i> is
111    * specified, the returned ID is unique only if the <i>groupId</i> is unique.
112    *
113    * @see #nextId(int, String, PageContext, String)
114    * @see #nextIdVal(int, String, PageContext)
115    *
116    * @param scope the scope of the ID
117    * @param key the key (aka name) of the ID
118    * @param pageContext provides access to the different scopes
119    * @param groupId the group ID
120    * @return a unique ID value
121    * @throws IllegalStateException when aborting to avoid overwriting someone
122    * else's scoped attribute or if trying to access a non-existant
123    * session
124    */

125   private static long nextIdVal(
126       int scope, String JavaDoc key, PageContext JavaDoc pageContext, String JavaDoc groupId) {
127     //return nextIdVal(scope, key, pageContext, null);
128
// Read the current value of the unique ID
129
Id currId;
130     try {
131       currId = (Id) pageContext.getAttribute(key, scope);
132     }
133     catch (ClassCastException JavaDoc e) {
134       throw new IllegalStateException JavaDoc(
135           "Cannot create an ID named '" + key + "' in scope '" + scope + "'." +
136           " Another object is occupying that spot.");
137     }
138
139     // Below we'll increment the ID value and put it back to the scope.
140
// The risk of accidentally overwriting someone else's scoped attribute
141
// has been eliminated by the cast above. A ClassCastException would've
142
// been thrown if a scoped attribute whose type is not ScopedIdGenerator.Id
143
// already exists under the same name. This works assuming the caller of
144
// this method does synchronization correctly.
145

146     long newId = 1;
147     if (currId == null) {
148       currId = new Id();
149       pageContext.setAttribute(key, currId, scope);
150     }
151     else if (currId.contains(groupId)) {
152       return currId.getValue(groupId);
153     }
154     else {
155       newId = currId.getCurrentValue() + 1;
156     }
157
158     currId.addValue(groupId, newId);
159     return newId;
160   }
161
162   /**
163    * Holds the ID value that is stored in one of the scopes. This special
164    * type is needed to eliminate the risk of overwriting someone else's scoped
165    * attribute.
166    */

167   private static final class Id implements Serializable JavaDoc {
168     private static final long serialVersionUID = 100L;
169
170     /**
171      * The ID value to hold
172      */

173     private long currentValue;
174
175     /**
176      * Unique ID values keyed on group IDs.
177      */

178     private HashMap JavaDoc valueMap;
179
180     /**
181      * Creates and initializes this object.
182      */

183     private Id() {
184       this.valueMap = new HashMap JavaDoc();
185     }
186
187     /**
188      * Adds a value along with its group.
189      *
190      * @param value the ID value to hold
191      * @param groupId the group ID
192      */

193     private void addValue(String JavaDoc groupId, long value) {
194       this.valueMap.put(groupId, new Long JavaDoc(value));
195       this.currentValue = value;
196     }
197
198     /**
199      * Checks whether a group ID exists.
200      *
201      * @param groupId the group ID
202      * @return true if the group exists, false otherwise
203      */

204     private boolean contains(String JavaDoc groupId) {
205       // groupId == null means no group ID was specified
206
if (groupId == null) {
207         return false;
208       }
209       return this.valueMap.containsKey(groupId);
210     }
211
212     /**
213      * Returns the ID value corresponding to the specified group ID.
214      *
215      * @param groupId the group ID
216      * @return the ID value
217      */

218     private long getValue(String JavaDoc groupId) {
219       // groupId == null means no group ID was specified
220
if (groupId == null) {
221         return this.currentValue;
222       }
223       return ((Long JavaDoc) this.valueMap.get(groupId)).longValue();
224     }
225
226     /**
227      * Returns the current ID value.
228      *
229      * @return the ID value
230      */

231     private long getCurrentValue() {
232       return this.currentValue;
233     }
234   }
235 }
236
Popular Tags