Make WAYF reload sites file when it changes.
authorwassa <wassa@ab3bd59b-922f-494d-bb5f-6f0a3c29deca>
Wed, 12 Nov 2003 20:07:15 +0000 (20:07 +0000)
committerwassa <wassa@ab3bd59b-922f-494d-bb5f-6f0a3c29deca>
Wed, 12 Nov 2003 20:07:15 +0000 (20:07 +0000)
git-svn-id: https://subversion.switch.ch/svn/shibboleth/java-idp/trunk@785 ab3bd59b-922f-494d-bb5f-6f0a3c29deca

src/edu/internet2/middleware/shibboleth/common/ResourceWatchdog.java [new file with mode: 0644]
src/edu/internet2/middleware/shibboleth/common/ResourceWatchdogExecutionException.java [new file with mode: 0644]
src/edu/internet2/middleware/shibboleth/wayf/WayfService.java
webAppConfig/all.xml
webAppConfig/wayf.xml

diff --git a/src/edu/internet2/middleware/shibboleth/common/ResourceWatchdog.java b/src/edu/internet2/middleware/shibboleth/common/ResourceWatchdog.java
new file mode 100644 (file)
index 0000000..9faef42
--- /dev/null
@@ -0,0 +1,199 @@
+/* 
+ * The Shibboleth License, Version 1. 
+ * Copyright (c) 2002 
+ * University Corporation for Advanced Internet Development, Inc. 
+ * All rights reserved
+ * 
+ * 
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ * Redistributions of source code must retain the above copyright notice, this 
+ * list of conditions and the following disclaimer.
+ * 
+ * Redistributions in binary form must reproduce the above copyright notice, 
+ * this list of conditions and the following disclaimer in the documentation 
+ * and/or other materials provided with the distribution, if any, must include 
+ * the following acknowledgment: "This product includes software developed by 
+ * the University Corporation for Advanced Internet Development 
+ * <http://www.ucaid.edu>Internet2 Project. Alternately, this acknowledegement 
+ * may appear in the software itself, if and wherever such third-party 
+ * acknowledgments normally appear.
+ * 
+ * Neither the name of Shibboleth nor the names of its contributors, nor 
+ * Internet2, nor the University Corporation for Advanced Internet Development, 
+ * Inc., nor UCAID may be used to endorse or promote products derived from this 
+ * software without specific prior written permission. For written permission, 
+ * please contact shibboleth@shibboleth.org
+ * 
+ * Products derived from this software may not be called Shibboleth, Internet2, 
+ * UCAID, or the University Corporation for Advanced Internet Development, nor 
+ * may Shibboleth appear in their name, without prior written permission of the 
+ * University Corporation for Advanced Internet Development.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND WITH ALL FAULTS. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 
+ * PARTICULAR PURPOSE, AND NON-INFRINGEMENT ARE DISCLAIMED AND THE ENTIRE RISK 
+ * OF SATISFACTORY QUALITY, PERFORMANCE, ACCURACY, AND EFFORT IS WITH LICENSEE. 
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER, CONTRIBUTORS OR THE UNIVERSITY 
+ * CORPORATION FOR ADVANCED INTERNET DEVELOPMENT, INC. BE LIABLE FOR ANY DIRECT, 
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package edu.internet2.middleware.shibboleth.common;
+
+import java.io.IOException;
+import java.net.URLConnection;
+
+import org.apache.log4j.Logger;
+/**
+ * Watchdog thread that polls resources at a specified interval and takes actions
+ * as prescribed by implementors.
+ * 
+ * @author     Walter Hoehn (wassa@columbia.edu)
+ */
+public abstract class ResourceWatchdog extends Thread {
+
+       private static Logger log = Logger.getLogger(ResourceWatchdog.class.getName());
+
+       final static public long DEFAULT_DELAY = 60000;
+       private long delay = DEFAULT_DELAY;
+       protected ShibResource resource;
+
+       private long lastModified = 0;
+       protected boolean interrupted = false;
+       protected long retries = 0;
+       protected long maxRetries;
+       final static public long DEFAULT_MAX_RETRIES = 10;
+
+       protected ResourceWatchdog(ShibResource resource) {
+               this.resource = resource;
+               setDaemon(true);
+               setDelay(DEFAULT_DELAY);
+               this.maxRetries = DEFAULT_MAX_RETRIES;
+               lastModified = System.currentTimeMillis();
+       }
+
+       protected ResourceWatchdog(ShibResource resource, long delay, long maxRetries) {
+               this(resource, delay);
+               this.maxRetries = maxRetries;
+       }
+
+       protected ResourceWatchdog(ShibResource resource, long delay) {
+               this(resource);
+               if (delay > 4) {
+                       setDelay(delay);
+                       return;
+               }
+               try {
+                       log.warn(
+                               "You have set the reload delay on resource ("
+                                       + resource.getURL().toString()
+                                       + ") to ("
+                                       + delay
+                                       + ") seconds, which will probably cause perfomance problems.  Running with default reload "
+                                       + "time of ("
+                                       + DEFAULT_DELAY
+                                       + ") seconds...");
+               } catch (IOException e) {
+                       log.warn(
+                               "You have set the reload delay on a resource to ("
+                                       + delay
+                                       + ") seconds, which will probably cause perfomance problems.  Running with default reload "
+                                       + "time of ("
+                                       + DEFAULT_DELAY
+                                       + ") seconds...");
+               } finally {
+                       setDelay(DEFAULT_DELAY);
+               }
+       }
+
+       /**
+          Set the delay to observe between each check of the file changes.
+        */
+       public void setDelay(long delay) {
+               this.delay = delay;
+       }
+
+       /**
+        * This method is called when the Watchdog detects a change in the resource.
+        * 
+        * @throws WatchdogException if it cannot perform the intended operation
+        */
+       abstract protected void doOnChange() throws ResourceWatchdogExecutionException;
+
+       protected void checkAndRun() {
+
+               try {
+                       URLConnection connection = resource.getURL().openConnection();
+                       connection.connect();
+
+                       log.debug("Checking for updates to resource (" + resource.getURL().toString() + ")");
+
+                       long newLastModified = connection.getLastModified();
+
+                       if (newLastModified < 1) {
+                               interrupted = true;
+                               log.error(
+                                       "Resource ("
+                                               + resource.getURL().toString()
+                                               + ") does not provide modification dates.  "
+                                               + "Resource cannot be reloaded.");
+                               return;
+                       }
+
+                       if (newLastModified > lastModified) {
+                               log.debug("Previous Last Modified: " + lastModified + " New Last Modified: " + newLastModified);
+                               log.info("Found update for resource (" + resource.getURL().toString() + ")");
+                               lastModified = newLastModified;
+                               doOnChange();
+                               retries = 0;
+
+                       }
+
+               } catch (Exception e) {
+                       try {
+                               if (retries < maxRetries) {
+                                       log.error(
+                                               "Resource (" + resource.getURL().toString() + ") could not be loaded.  " + "Will retry later.");
+                                       retries++;
+                                       return;
+
+                               } else {
+                                       log.error(
+                                               "Unsuccessfully attempted to load resource ("
+                                                       + resource.getURL().toString()
+                                                       + ") too many times.  "
+                                                       + "Resource cannot be reloaded.");
+                                       interrupted = true;
+                                       return;
+                               }
+                       } catch (IOException ioe) {
+                               log.error(
+                                       "Unsuccessfully attempted to load a resource too many times.  " + "Resource cannot be reloaded.");
+                               interrupted = true;
+                               return;
+                       }
+               }
+
+       }
+
+       public void run() {
+               while (!interrupted) {
+                       try {
+                               Thread.sleep(delay);
+                       } catch (InterruptedException e) {
+                               // not applicable
+                       }
+                       checkAndRun();
+               }
+       }
+
+}
diff --git a/src/edu/internet2/middleware/shibboleth/common/ResourceWatchdogExecutionException.java b/src/edu/internet2/middleware/shibboleth/common/ResourceWatchdogExecutionException.java
new file mode 100644 (file)
index 0000000..10c1629
--- /dev/null
@@ -0,0 +1,64 @@
+/* 
+ * The Shibboleth License, Version 1. 
+ * Copyright (c) 2002 
+ * University Corporation for Advanced Internet Development, Inc. 
+ * All rights reserved
+ * 
+ * 
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ * Redistributions of source code must retain the above copyright notice, this 
+ * list of conditions and the following disclaimer.
+ * 
+ * Redistributions in binary form must reproduce the above copyright notice, 
+ * this list of conditions and the following disclaimer in the documentation 
+ * and/or other materials provided with the distribution, if any, must include 
+ * the following acknowledgment: "This product includes software developed by 
+ * the University Corporation for Advanced Internet Development 
+ * <http://www.ucaid.edu>Internet2 Project. Alternately, this acknowledegement 
+ * may appear in the software itself, if and wherever such third-party 
+ * acknowledgments normally appear.
+ * 
+ * Neither the name of Shibboleth nor the names of its contributors, nor 
+ * Internet2, nor the University Corporation for Advanced Internet Development, 
+ * Inc., nor UCAID may be used to endorse or promote products derived from this 
+ * software without specific prior written permission. For written permission, 
+ * please contact shibboleth@shibboleth.org
+ * 
+ * Products derived from this software may not be called Shibboleth, Internet2, 
+ * UCAID, or the University Corporation for Advanced Internet Development, nor 
+ * may Shibboleth appear in their name, without prior written permission of the 
+ * University Corporation for Advanced Internet Development.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND WITH ALL FAULTS. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 
+ * PARTICULAR PURPOSE, AND NON-INFRINGEMENT ARE DISCLAIMED AND THE ENTIRE RISK 
+ * OF SATISFACTORY QUALITY, PERFORMANCE, ACCURACY, AND EFFORT IS WITH LICENSEE. 
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER, CONTRIBUTORS OR THE UNIVERSITY 
+ * CORPORATION FOR ADVANCED INTERNET DEVELOPMENT, INC. BE LIABLE FOR ANY DIRECT, 
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package edu.internet2.middleware.shibboleth.common;
+
+/**
+ * Signals that an error occurred while taking actions specified by
+ * implementors of <code>ResourceWatchdog</code>
+ * 
+ * @author     Walter Hoehn (wassa@columbia.edu)
+ */
+public class ResourceWatchdogExecutionException extends Exception {
+
+       public ResourceWatchdogExecutionException(String message) {
+               super(message);
+       }
+
+}
index 86f185a..e9e5f7b 100755 (executable)
@@ -63,7 +63,10 @@ import javax.servlet.http.HttpServletResponse;
 import org.apache.log4j.Logger;
 import org.xml.sax.SAXException;
 
