001 // Copyright 2004, 2005 The Apache Software Foundation
002 //
003 // Licensed under the Apache License, Version 2.0 (the "License");
004 // you may not use this file except in compliance with the License.
005 // You may obtain a copy of the License at
006 //
007 // http://www.apache.org/licenses/LICENSE-2.0
008 //
009 // Unless required by applicable law or agreed to in writing, software
010 // distributed under the License is distributed on an "AS IS" BASIS,
011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012 // See the License for the specific language governing permissions and
013 // limitations under the License.
014
015 package org.apache.tapestry.util;
016
017 import java.util.HashMap;
018 import java.util.Map;
019
020 import org.apache.hivemind.util.Defense;
021
022 /**
023 * Used to "uniquify" names within a given context. A base name is passed in, and the return value
024 * is the base name, or the base name extended with a suffix to make it unique.
025 *
026 * @author Howard Lewis Ship
027 * @since 3.0
028 */
029
030 public class IdAllocator
031 {
032 private static final String SEPARATOR = "_";
033
034 private final Map _generatorMap = new HashMap();
035
036 private final String _namespace;
037
038 private static class NameGenerator
039 {
040 private final String _baseId;
041
042 private int _index;
043
044 NameGenerator(String baseId)
045 {
046 _baseId = baseId + SEPARATOR;
047 }
048
049 public String nextId()
050 {
051 return _baseId + _index++;
052 }
053 }
054
055 public IdAllocator()
056 {
057 this("");
058 }
059
060 public IdAllocator(String namespace)
061 {
062 Defense.notNull(namespace, "namespace");
063
064 _namespace = namespace;
065 }
066
067 /**
068 * Allocates the id. Repeated calls for the same name will return "name", "name_0", "name_1",
069 * etc.
070 */
071
072 public String allocateId(String name)
073 {
074 String key = name + _namespace;
075
076 NameGenerator g = (NameGenerator) _generatorMap.get(key);
077 String result = null;
078
079 if (g == null)
080 {
081 g = new NameGenerator(key);
082 result = key;
083 }
084 else
085 result = g.nextId();
086
087 // Handle the degenerate case, where a base name of the form "foo$0" has been
088 // requested. Skip over any duplicates thus formed.
089
090 while (_generatorMap.containsKey(result))
091 result = g.nextId();
092
093 _generatorMap.put(result, g);
094
095 return result;
096 }
097
098 /**
099 * Clears the allocator, resetting it to freshly allocated state.
100 */
101
102 public void clear()
103 {
104 _generatorMap.clear();
105 }
106 }