cocoon-cvs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jheym...@apache.org
Subject svn commit: r330548 [30/132] - in /cocoon/whiteboard/maven2/cocoon-flat-layout: ./ cocoon-ajax-block/ cocoon-ajax-block/api/ cocoon-ajax-block/api/src/ cocoon-ajax-block/api/src/main/ cocoon-ajax-block/api/src/main/java/ cocoon-ajax-block/api/src/main/...
Date Thu, 03 Nov 2005 14:00:48 GMT
Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/TreeProcessor.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/TreeProcessor.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/TreeProcessor.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/TreeProcessor.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,817 @@
+/*
+ * Copyright 1999-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.treeprocessor;
+
+import java.io.File;
+import java.io.IOException;
+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;
+import org.apache.avalon.framework.configuration.Configuration;
+import org.apache.avalon.framework.configuration.ConfigurationException;
+import org.apache.avalon.framework.configuration.NamespacedSAXConfigurationHandler;
+import org.apache.avalon.framework.configuration.SAXConfigurationHandler;
+import org.apache.avalon.framework.container.ContainerUtil;
+import org.apache.avalon.framework.context.Context;
+import org.apache.avalon.framework.context.ContextException;
+import org.apache.avalon.framework.context.Contextualizable;
+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.ProcessingException;
+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;
+import org.apache.cocoon.components.source.impl.DelayedRefreshSourceWrapper;
+import org.apache.cocoon.components.treeprocessor.sitemap.FlowNode;
+import org.apache.cocoon.core.Core;
+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.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;
+import org.xml.sax.SAXException;
+
+/**
+ * Interpreted tree-traversal implementation of a pipeline assembly language.
+ *
+ * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
+ * @version CVS $Id: TreeProcessor.java 312930 2005-10-11 18:13:35Z cziegeler $
+ */
+public class TreeProcessor extends AbstractLogEnabled
+                           implements ThreadSafe, Processor, Serviceable,
+                                      Configurable, Contextualizable,
+                                      Disposable, Initializable {
+
+    private static final String XCONF_URL =
+        "resource://org/apache/cocoon/components/treeprocessor/sitemap-language.xml";
+
+    /** The parent TreeProcessor, if any */
+    protected TreeProcessor parent;
+
+    /** The context */
+    protected Context context;
+
+    /**
+     * The component manager given by the upper level
+     * (root manager or parent concrete processor)
+     */
+    protected ServiceManager manager;
+
+    /** The core object. */
+    protected Core core;
+
+    /** Last modification time */
+    protected long lastModified = 0;
+
+    /** The source of the tree definition */
+    protected DelayedRefreshSourceWrapper source;
+
+    /** Delay for <code>sourceLastModified</code>. */
+    protected long lastModifiedDelay;
+
+    /** Check for reload? */
+    protected boolean checkReload;
+    
+    protected SitemapMonitor fam;
+    
+    /** The source resolver */
+    protected SourceResolver resolver;
+
+    /** The environment helper */
+    private EnvironmentHelper environmentHelper;
+
+    /** The actual sitemap executor */
+    private SitemapExecutor sitemapExecutor;
+
+    /** Indicates whether this is our component or not */
+    private boolean releaseSitemapExecutor;
+
+    /** The actual processor */
+    protected ConcreteTreeProcessor concreteProcessor;
+
+    /** The tree builder configuration */
+    private Configuration treeBuilderConfiguration;
+
+    /**
+     * Create a TreeProcessor.
+     */
+    public TreeProcessor() {
+        this.checkReload = true;
+        this.lastModifiedDelay = 1000;
+    }
+
+    /**
+     * Create a child processor for a given language
+     */
+    protected TreeProcessor(TreeProcessor parent,
+                            DelayedRefreshSourceWrapper sitemapSource,
+                            boolean checkReload,
+                            String prefix)
+    throws Exception {
+        this.parent = parent;
+        enableLogging(parent.getLogger());
+
+        // Copy all that can be copied from the parent
+        this.context = parent.context;
+        this.source = sitemapSource;
+        this.treeBuilderConfiguration = parent.treeBuilderConfiguration;
+        this.checkReload = checkReload;
+        this.lastModifiedDelay = parent.lastModifiedDelay;
+
+        this.manager = parent.concreteProcessor.getServiceManager();
+
+        this.resolver = (SourceResolver) this.manager.lookup(SourceResolver.ROLE);
+        this.fam = (SitemapMonitor) this.manager.lookup(SitemapMonitor.ROLE);
+        this.core = (Core) this.manager.lookup(Core.ROLE);
+        this.environmentHelper = new EnvironmentHelper(parent.environmentHelper);
+        // Setup environment helper
+        ContainerUtil.enableLogging(this.environmentHelper, this.getLogger());
+        ContainerUtil.service(this.environmentHelper, this.manager);
+        this.environmentHelper.changeContext(sitemapSource, prefix);
+        this.sitemapExecutor = parent.sitemapExecutor;
+    }
+
+    /**
+     * Create a new child of this processor (used for mounting submaps).
+     *
+     * @return a new child processor.
+     */
+    public TreeProcessor createChildProcessor(String src,
+                                              boolean checkReload,
+                                              String  prefix)
+    throws Exception {
+        DelayedRefreshSourceWrapper delayedSource = new DelayedRefreshSourceWrapper(
+                this.resolver.resolveURI(src), this.lastModifiedDelay);
+        return new TreeProcessor(this, delayedSource, checkReload, prefix);
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.avalon.framework.context.Contextualizable#contextualize(org.apache.avalon.framework.context.Context)
+     */
+    public void contextualize(Context context) throws ContextException {
+        this.context = context;
+    }
+
+    /* (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) this.manager.lookup(SourceResolver.ROLE);
+        this.fam = (SitemapMonitor) this.manager.lookup(SitemapMonitor.ROLE);
+        this.core = (Core) this.manager.lookup(Core.ROLE);
+    }
+
+    /**
+     * @see org.apache.avalon.framework.activity.Initializable#initialize()
+     */
+    public void initialize() throws Exception {
+        // setup the environment helper
+        if (this.environmentHelper == null) {
+            this.environmentHelper = new EnvironmentHelper(
+                    (URL) this.context.get(ContextHelper.CONTEXT_ROOT_URL));
+        }
+        ContainerUtil.enableLogging(this.environmentHelper, getLogger());
+        ContainerUtil.service(this.environmentHelper, this.manager);
+
+        // Create sitemap executor
+        if (this.parent == null) {
+            if (this.manager.hasService(SitemapExecutor.ROLE)) {
+                this.sitemapExecutor = (SitemapExecutor) this.manager.lookup(SitemapExecutor.ROLE);
+                this.releaseSitemapExecutor = true;
+            } else {
+                this.sitemapExecutor = new DefaultExecutor();
+            }
+        } else {
+            this.sitemapExecutor = this.parent.sitemapExecutor;
+        }
+    }
+
+    /**
+     * Configure the tree processor:
+     * &lt;processor file="{Location of the sitemap}"
+     *               check-reload="{true|false}"
+     *               config="{Location of sitemap tree processor config}&gt;
+     *   &lt;reload delay="10"/&gt;
+     * &lt;/processor&gt;
+     *
+     * Only the file attribute is required; everything else is optional.
+     *
+     * @see org.apache.avalon.framework.configuration.Configurable#configure(org.apache.avalon.framework.configuration.Configuration)
+     */
+    public void configure(Configuration config)
+    throws ConfigurationException {
+
+        this.checkReload = config.getAttributeAsBoolean("check-reload",
+                             this.core.getSettings().isReloadingEnabled("sitemap"));
+
+        // Obtain the configuration file, or use the XCONF_URL if none
+        // is defined
+        String xconfURL = config.getAttribute("config", XCONF_URL);
+
+        // Reload check delay. Default is 1 second.
+        this.lastModifiedDelay = config.getChild("reload").getAttributeAsLong("delay", this.core.getSettings().getReloadDelay("sitemap"));
+
+        String fileName = config.getAttribute("file", "sitemap.xmap");
+        
+        try {
+            this.source = new DelayedRefreshSourceWrapper(this.resolver.resolveURI(fileName), lastModifiedDelay);
+        } catch (Exception e) {
+            throw new ConfigurationException("Cannot resolve " + fileName, e);
+        }
+
+        // Read the builtin languages definition file
+        try {
+            Source source = this.resolver.resolveURI(xconfURL);
+            try {
+                SAXConfigurationHandler handler = new SAXConfigurationHandler();
+                SourceUtil.toSAX(this.manager, source, null, handler);
+                this.treeBuilderConfiguration = handler.getConfiguration();
+            } finally {
+                this.resolver.release(source);
+            }
+        } catch (Exception e) {
+            String msg = "Error while reading " + xconfURL + ": " + e.getMessage();
+            throw new ConfigurationException(msg, e);
+        }
+    }
+
+    /**
+     * Process the given <code>Environment</code> producing the output.
+     * @return If the processing is successfull <code>true</code> is returned.
+     *         If not match is found in the sitemap <code>false</code>
+     *         is returned.
+     * @throws org.apache.cocoon.ResourceNotFoundException If a sitemap component tries
+     *                                   to access a resource which can not
+     *                                   be found, e.g. the generator
+     *         ConnectionResetException  If the connection was reset
+     */
+    public boolean process(Environment environment) throws Exception {
+        // Get the concrete processor and delegate it the job
+        setupConcreteProcessor(environment);
+        return this.concreteProcessor.process(environment);
+    }
+
+
+    /**
+     * Process the given <code>Environment</code> to assemble
+     * a <code>ProcessingPipeline</code>.
+     * @since 2.1
+     */
+    public InternalPipelineDescription buildPipeline(Environment environment)
+    throws Exception {
+        // Get the concrete processor and delegate it the job
+        setupConcreteProcessor(environment);
+        return this.concreteProcessor.buildPipeline(environment);
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.cocoon.Processor#getRootProcessor()
+     */
+    public Processor getRootProcessor() {
+        TreeProcessor result = this;
+        while (result.parent != null) {
+            result = result.parent;
+        }
+
+        return result;
+    }
+
+//    /**
+//     * Set the sitemap component configurations
+//     */
+//    public void setComponentConfigurations(Configuration componentConfigurations) {
+//        this.concreteProcessor.setComponentConfigurations(componentConfigurations);
+//    }
+
+    /* (non-Javadoc)
+     * @see org.apache.cocoon.Processor#getComponentConfigurations()
+     */
+    public Configuration[] getComponentConfigurations() {
+        return this.concreteProcessor.getComponentConfigurations();
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.cocoon.Processor#getContext()
+     */
+    public String getContext() {
+        return this.environmentHelper.getContext();
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.cocoon.Processor#getEnvironmentHelper()
+     */
+    public org.apache.cocoon.environment.SourceResolver getSourceResolver() {
+        return this.environmentHelper;
+    }
+
+    /**
+     * The current environment helper used by the MountNode
+     * @return EnvironmentHelper
+     */
+    public EnvironmentHelper getEnvironmentHelper() {
+        return this.environmentHelper;
+    }
+
+    /**
+     * Get the tree builder role from the sitemap program (as a configuration object).
+     * This method should report very any problem very clearly, as it is the entry point of any
+     * Cocoon application.
+     *
+     * @param sitemapProgram the sitemap
+     * @return the treebuilder role
+     * @throws ConfigurationException if a suitable role could not be found
+     */
+    private TreeBuilder getTreeBuilder(Configuration sitemapProgram) throws ConfigurationException {
+        String ns = sitemapProgram.getNamespace();
+
+        RE re = new RE("http://apache.org/cocoon/sitemap/(\\d\\.\\d)");
+        if (!re.match(ns)) {
+            throw new ConfigurationException("Unknown sitemap namespace (" + ns + ") at " +
+                    this.source.getURI());
+        }
+
+        String version = re.getParen(1);
+        String result = TreeBuilder.ROLE + "/sitemap-" + version;
+
+        try {
+            return (TreeBuilder) this.manager.lookup(result);
+        } catch (Exception e) {
+            throw new ConfigurationException("This version of Cocoon does not handle sitemap version " +
+                                             version + " at " + this.source.getURI(), e);
+        }
+    }
+
+    /**
+     * Sets up the concrete processor, building or rebuilding it if necessary.
+     */
+    private void setupConcreteProcessor(Environment env) throws Exception {
+
+        if (this.parent == null) {
+            // Ensure root sitemap uses the correct context, even if not located in the webapp context
+            this.environmentHelper.changeContext(this.source, "");
+        }
+
+        if (this.concreteProcessor == null || this.concreteProcessor.isReloadNeeded() ||
+                (this.checkReload && this.source.getLastModified() != this.lastModified)) {
+            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();
+        
+        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);
+        }
+    }
+
+    
+    private Configuration createSitemapProgram(Source source) throws ProcessingException, SAXException, IOException {
+        NamespacedSAXConfigurationHandler handler = new NamespacedSAXConfigurationHandler();
+        AnnotationsFilter annotationsFilter = new AnnotationsFilter(handler);
+        SourceUtil.toSAX(source, annotationsFilter);
+        return handler.getConfiguration();        
+    }
+    
+    private void subscribeListeners(Map listerens, ConcreteTreeProcessor processor) {
+        if (getLogger().isDebugEnabled()) {
+            getLogger().debug("setting up listeners " + listerens);
+        }
+        for (final Iterator it = listerens.values().iterator(); it.hasNext();) {
+            final NotifyingListener newListener = (NotifyingListener) it.next();
+            
+            newListener.setNotificationListener(processor);
+            
+            fam.subscribe(newListener);
+        }        
+    }
+
+    private void unsubscribeListeners(Map listerens) {
+        if (listerens != null && listerens.size() > 0) {
+            if (getLogger().isDebugEnabled()) {
+                getLogger().debug("unsubscribing " + listerens + " from fam");
+            }
+            for (final Iterator it = listerens.values().iterator(); it.hasNext();) {
+                final FilesystemAlterationListener oldListener = (FilesystemAlterationListener) it.next();
+                fam.unsubscribe(oldListener);
+            }
+        }        
+    }
+    
+    private void waitForInitialCompilation(Map listeners) throws Exception {
+        if (listeners.size() > 0) {
+            // wait for the new ones to complete for the first time                
+            for (final Iterator it = listeners.values().iterator(); it.hasNext();) {
+                final NotifyingListener newListener = (NotifyingListener) it.next();
+                if (getLogger().isDebugEnabled()) {
+                    getLogger().debug("waiting for initial compilation");
+                }
+                newListener.waitForFirstCheck();
+            }
+        }        
+    }
+    
+    private void provideClasses(Map listeners, ClassLoader classloader) {
+        for (final Iterator it = listeners.values().iterator(); it.hasNext();) {
+            final NotifyingListener newListener = (NotifyingListener) it.next();
+
+            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());
+                }
+            }                
+        }        
+    }
+
+    
+    /**
+     * Build the concrete processor (i.e. loads the sitemap). Should be called
+     * only by setupProcessor();
+     */
+    private synchronized void buildConcreteProcessor(Environment env) throws Exception {
+
+        // Now that we entered the synchronized area, recheck what's already
+        // been checked in process().
+        if (this.concreteProcessor != null && source.getLastModified() == this.lastModified && !this.concreteProcessor.isReloadNeeded()) {
+            // Nothing changed
+            return;
+        }
+
+        long startTime = System.currentTimeMillis();
+        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");
+            }            
+        }
+        
+        // Dispose the old processor, if any
+        if (oldProcessor != null) {
+            oldProcessor.markForDisposal();
+        }
+
+
+        // We have to do a call to enterProcessor() here as during building
+        // of the tree, components (e.g. actions) are already instantiated
+        // (ThreadSafe ones mostly).
+        // If these components try to access the current processor or the
+        // current service manager they must get this one - which is currently
+        // in the process of initialization.
+        EnvironmentHelper.enterProcessor(this, this.manager, env);
+
+        try {
+
+            Configuration sitemapProgram = createSitemapProgram(this.source);
+            newLastModified = this.source.getLastModified();
+
+            newProcessor = createConcreteTreeProcessor();
+
+            // setup sitemap specific classloader
+            // (RP) Should we really support sitemap specific classloader when the global 
+            //      BlocksClassloader is in place?
+            Configuration classpathConfig = sitemapProgram.getChild("components").getChild("classpath", false);
+            if (classpathConfig != null) {
+                if (getLogger().isDebugEnabled()) {
+                    getLogger().debug("ConcreteTreeProcessor has a special classpath");
+                }
+                
+                // create a reloading classloader and make it the context classloader
+                ClassLoader classloader = createClassLoader(classpathConfig);
+                Thread.currentThread().setContextClassLoader(classloader);
+                
+                // create the listeners for all classpath entries (lib, classes, src)
+                newListeners = createClasspathListeners(oldListeners, classpathConfig);
+                
+                // store the listeners in the the concreteTreeProcessor instance
+                newProcessor.setClasspathListeners(newListeners);
+                
+                // subscribe all listeners to filesystem altering monitor (FAM)
+                subscribeListeners(newListeners, newProcessor);
+                
+                // use the information about the listeners to create the classpath
+                provideClasses(newListeners, classloader);
+            }
+
+            unsubscribeListeners(oldListeners);
+            
+            waitForInitialCompilation(newListeners);
+            
+
+            // Get the treebuilder that can handle this version of the sitemap.
+            TreeBuilder treeBuilder = getTreeBuilder(sitemapProgram);
+            try {
+                treeBuilder.setProcessor(newProcessor);
+                treeBuilder.setParentProcessorManager(this.manager);
+
+                ProcessingNode root = treeBuilder.build(sitemapProgram);
+                newProcessor.setProcessorData(
+                        treeBuilder.getBuiltProcessorManager(),
+                        treeBuilder.getBuiltProcessorClassLoader(),
+                        root,
+                        treeBuilder.getDisposableNodes(),
+                        treeBuilder.getComponentLocator(),
+                        treeBuilder.getEnterSitemapEventListeners(),
+                        treeBuilder.getLeaveSitemapEventListeners());
+                
+                if (getLogger().isDebugEnabled()) {
+                    getLogger().debug("ConcreteTreeProcessor ready");
+                }
+
+                // Get the actual interpreter
+                FlowNode flowNode = (FlowNode)treeBuilder.getRegisteredNode("flow");
+                if ( flowNode != null ) {
+                    final Interpreter interpreter = flowNode.getInterpreter();
+                    newProcessor.setAttribute(Interpreter.ROLE, interpreter);
+                }
+                
+            } finally {
+                this.manager.release(treeBuilder);
+            }
+        } finally {
+            EnvironmentHelper.leaveProcessor();
+        }
+
+        if (getLogger().isDebugEnabled()) {
+            double time = (System.currentTimeMillis() - startTime) / 1000.0;
+            getLogger().debug("TreeProcessor built in " + time + " secs from " + source.getURI());
+        }
+
+        // Switch to the new processor (ensure it's never temporarily null)
+        this.concreteProcessor = newProcessor;
+        this.lastModified = newLastModified;
+    }
+
+    private ConcreteTreeProcessor createConcreteTreeProcessor() {
+        ConcreteTreeProcessor newProcessor = new ConcreteTreeProcessor(this, this.sitemapExecutor);
+        setupLogger(newProcessor);
+        return newProcessor;
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.avalon.framework.activity.Disposable#dispose()
+     */
+    public void dispose() {
+        // Dispose the concrete processor. No need to check for existing requests, as there
+        // are none when a TreeProcessor is disposed.
+        ContainerUtil.dispose(this.concreteProcessor);
+        this.concreteProcessor = null;
+
+        if (this.releaseSitemapExecutor) {
+            this.manager.release(this.sitemapExecutor);
+            this.sitemapExecutor = null;
+        }
+
+        if (this.manager != null) {
+            if (this.source != null) {
+                this.resolver.release(this.source.getSource());
+                this.source = null;
+            }
+            this.manager.release(this.fam);
+            this.manager.release(this.resolver);
+            this.manager.release(this.core);
+            this.resolver = null;
+            this.manager = null;
+            this.core = null;
+        }
+    }
+
+    /**
+     * @see org.apache.cocoon.Processor#getAttribute(java.lang.String)
+     */
+    public Object getAttribute(String name) {
+        return this.concreteProcessor.getAttribute(name);
+    }
+
+    /**
+     * @see org.apache.cocoon.Processor#removeAttribute(java.lang.String)
+     */
+    public Object removeAttribute(String name) {
+        return this.concreteProcessor.removeAttribute(name);
+    }
+
+    /**
+     * @see org.apache.cocoon.Processor#setAttribute(java.lang.String, java.lang.Object)
+     */
+    public void setAttribute(String name, Object value) {
+        this.concreteProcessor.setAttribute(name, value);
+    }
+}

Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/TreeProcessor.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/package.html
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/package.html?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/package.html (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/package.html Thu Nov  3 05:41:06 2005
@@ -0,0 +1,25 @@
+<!--
+  Copyright 1999-2004 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.
+-->
+<html>
+<head>
+ <title>Tree Processor</title>
+</head>
+<body>
+ <h1>Evaluation tree based implementation of the <code>Processor</code> interface</h1>
+ <p>
+ </p>
+</body>
+</html>

Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/package.html
------------------------------------------------------------------------------
    svn:eol-style = native

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap-language.xml
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap-language.xml?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap-language.xml (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap-language.xml Thu Nov  3 05:41:06 2005
@@ -0,0 +1,148 @@
+<?xml version="1.0"?>
+<!--
+  Copyright 1999-2004 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.
+-->
+
+<!DOCTYPE sitemap-language [
+  <!ELEMENT sitemap-language (nodes)>
+  <!ELEMENT nodes (node+)>
+  <!ELEMENT node (allowed-children*, ignored-children*, forbidden-children*)>
+  <!ATTLIST node
+    name CDATA #REQUIRED
+    builder CDATA #REQUIRED
+  >
+  <!ELEMENT allowed-children (#PCDATA)>
+  <!ELEMENT ignored-children (#PCDATA)>
+  <!ELEMENT forbidden-children (#PCDATA)>
+]>
+
+<!--+
+    | The sitemap language.
+    | $Id: sitemap-language.xml 160478 2005-04-07 22:18:29Z danielf $
+    +-->
+<sitemap-language>
+
+    <!-- node definitions for the sitemap language -->
+    <nodes>
+      <!-- A node has the following attributes :
+           - name : the node name, given as a local name in the language namespace (no prefix)
+           - builder : the class name of the ProcessingNodeBuilder for this node
+           
+           The contents of a node definition is the configuration of Configurable
+           ProcessingNodeBuilders.
+        -->
+      
+      <!-- Sitemap root node -->
+      <node name="sitemap" builder="org.apache.cocoon.components.treeprocessor.sitemap.SitemapNodeBuilder">
+        <allowed-children>components, views, action-sets, resources, flow, pipelines</allowed-children>
+      </node>
+
+      <node name="components" builder="org.apache.cocoon.components.treeprocessor.sitemap.ComponentsNodeBuilder"/>
+
+      <node name="generators" builder="org.apache.cocoon.components.treeprocessor.sitemap.VPCsNodeBuilder"/>
+
+      <node name="generator" builder="org.apache.cocoon.components.treeprocessor.sitemap.VPCNodeBuilder">
+        <ignored-children>source</ignored-children>
+      </node>
+
+      <node name="transformers" builder="org.apache.cocoon.components.treeprocessor.sitemap.VPCsNodeBuilder"/>
+
+      <node name="transformer" builder="org.apache.cocoon.components.treeprocessor.sitemap.VPCNodeBuilder">
+        <ignored-children>source</ignored-children>
+      </node>
+
+      <node name="serializers" builder="org.apache.cocoon.components.treeprocessor.sitemap.VPCsNodeBuilder"/>
+
+      <node name="serializer" builder="org.apache.cocoon.components.treeprocessor.sitemap.VPCNodeBuilder">
+        <ignored-children>source</ignored-children>
+      </node>
+
+      <node name="readers" builder="org.apache.cocoon.components.treeprocessor.sitemap.VPCsNodeBuilder"/>
+
+      <node name="reader" builder="org.apache.cocoon.components.treeprocessor.sitemap.VPCNodeBuilder">
+        <ignored-children>source</ignored-children>
+      </node>
+
+      <node name="views" builder="org.apache.cocoon.components.treeprocessor.CategoryNodeBuilder">
+        <allowed-children>view</allowed-children>
+      </node>
+
+      <node name="view" builder="org.apache.cocoon.components.treeprocessor.sitemap.ViewNodeBuilder"/>
+
+      <node name="action-sets" builder="org.apache.cocoon.components.treeprocessor.CategoryNodeBuilder">
+        <allowed-children>action-set</allowed-children>
+      </node>
+
+      <node name="action-set" builder="org.apache.cocoon.components.treeprocessor.sitemap.ActionSetNodeBuilder"/>
+
+      <node name="resources" builder="org.apache.cocoon.components.treeprocessor.CategoryNodeBuilder">
+        <allowed-children>resource</allowed-children>
+      </node>
+
+      <node name="resource" builder="org.apache.cocoon.components.treeprocessor.NamedContainerNodeBuilder"/>
+
+      <node name="flow" builder="org.apache.cocoon.components.treeprocessor.sitemap.FlowNodeBuilder">
+        <allowed-children>script</allowed-children>
+      </node>
+
+      <node name="script" builder="org.apache.cocoon.components.treeprocessor.sitemap.ScriptNodeBuilder"/>
+
+      <node name="pipelines" builder="org.apache.cocoon.components.treeprocessor.sitemap.PipelinesNodeBuilder">
+        <allowed-children>pipeline, handle-errors</allowed-children>
+        <ignored-children>component-configurations</ignored-children>
+      </node>
+
+      <node name="pipeline" builder="org.apache.cocoon.components.treeprocessor.sitemap.PipelineNodeBuilder">
+        <forbidden-children>sitemap, components, pipeline</forbidden-children>
+      </node>
+
+      <node name="match" builder="org.apache.cocoon.components.treeprocessor.sitemap.MatchNodeBuilder">
+        <forbidden-children>sitemap, components, pipeline, handle-errors</forbidden-children>
+      </node>
+
+      <node name="select" builder="org.apache.cocoon.components.treeprocessor.sitemap.SelectNodeBuilder">
+        <forbidden-children>sitemap, components, pipeline, handle-errors</forbidden-children>
+      </node>
+
+      <node name="act" builder="org.apache.cocoon.components.treeprocessor.sitemap.ActNodeBuilder">
+        <forbidden-children>sitemap, components, pipeline, handle-errors</forbidden-children>
+      </node>
+
+      <node name="redirect-to" builder="org.apache.cocoon.components.treeprocessor.sitemap.RedirectToNodeBuilder"/>
+
+      <node name="call" builder="org.apache.cocoon.components.treeprocessor.sitemap.CallNodeBuilder"/>
+
+      <node name="mount" builder="org.apache.cocoon.components.treeprocessor.sitemap.MountNodeBuilder"/>
+
+      <node name="read" builder="org.apache.cocoon.components.treeprocessor.sitemap.ReadNodeBuilder"/>
+
+      <node name="aggregate" builder="org.apache.cocoon.components.treeprocessor.sitemap.AggregateNodeBuilder"/>
+
+      <node name="generate" builder="org.apache.cocoon.components.treeprocessor.sitemap.GenerateNodeBuilder"/>
+
+      <node name="transform" builder="org.apache.cocoon.components.treeprocessor.sitemap.TransformNodeBuilder"/>
+
+      <node name="serialize" builder="org.apache.cocoon.components.treeprocessor.sitemap.SerializeNodeBuilder"/>
+
+      <node name="handle-errors" builder="org.apache.cocoon.components.treeprocessor.sitemap.HandleErrorsNodeBuilder"/>
+
+    </nodes>
+
+    <!--+
+        | You can add specific nodes for a specific sitemap version, using
+        | &lt;nodes-{version}&gt;
+        +-->
+
+</sitemap-language>

Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap-language.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/ActNodeBuilder.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/ActNodeBuilder.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/ActNodeBuilder.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/ActNodeBuilder.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,107 @@
+/*
+ * Copyright 1999-2004 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.treeprocessor.sitemap;
+
+import org.apache.avalon.framework.configuration.Configuration;
+import org.apache.avalon.framework.configuration.ConfigurationException;
+import org.apache.cocoon.acting.Action;
+import org.apache.cocoon.components.treeprocessor.AbstractParentProcessingNodeBuilder;
+import org.apache.cocoon.components.treeprocessor.CategoryNode;
+import org.apache.cocoon.components.treeprocessor.CategoryNodeBuilder;
+import org.apache.cocoon.components.treeprocessor.LinkedProcessingNodeBuilder;
+import org.apache.cocoon.components.treeprocessor.ProcessingNode;
+import org.apache.cocoon.components.treeprocessor.variables.VariableResolverFactory;
+
+/**
+ *
+ * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
+ * @version CVS $Id: ActNodeBuilder.java 165284 2005-04-29 09:24:28Z cziegeler $
+ */
+public class ActNodeBuilder extends AbstractParentProcessingNodeBuilder
+                            implements LinkedProcessingNodeBuilder {
+
+    private ActSetNode  actSetNode;
+    private String      actSetName;
+
+    public ProcessingNode buildNode(Configuration config) throws Exception {
+        
+        boolean inActionSet = this.treeBuilder.getAttribute(ActionSetNodeBuilder.IN_ACTION_SET) != null;
+
+        // Is it an action-set call ?
+        this.actSetName = config.getAttribute("set", null);
+        if (actSetName == null) {
+            
+            if (inActionSet) {
+                // Check that children are only parameters or actions
+                Configuration children[] = config.getChildren();
+                for (int i = 0; i < children.length; i++) {
+                    String name = children[i].getName();
+                    if (!"act".equals(name) && !"parameter".equals(name)) {
+                        throw new ConfigurationException("An action set can only contain actions and not '" 
+                            + name + "' at " + children[i].getLocation());
+                    }
+                }
+            }
+
+            String name = config.getAttribute("name", null);
+            String source = config.getAttribute("src", null);
+            String type = this.treeBuilder.getTypeForStatement(config, Action.ROLE);
+
+            ActTypeNode actTypeNode = new ActTypeNode(
+                type,
+                VariableResolverFactory.getResolver(source, this.manager),
+                name,
+                inActionSet
+            );
+            this.treeBuilder.setupNode(actTypeNode, config);
+
+            actTypeNode.setChildren(buildChildNodes(config));
+
+            return actTypeNode;
+
+        }
+
+        if (inActionSet) {
+            throw new ConfigurationException("Cannot call an action set from an action set at " + config.getLocation());
+        }
+
+        // Action set call
+        if (config.getAttribute("src", null) != null) {
+            getLogger().warn("The 'src' attribute is ignored for action-set call at " + config.getLocation());
+        }
+        this.actSetNode = new ActSetNode();
+        this.treeBuilder.setupNode(this.actSetNode, config);
+
+        this.actSetNode.setChildren(buildChildNodes(config));
+
+        return this.actSetNode;
+    }
+
+    public void linkNode() throws Exception {
+
+        if (this.actSetNode != null) {
+            // Link action-set call to the action set
+            CategoryNode actionSets = CategoryNodeBuilder.getCategoryNode(this.treeBuilder, "action-sets");
+
+            if (actionSets == null)
+                throw new ConfigurationException("This sitemap contains no action sets. Cannot call at " + actSetNode.getLocation());
+
+            ActionSetNode actionSetNode = (ActionSetNode)actionSets.getNodeByName(this.actSetName);
+
+            this.actSetNode.setActionSet(actionSetNode);
+        }
+    }
+}

Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/ActNodeBuilder.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/ActSetNode.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/ActSetNode.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/ActSetNode.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/ActSetNode.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,82 @@
+/*
+ * Copyright 1999-2004 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.treeprocessor.sitemap;
+
+import org.apache.avalon.framework.parameters.Parameters;
+import org.apache.cocoon.components.treeprocessor.InvokeContext;
+import org.apache.cocoon.components.treeprocessor.ParameterizableProcessingNode;
+import org.apache.cocoon.components.treeprocessor.SimpleParentProcessingNode;
+import org.apache.cocoon.components.treeprocessor.variables.VariableResolver;
+import org.apache.cocoon.environment.Environment;
+
+import java.util.Map;
+
+/**
+ * Handles &lt;map:act type="..."&gt; (action-sets calls are handled by {@link ActSetNode}).
+ *
+ * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
+ * @version CVS $Id: ActSetNode.java 30941 2004-07-29 19:56:58Z vgritsenko $
+ */
+
+public class ActSetNode extends SimpleParentProcessingNode
+  implements ParameterizableProcessingNode {
+
+    /** The parameters of this node */
+    private Map parameters;
+
+    /** The action set to call */
+    private ActionSetNode actionSet;
+
+    public ActSetNode() {
+        super(null);
+    }
+    
+    public void setParameters(Map parameterMap) {
+        this.parameters = parameterMap;
+    }
+
+    public void setActionSet(ActionSetNode actionSet) {
+        this.actionSet = actionSet;
+    }
+
+    public final boolean invoke(Environment env, InvokeContext context)
+      throws Exception {
+
+        // Perform any common invoke functionality 
+        super.invoke(env, context);
+
+        Parameters resolvedParams = VariableResolver.buildParameters(
+            this.parameters,
+            context,
+            env.getObjectModel()
+        );
+
+        Map result = this.actionSet.call(env, context, resolvedParams);
+
+        if (context.getRedirector().hasRedirected()) {
+            return true;
+
+        } else if (result == null) {
+            return false;
+
+        } else if (this.children == null) {
+            return true;
+
+        } else {
+            return this.invokeNodes(this.children, env, context, null, result);
+        }
+    }
+}

Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/ActSetNode.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/ActTypeNode.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/ActTypeNode.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/ActTypeNode.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/ActTypeNode.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,143 @@
+/*
+ * Copyright 1999-2004 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.treeprocessor.sitemap;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.avalon.framework.parameters.Parameters;
+import org.apache.cocoon.acting.Action;
+import org.apache.cocoon.components.treeprocessor.InvokeContext;
+import org.apache.cocoon.components.treeprocessor.ParameterizableProcessingNode;
+import org.apache.cocoon.components.treeprocessor.SimpleSelectorProcessingNode;
+import org.apache.cocoon.components.treeprocessor.variables.VariableResolver;
+import org.apache.cocoon.environment.Environment;
+import org.apache.cocoon.environment.Redirector;
+import org.apache.cocoon.environment.SourceResolver;
+import org.apache.cocoon.environment.internal.EnvironmentHelper;
+
+/**
+ * Handles &lt;map:act type="..."&gt; (action-sets calls are handled by {@link ActSetNode}).
+ *
+ * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
+ * @version CVS $Id: ActTypeNode.java 30941 2004-07-29 19:56:58Z vgritsenko $
+ */
+
+public class ActTypeNode extends SimpleSelectorProcessingNode
+  implements ParameterizableProcessingNode {
+
+    /** The parameters of this node */
+    private Map parameters;
+
+    /** The 'src' attribute */
+    protected VariableResolver source;
+
+    /** The 'name' for the variable anchor */
+    protected String name;
+
+    protected boolean inActionSet;
+
+    public ActTypeNode(String type, 
+                       VariableResolver source, 
+                       String name,
+                       boolean inActionSet)  {
+        super(Action.ROLE + "Selector", type);
+        this.source = source;
+        this.name = name;
+        this.inActionSet = inActionSet;
+    }
+
+    public void setParameters(Map parameterMap) {
+        this.parameters = parameterMap;
+    }
+
+    public final boolean invoke(Environment env, InvokeContext context)
+          throws Exception {
+
+        // Perform any common invoke functionality 
+        super.invoke(env, context);
+
+        // Prepare data needed by the action
+        Map objectModel = env.getObjectModel();
+        Redirector redirector = context.getRedirector();
+        SourceResolver resolver = EnvironmentHelper.getCurrentProcessor().getSourceResolver();
+        String resolvedSource = source.resolve(context, objectModel);
+        Parameters resolvedParams =
+            VariableResolver.buildParameters(this.parameters,
+                    context, objectModel);
+
+        Map actionResult;
+
+        // If in action set, merge parameters
+        if (inActionSet) {
+            Parameters callerParams =
+                (Parameters)env.getAttribute(ActionSetNode.CALLER_PARAMETERS);
+            if (resolvedParams == Parameters.EMPTY_PARAMETERS) {
+                // Just swap
+                resolvedParams = callerParams;
+            } else if (callerParams != Parameters.EMPTY_PARAMETERS) {
+                // Build new Parameters object, the both we hare are read-only!
+                Parameters newParams = new Parameters();
+                // And merge both
+                newParams.merge(resolvedParams);
+                newParams.merge(callerParams);
+                resolvedParams = newParams;
+            }
+        }
+
+        Action action = (Action)getComponent();
+        try {
+            actionResult = this.executor.invokeAction(this,
+                                             objectModel, 
+                                             action, 
+                                             redirector, 
+                                             resolver, 
+                                             resolvedSource, 
+                                             resolvedParams);
+        } finally {
+            releaseComponent(action);
+        }
+
+        if (redirector.hasRedirected()) {
+            return true;
+        }
+
+        if (actionResult != null) {
+            // Action succeeded : process children if there are some, with the action result
+            if (this.children != null) {
+                boolean result = this.invokeNodes(this.children, env, context, name, actionResult);
+
+                if (inActionSet) {
+                    // Merge child action results, if any
+                    Map childMap = (Map)env.getAttribute(ActionSetNode.ACTION_RESULTS);
+                    if (childMap != null) {
+                        Map newResults = new HashMap(childMap);
+                        newResults.putAll(actionResult);
+                        env.setAttribute(ActionSetNode.ACTION_RESULTS, newResults);
+                    } else {
+                        // No previous results
+                        env.setAttribute(ActionSetNode.ACTION_RESULTS, actionResult);
+                    }
+                }
+                return result;
+            }// else {
+               // return false; // Return false to continue sitemap invocation
+            //}
+        }// else {
+            return false;   // Action failed
+        //}
+    }
+}

Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/ActTypeNode.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/ActionSetNode.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/ActionSetNode.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/ActionSetNode.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/ActionSetNode.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,116 @@
+/*
+ * Copyright 1999-2004 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.treeprocessor.sitemap;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.avalon.framework.parameters.Parameters;
+import org.apache.cocoon.components.treeprocessor.AbstractProcessingNode;
+import org.apache.cocoon.components.treeprocessor.InvokeContext;
+import org.apache.cocoon.components.treeprocessor.NamedProcessingNode;
+import org.apache.cocoon.components.treeprocessor.ProcessingNode;
+import org.apache.cocoon.environment.Environment;
+
+/**
+ *
+ * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
+ * @version CVS $Id: ActionSetNode.java 30941 2004-07-29 19:56:58Z vgritsenko $
+ */
+
+public class ActionSetNode extends AbstractProcessingNode
+  implements NamedProcessingNode {
+      
+    public static final String CALLER_PARAMETERS = ActionSetNode.class.getName() + "/CallerParameters";
+    public static final String ACTION_RESULTS = ActionSetNode.class.getName() + "/ActionResults";
+
+    /** The action nodes */
+    private ProcessingNode[] nodes;
+
+    /** The 'action' attribute for each action */
+    private String[] actionNames;
+
+    public ActionSetNode(
+      String name, ProcessingNode[] nodes, String[] actionNames) {
+        super(name);
+        this.nodes = nodes;
+        this.actionNames = actionNames;
+    }
+
+    public final boolean invoke(Environment env, InvokeContext context)
+      throws Exception {
+	
+        // Perform any common invoke functionalty 
+        // super.invoke(env, context);
+        String msg = "An action-set cannot be invoked, at " + this.getLocation();
+        throw new UnsupportedOperationException(msg);
+    }
+
+    /**
+     * Call the actions composing the action-set and return the combined result of
+     * these actions.
+     */
+    public final Map call(Environment env, InvokeContext context, Parameters params) throws Exception {
+
+        String cocoonAction = env.getAction();
+
+        // Store the parameters from the caller into the environment so that they can be merged with
+        // each action's parameters.
+        
+
+        Map result = null;
+
+        // Call each action that either has no cocoonAction, or whose cocoonAction equals
+        // the one from the environment.
+        env.setAttribute(CALLER_PARAMETERS, params);
+
+        for (int i = 0; i < nodes.length; i++) {
+
+
+            String actionName = actionNames[i];
+            if (actionName == null || actionName.equals(cocoonAction)) {
+                
+                this.nodes[i].invoke(env, context);
+                
+                // Get action results. They're passed back through the environment since action-sets
+                // "violate" the tree hierarchy (the returned Map is visible outside of the node)
+                Map actionResult = (Map)env.getAttribute(ACTION_RESULTS);
+                // Don't forget to clear it
+                env.removeAttribute(ACTION_RESULTS);
+                
+                if (actionResult != null) {
+                    // Merge the result in the global result, creating it if necessary.
+                    if (result == null) {
+                        result = new HashMap(actionResult);
+                    } else {
+                        result.putAll(actionResult);
+                    }
+                }
+                
+            } // if (actionName...
+        } // for (int i...
+
+        return result;
+    }
+
+    /**
+     * Implementation of <code>NamedProcessingNode</code>.
+     */
+
+    public String getName() {
+        return this.componentName;
+    }
+}

Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/ActionSetNode.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/ActionSetNodeBuilder.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/ActionSetNodeBuilder.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/ActionSetNodeBuilder.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/ActionSetNodeBuilder.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,69 @@
+/*
+ * Copyright 1999-2004 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.treeprocessor.sitemap;
+
+import org.apache.avalon.framework.configuration.Configuration;
+import org.apache.avalon.framework.configuration.ConfigurationException;
+import org.apache.avalon.framework.thread.ThreadSafe;
+import org.apache.cocoon.components.treeprocessor.AbstractParentProcessingNodeBuilder;
+import org.apache.cocoon.components.treeprocessor.ProcessingNode;
+
+/**
+ *
+ * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
+ * @version CVS $Id: ActionSetNodeBuilder.java 30941 2004-07-29 19:56:58Z vgritsenko $
+ */
+
+public class ActionSetNodeBuilder extends AbstractParentProcessingNodeBuilder implements ThreadSafe {
+    
+    /** The TreeBuilder attribute indicating that an ActionSet is being built */
+    public static final String IN_ACTION_SET = ActionSetNodeBuilder.class.getName() + "/inActionSet";
+
+    public ProcessingNode buildNode(Configuration config) throws Exception {
+
+        String actionSetName = config.getAttribute("name");
+
+        Configuration[] childrenConfig = config.getChildren();
+        // Inform other builders that we're in an action-set
+        this.treeBuilder.setAttribute(IN_ACTION_SET, Boolean.TRUE);
+        
+        // Get the child actions
+        ProcessingNode[] nodes = this.buildChildNodes(config);
+        
+        // And get their names
+        String[] actions = new String[nodes.length];
+        for (int i = 0; i < childrenConfig.length; i++) {
+            Configuration childConfig = childrenConfig[i];
+            String name = childConfig.getName();
+
+            if ("act".equals(name)) {
+                actions[i] = childConfig.getAttribute("action", null);
+            } else {
+                // Unknown element
+                String msg = "Unknown element " + name + " in action-set at " + childConfig.getLocation();
+                throw new ConfigurationException(msg);
+            }            
+        }
+
+        ActionSetNode node = new ActionSetNode(actionSetName, nodes, actions);
+        this.treeBuilder.setupNode(node, config);
+
+        // Inform other builders that we're no more in an action-set
+        this.treeBuilder.setAttribute(IN_ACTION_SET, null);
+
+        return node;
+    }
+}

Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/ActionSetNodeBuilder.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/AggregateNode.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/AggregateNode.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/AggregateNode.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/AggregateNode.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,173 @@
+/*
+ * Copyright 1999-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.treeprocessor.sitemap;
+
+import org.apache.avalon.framework.parameters.Parameters;
+
+import org.apache.cocoon.components.pipeline.ProcessingPipeline;
+import org.apache.cocoon.components.treeprocessor.AbstractProcessingNode;
+import org.apache.cocoon.components.treeprocessor.InvokeContext;
+import org.apache.cocoon.components.treeprocessor.ProcessingNode;
+import org.apache.cocoon.components.treeprocessor.variables.VariableResolver;
+import org.apache.cocoon.environment.Environment;
+import org.apache.cocoon.sitemap.ContentAggregator;
+
+import java.util.Map;
+
+/**
+ * Aggregate sitemap node.
+ *
+ * <h3>View handling in aggregation</h3>
+ * <ul>
+ * <li>map:aggregate can have a label, but doesn't match view from-position="first" like generators
+ * </li>
+ * <li>each map:part can have a label
+ * </li>
+ * <li>if at least one of the parts has a label matching the current view, only parts matching
+ *     this view are added. Otherwise, all parts are added.
+ * </li>
+ * </ul>
+ * For more info on aggregation and views, see the mail archive
+ * <a href="http://marc.theaimsgroup.com/?l=xml-cocoon-dev&m=100525751417953">here</a> or
+ * <a href="http://marc.theaimsgroup.com/?l=xml-cocoon-dev&m=100517130418424">here</a>.
+ *
+ * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
+ * @version $Id: AggregateNode.java 157146 2005-03-11 20:15:51Z vgritsenko $
+ */
+public class AggregateNode extends AbstractProcessingNode {
+
+    private VariableResolver element;
+    private VariableResolver nsURI;
+    private VariableResolver nsPrefix;
+
+    /** All parts */
+    private Part[] allParts;
+
+    /** Pre-filtered Part[] for views that have a matching label in any of the parts */
+    private Map viewParts;
+
+    /** View nodes to jump to */
+    private Map viewNodes;
+
+    public AggregateNode(VariableResolver element, VariableResolver nsURI, VariableResolver nsPrefix) {
+        super(null);
+        this.element = element;
+        this.nsURI = nsURI;
+        this.nsPrefix = nsPrefix;
+    }
+
+    public void setParts(Part[] allParts, Map viewParts) {
+        this.allParts = allParts;
+        this.viewParts = viewParts;
+    }
+
+    public void setViewNodes(Map viewNodes) {
+        this.viewNodes = viewNodes;
+    }
+
+    public boolean invoke(Environment env, InvokeContext context)
+    throws Exception {
+        final boolean infoEnabled = getLogger().isInfoEnabled();
+
+        Map objectModel = env.getObjectModel();
+
+        // Setup aggregator
+        ProcessingPipeline processingPipeline = context.getProcessingPipeline();
+        processingPipeline.setGenerator("<aggregator>", null, Parameters.EMPTY_PARAMETERS, Parameters.EMPTY_PARAMETERS);
+
+        ContentAggregator aggregator = (ContentAggregator) processingPipeline.getGenerator();
+        aggregator.setRootElement(this.element.resolve(context, objectModel),
+                                  this.nsURI.resolve(context, objectModel),
+                                  this.nsPrefix.resolve(context, objectModel));
+
+        // Get actual parts, potentially filtered by the view
+        Part[] actualParts;
+
+        String cocoonView = env.getView();
+        if (cocoonView == null) {
+            // Keep all parts
+            actualParts = this.allParts;
+
+        } else {
+            // Are there some parts that match this view ?
+            actualParts = (Part[])this.viewParts.get(cocoonView);
+
+            // If not, keep all parts
+            if (actualParts == null) {
+                actualParts = this.allParts;
+            }
+        }
+
+        // Add parts
+        for (int i = 0; i < actualParts.length; i++) {
+            Part part = actualParts[i];
+            if (part != null) {
+                aggregator.addPart(
+                    part.source.resolve(context, objectModel),
+                    part.element.resolve(context, objectModel),
+                    part.nsURI.resolve(context, objectModel),
+                    part.stripRoot.resolve(context, objectModel),
+                    part.nsPrefix.resolve(context, objectModel)
+                );
+            }
+        }
+
+        // Bug #7196 : Some parts matched the view: jump to that view
+        if (actualParts != this.allParts) {
+            ProcessingNode viewNode = (ProcessingNode)this.viewNodes.get(cocoonView);
+            if (viewNode != null) {
+                if (infoEnabled) {
+                    getLogger().info("Jumping to view '" + cocoonView + "' from aggregate part at " + this.getLocation());
+                }
+                return viewNode.invoke(env, context);
+            }
+        }
+
+        // Check aggregate-level view
+        if (cocoonView != null && this.viewNodes != null) {
+            ProcessingNode viewNode = (ProcessingNode)this.viewNodes.get(cocoonView);
+            if (viewNode != null) {
+                if (infoEnabled) {
+                    getLogger().info("Jumping to view '" + cocoonView + "' from aggregate at " + this.getLocation());
+                }
+                return viewNode.invoke(env, context);
+            }
+        }
+
+        // Return false to continue sitemap invocation
+        return false;
+    }
+
+    public static class Part {
+        protected VariableResolver source;
+        protected VariableResolver element;
+        protected VariableResolver nsURI;
+        protected VariableResolver nsPrefix;
+        protected VariableResolver stripRoot;
+
+        public Part(VariableResolver source,
+                    VariableResolver element,
+                    VariableResolver nsURI,
+                    VariableResolver nsPrefix,
+                    VariableResolver stripRoot) {
+            this.source = source;
+            this.element = element;
+            this.nsURI = nsURI;
+            this.nsPrefix = nsPrefix;
+            this.stripRoot = stripRoot;
+        }
+    }
+}

Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/AggregateNode.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/AggregateNodeBuilder.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/AggregateNodeBuilder.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/AggregateNodeBuilder.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/AggregateNodeBuilder.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,156 @@
+/*
+ * Copyright 1999-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.treeprocessor.sitemap;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.avalon.framework.configuration.Configuration;
+import org.apache.avalon.framework.configuration.ConfigurationException;
+import org.apache.cocoon.components.treeprocessor.AbstractProcessingNodeBuilder;
+import org.apache.cocoon.components.treeprocessor.LinkedProcessingNodeBuilder;
+import org.apache.cocoon.components.treeprocessor.ProcessingNode;
+import org.apache.cocoon.components.treeprocessor.variables.VariableResolverFactory;
+
+/**
+ * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
+ * @version $Id: AggregateNodeBuilder.java 157146 2005-03-11 20:15:51Z vgritsenko $
+ */
+public class AggregateNodeBuilder extends AbstractProcessingNodeBuilder
+                                  implements LinkedProcessingNodeBuilder {
+
+    /** The views for the aggregate element */
+    private Collection views;
+
+    /** The built node */
+    private AggregateNode node;
+
+    public ProcessingNode buildNode(Configuration config) throws Exception {
+
+        // Get root node data
+        this.node = new AggregateNode(
+            VariableResolverFactory.getResolver(config.getAttribute("element"), this.manager),
+            VariableResolverFactory.getResolver(config.getAttribute("ns", ""), this.manager),
+            VariableResolverFactory.getResolver(config.getAttribute("prefix", ""), this.manager)
+        );
+        this.treeBuilder.setupNode(this.node, config);
+
+        this.views = ((SitemapLanguage)this.treeBuilder).getViewsForStatement("", "", config);
+
+        // Bug #7196 : ensure this.views is never null (see continuation of fix below)
+        if (this.views == null) {
+            this.views = new HashSet();
+        }
+
+        // The sitemap builder
+        SitemapLanguage sitemap = (SitemapLanguage)this.treeBuilder;
+
+        // All parts of the aggregate
+        List allParts = new ArrayList();
+
+        // For each view that a part matches, the list of all parts that match it
+        Map viewParts = new HashMap();
+
+        Configuration[] childConfigs = config.getChildren();
+        for (int i = 0; i < childConfigs.length; i++) {
+            Configuration childConfig = childConfigs[i];
+
+            if (!"part".equals(childConfig.getName())) {
+                String msg = "Unknown element '" + childConfig.getName() + " in aggregate ' at " +
+                    childConfig.getLocation();
+                throw new ConfigurationException(msg);
+            }
+
+            checkNamespace(childConfig);
+
+            AggregateNode.Part currentPart = new AggregateNode.Part(
+                VariableResolverFactory.getResolver(childConfig.getAttribute("src"), this.manager),
+                VariableResolverFactory.getResolver(childConfig.getAttribute("element", ""), this.manager),
+                VariableResolverFactory.getResolver(childConfig.getAttribute("ns", ""), this.manager),
+                VariableResolverFactory.getResolver(childConfig.getAttribute("prefix", ""), this.manager),
+                VariableResolverFactory.getResolver(childConfig.getAttribute("strip-root", "false"), this.manager)
+            );
+
+            allParts.add(currentPart);
+
+            // Get the views for this part
+            Collection viewsForPart = sitemap.getViewsForStatement("", "", childConfig);
+
+            // Associate this part to all the views it belongs to
+            if (viewsForPart != null) {
+
+                // Bug #7196 : add part view to aggregate views
+                this.views.addAll(viewsForPart);
+
+                Iterator iter = viewsForPart.iterator();
+                while(iter.hasNext()) {
+                    String currentView = (String)iter.next();
+
+                    // Get collection of parts for current view
+                    Collection currentViewParts = (Collection)viewParts.get(currentView);
+                    if (currentViewParts == null) {
+                        // None for now : create the collection
+                        currentViewParts = new ArrayList();
+                        viewParts.put(currentView, currentViewParts);
+                    }
+
+                    // Add the current part to the parts list of the view
+                    currentViewParts.add(currentPart);
+                }
+            }
+        }
+
+        if (allParts.size() == 0) {
+            String msg = "There must be at least one part in map:aggregate at " + config.getLocation();
+            throw new ConfigurationException(msg);
+        }
+
+        // Now convert all Collections to Array for faster traversal
+        AggregateNode.Part[] allPartsArray = (AggregateNode.Part[])allParts.toArray(
+            new AggregateNode.Part[allParts.size()]);
+
+        Iterator iter = viewParts.entrySet().iterator();
+        while(iter.hasNext()) {
+            Map.Entry entry = (Map.Entry)iter.next();
+
+            // Get collection of parts for this entry
+            Collection coll = (Collection)entry.getValue();
+
+            // Convert to array and replace the entry value
+            entry.setValue(
+                coll.toArray(new AggregateNode.Part[coll.size()])
+            );
+        }
+
+        node.setParts(allPartsArray, viewParts);
+
+        return node;
+
+    }
+
+    public void linkNode() throws Exception {
+
+        // Give the AggregateNode a Node for each view
+        SitemapLanguage sitemap = (SitemapLanguage)this.treeBuilder;
+
+        this.node.setViewNodes(sitemap.getViewNodes(this.views));
+    }
+}

Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/AggregateNodeBuilder.java
------------------------------------------------------------------------------
    svn:eol-style = native



Mime
View raw message