View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  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,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.myfaces.view.facelets.impl;
20  
21  import java.util.ArrayList;
22  import java.util.List;
23  
24  /**
25   * Hierarchical counter to generate unique ids.
26   * 
27   * @author Leonardo Uribe
28   *
29   */
30  public class SectionUniqueIdCounter
31  {
32      private List<Section> _counterStack;
33      
34      private int _activeSection;
35      
36      private final String _prefix;
37      
38      private final StringBuilder _builder;
39      
40      private char[] _bufferConversion;
41      
42      private final int _radix;
43      
44      private final String[] _uniqueIdsCache;
45      
46      public SectionUniqueIdCounter()
47      {
48          _activeSection = 0;
49          _radix = Character.MAX_RADIX;
50          _counterStack = new ArrayList<Section>();
51          _counterStack.add(new Section(null,1,_radix));
52          _prefix = null;
53          _builder = new StringBuilder(30);
54          _bufferConversion = new char[15];
55          _uniqueIdsCache = null;
56      }
57      
58      public SectionUniqueIdCounter(String prefix)
59      {
60          _activeSection = 0;
61          _radix = Character.MAX_RADIX;
62          _counterStack = new ArrayList<Section>();
63          _counterStack.add(new Section(null,1,_radix));
64          _prefix = prefix;
65          _builder = new StringBuilder(30);
66          _bufferConversion = new char[15];
67          _uniqueIdsCache = null;
68      }
69      
70      public SectionUniqueIdCounter(String prefix, String[] cache)
71      {
72          _activeSection = 0;
73          _radix = Character.MAX_RADIX;
74          _counterStack = new ArrayList<Section>();
75          _counterStack.add(new Section(null,1,_radix));
76          _prefix = prefix;
77          _builder = new StringBuilder(30);
78          _bufferConversion = new char[15];
79          _uniqueIdsCache = cache;
80      }
81      
82      public SectionUniqueIdCounter(String prefix, int radix)
83      {
84          _activeSection = 0;
85          _radix = radix;
86          _counterStack = new ArrayList<Section>();
87          _counterStack.add(new Section(null,1,_radix));
88          _prefix = prefix;
89          _builder = new StringBuilder(30);
90          _bufferConversion = new char[15];
91          _uniqueIdsCache = null;
92      }
93  
94      /**
95       * Creates an array of the generated unique ids for an specified prefix,
96       * than can be used later to prevent calculate the same String over and over.
97       * 
98       * @param prefix
99       * @param count
100      * @return 
101      */
102     public static String[] generateUniqueIdCache(String prefix, int count)
103     {
104         String[] cache = new String[count];
105         SectionUniqueIdCounter counter = new SectionUniqueIdCounter(prefix);
106         for (int i = 0; i < count ; i++)
107         {
108             cache[i] = counter.generateUniqueId();
109         }
110         return cache;
111     }
112 
113     public String startUniqueIdSection()
114     {
115         //1. Calculate prefix
116         _builder.delete(0, _builder.length());
117         
118         if (!_counterStack.isEmpty())
119         {
120             String lastPrefix = _counterStack.get(_counterStack.size()-1).getPrefix();
121             if (lastPrefix != null)
122             {
123                 _builder.append(lastPrefix);
124                 _builder.append('_');
125             }
126             appendToBuilder(_counterStack.get(_counterStack.size()-1).getCounter(),
127                 _radix, _builder, _bufferConversion);
128         }
129         
130         _counterStack.add(new Section(_builder.toString(),1,_radix));
131         _activeSection++;
132         return _builder.toString();
133     }
134     
135     public String startUniqueIdSection(String base)
136     {
137         //1. Calculate prefix
138         _builder.delete(0, _builder.length());
139         
140         if (!_counterStack.isEmpty())
141         {
142             String lastPrefix = _counterStack.get(_counterStack.size()-1).getPrefix();
143             if (lastPrefix != null)
144             {
145                 _builder.append(lastPrefix);
146                 _builder.append('_');
147             }
148             appendToBuilder(_counterStack.get(_counterStack.size()-1).getCounter()-1,
149                 _radix, _builder, _bufferConversion);
150         }
151 
152         if (base != null && base.length() > 0)
153         {
154             _builder.append('_');
155             _builder.append(base);
156         }
157         _counterStack.add(new Section(_builder.toString(),1,_radix));
158         _activeSection++;
159         return _builder.toString();
160     }
161 
162     public String generateUniqueId()
163     {
164         if (_activeSection == 0 && _uniqueIdsCache != null)
165         {
166             long i = _counterStack.get(_activeSection).getCounter();
167             if (((int)i) < (long)_uniqueIdsCache.length)
168             {
169                 _counterStack.get(_activeSection).incrementUniqueId();
170                 return _uniqueIdsCache[((int)i)-1];
171             }
172             else
173             {
174                 return _counterStack.get(_activeSection).generateUniqueId(_prefix);
175             }
176         }
177         else
178         {
179             return _counterStack.get(_activeSection).generateUniqueId(_prefix);
180         }
181     }
182     
183     public void generateUniqueId(StringBuilder builderToAdd)
184     {
185         _counterStack.get(_activeSection).generateUniqueId(_prefix, builderToAdd);
186     }
187     
188     public void incrementUniqueId()
189     {
190         _counterStack.get(_activeSection).incrementUniqueId();
191     }
192     
193     public void endUniqueIdSection()
194     {
195         if (_activeSection <= 0)
196         {
197             _counterStack.get(_activeSection).generateUniqueId(_prefix);
198             return;
199         }
200         else
201         {
202             _counterStack.remove(_activeSection);
203             _activeSection--;
204             _counterStack.get(_activeSection).generateUniqueId(_prefix);
205         }
206     }
207     
208     public void endUniqueIdSection(String base)
209     {
210         if (_activeSection <= 0)
211         {
212             return;
213         }
214         else
215         {
216             _counterStack.remove(_activeSection);
217             _activeSection--;
218         }
219     }
220     
221     private static class Section
222     {
223         
224         private String prefix;
225         private long counter;
226         private final StringBuilder _builder;
227         private char[] _bufferConversion;
228         private final int _radix;
229         
230         public Section(String prefix, long counter, int radix)
231         {
232             super();
233             this.prefix = prefix;
234             this.counter = counter;
235             _builder = new StringBuilder(30);
236             _bufferConversion = new char[15];
237             _radix = radix;
238         }
239 
240         public long getCounter()
241         {
242             return counter;
243         }
244         
245         public void incrementUniqueId()
246         {
247             this.counter++;
248         }
249 
250         public void generateUniqueId(String base, StringBuilder builder)
251         {
252             long i = this.counter;
253             this.counter++;
254             //_builder.delete(0, _builder.length());
255             if (base != null)
256             {
257                 builder.append(base);
258             }
259             if (this.prefix != null)
260             {
261                 builder.append(this.prefix);
262                 builder.append('_');
263             }
264             // By performance reasons, Long.toString is a very expensive
265             // operation in this location, because it triggers a new String()
266             //_builder.append(Long.toString(i, _radix));
267             appendToBuilder(i, _radix, builder, _bufferConversion);
268             //return _builder.toString();
269         }
270         
271         public String generateUniqueId(String base)
272         {
273             long i = this.counter;
274             this.counter++;
275             _builder.delete(0, _builder.length());
276             if (base != null)
277             {
278                 _builder.append(base);
279             }
280             if (this.prefix != null)
281             {
282                 _builder.append(this.prefix);
283                 _builder.append('_');
284             }
285             // By performance reasons, Long.toString is a very expensive
286             // operation in this location, because it triggers a new String()
287             //_builder.append(Long.toString(i, _radix));
288             appendToBuilder(i, _radix, _builder, _bufferConversion);
289             return _builder.toString();
290         }
291 
292         /**
293          * @return the prefix
294          */
295         public String getPrefix()
296         {
297             return prefix;
298         }
299     }
300     
301     //From Harmony Long.toString(l,radix)
302     private static void appendToBuilder(long l, int radix, StringBuilder builder, char[] bufferConversion)
303     {
304         if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX)
305         {
306             radix = 10;
307         }
308         if (l == 0)
309         {
310             builder.append('0');
311             return;
312         }
313 
314         int count = 2;
315         long j = l;
316         boolean negative = l < 0;
317         if (!negative)
318         {
319             count = 1;
320             j = -l;
321         }
322         while ((l /= radix) != 0)
323         {
324             count++;
325         }
326 
327         if (bufferConversion.length < count)
328         {
329             bufferConversion = new char[count];
330         }
331         int finalCount = count;
332 
333         char[] buffer = bufferConversion;
334         do 
335         {
336             int ch = 0 - (int) (j % radix);
337             if (ch > 9)
338             {
339                 ch = ch - 10 + 'a';
340             }
341             else
342             {
343                 ch += '0';
344             }
345             buffer[--count] = (char) ch;
346             j /= radix;
347         }
348         while (j != 0);
349         if (negative)
350         {
351             buffer[0] = '-';
352         }
353         for (int i = 0; i < finalCount; i++)
354         {
355             builder.append(buffer[i]);
356         }
357         //return new String(0, buffer.length, buffer);
358     }
359 }