Ripped out stale 1.3 XML parsing code.
[java-idp.git] / src / edu / internet2 / middleware / shibboleth / aa / arp / provider / BaseArpRepository.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.aa.arp.provider;
18
19 import java.io.IOException;
20 import java.security.Principal;
21 import java.util.HashMap;
22 import java.util.HashSet;
23 import java.util.Iterator;
24 import java.util.Map;
25 import java.util.Set;
26
27 import javax.xml.parsers.ParserConfigurationException;
28
29 import org.apache.log4j.Logger;
30 import org.w3c.dom.Element;
31 import org.xml.sax.SAXException;
32
33 import edu.internet2.middleware.shibboleth.aa.arp.Arp;
34 import edu.internet2.middleware.shibboleth.aa.arp.ArpMarshallingException;
35 import edu.internet2.middleware.shibboleth.aa.arp.ArpRepository;
36 import edu.internet2.middleware.shibboleth.aa.arp.ArpRepositoryException;
37
38 /**
39  * Provides marshalling/unmarshalling functionality common among <code>ArpRepository</code> implementations.
40  * 
41  * @author Walter Hoehn (wassa@columbia.edu)
42  */
43
44 public abstract class BaseArpRepository implements ArpRepository {
45
46         private static Logger log = Logger.getLogger(BaseArpRepository.class.getName());
47         private ArpCache arpCache;
48
49         BaseArpRepository(Element config) throws ArpRepositoryException {
50
51                 String rawArpTTL = config.getAttribute("arpTTL");
52                 long arpTTL = 0;
53                 try {
54                         if (rawArpTTL != null && !rawArpTTL.equals("")) {
55                                 arpTTL = Long.parseLong(rawArpTTL);
56                                 log.debug("ARP TTL set to: (" + arpTTL + ").");
57                         }
58                 } catch (NumberFormatException e) {
59                         log.error("ARP TTL must be set to a long integer.");
60                 }
61
62                 if (arpTTL > 0) {
63                         arpCache = ArpCache.instance();
64                         arpCache.setCacheLength(arpTTL);
65                 }
66         }
67
68         /**
69          * @see edu.internet2.middleware.shibboleth.aa.arp.ArpRepository#getAllPolicies(Principal)
70          */
71
72         public Arp[] getAllPolicies(Principal principal) throws ArpRepositoryException {
73
74                 log.debug("Received a query for all policies applicable to principal: (" + principal.getName() + ").");
75                 Set<Arp> allPolicies = new HashSet<Arp>();
76                 Arp sitePolicy = getSitePolicy();
77                 if (sitePolicy != null) {
78                         log.debug("Returning site policy.");
79                         allPolicies.add(sitePolicy);
80                 }
81
82                 Arp userPolicy = getUserPolicy(principal);
83                 if (userPolicy != null) {
84                         allPolicies.add(userPolicy);
85                         log.debug("Returning user policy.");
86                 }
87                 if (allPolicies.isEmpty()) {
88                         log.debug("No policies found.");
89                 }
90                 return (Arp[]) allPolicies.toArray(new Arp[0]);
91         }
92
93         /**
94          * @see edu.internet2.middleware.shibboleth.aa.arp.ArpRepository#getSitePolicy()
95          */
96         public Arp getSitePolicy() throws ArpRepositoryException {
97
98                 try {
99                         if (arpCache != null) {
100                                 Arp cachedArp = arpCache.retrieveSiteArpFromCache();
101                                 if (cachedArp != null) {
102                                         log.debug("Using cached site ARP.");
103                                         return cachedArp;
104                                 }
105                         }
106
107                         Element xml = retrieveSiteArpXml();
108                         if (xml == null) { return null; }
109
110                         Arp siteArp = new Arp();
111                         siteArp.marshall(xml);
112                         if (arpCache != null) {
113                                 arpCache.cache(siteArp);
114                         }
115                         return siteArp;
116                 } catch (ArpMarshallingException ame) {
117                         log.error("An error occurred while marshalling an ARP: " + ame);
118                         throw new ArpRepositoryException("An error occurred while marshalling an ARP.");
119                 } catch (IOException ioe) {
120                         log.error("An error occurred while loading an ARP: " + ioe);
121                         throw new ArpRepositoryException("An error occurred while loading an ARP.");
122                 } catch (SAXException se) {
123                         log.error("An error occurred while parsing an ARP: " + se);
124                         throw new ArpRepositoryException("An error occurred while parsing an ARP.");
125                 } catch (ParserConfigurationException e) {
126                         log.error("An error occurred while loading the XML parser: " + e);
127                         throw new ArpRepositoryException("An error occurred while loading the XML parser.");
128                 }
129         }
130
131         /**
132          * Inheritors must return the site Arp as an xml element.
133          * 
134          * @return Element
135          */
136         protected abstract Element retrieveSiteArpXml() throws IOException, SAXException, ParserConfigurationException;
137
138         public void destroy() {
139
140                 if (arpCache != null) {
141                         arpCache.destroy();
142                 }
143         }
144
145         /**
146          * @see edu.internet2.middleware.shibboleth.aa.arp.ArpRepository#getUserPolicy(Principal)
147          */
148         public Arp getUserPolicy(Principal principal) throws ArpRepositoryException {
149
150                 if (arpCache != null) {
151                         Arp cachedArp = arpCache.retrieveUserArpFromCache(principal);
152                         if (cachedArp != null) {
153                                 log.debug("Using cached user ARP.");
154                                 return cachedArp;
155                         }
156                 }
157
158                 try {
159                         Element xml = retrieveUserArpXml(principal);
160                         if (xml == null) { return null; }
161
162                         Arp userArp = new Arp();
163                         userArp.setPrincipal(principal);
164
165                         userArp.marshall(xml);
166                         if (arpCache != null) {
167                                 arpCache.cache(userArp);
168                         }
169                         return userArp;
170                 } catch (ArpMarshallingException ame) {
171                         log.error("An error occurred while marshalling an ARP: " + ame);
172                         throw new ArpRepositoryException("An error occurred while marshalling an ARP.");
173                 } catch (IOException ioe) {
174                         log.error("An error occurred while loading an ARP: " + ioe);
175                         throw new ArpRepositoryException("An error occurred while loading an ARP.");
176                 } catch (SAXException se) {
177                         log.error("An error occurred while parsing an ARP: " + se);
178                         throw new ArpRepositoryException("An error occurred while parsing an ARP.");
179                 } catch (ParserConfigurationException e) {
180                         log.error("An error occurred while loading the XML parser: " + e);
181                         throw new ArpRepositoryException("An error occurred while loading the XML parser.");
182                 }
183         }
184
185         /**
186          * Inheritors must return the user Arp as an xml element.
187          * 
188          * @return Element
189          */
190         protected abstract Element retrieveUserArpXml(Principal principal) throws IOException, SAXException,
191                         ParserConfigurationException;
192
193 }
194
195 class ArpCache {
196
197         private static ArpCache instance = null;
198         /** Time in seconds for which ARPs should be cached. */
199         private long cacheLength;
200         private Map<Principal, CachedArp> cache = new HashMap<Principal, CachedArp>();
201         private static Logger log = Logger.getLogger(ArpCache.class.getName());
202         private ArpCacheCleaner cleaner = new ArpCacheCleaner();
203
204         protected ArpCache() {
205
206         }
207
208         static synchronized ArpCache instance() {
209
210                 if (instance == null) {
211                         instance = new ArpCache();
212                         return instance;
213                 }
214                 return instance;
215         }
216
217         /** Set time in seconds for which ARPs should be cached. */
218         void setCacheLength(long cacheLength) {
219
220                 this.cacheLength = cacheLength;
221         }
222
223         void cache(Arp arp) {
224
225                 if (arp.isSitePolicy() == false) {
226                         synchronized (cache) {
227                                 cache.put(arp.getPrincipal(), new CachedArp(arp, System.currentTimeMillis()));
228                         }
229                 } else {
230                         synchronized (cache) {
231                                 cache.put(new SiteCachePrincipal(), new CachedArp(arp, System.currentTimeMillis()));
232                         }
233                 }
234         }
235
236         Arp retrieveUserArpFromCache(Principal principal) {
237
238                 return retrieveArpFromCache(principal);
239         }
240
241         Arp retrieveSiteArpFromCache() {
242
243                 return retrieveArpFromCache(new SiteCachePrincipal());
244         }
245
246         private Arp retrieveArpFromCache(Principal principal) {
247
248                 CachedArp cachedArp;
249                 synchronized (cache) {
250                         cachedArp = (CachedArp) cache.get(principal);
251                 }
252
253                 if (cachedArp == null) { return null; }
254
255                 if ((System.currentTimeMillis() - cachedArp.creationTimeMillis) < (cacheLength * 1000)) { return cachedArp.arp; }
256
257                 synchronized (cache) {
258                         cache.remove(principal);
259                 }
260                 return null;
261         }
262
263         /**
264          * @see java.lang.Object#finalize()
265          */
266         protected void finalize() throws Throwable {
267
268                 super.finalize();
269                 destroy();
270         }
271
272         public void destroy() {
273
274                 synchronized (cleaner) {
275                         if (cleaner != null) {
276                                 cleaner.shutdown = true;
277                                 cleaner.interrupt();
278                         }
279                 }
280         }
281
282         private class CachedArp {
283
284                 Arp arp;
285                 long creationTimeMillis;
286
287                 CachedArp(Arp arp, long creationTimeMillis) {
288
289                         this.arp = arp;
290                         this.creationTimeMillis = creationTimeMillis;
291                 }
292         }
293
294         private class SiteCachePrincipal implements Principal {
295
296                 public String getName() {
297
298                         return "ARP admin";
299                 }
300
301                 /**
302                  * @see java.lang.Object#equals(Object)
303                  */
304                 public boolean equals(Object object) {
305
306                         if (object instanceof SiteCachePrincipal) { return true; }
307                         return false;
308                 }
309
310                 /**
311                  * @see java.lang.Object#hashCode()
312                  */
313                 public int hashCode() {
314
315                         return "edu.internet2.middleware.shibboleth.aa.arp.provider.BaseArpRepository.SiteCachePrincipal"
316                                         .hashCode();
317                 }
318         }
319
320         private class ArpCacheCleaner extends Thread {
321
322                 private boolean shutdown = false;
323                 private Thread master;
324
325                 public ArpCacheCleaner() {
326
327                         super("edu.internet2.middleware.shibboleth.aa.arp.provider.BaseArpRepository.ArpCache.ArpCacheCleaner");
328                         master = Thread.currentThread();
329                         setDaemon(true);
330                         if (getPriority() > Thread.MIN_PRIORITY) {
331                                 setPriority(getPriority() - 1);
332                         }
333                         log.debug("Starting ArpCache Cleanup Thread.");
334                         start();
335                 }
336
337                 public void run() {
338
339                         try {
340                                 sleep(60 * 1000); // one minute
341                         } catch (InterruptedException e) {
342                                 log.debug("ArpCache Cleanup interrupted.");
343                         }
344                         while (true) {
345                                 try {
346                                         if (master == null) {
347                                                 log.debug("ArpCache cache cleaner is orphaned.");
348                                                 shutdown = true;
349                                         }
350                                         if (shutdown) {
351                                                 log.debug("Stopping ArpCache Cleanup Thread.");
352                                                 return;
353                                         }
354                                         log.debug("ArpCache cleanup thread searching for stale entries.");
355                                         Set<CachedArp> needsDeleting = new HashSet<CachedArp>();
356                                         synchronized (cache) {
357                                                 Iterator<CachedArp> iterator = cache.values().iterator();
358                                                 while (iterator.hasNext()) {
359                                                         CachedArp cachedArp = iterator.next();
360                                                         if ((System.currentTimeMillis() - cachedArp.creationTimeMillis) > (cacheLength * 1000)) {
361                                                                 needsDeleting.add(cachedArp);
362                                                         }
363                                                 }
364                                         }
365                                         // release the lock to be friendly
366                                         Iterator deleteIterator = needsDeleting.iterator();
367                                         while (deleteIterator.hasNext()) {
368                                                 synchronized (cache) {
369                                                         CachedArp cachedArp = (CachedArp) deleteIterator.next();
370                                                         if (cachedArp.arp.isSitePolicy()) {
371                                                                 log.debug("Expiring site ARP from the Cache.");
372                                                                 cache.remove(new SiteCachePrincipal());
373                                                         } else {
374                                                                 log.debug("Expiring an ARP from the Cache.");
375                                                                 cache.remove(cachedArp.arp.getPrincipal());
376                                                         }
377                                                 }
378                                         }
379
380                                         sleep(60 * 1000); // one minute
381                                 } catch (InterruptedException e) {
382                                         log.debug("ArpCache Cleanup interrupted.");
383                                 }
384                         }
385                 }
386         }
387
388 }