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.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            @Override
059            public String getCacheKey(String key) {
060                    if ((_maxLength > -1) && (key.length() < _maxLength)) {
061                            return key;
062                    }
063    
064                    try {
065                            _messageDigest.update(_charsetEncoder.encode(CharBuffer.wrap(key)));
066    
067                            byte[] bytes = _messageDigest.digest();
068    
069                            return encodeCacheKey(bytes);
070                    }
071                    catch (Exception e) {
072                            _log.error(e, e);
073    
074                            return key;
075                    }
076            }
077    
078            @Override
079            public String getCacheKey(String[] keys) {
080                    return getCacheKey(new StringBundler(keys));
081            }
082    
083            @Override
084            public String getCacheKey(StringBundler sb) {
085                    if ((_maxLength > -1) && (sb.length() < _maxLength)) {
086                            return sb.toString();
087                    }
088    
089                    try {
090                            for (int i = 0; i < sb.index(); i++) {
091                                    String key = sb.stringAt(i);
092    
093                                    _messageDigest.update(
094                                            _charsetEncoder.encode(CharBuffer.wrap(key)));
095                            }
096    
097                            byte[] bytes = _messageDigest.digest();
098    
099                            return encodeCacheKey(bytes);
100                    }
101                    catch (Exception e) {
102                            _log.error(e, e);
103    
104                            return sb.toString();
105                    }
106            }
107    
108            @Override
109            public boolean isCallingGetCacheKeyThreadSafe() {
110                    return _CALLING_GET_CACHE_KEY_THREAD_SAFE;
111            }
112    
113            public void setMaxLength(int maxLength) {
114                    _maxLength = maxLength;
115            }
116    
117            protected String encodeCacheKey(byte[] bytes) {
118                    for (int i = 0; i < bytes.length; i++) {
119                            int value = bytes[i] & 0xff;
120    
121                            _encodeBuffer[i * 2] = _HEX_CHARACTERS[value >> 4];
122                            _encodeBuffer[i * 2 + 1] = _HEX_CHARACTERS[value & 0xf];
123                    }
124    
125                    return new String(_encodeBuffer);
126            }
127    
128            private static final String _ALGORITHM_MD5 = "MD5";
129    
130            private static final boolean _CALLING_GET_CACHE_KEY_THREAD_SAFE = false;
131    
132            private static final char[] _HEX_CHARACTERS = {
133                    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd',
134                    'e', 'f'
135            };
136    
137            private static Log _log = LogFactoryUtil.getLog(
138                    JavaMD5CacheKeyGenerator.class);
139    
140            private CharsetEncoder _charsetEncoder;
141            private char[] _encodeBuffer = new char[32];
142            private int _maxLength = -1;
143            private MessageDigest _messageDigest;
144    
145    }