You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@cocoon.apache.org by tc...@apache.org on 2005/03/27 17:03:58 UTC

svn commit: r159152 - in cocoon/trunk: lib/ lib/core/ lib/optional/ src/java/org/apache/cocoon/ src/java/org/apache/cocoon/components/fam/ src/java/org/apache/cocoon/components/treeprocessor/

Author: tcurdt
Date: Sun Mar 27 07:03:57 2005
New Revision: 159152

URL: http://svn.apache.org/viewcvs?view=rev&rev=159152
Log:
auto-reload the sitemap on classpath changes

Added:
    cocoon/trunk/lib/core/commons-jci-r159148.jar   (with props)
    cocoon/trunk/src/java/org/apache/cocoon/components/fam/
    cocoon/trunk/src/java/org/apache/cocoon/components/fam/SitemapMonitor.java
    cocoon/trunk/src/java/org/apache/cocoon/components/fam/SitemapMonitorImpl.java
Removed:
    cocoon/trunk/lib/optional/commons-jci-0.1-dev.jar
Modified:
    cocoon/trunk/lib/jars.xml
    cocoon/trunk/src/java/org/apache/cocoon/cocoon.roles
    cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/ConcreteTreeProcessor.java
    cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/TreeProcessor.java

Added: cocoon/trunk/lib/core/commons-jci-r159148.jar
URL: http://svn.apache.org/viewcvs/cocoon/trunk/lib/core/commons-jci-r159148.jar?view=auto&rev=159152
==============================================================================
Binary file - no diff available.

Propchange: cocoon/trunk/lib/core/commons-jci-r159148.jar
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Modified: cocoon/trunk/lib/jars.xml
URL: http://svn.apache.org/viewcvs/cocoon/trunk/lib/jars.xml?view=diff&r1=159151&r2=159152
==============================================================================
--- cocoon/trunk/lib/jars.xml (original)
+++ cocoon/trunk/lib/jars.xml Sun Mar 27 07:03:57 2005
@@ -1068,7 +1068,7 @@
       API for compiling java
     </description>
     <used-by>javaflow</used-by>
-    <lib>optional/commons-jci-0.1-dev.jar</lib>
+    <lib>core/commons-jci-0.1-dev.jar</lib>
     <homepage></homepage>
   </file>
 

Modified: cocoon/trunk/src/java/org/apache/cocoon/cocoon.roles
URL: http://svn.apache.org/viewcvs/cocoon/trunk/src/java/org/apache/cocoon/cocoon.roles?view=diff&r1=159151&r2=159152
==============================================================================
--- cocoon/trunk/src/java/org/apache/cocoon/cocoon.roles (original)
+++ cocoon/trunk/src/java/org/apache/cocoon/cocoon.roles Sun Mar 27 07:03:57 2005
@@ -183,6 +183,10 @@
 	
   <!--=========================================================================-->
   
+  <role name="org.apache.cocoon.components.fam.SitemapMonitor"
+        shorthand="fam"
+        default-class="org.apache.cocoon.components.fam.SitemapMonitorImpl"/>
+        
   <role name="org.apache.cocoon.components.classloader.ClassLoaderManager"
         shorthand="classloader"
         default-class="org.apache.cocoon.components.classloader.ClassLoaderManagerImpl"/>

