516990fc0a768bcb5e3f9c22bfac4c77e26fc14e
[java-idp.git] / src / edu / internet2 / middleware / shibboleth / common / ResourceWatchdog.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;
18
19 import java.io.IOException;
20 import java.net.URLConnection;
21
22 import org.apache.log4j.Logger;
23
24 /**
25  * Watchdog thread that polls resources at a specified interval and takes actions as prescribed by implementors.
26  * 
27  * @author Walter Hoehn (wassa@columbia.edu)
28  */
29 public abstract class ResourceWatchdog extends Thread {
30
31         private static Logger log = Logger.getLogger(ResourceWatchdog.class.getName());
32
33         final static public long DEFAULT_DELAY = 60000;
34         private long delay = DEFAULT_DELAY;
35         protected ShibResource resource;
36
37         private long lastModified = 0;
38         protected boolean interrupted = false;
39         protected long retries = 0;
40         protected long maxRetries;
41         final static public long DEFAULT_MAX_RETRIES = 10;
42
43         protected ResourceWatchdog(ShibResource resource) {
44
45                 this.resource = resource;
46                 setDaemon(true);
47                 setDelay(DEFAULT_DELAY);
48                 if (getPriority() > Thread.MIN_PRIORITY) {
49                         setPriority(getPriority() - 1);
50                 }
51                 this.maxRetries = DEFAULT_MAX_RETRIES;
52                 lastModified = System.currentTimeMillis();
53         }
54
55         /**
56          * @param delay
57          *            the delay to observe between each check of the file changes.
58          * @param maxRetries
59          *            the maximum number of times to retry loading after the resource becomes unreachable or 0 for no
60          *            maximum
61          */
62         protected ResourceWatchdog(ShibResource resource, long delay, long maxRetries) {
63
64                 this(resource, delay);
65                 this.maxRetries = maxRetries;
66         }
67
68         protected ResourceWatchdog(ShibResource resource, long delay) {
69
70                 this(resource);
71                 if (delay > 5000) {
72                         setDelay(delay);
73                         return;
74                 }
75                 try {
76                         log.warn("You have set the reload delay on resource (" + resource.getURL().toString() + ") to (" + delay
77                                         + ") seconds, which will probably cause perfomance problems.  Running with default reload "
78                                         + "time of (" + DEFAULT_DELAY + ") seconds...");
79                 } catch (IOException e) {
80                         log.warn("You have set the reload delay on a resource to (" + delay
81                                         + ") seconds, which will probably cause perfomance problems.  Running with default reload "
82                                         + "time of (" + DEFAULT_DELAY + ") seconds...");
83                 } finally {
84                         setDelay(DEFAULT_DELAY);
85                 }
86         }
87
88         /**
89          * Set the delay to observe between each check of the file changes.
90          */
91         public void setDelay(long delay) {
92
93                 this.delay = delay;
94         }
95
96         /**
97          * This method is called when the Watchdog detects a change in the resource.
98          * 
99          * @throws WatchdogException
100          *             if it cannot perform the intended operation
101          */
102         abstract protected void doOnChange() throws ResourceWatchdogExecutionException;
103
104         protected void checkAndRun() {
105
106                 URLConnection connection = null;
107                 try {
108                         connection = resource.getURL().openConnection();
109                         connection.connect();
110
111                         log.debug("Checking for updates to resource (" + resource.getURL().toString() + ")");
112
113                         long newLastModified = connection.getLastModified();
114
115                         if (newLastModified < 1) {
116                                 interrupted = true;
117                                 log.error("Resource (" + resource.getURL().toString() + ") does not provide modification dates.  "
118                                                 + "Resource cannot be reloaded.");
119                                 return;
120                         }
121
122                         if (newLastModified > lastModified) {
123                                 log.debug("Previous Last Modified: " + lastModified + " New Last Modified: " + newLastModified);
124                                 log.info("Found update for resource (" + resource.getURL().toString() + ")");
125                                 lastModified = newLastModified;
126                                 doOnChange();
127                                 retries = 0;
128
129                         }
130
131                 } catch (Exception e) {
132                         try {
133                                 if (maxRetries == 0 || retries < maxRetries) {
134                                         log.error("Resource (" + resource.getURL().toString() + ") could not be loaded.  "
135                                                         + "Will retry later.");
136                                         retries++;
137                                         return;
138
139                                 } else {
140                                         log.error("Unsuccessfully attempted to load resource (" + resource.getURL().toString()
141                                                         + ") too many times.  " + "Resource cannot be reloaded.");
142                                         interrupted = true;
143                                         return;
144                                 }
145                         } catch (IOException ioe) {
146                                 log.error("Unsuccessfully attempted to load a resource too many times.  "
147                                                 + "Resource cannot be reloaded.");
148                                 interrupted = true;
149                                 return;
150                         }
151                 } finally {
152                         // Silliness to avoid file descriptor leaks
153                         if (connection != null) {
154                                 try {
155                                         connection.getInputStream().close();
156                                 } catch (IOException e1) {
157                                         // ignore
158                                 }
159                         }
160                 }
161
162         }
163
164         public void run() {
165
166                 while (!interrupted) {
167                         try {
168                                 Thread.sleep(delay);
169                         } catch (InterruptedException e) {
170                                 // not applicable
171                         }
172                         checkAndRun();
173                 }
174         }
175
176 }