+import edu.internet2.middleware.shibboleth.common.ResourceWatchdog;
 import edu.internet2.middleware.shibboleth.common.ShibResource;
+import edu.internet2.middleware.shibboleth.common.ResourceWatchdogExecutionException;
+import edu.internet2.middleware.shibboleth.common.ShibResource.ResourceNotAvailableException;
 
 /**
  * A servlet implementation of the Shibboleth WAYF service.  Allows a browser user to 
@@ -91,11 +94,19 @@ public class WayfService extends HttpServlet {
                loadInitParams();
                log.info("Loading configuration from file.");
                configure();
-               
+
+               log.info("Initailizing site metadata watchdog.");
+               try {
+                       ResourceWatchdog watchdog = new SitesFileWatchdog(siteConfigFileLocation, this);
+                       watchdog.start();
+               } catch (ResourceNotAvailableException e) {
+                       log.error("Sites file watchdog could not be initialized: " + e);
+               }
+
                //Setup Cacheing options
                wOptions.setDomain(config.getCacheDomain());
                wOptions.setExpiration(config.getCacheExpiration());
-               
+
                initViewConfig();
                log.info("WAYF initialization completed.");
        }
@@ -120,10 +131,11 @@ public class WayfService extends HttpServlet {
 
                loadSiteConfig();
        }
-       
+
        private void loadSiteConfig() throws UnavailableException {
                try {
-                       InputStream siteIs = getServletContext().getResourceAsStream(siteConfigFileLocation);
+
+                       InputStream siteIs = new ShibResource(siteConfigFileLocation, this.getClass()).getInputStream();
                        OriginSitesDigester siteDigester = new OriginSitesDigester();
                        siteDigester.setValidating(true);
                        originConfig = (WayfOrigins) siteDigester.parse(siteIs);
@@ -188,10 +200,7 @@ public class WayfService extends HttpServlet {
                                WayfCacheFactory.getInstance(config.getCacheType(), wOptions).deleteHsFromCache(req, res);
                                handleLookup(req, res);
                        } else if (WayfCacheFactory.getInstance(config.getCacheType()).hasCachedHS(req)) {
-                               forwardToHS(
-                                       req,
-                                       res,
-                                       WayfCacheFactory.getInstance(config.getCacheType()).getCachedHS(req));
+                               forwardToHS(req, res, WayfCacheFactory.getInstance(config.getCacheType()).getCachedHS(req));
                        } else if (requestType.equals("search")) {
                                handleSearch(req, res);
                        } else if (requestType.equals("selection")) {
@@ -229,7 +238,7 @@ public class WayfService extends HttpServlet {
                        throw new WayfException("Problem displaying WAYF UI." + se.toString());
                }
        }
-       
+
        /**
         * Looks for origin sites that match search terms supplied by the user
         */