Added: cocoon/trunk/src/java/org/apache/cocoon/components/fam/SitemapMonitor.java
URL: http://svn.apache.org/viewcvs/cocoon/trunk/src/java/org/apache/cocoon/components/fam/SitemapMonitor.java?view=auto&rev=159152
==============================================================================
--- cocoon/trunk/src/java/org/apache/cocoon/components/fam/SitemapMonitor.java (added)
+++ cocoon/trunk/src/java/org/apache/cocoon/components/fam/SitemapMonitor.java Sun Mar 27 07:03:57 2005
@@ -0,0 +1,29 @@
+/* 
+ * Copyright 2002-2005 The Apache Software Foundation
+ * Licensed  under the  Apache License,  Version 2.0  (the "License");
+ * you may not use  this file  except in  compliance with the License.
+ * You may obtain a copy of the License at 
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed  under the  License is distributed on an "AS IS" BASIS,
+ * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
+ * implied.
+ * 
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cocoon.components.fam;
+
+import org.apache.avalon.framework.configuration.Configuration;
+import org.apache.avalon.framework.configuration.ConfigurationException;
+import org.apache.commons.jci.monitor.FilesystemAlterationListener;
+
+public interface SitemapMonitor {
+	String ROLE = SitemapMonitor.class.getName();
+
+    void subscribeSitemap( FilesystemAlterationListener listener, Configuration sitemap ) throws ConfigurationException;
+
+    void unsubscribeSitemap( FilesystemAlterationListener listener);
+}

Added: cocoon/trunk/src/java/org/apache/cocoon/components/fam/SitemapMonitorImpl.java
URL: http://svn.apache.org/viewcvs/cocoon/trunk/src/java/org/apache/cocoon/components/fam/SitemapMonitorImpl.java?view=auto&rev=159152
==============================================================================
--- cocoon/trunk/src/java/org/apache/cocoon/components/fam/SitemapMonitorImpl.java (added)
+++ cocoon/trunk/src/java/org/apache/cocoon/components/fam/SitemapMonitorImpl.java Sun Mar 27 07:03:57 2005
@@ -0,0 +1,104 @@
+/* 
+ * Copyright 2002-2005 The Apache Software Foundation
+ * Licensed  under the  Apache License,  Version 2.0  (the "License");
+ * you may not use  this file  except in  compliance with the License.
+ * You may obtain a copy of the License at 
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed  under the  License is distributed on an "AS IS" BASIS,
+ * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
+ * implied.
+ * 
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cocoon.components.fam;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.avalon.framework.activity.Disposable;
+import org.apache.avalon.framework.activity.Initializable;
+import org.apache.avalon.framework.configuration.Configuration;
+import org.apache.avalon.framework.configuration.ConfigurationException;
+import org.apache.avalon.framework.logger.AbstractLogEnabled;
+import org.apache.avalon.framework.service.ServiceException;
+import org.apache.avalon.framework.service.ServiceManager;
+import org.apache.avalon.framework.service.Serviceable;
+import org.apache.avalon.framework.thread.ThreadSafe;
+import org.apache.commons.jci.monitor.FilesystemAlterationListener;
+import org.apache.commons.jci.monitor.FilesystemAlterationMonitor;
+import org.apache.excalibur.source.Source;
+import org.apache.excalibur.source.SourceResolver;
+
+public final class SitemapMonitorImpl extends AbstractLogEnabled implements SitemapMonitor, Serviceable, ThreadSafe, Initializable, Disposable {
+
+    private ServiceManager manager;
+    private SourceResolver resolver;
+    private FilesystemAlterationMonitor monitor = new FilesystemAlterationMonitor();
+
+
+    public void service( ServiceManager manager ) throws ServiceException {
+        this.manager = manager;
+        this.resolver = (SourceResolver) manager.lookup(SourceResolver.ROLE);
+    }
+
+    private File[] parseConfiguration(Configuration config) throws ConfigurationException {
+        List urlList = new ArrayList();
+        Configuration[] children = config.getChild("components").getChild("classpath").getChildren();
+        for (int i = 0; i < children.length; i++) {
+            Configuration child = children[i];
+            String name = child.getName();
+            Source src = null;
+            try {
+                src = resolver.resolveURI(child.getAttribute("src"));
+
+                if ("class-dir".equals(name)) {
+                    String dir = src.getURI();
+                    if (getLogger().isDebugEnabled()) {
+                        getLogger().debug("class-dir:" + dir);
+                    }
+                    urlList.add(new File(dir.substring(5)));
+                } else if ("lib-dir".equals(name)) {
+                    String dir = src.getURI();
+                    if (getLogger().isDebugEnabled()) {
+                        getLogger().debug("lib-dir:" + dir);
+                    }
+                    urlList.add(new File(dir.substring(5)));
+                } else {
+                    throw new ConfigurationException("Unexpected element " + name + " at " + child.getLocation());
+                }
+            } catch(ConfigurationException ce) {
+                resolver.release(src);
+                throw ce;
+            } catch(Exception e) {
+                resolver.release(src);
+                throw new ConfigurationException("Error loading " + name + " at " + child.getLocation(), e);
+            }
+        }
+        
+        return (File[])urlList.toArray(new File[urlList.size()]);
+    }
+
+    public void subscribeSitemap( FilesystemAlterationListener listener, Configuration sitemap ) throws ConfigurationException {
+        File[] dirs = parseConfiguration(sitemap);
+        for (int i = 0; i < dirs.length; i++) {
+            monitor.addListener(listener, dirs[i]);            
+        }
+    }
+
+    public void unsubscribeSitemap( FilesystemAlterationListener listener) {
+        monitor.removeListener(listener);
+    }
+    
+    public void initialize() throws Exception {
+        Thread myThread = new Thread(monitor);
+        myThread.start();
+    }
+
+
+    public void dispose() {
+    }
+}

Modified: cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/ConcreteTreeProcessor.java
URL: http://svn.apache.org/viewcvs/cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/ConcreteTreeProcessor.java?view=diff&r1=159151&r2=159152
==============================================================================
--- cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/ConcreteTreeProcessor.java (original)
+++ cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/ConcreteTreeProcessor.java Sun Mar 27 07:03:57 2005
@@ -15,6 +15,7 @@
  */
 package org.apache.cocoon.components.treeprocessor;
 
