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
015package org.apache.tapestry.util;
016
017import java.util.HashMap;
018import java.util.Map;
019
020import 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
030public 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}