use the new session manager interface
[java-idp.git] / src / edu / internet2 / middleware / shibboleth / common / provider / MemoryCache.java
1 /*
2  * Copyright [2005] [University Corporation for Advanced Internet Development, Inc.]
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package edu.internet2.middleware.shibboleth.common.provider;
18
19 import java.util.Collections;
20 import java.util.HashMap;
21 import java.util.HashSet;
22 import java.util.Iterator;
23 import java.util.Map;
24 import java.util.Set;
25 import java.util.Map.Entry;
26
27 import org.apache.log4j.Logger;
28
29 import edu.internet2.middleware.shibboleth.common.Cache;
30 import edu.internet2.middleware.shibboleth.common.CacheException;
31
32 /**
33  * <code>Cache</code> implementation that uses java objects to cache data. This implementation will reap expired
34  * entries.
35  * 
36  * @author Walter Hoehn
37  */
38
39 public class MemoryCache extends BaseCache implements Cache {
40
41         private MemoryCacheCleaner cleaner = new MemoryCacheCleaner();
42         private static Logger log = Logger.getLogger(MemoryCache.class.getName());
43         private Map<String, CacheEntry> entries = Collections.synchronizedMap(new HashMap<String, CacheEntry>());
44
45         public MemoryCache(String name) {
46
47                 super(name, Cache.CacheType.SERVER_SIDE);
48         }
49
50         public boolean contains(String key) throws CacheException {
51
52                 CacheEntry entry = entries.get(key);
53                 if (entry == null) { return false; }
54
55                 // Clean cache if it is expired
56                 if (entry.isExpired()) {
57                         log.debug("Found expired object.  Deleting...");
58                         entries.remove(key);
59                         return false;
60                 }
61
62                 // OK, we have it
63                 return true;
64         }
65
66         public void remove(String key) throws CacheException {
67
68                 entries.remove(key);
69         }
70
71         public String retrieve(String key) throws CacheException {
72
73                 CacheEntry entry = entries.get(key);
74                 if (entry == null) { return null; }
75
76                 // Clean cache if it is expired
77                 if (entry.isExpired()) {
78                         log.debug("Found expired object.  Deleting...");
79                         entries.remove(key);
80                         return null;
81                 }
82
83                 return entry.value;
84         }
85
86         public void store(String key, String value, long duration) throws CacheException {
87
88                 entries.put(key, new CacheEntry(value, duration));
89         }
90
91         protected void destroy() {
92
93                 synchronized (cleaner) {
94                         if (cleaner != null) {
95                                 cleaner.shutdown = true;
96                                 cleaner.interrupt();
97                         }
98                 }
99         }
100
101         protected void finalize() throws Throwable {
102
103                 super.finalize();
104                 destroy();
105         }
106
107         private class MemoryCacheCleaner extends Thread {
108
109                 private boolean shutdown = false;
110                 private Thread master;
111
112                 private MemoryCacheCleaner() {
113
114                         super("edu.internet2.middleware.shibboleth.idp.common.provider.MemoryCache.MemoryCacheCleaner");
115                         this.master = Thread.currentThread();
116                         setDaemon(true);
117                         if (getPriority() > Thread.MIN_PRIORITY) {
118                                 setPriority(getPriority() - 1);
119                         }
120                         log.debug("Starting memory-based cache cleanup thread (" + getName() + ").");
121                         start();
122                 }
123
124                 public void run() {
125
126                         try {
127                                 sleep(60 * 1000); // one minute
128                         } catch (InterruptedException e) {
129                                 log.debug("Memory-based cache cleanup interrupted (" + getName() + ").");
130                         }
131                         while (true) {
132                                 try {
133                                         if (!master.isAlive()) {
134                                                 shutdown = true;
135                                                 log.debug("Memory-based cache cleaner is orphaned (" + getName() + ").");
136                                         }
137                                         if (shutdown) {
138                                                 log.debug("Stopping Memory-based cache cleanup thread (" + getName() + ").");
139                                                 return;
140                                         }
141                                         log.debug("Memory-based cache cleanup thread searching for stale entries (" + getName() + ").");
142                                         Set<String> needsDeleting = new HashSet<String>();
143                                         synchronized (entries) {
144                                                 Iterator<Entry<String, CacheEntry>> iterator = entries.entrySet().iterator();
145                                                 while (iterator.hasNext()) {
146                                                         Entry<String, CacheEntry> entry = iterator.next();
147                                                         CacheEntry cacheEntry = entry.getValue();
148                                                         if (cacheEntry.isExpired()) {
149                                                                 needsDeleting.add(entry.getKey());
150                                                         }
151                                                 }
152
153                                         }
154                                         // release the lock to be friendly
155                                         Iterator deleteIterator = needsDeleting.iterator();
156                                         while (deleteIterator.hasNext()) {
157                                                 synchronized (entries) {
158                                                         log.debug("Expiring an entry from the memory cache (" + getName() + ").");
159                                                         entries.remove(deleteIterator.next());
160                                                 }
161                                         }
162                                         sleep(60 * 1000); // one minute
163                                 } catch (InterruptedException e) {
164                                         log.debug("Memory-based cache cleanup interrupted (" + getName() + ").");
165                                 }
166                         }
167                 }
168         }
169 }