+import java.io.File;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Iterator;
@@ -42,6 +43,7 @@
 import org.apache.cocoon.sitemap.LeaveSitemapEventListener;
 import org.apache.cocoon.sitemap.SitemapExecutor;
 import org.apache.cocoon.sitemap.SitemapListener;
+import org.apache.commons.jci.monitor.FilesystemAlterationListener;
 
 /**
  * The concrete implementation of {@link Processor}, containing the evaluation tree and associated
@@ -50,7 +52,7 @@
  * @version $Id$
  */
 public class ConcreteTreeProcessor extends AbstractLogEnabled
-                                   implements Processor, Disposable {
+                                   implements Processor, Disposable, FilesystemAlterationListener {
 
     /** Our ServiceManager */
     private ServiceManager manager;
@@ -84,6 +86,75 @@
     /** Optional event listeners for the leave sitemap event */
     private List leaveSitemapEventListeners = new ArrayList();
 
+    /** Needs a reload? */
+    protected volatile boolean needsReload = false;
+    protected boolean fresh = true;
+    
+    public void onChangeDirectory( final File changeDirectory ) {
+        if (!fresh) {
+            if (getLogger().isDebugEnabled()) {
+                getLogger().debug("Sitemap reload required");
+            }
+            needsReload = true;
+        }
+    }
+
+    public void onChangeFile( final File changedFile ) {
+        if (!fresh) {
+            if (getLogger().isDebugEnabled()) {
+                getLogger().debug("Sitemap reload required");
+            }
+            needsReload = true;
+        }
+    }
+
+    public void onCreateDirectory( final File createdDirectory ) {
+        if (!fresh) {
+            if (getLogger().isDebugEnabled()) {
+                getLogger().debug("Sitemap reload required");
+            }
+            needsReload = true;
+        }
+    }
+
+    public void onCreateFile( final File createdFile ) {
+        if (!fresh) {
+            if (getLogger().isDebugEnabled()) {
+                getLogger().debug("Sitemap reload required");
+            }
+            needsReload = true;
+        }
+    }
+
+    public void onDeleteDirectory( final File deletedDirectory ) {
+        if (!fresh) {
+            if (getLogger().isDebugEnabled()) {
+                getLogger().debug("Sitemap reload required");
+            }
+            needsReload = true;
+        }
+    }
+
+    public void onDeleteFile( final File deletedFile ) {
+        if (!fresh) {
+            if (getLogger().isDebugEnabled()) {
+                getLogger().debug("Sitemap reload required");
+            }
+            needsReload = true;
+        }
+    }
+
+    public void onStart() {
+    }
+
+    public void onStop() {
+        if (getLogger().isDebugEnabled()) {
+            getLogger().debug("Now tracking classpath changes");
+        }
+        fresh = false;
+    }
+
+    
     /**
      * Builds a concrete processig, given the wrapping processor
      */
@@ -161,6 +232,10 @@
         }
     }
 
+    boolean isReloadNeeded() {
+        return needsReload;
+    }
+    
     public TreeProcessor getWrappingProcessor() {
         return this.wrappingProcessor;
     }

Modified: cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/TreeProcessor.java
URL: http://svn.apache.org/viewcvs/cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/TreeProcessor.java?view=diff&r1=159151&r2=159152
==============================================================================
--- cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/TreeProcessor.java (original)
+++ cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/TreeProcessor.java Sun Mar 27 07:03:57 2005
@@ -16,7 +16,6 @@
 package org.apache.cocoon.components.treeprocessor;
 
 import java.net.URL;
-
 import org.apache.avalon.framework.activity.Disposable;
 import org.apache.avalon.framework.activity.Initializable;
 import org.apache.avalon.framework.configuration.Configurable;
@@ -33,16 +32,15 @@
 import org.apache.avalon.framework.service.ServiceManager;
 import org.apache.avalon.framework.service.Serviceable;
 import org.apache.avalon.framework.thread.ThreadSafe;
