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     */
019    package org.apache.shiro.cache.ehcache;
020    
021    import net.sf.ehcache.Element;
022    import org.apache.shiro.cache.Cache;
023    import org.apache.shiro.cache.CacheException;
024    import org.apache.shiro.util.CollectionUtils;
025    import org.slf4j.Logger;
026    import org.slf4j.LoggerFactory;
027    
028    import 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     */
035    public 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    }