001    /**
002     * Copyright (c) 2000-2012 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.cache.key;
016    
017    import com.liferay.portal.kernel.cache.key.CacheKeyGenerator;
018    import com.liferay.portal.kernel.log.Log;
019    import com.liferay.portal.kernel.log.LogFactoryUtil;
020    import com.liferay.portal.kernel.nio.charset.CharsetEncoderUtil;
021    import com.liferay.portal.kernel.util.StringBundler;
022    import com.liferay.portal.kernel.util.StringPool;
023    
024    import java.nio.CharBuffer;
025    import java.nio.charset.CharsetEncoder;
026    
027    import java.security.MessageDigest;
028    import java.security.NoSuchAlgorithmException;
029    
030    /**
031     * @author Michael C. Han
032     * @author Shuyang Zhou
033     */
034    public class JavaMD5CacheKeyGenerator extends BaseCacheKeyGenerator {
035    
036            public JavaMD5CacheKeyGenerator() throws NoSuchAlgorithmException {
037                    this(-1);
038            }
039    
040            public JavaMD5CacheKeyGenerator(int maxLength)
041                    throws NoSuchAlgorithmException {
042    
043                    _maxLength = maxLength;
044                    _messageDigest = MessageDigest.getInstance(_ALGORITHM_MD5);
045                    _charsetEncoder = CharsetEncoderUtil.getCharsetEncoder(StringPool.UTF8);
046            }
047    
048            @Override
049            public CacheKeyGenerator clone() {
050                    try {
051                            return new JavaMD5CacheKeyGenerator(_maxLength);
052                    }
053                    catch (NoSuchAlgorithmException nsae) {
054                            throw new IllegalStateException(nsae.getMessage(), nsae);
055                    }
056            }
057    
058            public String getCacheKey(String key) {
059                    if ((_maxLength > -1) && (key.length() < _maxLength)) {
060                            return key;
061                    }
062    
063                    try {
064                            _messageDigest.update(_charsetEncoder.encode(CharBuffer.wrap(key)));
065    
066                            byte[] bytes = _messageDigest.digest();
067    
068                            return encodeCacheKey(bytes);
069                    }
070                    catch (Exception e) {
071                            _log.error(e, e);
072    
073                            return key;
074                    }
075            }
076    
077            public String getCacheKey(String[] keys) {
078                    return getCacheKey(new StringBundler(keys));
079            }
080    
081            public String getCacheKey(StringBundler sb) {
082                    if ((_maxLength > -1) && (sb.length() < _maxLength)) {
083                            return sb.toString();
084                    }
085    
086                    try {
087                            for (int i = 0; i < sb.index(); i++) {
088                                    String key = sb.stringAt(i);
089    
090                                    _messageDigest.update(
091                                            _charsetEncoder.encode(CharBuffer.wrap(key)));
092                            }
093    
094                            byte[] bytes = _messageDigest.digest();
095    
096                            return encodeCacheKey(bytes);
097                    }
098                    catch (Exception e) {
099                            _log.error(e, e);
100    
101                            return sb.toString();
102                    }
103            }
104    
105            @Override
106            public boolean isCallingGetCacheKeyThreadSafe() {
107                    return _CALLING_GET_CACHE_KEY_THREAD_SAFE;
108            }
109    
110            public void setMaxLength(int maxLength) {
111                    _maxLength = maxLength;
112            }
113    
114            protected String encodeCacheKey(byte[] bytes) {
115                    for (int i = 0; i < bytes.length; i++) {
116                            int value = bytes[i] & 0xff;
117    
118                            _encodeBuffer[i * 2] = _HEX_CHARACTERS[value >> 4];
119                            _encodeBuffer[i * 2 + 1] = _HEX_CHARACTERS[value & 0xf];
120                    }
121    
122                    return new String(_encodeBuffer);
123            }
124    
125            private static final String _ALGORITHM_MD5 = "MD5";
126    
127            private static final boolean _CALLING_GET_CACHE_KEY_THREAD_SAFE = false;
128    
129            private static final char[] _HEX_CHARACTERS = {
130                    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd',
131                    'e', 'f'
132            };
133    
134            private static Log _log = LogFactoryUtil.getLog(
135                    JavaMD5CacheKeyGenerator.class);
136    
137            private CharsetEncoder _charsetEncoder;
138            private char[] _encodeBuffer = new char[32];
139            private int _maxLength = -1;
140            private MessageDigest _messageDigest;
141    
142    }