-
 import org.apache.cocoon.Processor;
 import org.apache.cocoon.components.ContextHelper;
+import org.apache.cocoon.components.fam.SitemapMonitor;
 import org.apache.cocoon.components.source.SourceUtil;
 import org.apache.cocoon.components.source.impl.DelayedRefreshSourceWrapper;
 import org.apache.cocoon.environment.Environment;
 import org.apache.cocoon.environment.internal.EnvironmentHelper;
 import org.apache.cocoon.sitemap.SitemapExecutor;
 import org.apache.cocoon.sitemap.impl.DefaultExecutor;
-
 import org.apache.excalibur.source.Source;
 import org.apache.excalibur.source.SourceResolver;
 import org.apache.regexp.RE;
@@ -87,7 +85,9 @@
 
     /** Check for reload? */
     protected boolean checkReload;
-
+    
+    protected SitemapMonitor fom;
+    
     /** The source resolver */
     protected SourceResolver resolver;
 
@@ -135,6 +135,7 @@
         this.manager = parent.concreteProcessor.getServiceManager();
 
         this.resolver = (SourceResolver) this.manager.lookup(SourceResolver.ROLE);
+        this.fom = (SitemapMonitor) this.manager.lookup(SitemapMonitor.ROLE);
         this.environmentHelper = new EnvironmentHelper(parent.environmentHelper);
         // Setup environment helper
         ContainerUtil.enableLogging(this.environmentHelper, this.getLogger());
@@ -170,6 +171,7 @@
     public void service(ServiceManager manager) throws ServiceException {
         this.manager = manager;
         this.resolver = (SourceResolver) this.manager.lookup(SourceResolver.ROLE);
+        this.fom = (SitemapMonitor) this.manager.lookup(SitemapMonitor.ROLE);
     }
 
     public void initialize() throws Exception {
@@ -345,7 +347,7 @@
      */
     private void setupConcreteProcessor(Environment env) throws Exception {
         // first, check for sitemap changes
-        if (this.concreteProcessor == null ||
+        if (this.concreteProcessor == null || this.concreteProcessor.isReloadNeeded() ||
                 (this.checkReload && this.source.getLastModified() != this.lastModified)) {
             buildConcreteProcessor(env);
         }
@@ -359,7 +361,7 @@
 
         // Now that we entered the synchronized area, recheck what's already
         // been checked in process().
-        if (this.concreteProcessor != null && source.getLastModified() == this.lastModified) {
+        if (this.concreteProcessor != null && source.getLastModified() == this.lastModified && !this.concreteProcessor.isReloadNeeded()) {
             // Nothing changed
             return;
         }
@@ -367,6 +369,7 @@
         long startTime = System.currentTimeMillis();
         long newLastModified;
         ConcreteTreeProcessor newProcessor;
+        ConcreteTreeProcessor oldProcessor = this.concreteProcessor;
 
         // We have to do a call to enterProcessor() here as during building
         // of the tree, components (e.g. actions) are already instantiated
@@ -408,6 +411,21 @@
                         treeBuilder.getComponentLocator(),
                         treeBuilder.getEnterSitemapEventListeners(),
                         treeBuilder.getLeaveSitemapEventListeners());
+
+                fom.unsubscribeSitemap(oldProcessor);
+
+                Configuration classpath = sitemapProgram.getChild("components").getChild("classpath", false);
+                if (classpath != null) {
+                    if (getLogger().isDebugEnabled()) {
+                        getLogger().debug("ConcreteTreeProcessor listening for changes");
+                    }
+                    
+                    fom.subscribeSitemap(newProcessor, sitemapProgram);                   
+                }
+                
+                if (getLogger().isDebugEnabled()) {
+                    getLogger().debug("ConcreteTreeProcessor ready");
+                }
             } finally {
                 this.manager.release(treeBuilder);
             }
@@ -421,10 +439,10 @@
         }
 
         // Switch to the new processor (ensure it's never temporarily null)
-        ConcreteTreeProcessor oldProcessor = this.concreteProcessor;
         this.concreteProcessor = newProcessor;
         this.lastModified = newLastModified;
 
+        
         // Dispose the old processor, if any
         if (oldProcessor != null) {
             oldProcessor.markForDisposal();
@@ -456,6 +474,7 @@
                 this.resolver.release(this.source.getSource());
                 this.source = null;
             }
+            this.manager.release(this.fom);
             this.manager.release(this.resolver);
             this.resolver = null;
             this.manager = null;