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/09/24 15:25:25 UTC

svn commit: r291301 - in /cocoon: blocks/javaflow/trunk/java/org/apache/cocoon/components/flow/java/ blocks/xsp/trunk/java/org/apache/cocoon/components/language/programming/java/ trunk/lib/ trunk/lib/core/ trunk/lib/optional/ trunk/src/java/org/apache/...

Author: tcurdt
Date: Sat Sep 24 06:22:13 2005
New Revision: 291301

URL: http://svn.apache.org/viewcvs?rev=291301&view=rev
Log:
upgraded and further integrated the latest jci and javaflow,
the introduced dependency of the core on javaflow is just temporary,
also upgraded the jdtcore

Added:
    cocoon/trunk/lib/core/commons-javaflow-r291286.jar   (with props)
    cocoon/trunk/lib/core/commons-jci-r291284.jar   (with props)
    cocoon/trunk/lib/optional/jdtcore-3.1.0.jar   (with props)
    cocoon/trunk/src/java/org/apache/cocoon/components/classloader/ReloadingClassLoaderFactory.java
Removed:
    cocoon/trunk/lib/core/commons-jci-r159148.jar
    cocoon/trunk/lib/optional/commons-javaflow-0.1-dev.jar
    cocoon/trunk/lib/optional/jdtcore-3.0.2.jar
Modified:
    cocoon/blocks/javaflow/trunk/java/org/apache/cocoon/components/flow/java/CocoonContinuationContext.java
    cocoon/blocks/javaflow/trunk/java/org/apache/cocoon/components/flow/java/JavaInterpreter.java
    cocoon/blocks/xsp/trunk/java/org/apache/cocoon/components/language/programming/java/EclipseJavaCompiler.java
    cocoon/trunk/lib/jars.xml
    cocoon/trunk/src/java/org/apache/cocoon/components/fam/SitemapMonitor.java
    cocoon/trunk/src/java/org/apache/cocoon/components/fam/SitemapMonitorImpl.java
    cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/ConcreteTreeProcessor.java
    cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/DefaultTreeBuilder.java
    cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/TreeProcessor.java
    cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/sitemap/SitemapLanguage.java

Modified: cocoon/blocks/javaflow/trunk/java/org/apache/cocoon/components/flow/java/CocoonContinuationContext.java
URL: http://svn.apache.org/viewcvs/cocoon/blocks/javaflow/trunk/java/org/apache/cocoon/components/flow/java/CocoonContinuationContext.java?rev=291301&r1=291300&r2=291301&view=diff
==============================================================================
--- cocoon/blocks/javaflow/trunk/java/org/apache/cocoon/components/flow/java/CocoonContinuationContext.java (original)
+++ cocoon/blocks/javaflow/trunk/java/org/apache/cocoon/components/flow/java/CocoonContinuationContext.java Sat Sep 24 06:22:13 2005
@@ -20,7 +20,6 @@
 import org.apache.avalon.framework.parameters.Parameters;
 import org.apache.avalon.framework.service.ServiceManager;
 import org.apache.cocoon.environment.Redirector;
-import org.apache.commons.javaflow.ContinuationContext;
 
 /**
  * Helper class to associate cocoon flow informations to the continuation.
@@ -29,7 +28,7 @@
  * @author <a href="mailto:stephan@apache.org">Stephan Michels</a>
  * @version CVS $Id$
  */
