001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.kernel.util;
016    
017    import java.util.HashMap;
018    import java.util.Map;
019    
020    /**
021     * <p>
022     * See http://issues.liferay.com/browse/LPS-6872.
023     * </p>
024     *
025     * @author Shuyang Zhou
026     * @author Brian Wing Shun Chan
027     */
028    public class DeterminateKeyGenerator {
029    
030            public static String generate(String input) {
031                    return generate(input, _DEFAULT_LENGTH);
032            }
033    
034            public static String generate(String input, int length) {
035                    if (input == null) {
036                            throw new IllegalArgumentException("Input is null");
037                    }
038    
039                    if (length <= 0) {
040                            throw new IllegalArgumentException(
041                                    "Length is less than or equal to 0");
042                    }
043    
044                    Map<String, Integer> seedMap = _seedMap.get();
045    
046                    Integer previousSeed = seedMap.get(input);
047    
048                    int seed = 0;
049    
050                    if (previousSeed == null) {
051                            seed = input.hashCode();
052                    }
053                    else {
054                            seed = previousSeed;
055                    }
056    
057                    StringBuilder sb = new StringBuilder(length);
058    
059                    for (int i = 0; i < length; i++) {
060                            int index = 0;
061    
062                            if (seed > 0) {
063                                    index = seed % 26;
064                            }
065                            else {
066                                    index = -seed % 26;
067                            }
068    
069                            sb.append(_CHARACTERS[index]);
070    
071                            seed = _nextRandom(seed);
072                    }
073    
074                    seedMap.put(input, seed);
075    
076                    return sb.toString();
077            }
078    
079            public static void reset() {
080                    Map<String, Integer> seedMap = _seedMap.get();
081    
082                    seedMap.clear();
083            }
084    
085            public static void reset(String key) {
086                    Map<String, Integer> seedMap = _seedMap.get();
087    
088                    seedMap.remove(key);
089            }
090    
091            private static int _nextRandom(int seed) {
092                    return (seed % 127773) * 16807 - (seed / 127773) * 2836;
093            }
094    
095            private static final char[] _CHARACTERS =
096                    "abcdefghijklmnopqrstuvwxyz".toCharArray();
097    
098            private static final int _DEFAULT_LENGTH = 4;
099    
100            private static ThreadLocal<Map<String, Integer>> _seedMap =
101                    new AutoResetThreadLocal<Map<String, Integer>>(
102                            DeterminateKeyGenerator.class + "._seedMap",
103                            new HashMap<String, Integer>());
104    
105    }