Save This Page
Home » tapestry-src-5.0.19 » org.apache.tapestry5.ioc.internal.util » [javadoc | source]
    1   // Copyright 2004, 2005, 2006 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.tapestry5.ioc.internal.util;
   16   
   17   import java.util.HashMap;
   18   import java.util.IdentityHashMap;
   19   import java.util.List;
   20   import java.util.Map;
   21   
   22   
   23   /**
   24    * Used to "uniquify" names within a given context. A base name is passed in, and the return value is the base name, or
   25    * the base name extended with a suffix to make it unique.
   26    * <p/>
   27    * This class is not threadsafe.
   28    */
   29   
   30   public final class IdAllocator
   31   {
   32       private static final String SEPARATOR = "_";
   33   
   34       /**
   35        * Map from allocated id to a generator for names associated with the allocated id.
   36        */
   37       private final Map<String, NameGenerator> generatorMap;
   38   
   39       private final String namespace;
   40   
   41       /**
   42        * Generates unique names with a particular prefix.
   43        */
   44       private static class NameGenerator implements Cloneable
   45       {
   46           private final String baseId;
   47   
   48           private int index;
   49   
   50           NameGenerator(String baseId)
   51           {
   52               this.baseId = baseId + SEPARATOR;
   53           }
   54   
   55           public String nextId()
   56           {
   57               return baseId + index++;
   58           }
   59   
   60           /**
   61            * Clones this instance, returning an equivalent but seperate copy.
   62            */
   63           @SuppressWarnings({ "CloneDoesntDeclareCloneNotSupportedException" })
   64           @Override
   65           public NameGenerator clone()
   66           {
   67               try
   68               {
   69                   return (NameGenerator) super.clone();
   70               }
   71               catch (CloneNotSupportedException ex)
   72               {
   73                   // Unreachable!
   74                   throw new RuntimeException(ex);
   75               }
   76           }
   77       }
   78   
   79       /**
   80        * Creates a new allocator with no namespace.
   81        */
   82       public IdAllocator()
   83       {
   84           this("");
   85       }
   86   
   87       /**
   88        * Creates a new allocator with the provided namespace.
   89        */
   90       public IdAllocator(String namespace)
   91       {
   92           this(namespace, new HashMap<String, NameGenerator>());
   93       }
   94   
   95       private IdAllocator(String namespace, Map<String, NameGenerator> generatorMap)
   96       {
   97           this.namespace = namespace;
   98           this.generatorMap = generatorMap;
   99       }
  100   
  101       /**
  102        * Returns a list of all allocated ids, sorted alphabetically.
  103        */
  104       public List<String> getAllocatedIds()
  105       {
  106           return InternalUtils.sortedKeys(generatorMap);
  107       }
  108   
  109       /**
  110        * Creates a clone of this IdAllocator instance, copying the allocator's namespace and key map.
  111        */
  112       @SuppressWarnings({ "CloneDoesntCallSuperClone" })
  113       @Override
  114       public IdAllocator clone()
  115       {
  116           // Copying the generatorMap is tricky; multiple keys will point to the same NameGenerator
  117           // instance. We need to clone the NameGenerators, then build a new map around the clones.
  118   
  119           IdentityHashMap<NameGenerator, NameGenerator> transformMap = new IdentityHashMap<NameGenerator, NameGenerator>();
  120   
  121           for (NameGenerator original : generatorMap.values())
  122           {
  123               NameGenerator copy = original.clone();
  124   
  125               transformMap.put(original, copy);
  126           }
  127   
  128           Map<String, NameGenerator> mapCopy = CollectionFactory.newMap();
  129   
  130           for (String key : generatorMap.keySet())
  131           {
  132               NameGenerator original = generatorMap.get(key);
  133               NameGenerator copy = transformMap.get(original);
  134   
  135               mapCopy.put(key, copy);
  136           }
  137   
  138           return new IdAllocator(namespace, mapCopy);
  139       }
  140   
  141       /**
  142        * Allocates the id. Repeated calls for the same name will return "name", "name_0", "name_1", etc.
  143        */
  144   
  145       public String allocateId(String name)
  146       {
  147           String key = name + namespace;
  148   
  149           NameGenerator g = generatorMap.get(key);
  150           String result;
  151   
  152           if (g == null)
  153           {
  154               g = new NameGenerator(key);
  155               result = key;
  156           }
  157           else result = g.nextId();
  158   
  159           // Handle the degenerate case, where a base name of the form "foo_0" has been
  160           // requested. Skip over any duplicates thus formed.
  161   
  162           while (generatorMap.containsKey(result)) result = g.nextId();
  163   
  164           generatorMap.put(result, g);
  165   
  166           return result;
  167       }
  168   
  169       /**
  170        * Checks to see if a given name has been allocated.
  171        */
  172       public boolean isAllocated(String name)
  173       {
  174           return generatorMap.containsKey(name);
  175       }
  176   
  177       /**
  178        * Clears the allocator, resetting it to freshly allocated state.
  179        */
  180   
  181       public void clear()
  182       {
  183           generatorMap.clear();
  184       }
  185   }

Save This Page
Home » tapestry-src-5.0.19 » org.apache.tapestry5.ioc.internal.util » [javadoc | source]