-public class CocoonContinuationContext extends ContinuationContext {
+public class CocoonContinuationContext {
 
     private Logger logger;
     private Context avalonContext;

Modified: cocoon/blocks/javaflow/trunk/java/org/apache/cocoon/components/flow/java/JavaInterpreter.java
URL: http://svn.apache.org/viewcvs/cocoon/blocks/javaflow/trunk/java/org/apache/cocoon/components/flow/java/JavaInterpreter.java?rev=291301&r1=291300&r2=291301&view=diff
==============================================================================
--- cocoon/blocks/javaflow/trunk/java/org/apache/cocoon/components/flow/java/JavaInterpreter.java (original)
+++ cocoon/blocks/javaflow/trunk/java/org/apache/cocoon/components/flow/java/JavaInterpreter.java Sat Sep 24 06:22:13 2005
@@ -15,12 +15,12 @@
  */
 package org.apache.cocoon.components.flow.java;
 
+import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-
 import org.apache.avalon.framework.parameters.Parameters;
 import org.apache.cocoon.ProcessingException;
 import org.apache.cocoon.components.ContextHelper;
@@ -30,7 +30,6 @@
 import org.apache.cocoon.components.flow.WebContinuation;
 import org.apache.cocoon.environment.Redirector;
 import org.apache.commons.javaflow.Continuation;
-import org.apache.commons.javaflow.MethodLookup;
 import org.apache.commons.javaflow.utils.ReflectionUtils;
 import org.apache.commons.jxpath.JXPathIntrospector;
 
@@ -62,13 +61,26 @@
     
     private Map methods = new HashMap();
 
-    private MethodLookup lookup = new MethodLookup() {
-        public Method getMethod(final String methodName) {
-            final Method method = (Method) methods.get(methodName);            
-            return method;
+    private class Invoker implements Runnable {
+        private final Method method;
+        private final Object instance;
+
+        public Invoker(Method method) throws IllegalAccessException, InstantiationException {
+            this.method = method;
+            this.instance = method.getDeclaringClass().newInstance();
+        }
+
+        public void run() {
+            try {
+                method.invoke(instance, new Object[0]);
+            } catch (IllegalAccessException e) {
+                getLogger().error("", e);
+            } catch (InvocationTargetException e) {
+                getLogger().error("", e);
+            }
         }
-        
-    };
+    }
+
     
     private CocoonContinuationContext createContinuationContext( final List params, final Redirector redirector ) {
         final CocoonContinuationContext context = new CocoonContinuationContext();
@@ -77,7 +89,6 @@
         context.setLogger(getLogger());
         context.setServiceManager(manager);
         context.setRedirector(redirector);
-        context.setMethodLookup(lookup);
 
         final Parameters parameters = new Parameters();
         for(final Iterator i = params.iterator(); i.hasNext();) {
@@ -146,7 +157,8 @@
         // REVISIT: subscribe to jci events and only update accordingly
         updateMethodIndex();
         
-        if (lookup.getMethod(methodName) == null) {
+        final Method method = (Method) methods.get(methodName);
+        if (method == null) {
             throw new ProcessingException("no method '" + methodName + "' found in " + methods);
         }
 
@@ -160,7 +172,7 @@
         FlowHelper.setWebContinuation(
                 ContextHelper.getObjectModel(avalonContext), wk);
 
-        final Continuation newContinuation = Continuation.startWith(methodName, context);
+        final Continuation newContinuation = Continuation.startWith(new Invoker(method), context);
 
         handler.setContinuation(newContinuation);        
     }

Modified: cocoon/blocks/xsp/trunk/java/org/apache/cocoon/components/language/programming/java/EclipseJavaCompiler.java
URL: http://svn.apache.org/viewcvs/cocoon/blocks/xsp/trunk/java/org/apache/cocoon/components/language/programming/java/EclipseJavaCompiler.java?rev=291301&r1=291300&r2=291301&view=diff
==============================================================================
--- cocoon/blocks/xsp/trunk/java/org/apache/cocoon/components/language/programming/java/EclipseJavaCompiler.java (original)
+++ cocoon/blocks/xsp/trunk/java/org/apache/cocoon/components/language/programming/java/EclipseJavaCompiler.java Sat Sep 24 06:22:13 2005
@@ -250,7 +250,7 @@
                             ICompilationUnit compilationUnit = 
                                 new CompilationUnit(sourceFile, className);
                             return 
-                                new NameEnvironmentAnswer(compilationUnit);
+                                new NameEnvironmentAnswer(compilationUnit, null);
                         }
                         String resourceName = 
                             className.replace('.', '/') + ".class";
@@ -272,7 +272,7 @@
                                 new ClassFileReader(classBytes, fileName, 
                                                     true);
                             return 
-                                new NameEnvironmentAnswer(classFileReader);
+                                new NameEnvironmentAnswer(classFileReader, null);
                         }
                     } catch (IOException exc) {
                         handleError(className, -1, -1, 

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

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

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

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

Modified: cocoon/trunk/lib/jars.xml
URL: http://svn.apache.org/viewcvs/cocoon/trunk/lib/jars.xml?rev=291301&r1=291300&r2=291301&view=diff
==============================================================================
--- cocoon/trunk/lib/jars.xml (original)
+++ cocoon/trunk/lib/jars.xml Sat Sep 24 06:22:13 2005
@@ -608,7 +608,7 @@
     <title>Eclipse Java Development Tools Core</title>
     <description>Eclipse Java Compiler</description>
     <used-by>XSP</used-by>
-    <lib>optional/jdtcore-3.0.2.jar</lib>
+    <lib>optional/jdtcore-3.1.0.jar</lib>
     <homepage>http://www.eclipse.org/jdt/</homepage>
   </file>
 
@@ -1149,7 +1149,7 @@
       API for compiling java
     </description>
     <used-by>javaflow</used-by>
-    <lib>core/commons-jci-r159148.jar</lib>
+    <lib>core/commons-jci-r291284.jar</lib>
     <homepage></homepage>
   </file>
 
@@ -1159,7 +1159,7 @@
       API java continuations
     </description>
     <used-by>javaflow</used-by>
-    <lib>optional/commons-javaflow-0.1-dev.jar</lib>
+    <lib>core/commons-javaflow-r291286.jar</lib>
     <homepage></homepage>
   </file>
 

Added: cocoon/trunk/lib/optional/jdtcore-3.1.0.jar
URL: http://svn.apache.org/viewcvs/cocoon/trunk/lib/optional/jdtcore-3.1.0.jar?rev=291301&view=auto
==============================================================================
Binary file - no diff available.

Propchange: cocoon/trunk/lib/optional/jdtcore-3.1.0.jar
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: cocoon/trunk/src/java/org/apache/cocoon/components/classloader/ReloadingClassLoaderFactory.java
URL: http://svn.apache.org/viewcvs/cocoon/trunk/src/java/org/apache/cocoon/components/classloader/ReloadingClassLoaderFactory.java?rev=291301&view=auto
==============================================================================
--- cocoon/trunk/src/java/org/apache/cocoon/components/classloader/ReloadingClassLoaderFactory.java (added)
+++ cocoon/trunk/src/java/org/apache/cocoon/components/classloader/ReloadingClassLoaderFactory.java Sat Sep 24 06:22:13 2005
@@ -0,0 +1,306 @@
+/* 
+ * 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.classloader;
+
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.net.URLStreamHandlerFactory;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import org.apache.avalon.framework.activity.Disposable;
+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.cocoon.matching.helpers.WildcardHelper;
+import org.apache.commons.jci.stores.ResourceStore;
+import org.apache.excalibur.source.Source;
+import org.apache.excalibur.source.SourceResolver;
+import org.apache.excalibur.source.TraversableSource;
+
+/**
+ * Default implementation of {@link ClassLoaderFactory}. It accepts both class directory and jar
+ * directory configurations.
+ * <p>
+ * Wildcard patterns can also be specified to include or exclude some classes to be loaded in the
+ * classloader. In such case, the class is directly loaded from the parent classloader. The default
+ * is to include all classes.
+ * <p>
+ * Example:
+ * <pre>
+ * &lt;classpath&gt;
+ *   &lt;class-dir src="BLOCK-INF/classes"/&gt;
+ *   &lt;lib-dir src="BLOCK-INF/lib"/&gt;
+ *   &lt;include-classes pattern="org.apache.cocoon.**"/&gt;
+ *   &lt;exclude-classes pattern="org.apache.cocoon.transformation.**"/&gt;
+ * &/lt;classpath&gt;
+ * </pre>
+ */
+public class ReloadingClassLoaderFactory extends AbstractLogEnabled implements ClassLoaderFactory,
+    Serviceable, ThreadSafe, Disposable {
+
+    private ServiceManager manager;
+    private SourceResolver resolver;
+    
+    /* (non-Javadoc)
+     * @see org.apache.avalon.framework.service.Serviceable#service(org.apache.avalon.framework.service.ServiceManager)
+     */
+    public void service(ServiceManager manager) throws ServiceException {
+        this.manager = manager;
+        this.resolver = (SourceResolver)manager.lookup(SourceResolver.ROLE);
+    }
+    
+    private void ensureIsDirectory(Source src, String location) throws ConfigurationException {
+        if (!src.exists()) {
+            throw new ConfigurationException(src.getURI() + " doesn't exist, at " + location);
+        } else if (!(src instanceof TraversableSource) || !((TraversableSource)src).isCollection()) {
+            throw new ConfigurationException(src.getURI() + " is not a directory, at " + location);
+        }
+    }
+    
+    /* (non-Javadoc)
+     * @see org.apache.cocoon.core.ClassLoaderFactory#createClassLoader(java.lang.ClassLoader)
+     */
+    public ClassLoader createClassLoader(ClassLoader parent, Configuration config) throws ConfigurationException {
+        List urlList = new ArrayList();
+
+        Configuration[] libDirConfig = config.getChildren("lib-dir");
+        for (int i = 0; i < libDirConfig.length; i++) {
+            Configuration child = libDirConfig[i];
+
+            Source src = null;
+            try {
+                src = resolver.resolveURI(child.getAttribute("src"));
+                ensureIsDirectory(src, child.getLocation());
+                Iterator iter = ((TraversableSource)src).getChildren().iterator();
+                while (iter.hasNext()) {
+                    Source childSrc = (Source)iter.next();
+                    String childURI = childSrc.getURI();
+                    resolver.release(childSrc);
+                    if (childURI.endsWith(".jar") || childURI.endsWith(".zip")) {
+                        urlList.add(new URL(childURI));
+                    }
+                }
+            } catch(ConfigurationException ce) {
+                throw ce;
+            } catch(Exception e) {
+                throw new ConfigurationException("Error loading classpath at " + child.getLocation(), e);
+            } finally {
+                resolver.release(src);
+                src = null;
+            }
+        }
+        
+        URL[] urls = (URL[])urlList.toArray(new URL[urlList.size()]);
+
+        int[][] includes = compilePatterns(config.getChildren("include-classes"));
+        int[][] excludes = compilePatterns(config.getChildren("exclude-classes"));
+        
+        return new DefaultClassLoader(urls, includes, excludes, parent);
+    }
+
+    private int[][] compilePatterns(Configuration[] patternConfigs) throws ConfigurationException {
+        if (patternConfigs.length == 0) {
+            return null;
+        }
+        
+        int[][] patterns = new int[patternConfigs.length][];
+        
+        for (int i = 0; i < patternConfigs.length; i++) {
+            patterns[i] = WildcardHelper.compilePattern(patternConfigs[i].getAttribute("pattern"));
+        }
+        
+        return patterns;
+    }
+    
+    public class DefaultClassLoader extends URLClassLoader {
+        
+        private ResourceStore[] stores = new ResourceStore[0];
+        private final int[][] includes;
+        private final int[][] excludes;
+
+        /**
+         * Alternate constructor to define a parent and initial <code>URL</code>
+         * s.
+         */
+        public DefaultClassLoader(URL[] urls, int[][] includes, int[][] excludes, final ClassLoader parent) {
+            this(urls, includes, excludes, parent, null);
+        }
+
+        /**
+         * Alternate constructor to define a parent, initial <code>URL</code>s,
+         * and a default <code>URLStreamHandlerFactory</code>.
+         */
+        public DefaultClassLoader(final URL[] urls, int[][] includes, int[][] excludes, ClassLoader parent, URLStreamHandlerFactory factory) {
+            super(urls, parent, factory);
+            this.includes = includes;
+            this.excludes = excludes;
+        }
+        
+        
+        public void addResourceStore(final ResourceStore pStore) {
+            final int n = stores.length;
+            final ResourceStore[] newStores = new ResourceStore[n + 1];
+            System.arraycopy(stores, 0, newStores, 0, n);
+            newStores[n] = pStore;
+            stores = newStores;
+            if (getLogger().isDebugEnabled()) {
+                getLogger().debug("added store " + stores);
+            }
+        }
+
+        private Class fastFindClass(final String name) {
+            
+            if (stores != null) {
+                for (int i = 0; i < stores.length; i++) {
+                    final ResourceStore store = stores[i];
+                    final byte[] clazzBytes = store.read(name);
+                    if (clazzBytes != null) {
+                        
+                        if (getLogger().isDebugEnabled()) {
+                            getLogger().debug("found class " + name + " in stores");
+                        }
+
+                        return defineClass(name, clazzBytes, 0, clazzBytes.length);
+                    }            
+                }
+            }
+
+            if (getLogger().isDebugEnabled()) {
+                getLogger().debug("did not find class " + name + " in stores");
+            }
+            
+            return null;            
+        }
+        
+        private boolean tryClassHere(String name) {
+            // Scan includes, then excludes
+            boolean tryHere;
+            
+            // If no explicit includes, try here
+            if (this.includes == null) {
+                tryHere = true;
+            } else {
+                // See if it matches include patterns
+                tryHere = false;
+                for (int i = 0; i < this.includes.length; i++) {
+                    if (WildcardHelper.match(null, name, includes[i])) {
+                        tryHere = true;
+                        break;
+                    }
+                }
+            }
+            
+            // Go through the exclusion list
+            if (tryHere && excludes != null) {
+                for (int i = 0; i < this.excludes.length; i++) {
+                    if (WildcardHelper.match(null, name, excludes[i])) {
+                        tryHere = false;
+                        break;
+                    }
+                }
+            }
+            
+            return tryHere;
+        }
+
+        /**
+         * Loads the class from this <code>ClassLoader</class>.  If the
+         * class does not exist in this one, we check the parent.  Please
+         * note that this is the exact opposite of the
+         * <code>ClassLoader</code> spec.  We use it to work around
+         * inconsistent class loaders from third party vendors.
+         *
+         * @param     name the name of the class
+         * @param     resolve if <code>true</code> then resolve the class
+         * @return    the resulting <code>Class</code> object
+         * @exception ClassNotFoundException if the class could not be found
+         */
+        public final Class loadClass(String name, boolean resolve) throws ClassNotFoundException {
+            // First check if it's already loaded
+            Class clazz = findLoadedClass(name);
+
+            if (clazz == null) {
+                
+                ClassLoader parent = getParent();
+
+                if (tryClassHere(name)) {
+                    
+                    clazz = fastFindClass(name);
+                    
+                    if (clazz == null) {                    
+                        try {
+                            clazz = findClass(name);
+                            //System.err.println("Paranoid load : " + name);
+                        } catch (ClassNotFoundException cnfe) {
+                            if (parent == null) {
+                                // Propagate exception
+                                throw cnfe;                        
+                            }
+                        }
+                    }
+                }
+                
+                if (clazz == null) {
+                    if (parent == null) {
+                        throw new ClassNotFoundException(name);
+                    } else {
+                        // Will throw a CFNE if not found in parent
+                        clazz = parent.loadClass(name);
+                    }
+                }
+            }
+
+            if (resolve) {
+                resolveClass(clazz);
+            }
+
+            return clazz;
+        }
+
+        /**
+         * Gets a resource from this <code>ClassLoader</class>.  If the
+         * resource does not exist in this one, we check the parent.
+         * Please note that this is the exact opposite of the
+         * <code>ClassLoader</code> spec.  We use it to work around
+         * inconsistent class loaders from third party vendors.
+         *
+         * @param name of resource
+         */
+        public final URL getResource(final String name) {
+
+            URL resource = findResource(name);
+            ClassLoader parent = this.getParent();
+            if (resource == null && parent != null) {
+                resource = parent.getResource(name);
+            }
+
+            return resource;
+        }
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.avalon.framework.activity.Disposable#dispose()
+     */
+    public void dispose() {
+        this.manager.release(this.resolver);
+    }
+}

Modified: 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?rev=291301&r1=291300&r2=291301&view=diff
==============================================================================
--- cocoon/trunk/src/java/org/apache/cocoon/components/fam/SitemapMonitor.java (original)
+++ cocoon/trunk/src/java/org/apache/cocoon/components/fam/SitemapMonitor.java Sat Sep 24 06:22:13 2005
@@ -16,14 +16,11 @@
  */
 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);
+    
+    void subscribe(final FilesystemAlterationListener listener);    
+    void unsubscribe(final FilesystemAlterationListener listener);
 }

Modified: 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?rev=291301&r1=291300&r2=291301&view=diff
==============================================================================
--- cocoon/trunk/src/java/org/apache/cocoon/components/fam/SitemapMonitorImpl.java (original)
+++ cocoon/trunk/src/java/org/apache/cocoon/components/fam/SitemapMonitorImpl.java Sat Sep 24 06:22:13 2005
@@ -16,13 +16,8 @@
  */
 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;
@@ -30,77 +25,33 @@
 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();
-
+    private FilesystemAlterationMonitor monitor;
 
     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 {
-                if ("class-dir".equals(name)) {
-                    src = resolver.resolveURI(child.getAttribute("src"));
-                    String dir = src.getURI();
-                    resolver.release(src);
-                    if (getLogger().isDebugEnabled()) {
-                        getLogger().debug("class-dir:" + dir);
-                    }
-                    urlList.add(new File(dir.substring(5)));
-                } else if ("lib-dir".equals(name)) {
-                    src = resolver.resolveURI(child.getAttribute("src"));
-                    String dir = src.getURI();
-                    resolver.release(src);
-                    if (getLogger().isDebugEnabled()) {
-                        getLogger().debug("lib-dir:" + dir);
-                    }
-                    urlList.add(new File(dir.substring(5)));
-                } else {
-                    // ignore for now include and exclude patterns
-                }
-            } 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 initialize() throws Exception {
+        monitor = new FilesystemAlterationMonitor();
+        monitor.start();
     }
 
-    public void unsubscribeSitemap( FilesystemAlterationListener listener) {
-        monitor.removeListener(listener);
+    public void dispose() {
+        monitor.stop();
     }
     
-    public void initialize() throws Exception {
-        Thread myThread = new Thread(monitor);
-        myThread.start();
+    public void subscribe(final FilesystemAlterationListener listener) {
+        monitor.addListener(listener);
     }
-
-
-    public void dispose() {
+    
+    public void unsubscribe(final FilesystemAlterationListener listener) {
+        monitor.removeListener(listener);
     }
 }

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?rev=291301&r1=291300&r2=291301&view=diff
==============================================================================
--- cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/ConcreteTreeProcessor.java (original)
+++ cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/ConcreteTreeProcessor.java Sat Sep 24 06:22:13 2005
@@ -15,14 +15,12 @@
  */
 package org.apache.cocoon.components.treeprocessor;
 
-import java.io.File;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-
 import org.apache.avalon.framework.activity.Disposable;
 import org.apache.avalon.framework.configuration.Configuration;
 import org.apache.avalon.framework.container.ContainerUtil;
@@ -48,7 +46,7 @@
 import org.apache.cocoon.sitemap.SitemapListener;
 import org.apache.cocoon.util.location.Location;
 import org.apache.cocoon.util.location.LocationImpl;
-import org.apache.commons.jci.monitor.FilesystemAlterationListener;
+import org.apache.commons.jci.listeners.NotificationListener;
 
 /**
  * The concrete implementation of {@link Processor}, containing the evaluation tree and associated
@@ -57,7 +55,7 @@
  * @version $Id$
  */
 public class ConcreteTreeProcessor extends AbstractLogEnabled
-                                   implements Processor, Disposable, FilesystemAlterationListener, ExecutionContext {
+                                   implements Processor, Disposable, ExecutionContext, NotificationListener {
 
     /** Our ServiceManager */
     private ServiceManager manager;
@@ -93,82 +91,11 @@
 
     /** Needs a reload? */
     protected volatile boolean needsReload = false;
-    protected boolean fresh = true;
     
     /** Processor attributes */
     protected Map processorAttributes = new HashMap();
 
-    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;
-        }
-    }
-
-    /**
-     * @see org.apache.commons.jci.monitor.FilesystemAlterationListener#onStart()
-     */
-    public void onStart() {
-        // nothing to do
-    }
-
-    /**
-     * @see org.apache.commons.jci.monitor.FilesystemAlterationListener#onStop()
-     */
-    public void onStop() {
-        if (getLogger().isDebugEnabled()) {
-            getLogger().debug("Now tracking classpath changes");
-        }
-        fresh = false;
-    }
-
+    private Map classpathListeners;
     
     /**
      * Builds a concrete processig, given the wrapping processor
@@ -179,17 +106,32 @@
         this.wrappingProcessor = wrappingProcessor;
 
         // Get the sitemap executor - we use the same executor for each sitemap
-        this.sitemapExecutor = sitemapExecutor;
+        this.sitemapExecutor = sitemapExecutor;        
     }
 
+    public void handleNotification() {
+        if (getLogger().isDebugEnabled()) {
+            getLogger().debug(this + " got notified that a reload is required");
+        }
+        needsReload = true;
+    }
+    
+    public void setClasspathListeners(Map classpathListeners) {
+        this.classpathListeners = classpathListeners;
+    }
+    
+    public Map getClasspathListeners() {
+        return this.classpathListeners;
+    }    
+    
     /** Set the processor data, result of the treebuilder job */
     public void setProcessorData(ServiceManager manager, 
                                  ClassLoader classloader, 
                                  ProcessingNode rootNode, 
                                  List disposableNodes,
                                  ComponentLocator componentLocator,
-                                 List             enterSitemapEventListeners,
-                                 List             leaveSitemapEventListeners) {
+                                 List enterSitemapEventListeners,
+                                 List leaveSitemapEventListeners) {
         if (this.rootNode != null) {
             throw new IllegalStateException("setProcessorData() can only be called once");
         }

Modified: cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/DefaultTreeBuilder.java
URL: http://svn.apache.org/viewcvs/cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/DefaultTreeBuilder.java?rev=291301&r1=291300&r2=291301&view=diff
==============================================================================
--- cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/DefaultTreeBuilder.java (original)
+++ cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/DefaultTreeBuilder.java Sat Sep 24 06:22:13 2005
@@ -27,6 +27,7 @@
 import org.apache.avalon.framework.configuration.AbstractConfiguration;
 import org.apache.avalon.framework.configuration.Configuration;
 import org.apache.avalon.framework.configuration.ConfigurationException;
+import org.apache.avalon.framework.configuration.DefaultConfiguration;
 import org.apache.avalon.framework.configuration.SAXConfigurationHandler;
 import org.apache.avalon.framework.context.Context;
 import org.apache.avalon.framework.context.ContextException;
@@ -213,6 +214,12 @@
         return this.context;
     }
 
+    protected ClassLoader createClassLoader(Configuration tree) throws Exception {
+        // Useless method as it's redefined in SitemapLanguage
+        // which is the only used incarnation.
+        return Thread.currentThread().getContextClassLoader();        
+    }
+    
     /**
      * Create a service manager that will be used for all <code>Serviceable</code>
      * <code>ProcessingNodeBuilder</code>s and <code>ProcessingNode</code>s.
@@ -226,11 +233,8 @@
      *
      * @return a component manager
      */
-    protected ServiceManager createServiceManager(Context context, Configuration tree)
+    protected ServiceManager createServiceManager(ClassLoader classloader, Context context, Configuration tree)
     throws Exception {
-        // Useless method as it's redefined in SitemapLanguage
-        // which is the only used incarnation.
-        this.itsClassLoader = Thread.currentThread().getContextClassLoader();
         return this.manager;
     }
 
@@ -371,9 +375,25 @@
         // The namespace used in the whole sitemap is the one of the root element
         this.itsNamespace = tree.getNamespace();
 
-        // Context and manager for the sitemap we build
+        Configuration componentConfig = tree.getChild("components", false);
+
+        if (componentConfig == null) {
+            if (getLogger().isDebugEnabled()) {
+                getLogger().debug("Sitemap has no components definition at " + tree.getLocation());
+            }
+            componentConfig = new DefaultConfiguration("", "");
+        }
+
+        // Context and manager and classloader for the sitemap we build
         this.itsContext = createContext(tree);
-        this.itsManager = createServiceManager(this.itsContext, tree);
+//        this.itsClassLoader = createClassLoader(componentConfig);
+//        
+//        Thread currentThread = Thread.currentThread();
+        //ClassLoader oldClassLoader = currentThread.getContextClassLoader();
+//        currentThread.setContextClassLoader(this.itsClassLoader);
+        this.itsClassLoader = Thread.currentThread().getContextClassLoader();
+
+        this.itsManager = createServiceManager(this.itsClassLoader, this.itsContext, componentConfig);
         this.itsComponentInfo = (ProcessorComponentInfo)this.itsManager.lookup(ProcessorComponentInfo.ROLE);
 
         // Create a helper object to setup components

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?rev=291301&r1=291300&r2=291301&view=diff
==============================================================================
--- cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/TreeProcessor.java (original)
+++ cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/TreeProcessor.java Sat Sep 24 06:22:13 2005
@@ -15,8 +15,12 @@
  */
 package org.apache.cocoon.components.treeprocessor;
 
+import java.io.File;
 import java.net.URL;
-
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
 import org.apache.avalon.framework.activity.Disposable;
 import org.apache.avalon.framework.activity.Initializable;
 import org.apache.avalon.framework.configuration.Configurable;
@@ -35,6 +39,8 @@
 import org.apache.avalon.framework.thread.ThreadSafe;
 import org.apache.cocoon.Processor;
 import org.apache.cocoon.components.ContextHelper;
+import org.apache.cocoon.components.classloader.ClassLoaderFactory;
+import org.apache.cocoon.components.classloader.ReloadingClassLoaderFactory;
 import org.apache.cocoon.components.fam.SitemapMonitor;
 import org.apache.cocoon.components.flow.Interpreter;
 import org.apache.cocoon.components.source.SourceUtil;
@@ -44,6 +50,16 @@
 import org.apache.cocoon.environment.internal.EnvironmentHelper;
 import org.apache.cocoon.sitemap.SitemapExecutor;
 import org.apache.cocoon.sitemap.impl.DefaultExecutor;
+import org.apache.commons.jci.compilers.JavaCompiler;
+import org.apache.commons.jci.compilers.eclipse.EclipseJavaCompiler;
+import org.apache.commons.jci.listeners.CompilingListener;
+import org.apache.commons.jci.listeners.FileChangeListener;
+import org.apache.commons.jci.listeners.NotifyingListener;
+import org.apache.commons.jci.listeners.ReloadingListener;
+import org.apache.commons.jci.listeners.ResourceStoringListener;
+import org.apache.commons.jci.monitor.FilesystemAlterationListener;
+import org.apache.commons.jci.stores.ResourceStore;
+import org.apache.commons.jci.stores.TransactionalResourceStore;
 import org.apache.excalibur.source.Source;
 import org.apache.excalibur.source.SourceResolver;
 import org.apache.regexp.RE;
@@ -86,7 +102,7 @@
     /** Check for reload? */
     protected boolean checkReload;
     
-    protected SitemapMonitor fom;
+    protected SitemapMonitor fam;
     
     /** The source resolver */
     protected SourceResolver resolver;
@@ -135,7 +151,7 @@
         this.manager = parent.concreteProcessor.getServiceManager();
 
         this.resolver = (SourceResolver) this.manager.lookup(SourceResolver.ROLE);
-        this.fom = (SitemapMonitor) this.manager.lookup(SitemapMonitor.ROLE);
+        this.fam = (SitemapMonitor) this.manager.lookup(SitemapMonitor.ROLE);
         this.environmentHelper = new EnvironmentHelper(parent.environmentHelper);
         // Setup environment helper
         ContainerUtil.enableLogging(this.environmentHelper, this.getLogger());
@@ -171,7 +187,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);
+        this.fam = (SitemapMonitor) this.manager.lookup(SitemapMonitor.ROLE);
     }
 
     /**
@@ -179,7 +195,7 @@
      */
     public void initialize() throws Exception {
         // setup the environment helper
-        if (this.environmentHelper == null ) {
+        if (this.environmentHelper == null) {
             this.environmentHelper = new EnvironmentHelper(
                     (URL) this.context.get(ContextHelper.CONTEXT_ROOT_URL));
         }
@@ -188,7 +204,7 @@
 
         // Create sitemap executor
         if (this.parent == null) {
-            if ( this.manager.hasService(SitemapExecutor.ROLE) ) {
+            if (this.manager.hasService(SitemapExecutor.ROLE)) {
                 this.sitemapExecutor = (SitemapExecutor) this.manager.lookup(SitemapExecutor.ROLE);
                 this.releaseSitemapExecutor = true;
             } else {
@@ -368,7 +384,183 @@
             buildConcreteProcessor(env);
         }
     }
+    
+    private JavaCompiler createJavaCompiler(final Configuration config) {
+        // FIXME: extract compiler and compiler configuration from config
+        return new EclipseJavaCompiler();
+    }
+    
+    private ResourceStore createResourceStore(final Configuration storeConfig) throws Exception {
+        final String className = storeConfig.getAttribute("class","org.apache.commons.jci.stores.MemoryResourceStore");
+        final ResourceStore store = (ResourceStore) Class.forName(className).newInstance();
+        if (getLogger().isDebugEnabled()) {
+            getLogger().debug("storing resources in " + store.getClass().getName());
+        }
+        return store;
+    }
+    
+    private FilesystemAlterationListener createCompilingListener(
+            final Configuration dirConfig
+            ) throws Exception {
+        Source src = null;
+        
+        try {
+            src = resolver.resolveURI(dirConfig.getAttribute("src"));
+            final File repository = new File(src.getURI().substring(5));
+
+            if (getLogger().isDebugEnabled()) {
+                getLogger().debug("monitoring src dir " + dirConfig.getAttribute("src"));
+            }
+
+            return new CompilingListener(
+                repository,
+                createJavaCompiler(dirConfig.getChild("compiler")),
+                new TransactionalResourceStore(createResourceStore(dirConfig.getChild("store")))
+              );
+        } finally {
+            resolver.release(src);
+        }
+    }
+
+    private FilesystemAlterationListener createReloadingListener(
+            final Configuration dirConfig
+            ) throws Exception {
+        Source src = null;
+        
+        try {
+            src = resolver.resolveURI(dirConfig.getAttribute("src"));
+            final File repository = new File(src.getURI().substring(5));
+
+            if (getLogger().isDebugEnabled()) {
+                getLogger().debug("monitoring class dir " + dirConfig.getAttribute("src"));
+            }
+
+            return new ReloadingListener(
+                repository,
+                createResourceStore(dirConfig.getChild("store"))
+                );
+        } finally {
+            resolver.release(src);
+        }
+    }
+
+    private FilesystemAlterationListener createFileChangeListener(
+            final Configuration dirConfig
+            ) throws Exception {
+        Source src = null;
+        
+        try {
+            src = resolver.resolveURI(dirConfig.getAttribute("src"));
+            final File repository = new File(src.getURI().substring(5));
+
+            if (getLogger().isDebugEnabled()) {
+                getLogger().debug("monitoring lib dir " + dirConfig.getAttribute("src"));
+            }
+
+            return new FileChangeListener(repository);
+        } finally {
+            resolver.release(src);
+        }
+    }
+
+    
+    private boolean containsListener(Map map, String src, Class clazz) {
+        FilesystemAlterationListener listener = (FilesystemAlterationListener) map.get(src);
+        if (listener == null) {
+            if (getLogger().isDebugEnabled()) {
+                getLogger().debug("no previous listener for " + src);
+            }
+            return false;
+        }
+        if (!listener.getClass().equals(clazz)) {
+            if (getLogger().isDebugEnabled()) {
+                getLogger().debug("previous listener was of a different type");
+            }
+            return false;
+        }
+        
+        return true;
+    }
+    
+    private Map createClasspathListeners(Map oldListeners, Configuration classpathConfig) throws Exception {
+
+        final Configuration[] classDirConfigs = classpathConfig.getChildren("class-dir");        
+        final Configuration[] srcDirConfigs = classpathConfig.getChildren("src-dir");        
+        final Configuration[] libDirConfigs = classpathConfig.getChildren("lib-dir");    
+
+        Map newListeners = new HashMap();
+        int r = 0;
+        
+        for (int i = 0; i < classDirConfigs.length; i++) {
+            final Configuration dirConfig = classDirConfigs[i];
+            final String src = dirConfig.getAttribute("src");
+            if (containsListener(oldListeners,src, ReloadingListener.class)) {
+                if (getLogger().isDebugEnabled()) {
+                    getLogger().debug("keeping ReloadingListener for " + src);
+                }
+                newListeners.put(src, oldListeners.get(src));
+                oldListeners.remove(src);
+            } else {
+                if (getLogger().isDebugEnabled()) {
+                    getLogger().debug("new ReloadingListener for " + src);
+                }
+                newListeners.put(src, createReloadingListener(dirConfig));
+            }
+        }
+
+        for (int i = 0; i < srcDirConfigs.length; i++) {
+            final Configuration dirConfig = srcDirConfigs[i];
+            final String src = dirConfig.getAttribute("src");
+            if (containsListener(oldListeners, src, CompilingListener.class)) {
+                if (getLogger().isDebugEnabled()) {
+                    getLogger().debug("keeping CompilingListener for " + src);
+                }
+                newListeners.put(src, oldListeners.get(src));
+                oldListeners.remove(src);
+            } else {
+                if (getLogger().isDebugEnabled()) {
+                    getLogger().debug("new CompilingListener for " + src);
+                }
+                newListeners.put(src, createCompilingListener(dirConfig));
+            }
+        }
+
+        for (int i = 0; i < libDirConfigs.length; i++) {
+            final Configuration dirConfig = libDirConfigs[i];
+            final String src = dirConfig.getAttribute("src");
+            if (containsListener(oldListeners, src, FileChangeListener.class)) {
+                if (getLogger().isDebugEnabled()) {
+                    getLogger().debug("keeping FileChangeListener for " + src);
+                }
+                newListeners.put(src, oldListeners.get(src));
+                oldListeners.remove(src);
+            } else {
+                if (getLogger().isDebugEnabled()) {
+                    getLogger().debug("new FileChangeListener for " + src);
+                }
+                newListeners.put(src, createFileChangeListener(dirConfig));
+            }
+        }
+             
+        return newListeners;
+    }
+    
+    protected ClassLoader createClassLoader(Configuration classpathConfig)
+    throws Exception {
+        String factoryRole = classpathConfig.getAttribute("factory-role", ClassLoaderFactory.ROLE + "/ReloadingClassLoaderFactory");
+        // Create a new classloader
+        ClassLoaderFactory clFactory = (ClassLoaderFactory)this.manager.lookup(factoryRole);
+        try {
+            return clFactory.createClassLoader(
+                    Thread.currentThread().getContextClassLoader(),
+                    classpathConfig
+            );
+        } finally {
+            this.manager.release(clFactory);
+        }
+    }
 
+    
     /**
      * Build the concrete processor (i.e. loads the sitemap). Should be called
      * only by setupProcessor();
@@ -386,6 +578,20 @@
         long newLastModified;
         ConcreteTreeProcessor newProcessor;
         ConcreteTreeProcessor oldProcessor = this.concreteProcessor;
+        Map oldListeners = Collections.EMPTY_MAP;
+        Map newListeners = Collections.EMPTY_MAP;
+                
+        if (oldProcessor != null) {
+            if (getLogger().isDebugEnabled()) {
+                getLogger().debug("found a previous ConcreteTreeProcessor");
+            }            
+            oldListeners = oldProcessor.getClasspathListeners();                    
+        } else {
+            if (getLogger().isDebugEnabled()) {
+                getLogger().debug("first version of the ConcreteTreeProcessor");
+            }            
+        }
+        
 
         // We have to do a call to enterProcessor() here as during building
         // of the tree, components (e.g. actions) are already instantiated
@@ -400,12 +606,69 @@
             // Build a namespace-aware configuration object
             NamespacedSAXConfigurationHandler handler = new NamespacedSAXConfigurationHandler();
             AnnotationsFilter annotationsFilter = new AnnotationsFilter(handler);
-            SourceUtil.toSAX(this.source, annotationsFilter );
+            SourceUtil.toSAX(this.source, annotationsFilter);
             Configuration sitemapProgram = handler.getConfiguration();
             newLastModified = this.source.getLastModified();
 
             newProcessor = createConcreteTreeProcessor();
 
+            Configuration classpathConfig = sitemapProgram.getChild("components").getChild("classpath", false);
+            if (classpathConfig != null) {
+                if (getLogger().isDebugEnabled()) {
+                    getLogger().debug("ConcreteTreeProcessor has a special classpath");
+                }
+
+                ClassLoader classloader = createClassLoader(classpathConfig);
+                Thread.currentThread().setContextClassLoader(classloader);
+                
+                newListeners = createClasspathListeners(oldListeners, classpathConfig);
+                newProcessor.setClasspathListeners(newListeners);
+                
+                if (getLogger().isDebugEnabled()) {
+                    getLogger().debug("setting up listeners " + newListeners);
+                }
+                for (final Iterator it = newListeners.values().iterator(); it.hasNext();) {
+                    final NotifyingListener newListener = (NotifyingListener) it.next();
+                    
+                    newListener.setNotificationListener(newProcessor);
+                    
+                    fam.subscribe(newListener);
+
+                    if (newListener instanceof ResourceStoringListener) {
+                        ResourceStoringListener l = (ResourceStoringListener)newListener;
+                        if (classloader instanceof ReloadingClassLoaderFactory.DefaultClassLoader) {
+                            if (getLogger().isDebugEnabled()) {
+                                getLogger().debug("adding store " + l.getStore() + " to classloader");
+                            }
+                            ReloadingClassLoaderFactory.DefaultClassLoader cl = (ReloadingClassLoaderFactory.DefaultClassLoader) classloader;
+                            cl.addResourceStore(l.getStore());
+                        }
+                    }                
+                }
+            }
+
+            if (oldListeners.size() > 0) {
+                if (getLogger().isDebugEnabled()) {
+                    getLogger().debug("unsubscribing " + oldListeners + " from fam");
+                }
+                for (final Iterator it = oldListeners.values().iterator(); it.hasNext();) {
+                    final FilesystemAlterationListener oldListener = (FilesystemAlterationListener) it.next();
+                    fam.unsubscribe(oldListener);
+                }
+            }
+
+            
+            if (newListeners.size() > 0) {
+                // wait for the new ones to complete for the first time                
+                for (final Iterator it = newListeners.values().iterator(); it.hasNext();) {
+                    final NotifyingListener newListener = (NotifyingListener) it.next();
+                    if (getLogger().isDebugEnabled()) {
+                        getLogger().debug("waiting for initial compilation");
+                    }
+                    newListener.waitForFirstCheck();
+                }
+            }
+
             // Get the treebuilder that can handle this version of the sitemap.
             TreeBuilder treeBuilder = getTreeBuilder(sitemapProgram);
             try {
@@ -416,21 +679,11 @@
                 newProcessor.setProcessorData(
                         treeBuilder.getBuiltProcessorManager(),
                         treeBuilder.getBuiltProcessorClassLoader(),
-                        root, treeBuilder.getDisposableNodes(),
+                        root,
+                        treeBuilder.getDisposableNodes(),
                         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");
@@ -467,9 +720,9 @@
     }
 
     private ConcreteTreeProcessor createConcreteTreeProcessor() {
-        ConcreteTreeProcessor processor = new ConcreteTreeProcessor(this, this.sitemapExecutor);
-        setupLogger(processor);
-        return processor;
+        ConcreteTreeProcessor newProcessor = new ConcreteTreeProcessor(this, this.sitemapExecutor);
+        setupLogger(newProcessor);
+        return newProcessor;
     }
 
     /* (non-Javadoc)
@@ -491,7 +744,7 @@
                 this.resolver.release(this.source.getSource());
                 this.source = null;
             }
-            this.manager.release(this.fom);
+            this.manager.release(this.fam);
             this.manager.release(this.resolver);
             this.resolver = null;
             this.manager = null;
@@ -517,4 +770,5 @@
      */
     public void setAttribute(String name, Object value) {
         this.concreteProcessor.setAttribute(name, value);
-    }}
+    }
+}

Modified: cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/sitemap/SitemapLanguage.java
URL: http://svn.apache.org/viewcvs/cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/sitemap/SitemapLanguage.java?rev=291301&r1=291300&r2=291301&view=diff
==============================================================================
--- cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/sitemap/SitemapLanguage.java (original)
+++ cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/sitemap/SitemapLanguage.java Sat Sep 24 06:22:13 2005
@@ -23,7 +23,6 @@
 import java.util.Iterator;
 import java.util.Map;
 import java.util.Set;
-
 import org.apache.avalon.framework.configuration.Configuration;
 import org.apache.avalon.framework.configuration.ConfigurationException;
 import org.apache.avalon.framework.configuration.DefaultConfiguration;
@@ -33,7 +32,6 @@
 import org.apache.avalon.framework.service.ServiceManager;
 import org.apache.cocoon.Constants;
 import org.apache.cocoon.components.LifecycleHelper;
-import org.apache.cocoon.components.classloader.ClassLoaderFactory;
 import org.apache.cocoon.components.container.CocoonServiceManager;
 import org.apache.cocoon.components.treeprocessor.CategoryNode;
 import org.apache.cocoon.components.treeprocessor.CategoryNodeBuilder;
@@ -65,105 +63,87 @@
     private static final String COMMA_SPLIT_REGEXP = "[\\s]*,[\\s]*";
     private static final String EQUALS_SPLIT_REGEXP = "[\\s]*=[\\s]*";
 
+//    protected ClassLoader createClassLoader(Configuration config)
+//    throws Exception {
+//        ClassLoader newClassLoader;
+//        Configuration classpathConfig = config.getChild("classpath", false);
+//        if (classpathConfig == null) {
+//            return Thread.currentThread().getContextClassLoader();
+//        }
+//        
+//        String factoryRole = config.getAttribute("factory-role", ClassLoaderFactory.ROLE + "/ReloadingClassLoaderFactory");
+//        // Create a new classloader
+//        ClassLoaderFactory clFactory = (ClassLoaderFactory)this.parentProcessorManager.lookup(factoryRole);
+//        try {
+//            return clFactory.createClassLoader(
+//                    Thread.currentThread().getContextClassLoader(),
+//                    classpathConfig
+//            );
+//        } finally {
+//            this.parentProcessorManager.release(clFactory);
+//        }
+//    }
+    
     /**
      * Build a component manager with the contents of the &lt;map:components&gt; element of
      * the tree.
      */
-    protected ServiceManager createServiceManager(Context context, Configuration tree)
+    protected ServiceManager createServiceManager(ClassLoader classloader, Context context, Configuration config)
     throws Exception {
 
-        // Get the map:component node
-        // Don't check namespace here : this will be done by node builders
-        Configuration config = tree.getChild("components", false);
-
-        if (config == null) {
-            if (getLogger().isDebugEnabled()) {
-                getLogger().debug("Sitemap has no components definition at " + tree.getLocation());
-            }
-            config = new DefaultConfiguration("", "");
-        }
-        
         // Create the classloader, if needed.
-        ClassLoader newClassLoader;
-        Configuration classpathConfig = config.getChild("classpath", false);
-        if (classpathConfig == null) {
-            newClassLoader = Thread.currentThread().getContextClassLoader();
-        } else {
-            String factoryRole = config.getAttribute("factory-role", ClassLoaderFactory.ROLE);
-            // Create a new classloader
-            ClassLoaderFactory clFactory = (ClassLoaderFactory)this.parentProcessorManager.lookup(factoryRole);
-            try {
-                newClassLoader = clFactory.createClassLoader(
-                        Thread.currentThread().getContextClassLoader(),
-                        classpathConfig
-                );
-            } finally {
-                this.parentProcessorManager.release(clFactory);
-            }
-        }
-        
-        this.itsClassLoader = newClassLoader;
-        
-        // Create the manager within its own classloader
-        Thread currentThread = Thread.currentThread();
-        ClassLoader oldClassLoader = currentThread.getContextClassLoader();
-        currentThread.setContextClassLoader(newClassLoader);
         ServiceManager newManager;
         
-        try {
-            newManager = new CocoonServiceManager(this.parentProcessorManager, newClassLoader);
-    
+        newManager = new CocoonServiceManager(this.parentProcessorManager, classloader);
+
+        // Go through the component lifecycle
+        ContainerUtil.enableLogging(newManager, this.getLogger());
+        ContainerUtil.contextualize(newManager, context);
+        // before we pass the configuration we have to strip the
+        // additional configuration parts, like classpath etc. as these
+        // are not configurations for the service manager
+        final DefaultConfiguration c = new DefaultConfiguration(config.getName(), 
+                                                                config.getLocation(),
+                                                                config.getNamespace(),
+                                                                "");
+        c.addAll(config);
+        c.removeChild(config.getChild("application-container"));
+        c.removeChild(config.getChild("classpath"));
+        c.removeChild(config.getChild("listeners"));
+
+        ContainerUtil.configure(newManager, c);
+        ContainerUtil.initialize(newManager);
+
+        // check for an application specific container
+        final Configuration appContainer = config.getChild("application-container", false);
+        if ( appContainer != null ) {
+            final String clazzName = appContainer.getAttribute("class");
+
+            final ComponentLocator cl = (ComponentLocator)ClassUtils.newInstance(clazzName); 
             // Go through the component lifecycle
-            ContainerUtil.enableLogging(newManager, this.getLogger());
-            ContainerUtil.contextualize(newManager, context);
-            // before we pass the configuration we have to strip the
-            // additional configuration parts, like classpath etc. as these
-            // are not configurations for the service manager
-            final DefaultConfiguration c = new DefaultConfiguration(config.getName(), 
-                                                                    config.getLocation(),
-                                                                    config.getNamespace(),
-                                                                    "");
-            c.addAll(config);
-            c.removeChild(config.getChild("application-container"));
-            c.removeChild(config.getChild("classpath"));
-            c.removeChild(config.getChild("listeners"));
-
-            ContainerUtil.configure(newManager, c);
-            ContainerUtil.initialize(newManager);
-
-            // check for an application specific container
-            final Configuration appContainer = config.getChild("application-container", false);
-            if ( appContainer != null ) {
-                final String clazzName = appContainer.getAttribute("class");
-
-                final ComponentLocator cl = (ComponentLocator)ClassUtils.newInstance(clazzName); 
-                // Go through the component lifecycle
-                LifecycleHelper.setupComponent(cl, this.getLogger(), context, newManager, appContainer);
+            LifecycleHelper.setupComponent(cl, this.getLogger(), context, newManager, appContainer);
 
-                this.applicationContainer = cl;
+            this.applicationContainer = cl;
 
-                newManager = new ComponentManager(newManager, cl);
-            }
+            newManager = new ComponentManager(newManager, cl);
+        }
 
-            // and finally the listeners
-            if ( this.applicationContainer instanceof SitemapListener ) {
-                this.addListener(new TreeBuilder.EventComponent(this.applicationContainer, false));
-            }
+        // and finally the listeners
+        if ( this.applicationContainer instanceof SitemapListener ) {
+            this.addListener(new TreeBuilder.EventComponent(this.applicationContainer, false));
+        }
 
-            final Configuration listenersWrapper = config.getChild("listeners", false);
-            if ( listenersWrapper != null ) {
-                final Configuration[] listeners = listenersWrapper.getChildren("listener");                
-                for(int i = 0; i < listeners.length; i++) {
-                    final Configuration current = listeners[i];
-                    final TreeBuilder.EventComponent listener = this.createListener(newManager, context, current);
-                    if ( !(listener.component instanceof SitemapListener) ) {
-                        throw new ConfigurationException("Listener must implement the SitemapListener interface.");
-                    }
-                    this.addListener(listener);
+        final Configuration listenersWrapper = config.getChild("listeners", false);
+        if ( listenersWrapper != null ) {
+            final Configuration[] listeners = listenersWrapper.getChildren("listener");                
+            for(int i = 0; i < listeners.length; i++) {
+                final Configuration current = listeners[i];
+                final TreeBuilder.EventComponent listener = this.createListener(newManager, context, current);
+                if ( !(listener.component instanceof SitemapListener) ) {
+                    throw new ConfigurationException("Listener must implement the SitemapListener interface.");
                 }
+                this.addListener(listener);
             }
-        } finally {
-            currentThread.setContextClassLoader(oldClassLoader);
         }
 
         return newManager;