@@ -256,8 +265,7 @@ public class WayfService extends HttpServlet {
                if (handleService == null) {
                        handleLookup(req, res);
                } else {
-                       if ((req.getParameter("cache") != null)
-                               && req.getParameter("cache").equalsIgnoreCase("TRUE")) {
+                       if ((req.getParameter("cache") != null) && req.getParameter("cache").equalsIgnoreCase("TRUE")) {
                                WayfCacheFactory.getInstance(config.getCacheType(), wOptions).addHsToCache(handleService, req, res);
                        }
                        forwardToHS(req, res, handleService);
@@ -339,28 +347,60 @@ public class WayfService extends HttpServlet {
                }
                return target;
        }
-       
+
        private WayfOrigins getOrigins() {
                synchronized (originConfig) {
                        return originConfig;
                }
        }
-       
-       private void reloadOriginMetadata() {
+
+       private void reloadOriginMetadata() throws UnavailableException {
 
                WayfOrigins safetyCache = getOrigins();
                try {
                        synchronized (originConfig) {
                                loadSiteConfig();
+                               getServletContext().setAttribute("originsets", getOrigins().getOriginSets());
                        }
-                       getServletContext().setAttribute("originsets", getOrigins().getOriginSets());
+
                } catch (UnavailableException e) {
                        log.error("Failed to load updated origin site metadata: " + e);
                        synchronized (originConfig) {
                                originConfig = safetyCache;
                        }
+                       throw e;
                }
        }
 
-}
+       private class SitesFileWatchdog extends ResourceWatchdog {
+
+               private WayfService wayfService;
+               private SitesFileWatchdog(String sitesFileLocation, WayfService wayfService)
+                       throws ResourceNotAvailableException {
+
+                       super(new ShibResource(sitesFileLocation, wayfService.getClass()));
+                       this.wayfService = wayfService;
+               }
 
+               /**
+                * @see edu.internet2.middleware.shibboleth.common.ResourceWatchdog#doOnChange()
+                */
+               protected void doOnChange() throws ResourceWatchdogExecutionException {
+                       try {
+                               wayfService.reloadOriginMetadata();
+                       } catch (UnavailableException e) {
+                               try {
+                                               log.error(
+                                                       "Sites file at ("
+                                                               + resource.getURL().toString()
+                                                               + ") could not be loaded: " + e);
+                               } catch (IOException ioe) {
+                                       log.error("Sites file could not be loaded.");
+                               }
+                               finally {
+                                       throw new ResourceWatchdogExecutionException("Watchdog reload failed.");
+                               }
+                       }
+               }
+       }
+}
index 88c2b6f..3775417 100755 (executable)
@@ -31,7 +31,7 @@
                <servlet-class>edu.internet2.middleware.shibboleth.wayf.WayfService</servlet-class>
                 <init-param>
                     <param-name>SiteConfigFileLocation</param-name>
-                    <param-value>/sites.xml</param-value>
+                    <param-value>/conf/sites.xml</param-value>
                 </init-param>
        </servlet>
        
index 8ebb55c..e945daf 100755 (executable)
@@ -21,7 +21,7 @@
                <servlet-class>edu.internet2.middleware.shibboleth.wayf.WayfService</servlet-class>
                 <init-param>
                     <param-name>SiteConfigFileLocation</param-name>
-                    <param-value>/sites.xml</param-value>
+                    <param-value>/conf/sites.xml</param-value>
                 </init-param>
        </servlet>