001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied.  See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019package org.apache.shiro.cache.ehcache;
020
021import net.sf.ehcache.Element;
022import org.apache.shiro.cache.Cache;
023import org.apache.shiro.cache.CacheException;
024import org.apache.shiro.util.CollectionUtils;
025import org.slf4j.Logger;
026import org.slf4j.LoggerFactory;
027
028import java.util.*;
029
030/**
031 * Shiro {@link org.apache.shiro.cache.Cache} implementation that wraps an {@link net.sf.ehcache.Ehcache} instance.
032 *
033 * @since 0.2
034 */
035public class EhCache<K, V> implements Cache<K, V> {
036
037    /**
038     * Private internal log instance.
039     */
040    private static final Logger log = LoggerFactory.getLogger(EhCache.class);
041
042    /**
043     * The wrapped Ehcache instance.
044     */
045    private net.sf.ehcache.Ehcache cache;
046
047    /**
048     * Constructs a new EhCache instance with the given cache.
049     *
050     * @param cache - delegate EhCache instance this Shiro cache instance will wrap.
051     */
052    public EhCache(net.sf.ehcache.Ehcache cache) {
053        if (cache == null) {
054            throw new IllegalArgumentException("Cache argument cannot be null.");
055        }
056        this.cache = cache;
057    }
058
059    /**
060     * Gets a value of an element which matches the given key.
061     *
062     * @param key the key of the element to return.
063     * @return The value placed into the cache with an earlier put, or null if not found or expired
064     */
065    public V get(K key) throws CacheException {
066        try {
067            if (log.isTraceEnabled()) {
068                log.trace("Getting object from cache [" + cache.getName() + "] for key [" + key + "]");
069            }
070            if (key == null) {
071                return null;
072            } else {
073                Element element = cache.get(key);
074                if (element == null) {
075                    if (log.isTraceEnabled()) {
076                        log.trace("Element for [" + key + "] is null.");
077                    }
078                    return null;
079                } else {
080                    //noinspection unchecked
081                    return (V) element.getObjectValue();
082                }
083            }
084        } catch (Throwable t) {
085            throw new CacheException(t);
086        }
087    }
088
089    /**
090     * Puts an object into the cache.
091     *
092     * @param key   the key.
093     * @param value the value.
094     */
095    public V put(K key, V value) throws CacheException {
096        if (log.isTraceEnabled()) {
097            log.trace("Putting object in cache [" + cache.getName() + "] for key [" + key + "]");
098        }
099        try {
100            V previous = get(key);
101            Element element = new Element(key, value);
102            cache.put(element);
103            return previous;
104        } catch (Throwable t) {
105            throw new CacheException(t);
106        }
107    }
108
109    /**
110     * Removes the element which matches the key.
111     *
112     * <p>If no element matches, nothing is removed and no Exception is thrown.</p>
113     *
114     * @param key the key of the element to remove
115     */
116    public V remove(K key) throws CacheException {
117        if (log.isTraceEnabled()) {
118            log.trace("Removing object from cache [" + cache.getName() + "] for key [" + key + "]");
119        }
120        try {
121            V previous = get(key);
122            cache.remove(key);
123            return previous;
124        } catch (Throwable t) {
125            throw new CacheException(t);
126        }
127    }
128
129    /**
130     * Removes all elements in the cache, but leaves the cache in a useable state.
131     */
132    public void clear() throws CacheException {
133        if (log.isTraceEnabled()) {
134            log.trace("Clearing all objects from cache [" + cache.getName() + "]");
135        }
136        try {
137            cache.removeAll();
138        } catch (Throwable t) {
139            throw new CacheException(t);
140        }
141    }
142
143    public int size() {
144        try {
145            return cache.getSize();
146        } catch (Throwable t) {
147            throw new CacheException(t);
148        }
149    }
150
151    public Set<K> keys() {
152        try {
153            @SuppressWarnings({"unchecked"})
154            List<K> keys = cache.getKeys();
155            if (!CollectionUtils.isEmpty(keys)) {
156                return Collections.unmodifiableSet(new LinkedHashSet<K>(keys));
157            } else {
158                return Collections.emptySet();
159            }
160        } catch (Throwable t) {
161            throw new CacheException(t);
162        }
163    }
164
165    public Collection<V> values() {
166        try {
167            @SuppressWarnings({"unchecked"})
168            List<K> keys = cache.getKeys();
169            if (!CollectionUtils.isEmpty(keys)) {
170                List<V> values = new ArrayList<V>(keys.size());
171                for (K key : keys) {
172                    V value = get(key);
173                    if (value != null) {
174                        values.add(value);
175                    }
176                }
177                return Collections.unmodifiableList(values);
178            } else {
179                return Collections.emptyList();
180            }
181        } catch (Throwable t) {
182            throw new CacheException(t);
183        }
184    }
185
186    /**
187     * Returns the size (in bytes) that this EhCache is using in memory (RAM), or <code>-1</code> if that
188     * number is unknown or cannot be calculated.
189     *
190     * @return the size (in bytes) that this EhCache is using in memory (RAM), or <code>-1</code> if that
191     *         number is unknown or cannot be calculated.
192     */
193    public long getMemoryUsage() {
194        try {
195            return cache.calculateInMemorySize();
196        }
197        catch (Throwable t) {
198            return -1;
199        }
200    }
201
202    /**
203     * Returns the size (in bytes) that this EhCache's memory store is using (RAM), or <code>-1</code> if
204     * that number is unknown or cannot be calculated.
205     *
206     * @return the size (in bytes) that this EhCache's memory store is using (RAM), or <code>-1</code> if
207     *         that number is unknown or cannot be calculated.
208     */
209    public long getMemoryStoreSize() {
210        try {
211            return cache.getMemoryStoreSize();
212        }
213        catch (Throwable t) {
214            throw new CacheException(t);
215        }
216    }
217
218    /**
219     * Returns the size (in bytes) that this EhCache's disk store is consuming or <code>-1</code> if
220     * that number is unknown or cannot be calculated.
221     *
222     * @return the size (in bytes) that this EhCache's disk store is consuming or <code>-1</code> if
223     *         that number is unknown or cannot be calculated.
224     */
225    public long getDiskStoreSize() {
226        try {
227            return cache.getDiskStoreSize();
228        } catch (Throwable t) {
229            throw new CacheException(t);
230        }
231    }
232
233    /**
234     * Returns &quot;EhCache [&quot; + cache.getName() + &quot;]&quot;
235     *
236     * @return &quot;EhCache [&quot; + cache.getName() + &quot;]&quot;
237     */
238    public String toString() {
239        return "EhCache [" + cache.getName() + "]";
240    }
241}