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.memcached;
016    
017    import com.liferay.portal.kernel.cache.CacheListener;
018    import com.liferay.portal.kernel.cache.CacheListenerScope;
019    import com.liferay.portal.kernel.cache.PortalCache;
020    import com.liferay.portal.kernel.log.Log;
021    import com.liferay.portal.kernel.log.LogFactoryUtil;
022    
023    import java.util.ArrayList;
024    import java.util.Collection;
025    import java.util.List;
026    import java.util.Map;
027    import java.util.concurrent.Future;
028    import java.util.concurrent.TimeUnit;
029    
030    import net.spy.memcached.MemcachedClientIF;
031    
032    /**
033     * @author Michael C. Han
034     */
035    public class PooledMemcachePortalCache<V> implements PortalCache<String, V> {
036    
037            public PooledMemcachePortalCache(
038                    String name, MemcachedClientFactory memcachedClientFactory, int timeout,
039                    TimeUnit timeoutTimeUnit) {
040    
041                    _name = name;
042                    _memcachedClientFactory = memcachedClientFactory;
043                    _timeout = timeout;
044                    _timeoutTimeUnit = timeoutTimeUnit;
045            }
046    
047            public void destroy() {
048                    try {
049                            _memcachedClientFactory.close();
050                    }
051                    catch (Exception e) {
052                    }
053            }
054    
055            public Collection<V> get(Collection<String> keys) {
056                    MemcachedClientIF memcachedClient = null;
057    
058                    try {
059                            memcachedClient = _memcachedClientFactory.getMemcachedClient();
060                    }
061                    catch (Exception e) {
062                            return null;
063                    }
064    
065                    List<String> processedKeys = new ArrayList<String>(keys.size());
066    
067                    for (String key : keys) {
068                            String processedKey = _name.concat(key);
069    
070                            processedKeys.add(processedKey);
071                    }
072    
073                    Map<String, Object> values = null;
074    
075                    try {
076                            Future<Map<String, Object>> future = null;
077    
078                            try {
079                                    future = memcachedClient.asyncGetBulk(processedKeys);
080                            }
081                            catch (IllegalArgumentException iae) {
082                                    if (_log.isWarnEnabled()) {
083                                            _log.warn("Error retrieving with keys " + keys, iae);
084                                    }
085    
086                                    future.cancel(true);
087                            }
088    
089                            try {
090                                    values = future.get(_timeout, _timeoutTimeUnit);
091                            }
092                            catch (Throwable t) {
093                                    if (_log.isWarnEnabled()) {
094                                            _log.warn("Memcache operation error", t);
095                                    }
096    
097                                    future.cancel(true);
098                            }
099                    }
100                    finally {
101                            cleanupClient(memcachedClient);
102                    }
103    
104                    return (Collection<V>)values.values();
105            }
106    
107            public V get(String key) {
108                    MemcachedClientIF memcachedClient = null;
109    
110                    try {
111                            memcachedClient = _memcachedClientFactory.getMemcachedClient();
112                    }
113                    catch (Exception e) {
114                            return null;
115                    }
116    
117                    String processedKey = _name.concat(key);
118    
119                    try {
120                            Future<Object> future = null;
121    
122                            try {
123                                    future = memcachedClient.asyncGet(processedKey);
124                            }
125                            catch (IllegalArgumentException iae) {
126                                    if (_log.isWarnEnabled()) {
127                                            _log.warn("Error retrieving with key " + key, iae);
128                                    }
129                            }
130    
131                            Object value = null;
132    
133                            try {
134                                    value = future.get(_timeout, _timeoutTimeUnit);
135                            }
136                            catch (Exception e) {
137                                    future.cancel(true);
138                            }
139    
140                            return (V)value;
141                    }
142                    finally {
143                            cleanupClient(memcachedClient);
144                    }
145            }
146    
147            public String getName() {
148                    return _name;
149            }
150    
151            public void put(String key, V value) {
152                    put(key, value, _timeToLive);
153            }
154    
155            public void put(String key, V value, int timeToLive) {
156                    MemcachedClientIF memcachedClient = null;
157    
158                    try {
159                            memcachedClient = _memcachedClientFactory.getMemcachedClient();
160                    }
161                    catch (Exception e) {
162                            return;
163                    }
164    
165                    String processedKey = _name.concat(key);
166    
167                    try {
168                            memcachedClient.set(processedKey, timeToLive, value);
169                    }
170                    catch (IllegalArgumentException iae) {
171                            if (_log.isWarnEnabled()) {
172                                    _log.warn("Error storing value with key " + key, iae);
173                            }
174                    }
175                    finally {
176                            cleanupClient(memcachedClient);
177                    }
178            }
179    
180            public void registerCacheListener(CacheListener<String, V> cacheListener) {
181                    registerCacheListener(cacheListener, CacheListenerScope.ALL);
182            }
183    
184            public void registerCacheListener(
185                    CacheListener<String, V> cacheListener,
186                    CacheListenerScope cacheListenerScope) {
187    
188                    throw new UnsupportedOperationException();
189            }
190    
191            public void remove(String key) {
192                    MemcachedClientIF memcachedClient = null;
193    
194                    try {
195                            memcachedClient = _memcachedClientFactory.getMemcachedClient();
196                    }
197                    catch (Exception e) {
198                            return;
199                    }
200    
201                    String processedKey = _name.concat(key);
202    
203                    try {
204                            memcachedClient.delete(processedKey);
205                    }
206                    catch (IllegalArgumentException iae) {
207                            if (_log.isWarnEnabled()) {
208                                    _log.warn("Unable to delete value with key " + key, iae);
209                            }
210                    }
211                    finally {
212                            cleanupClient(memcachedClient);
213                    }
214            }
215    
216            public void removeAll() {
217                    MemcachedClientIF memcachedClient = null;
218    
219                    try {
220                            memcachedClient = _memcachedClientFactory.getMemcachedClient();
221                    }
222                    catch (Exception e) {
223                            return;
224                    }
225    
226                    try {
227                            memcachedClient.flush();
228                    }
229                    finally {
230                            cleanupClient(memcachedClient);
231                    }
232            }
233    
234            public void setTimeToLive(int timeToLive) {
235                    _timeToLive = timeToLive;
236            }
237    
238            public void unregisterCacheListener(
239                    CacheListener<String, V> cacheListener) {
240            }
241    
242            public void unregisterCacheListeners() {
243            }
244    
245            protected void cleanupClient(MemcachedClientIF memcachedClient) {
246                    try {
247                            _memcachedClientFactory.returnMemcachedObject(memcachedClient);
248                    }
249                    catch (Exception e) {
250                    }
251            }
252    
253            private static Log _log = LogFactoryUtil.getLog(MemcachePortalCache.class);
254    
255            private MemcachedClientFactory _memcachedClientFactory;
256            private String _name;
257            private int _timeout;
258            private TimeUnit _timeoutTimeUnit;
259            private int _timeToLive;
260    
261    }