cocoon-cvs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jheym...@apache.org
Subject svn commit: r330548 [33/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/sitemap/SitemapLanguage.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/SitemapLanguage.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/SitemapLanguage.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/SitemapLanguage.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,530 @@
+/*
+ * 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.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+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;
+import org.apache.avalon.framework.container.ContainerUtil;
+import org.apache.avalon.framework.context.Context;
+import org.apache.avalon.framework.context.DefaultContext;
+import org.apache.avalon.framework.logger.Logger;
+import org.apache.avalon.framework.service.ServiceManager;
+import org.apache.cocoon.Constants;
+import org.apache.cocoon.components.LifecycleHelper;
+import org.apache.cocoon.components.container.CocoonServiceManager;
+import org.apache.cocoon.components.treeprocessor.CategoryNode;
+import org.apache.cocoon.components.treeprocessor.CategoryNodeBuilder;
+import org.apache.cocoon.components.treeprocessor.DefaultTreeBuilder;
+import org.apache.cocoon.components.treeprocessor.TreeBuilder;
+import org.apache.cocoon.environment.Environment;
+import org.apache.cocoon.environment.internal.EnvironmentHelper;
+import org.apache.cocoon.generation.Generator;
+import org.apache.cocoon.serialization.Serializer;
+import org.apache.cocoon.sitemap.ComponentLocator;
+import org.apache.cocoon.sitemap.EnterSitemapEventListener;
+import org.apache.cocoon.sitemap.LeaveSitemapEventListener;
+import org.apache.cocoon.sitemap.PatternException;
+import org.apache.cocoon.sitemap.SitemapListener;
+import org.apache.cocoon.sitemap.impl.ComponentManager;
+import org.apache.cocoon.util.ClassUtils;
+import org.apache.cocoon.util.StringUtils;
+import org.apache.regexp.RE;
+
+/**
+ * The tree builder for the sitemap language.
+ *
+ * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
+ * @version CVS $Id: SitemapLanguage.java 291716 2005-09-26 19:18:20Z cziegeler $
+ */
+public class SitemapLanguage extends DefaultTreeBuilder {
+
+    // Regexp's for splitting expressions
+    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(ClassLoader classloader, Context context, Configuration config)
+    throws Exception {
+
+        // Create the classloader, if needed.
+        ServiceManager newManager;
+        
+        newManager = new CocoonServiceManager(this.parentProcessorManager, classloader);
+
+        // It's possible to define a logger on a per sitemap base.
+        // This is the default logger for all components defined with this sitemap.
+        Logger sitemapLogger = this.getLogger();
+        if ( config.getAttribute("logger", null) != null) {
+            sitemapLogger = sitemapLogger.getChildLogger(config.getAttribute("logger"));
+        }
+        // Go through the component lifecycle
+        ContainerUtil.enableLogging(newManager, sitemapLogger);
+        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, sitemapLogger, context, newManager, appContainer);
+
+            this.applicationContainer = cl;
+
+            newManager = new ComponentManager(newManager, cl);
+        }
+
+        // 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, sitemapLogger, context, current);
+                if ( !(listener.component instanceof SitemapListener) ) {
+                    throw new ConfigurationException("Listener must implement the SitemapListener interface.");
+                }
+                this.addListener(listener);
+            }
+        }
+
+        return newManager;
+    }
+
+    /**
+     * Create a listener
+     */
+    protected TreeBuilder.EventComponent createListener(ServiceManager manager,
+                                                        Logger sitemapLogger,
+                                                        Context context,
+                                                        Configuration config) 
+    throws Exception {
+        // role or class?
+        final String role = config.getAttribute("role", null);
+        if ( role != null ) {
+            return new TreeBuilder.EventComponent(manager.lookup(role), true);
+        }
+        final String className = config.getAttribute("class");
+        final Object component = ClassUtils.newInstance(className);
+
+        LifecycleHelper.setupComponent(component, sitemapLogger, context, manager, config);
+
+        return new TreeBuilder.EventComponent(component, false);
+    }
+
+    /**
+     * Add a listener
+     */
+    protected void addListener(TreeBuilder.EventComponent listener) {
+        if ( listener.component instanceof EnterSitemapEventListener ) {
+            this.enterSitemapEventListeners.add(listener);
+        } else if ( listener.component instanceof LeaveSitemapEventListener ) {
+            this.leaveSitemapEventListeners.add(listener);
+        }
+    }
+
+    /**
+     * @see org.apache.cocoon.components.treeprocessor.DefaultTreeBuilder#createContext(org.apache.avalon.framework.configuration.Configuration)
+     */
+    protected Context createContext(Configuration tree) throws Exception {
+        // Create sub-context for this sitemap
+        DefaultContext newContext = new DefaultContext(super.createContext(tree));
+        Environment env = EnvironmentHelper.getCurrentEnvironment();
+        newContext.put(Constants.CONTEXT_ENV_URI, env.getURI());
+        newContext.put(Constants.CONTEXT_ENV_PREFIX, env.getURIPrefix());
+        // FIXME How to get rid of EnvironmentHelper?
+        newContext.put(Constants.CONTEXT_ENV_HELPER, getProcessor().getWrappingProcessor().getEnvironmentHelper());
+
+        return newContext;
+    }
+
+    //---- Views management
+
+    /** Collection of view names for each label */
+    private Map labelViews = new HashMap();
+
+    /** The views CategoryNode */
+    private CategoryNode viewsNode;
+
+    /** Are we currently building a view ? */
+    private boolean isBuildingView = false;
+
+    /** Are we currently building a view ? */
+    private boolean isBuildingErrorHandler = false;
+
+    /**
+     * Pseudo-label for views <code>from-position="first"</code> (i.e. generator).
+     */
+    public static final String FIRST_POS_LABEL = "!first!";
+
+    /**
+     * Pseudo-label for views <code>from-position="last"</code> (i.e. serializer).
+     */
+    public static final String LAST_POS_LABEL = "!last!";
+
+    /* (non-Javadoc)
+     * @see org.apache.avalon.excalibur.pool.Recyclable#recycle()
+     */
+    public void recycle() {
+        super.recycle();
+
+        // Go back to initial state
+        this.labelViews.clear();
+        this.viewsNode = null;
+        this.isBuildingView = false;
+        this.isBuildingErrorHandler = false;
+    }
+
+    /**
+     * Set to <code>true</code> while building the internals of a &lt;map:view&gt;
+     */
+    public void setBuildingView(boolean building) {
+        this.isBuildingView = building;
+    }
+
+    /**
+     * Are we currently building a view ?
+     */
+    public boolean isBuildingView() {
+        return this.isBuildingView;
+    }
+
+    /**
+     * Set to <code>true</code> while building the internals of a &lt;map:handle-errors&gt;
+     */
+    public void setBuildingErrorHandler(boolean building) {
+        this.isBuildingErrorHandler = building;
+    }
+
+    /**
+     * Are we currently building an error handler ?
+     */
+    public boolean isBuildingErrorHandler() {
+        return this.isBuildingErrorHandler;
+    }
+
+    /**
+     * Add a view for a label. This is used to register all views that start from
+     * a given label.
+     *
+     * @param label the label (or pseudo-label) for the view
+     * @param view the view name
+     */
+    public void addViewForLabel(String label, String view) {
+        if (getLogger().isDebugEnabled()) {
+            getLogger().debug("views:addViewForLabel(" + label + ", " + view + ")");
+        }
+        Set views = (Set)this.labelViews.get(label);
+        if (views == null) {
+            views = new HashSet();
+            this.labelViews.put(label, views);
+        }
+
+        views.add(view);
+    }
+
+    /**
+     * Get the names of views for a given statement. If the cocoon view exists in the returned
+     * collection, the statement can directly branch to the view-handling node.
+     *
+     * @param role the component role (e.g. <code>Generator.ROLE</code>)
+     * @param hint the component hint, i.e. the 'type' attribute
+     * @param statement the sitemap statement
+     * @return the view names for this statement
+     */
+    public Collection getViewsForStatement(String role, String hint, Configuration statement) throws Exception {
+
+        String statementLabels = statement.getAttribute("label", null);
+
+        if (this.isBuildingView) {
+            // Labels are forbidden inside view definition
+            if (statementLabels != null) {
+                String msg = "Cannot put a 'label' attribute inside view definition at " + statement.getLocation();
+                throw new ConfigurationException(msg);
+            }
+
+            // We are currently building a view. Don't recurse !
+            return null;
+        }
+
+        // Compute the views attached to this component
+        Set views = null;
+
+        // Build the set for all labels for this statement
+        Set labels = new HashSet();
+
+        // 1 - labels defined on the component
+        if (role != null && role.length() > 0) {
+            String[] compLabels = this.itsComponentInfo.getLabels(role, hint);
+            if (compLabels != null) {
+                for (int i = 0; i < compLabels.length; i++) {
+                    labels.add(compLabels[i]);
+                }
+            }
+        }
+
+        // 2 - labels defined on this statement
+        if (statementLabels != null) {
+            labels.addAll(splitLabels(statementLabels));
+        }
+
+        // 3 - pseudo-label depending on the role
+        if (Generator.ROLE.equals(role)) {
+            labels.add("!first!");
+        } else if (Serializer.ROLE.equals(role)) {
+            labels.add("!last!");
+        }
+
+        // Build the set of views attached to these labels
+        views = new HashSet();
+
+        // Iterate on all labels for this statement
+        Iterator labelIter = labels.iterator();
+        while(labelIter.hasNext()) {
+
+            // Iterate on all views for this labek
+            Collection coll = (Collection)this.labelViews.get(labelIter.next());
+            if (coll != null) {
+                Iterator viewIter = coll.iterator();
+                while(viewIter.hasNext()) {
+                    String viewName = (String)viewIter.next();
+
+                    views.add(viewName);
+                }
+            }
+        }
+
+        // Don't keep empty result
+        if (views.size() == 0) {
+            views = null;
+
+            if (getLogger().isDebugEnabled()) {
+                getLogger().debug(statement.getName() + " has no views at " + statement.getLocation());
+            }
+        } else {
+            if (getLogger().isDebugEnabled()) {
+                // Dump matching views
+                StringBuffer buf = new StringBuffer(statement.getName() + " will match views [");
+                Iterator iter = views.iterator();
+                while(iter.hasNext()) {
+                    buf.append(iter.next()).append(" ");
+                }
+                buf.append("] at ").append(statement.getLocation());
+
+                getLogger().debug(buf.toString());
+            }
+        }
+
+        return views;
+    }
+
+    /**
+     * Before linking nodes, lookup the view category node used in {@link #getViewNodes(Collection)}.
+     */
+    protected void linkNodes() throws Exception {
+        // Get the views category node
+        this.viewsNode = CategoryNodeBuilder.getCategoryNode(this, "views");
+
+        super.linkNodes();
+    }
+
+    /**
+     * Get the {view name, view node} map for a collection of view names.
+     * This allows to resolve view nodes at build time, thus avoiding runtime lookup.
+     *
+     * @param viewNames the view names
+     * @return association of names to views
+     */
+    public Map getViewNodes(Collection viewNames) throws Exception {
+        if (viewNames == null || viewNames.size() == 0) {
+            return null;
+        }
+
+        if (this.viewsNode == null) {
+            return null;
+        }
+
+        Map result = new HashMap();
+
+        Iterator iter = viewNames.iterator();
+        while(iter.hasNext()) {
+            String viewName = (String)iter.next();
+            result.put(viewName, viewsNode.getNodeByName(viewName));
+        }
+
+        return result;
+    }
+
+    /**
+     * Extract pipeline-hints from the given statement (if any exist)
+     *
+     * @param role the component role (e.g. <code>Generator.ROLE</code>)
+     * @param hint the component hint, i.e. the 'type' attribute
+     * @param statement the sitemap statement
+     * @return the hint params <code>Map</code> for this statement, or null
+     *         if none exist
+     */
+    public Map getHintsForStatement(String role, String hint, Configuration statement) throws Exception {
+        // This method implemets the hintParam Syntax as follows:
+        //     A hints attribute has one or more comma separated hints
+        //     hints-attr :: hint [ ',' hint ]*
+        //     A hint is a name and an optional (string) value
+        //     If there is no value, it is considered as boolean string "true"
+        //     hint :: literal [ '=' litteral ]
+        //     literal :: <a character string where the chars ',' and '=' are not permitted>
+        //
+        //  A ConfigurationException is thrown if there is a problem "parsing"
+        //  the hint.
+
+        String statementHintParams = statement.getAttribute("pipeline-hints", null);
+        String componentHintParams = null;
+        String hintParams = null;
+
+        // firstly, determine if any pipeline-hints are defined at the component level
+        // if so, inherit these pipeline-hints (these hints can be overriden by local pipeline-hints)
+        componentHintParams = this.itsComponentInfo.getPipelineHint(role, hint);
+
+        if (componentHintParams != null) {
+            hintParams = componentHintParams;
+
+            if (statementHintParams != null) {
+                hintParams = hintParams + "," + statementHintParams;
+            }
+        } else {
+            hintParams = statementHintParams;
+        }
+
+        // if there are no pipeline-hints defined then
+        // it makes no sense to continue so, return null
+        if (hintParams == null) {
+            return null;
+        }
+
+        Map params = new HashMap();
+
+        RE commaSplit = new RE(COMMA_SPLIT_REGEXP);
+        RE equalsSplit = new RE(EQUALS_SPLIT_REGEXP);
+
+        String[]  expressions = commaSplit.split(hintParams.trim());
+
+        if (getLogger().isDebugEnabled()) {
+            getLogger().debug("pipeline-hints: (aggregate-hint) " + hintParams);
+        }
+
+        for (int i=0; i<expressions.length;i++) {
+            String [] nameValuePair = equalsSplit.split(expressions[i]);
+
+            try {
+                if (nameValuePair.length < 2) {
+                    if (getLogger().isDebugEnabled()) {
+                        getLogger().debug("pipeline-hints: (name) " + nameValuePair[0]
+                                       + "\npipeline-hints: (value) [implicit] true");
+                    }
+
+                    params.put(resolve(nameValuePair[0]), resolve("true"));
+                } else {
+                    if (getLogger().isDebugEnabled()) {
+                        getLogger().debug("pipeline-hints: (name) " + nameValuePair[0]
+                                          + "\npipeline-hints: (value) " + nameValuePair[1]);
+                    }
+
+                    params.put(resolve(nameValuePair[0]), resolve(nameValuePair[1]));
+                }
+            } catch(PatternException pe) {
+                String msg = "Invalid pattern '" + hintParams + "' at " + statement.getLocation();
+                getLogger().error(msg, pe);
+                throw new ConfigurationException(msg, pe);
+            }
+        }
+
+        return params;
+    }
+    
+    /**
+     * Get the mime-type for a component (either a serializer or a reader)
+     *
+     * @param role the component role (e.g. <code>Serializer.ROLE</code>)
+     * @param hint the component hint, i.e. the 'type' attribute
+     * @return the mime-type, or <code>null</code> if none was set
+     */
+    public String getMimeType(String role, String hint) {
+        return this.itsComponentInfo.getMimeType(role, hint);
+    }
+
+    /**
+     * Split a list of space/comma separated labels into a Collection
+     *
+     * @return the collection of labels (may be empty, nut never null)
+     */
+    private static final Collection splitLabels(String labels) {
+        if (labels == null) {
+            return Collections.EMPTY_SET;
+        }
+        return Arrays.asList(StringUtils.split(labels, ", \t\n\r"));
+    }
+}

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

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/SitemapNodeBuilder.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/SitemapNodeBuilder.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/SitemapNodeBuilder.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/SitemapNodeBuilder.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,88 @@
+/*
+ * 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;
+import org.apache.cocoon.components.treeprocessor.ProcessingNodeBuilder;
+
+/**
+ * Builds all nodes below the top-level &lt;sitemap&gt; element, and returns the
+ * &lt;pipelines&gt; node. There is no node for &gt;sitemap&lt; since no processing
+ * occurs at this level.
+ *
+ * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
+ * @version CVS $Id: SitemapNodeBuilder.java 30941 2004-07-29 19:56:58Z vgritsenko $
+ */
+
+public class SitemapNodeBuilder extends AbstractParentProcessingNodeBuilder implements ThreadSafe {
+    
+    // Name of children that have to be built in a particular order.
+    // For example, views have to be built before resources and both before pipelines.
+    private static final String[] orderedNames = { "components", "views", "resources" };
+
+    public ProcessingNode buildNode(Configuration config) throws Exception {
+        
+        // Start by explicitely ordered children
+        for (int i = 0; i < orderedNames.length; i++) {
+            Configuration childConfig = config.getChild(orderedNames[i], false);
+            if (childConfig != null) {
+                ProcessingNodeBuilder builder = this.treeBuilder.createNodeBuilder(childConfig);
+                // Don't build them since "pipelines" is not present in this list
+                builder.buildNode(childConfig);
+            }
+        }
+        
+        ProcessingNode pipelines = null;
+
+        // Now build all those that have no particular order
+        Configuration[] childConfigs = config.getChildren();
+        
+        loop: for (int i = 0; i < childConfigs.length; i++) {
+            
+            Configuration childConfig = childConfigs[i];
+            if (isChild(childConfig)) {
+                // Is it in the ordered list ?
+                for (int j = 0; j < orderedNames.length; j++) {
+                    if (orderedNames[j].equals(childConfig.getName())) {
+                        // yep : already built above
+                        continue loop;
+                    }
+                }
+                
+                ProcessingNodeBuilder builder = this.treeBuilder.createNodeBuilder(childConfig);
+                ProcessingNode node = builder.buildNode(childConfig);
+                if (node instanceof PipelinesNode) {
+                    if (pipelines != null) {
+                        String msg = "Only one 'pipelines' is allowed, at " + childConfig.getLocation();
+                        throw new ConfigurationException(msg);
+                    }
+                    pipelines = node;
+                }
+            }
+        }
+
+        if (pipelines == null) {
+            String msg = "Invalid sitemap : there must be a 'pipelines' at " + config.getLocation();
+            throw new ConfigurationException(msg);
+        }
+
+        return pipelines;
+    }
+}

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

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/SwitchSelectNode.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/SwitchSelectNode.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/SwitchSelectNode.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/SwitchSelectNode.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,96 @@
+/*
+ * 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.Map;
+
+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.ProcessingNode;
+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.selection.Selector;
+import org.apache.cocoon.selection.SwitchSelector;
+
+/**
+ *
+ * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
+ * @version CVS $Id: SwitchSelectNode.java 179045 2005-05-30 11:08:13Z cziegeler $
+ */
+public class SwitchSelectNode extends SimpleSelectorProcessingNode
+    implements ParameterizableProcessingNode {
+
+    /** The parameters of this node */
+    private Map parameters;
+
+    private ProcessingNode[][] whenNodes;
+
+    private VariableResolver[] whenTests;
+
+    private ProcessingNode[] otherwhiseNodes;
+
+    public SwitchSelectNode(String name) {
+        super(Selector.ROLE + "Selector", name);
+    }
+
+    public void setParameters(Map parameterMap) {
+        this.parameters = parameterMap;
+    }
+
+    public void setCases(ProcessingNode[][] whenNodes, VariableResolver[] whenTests, ProcessingNode[] otherwhiseNodes) {
+        this.whenNodes = whenNodes;
+        this.whenTests = whenTests;
+        this.otherwhiseNodes = otherwhiseNodes;
+    }
+
+    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
+        final Map objectModel = env.getObjectModel();
+        Parameters resolvedParams = VariableResolver.buildParameters(this.parameters, context, objectModel);
+
+        SwitchSelector switchSelector = (SwitchSelector)getComponent();
+
+        Object ctx = switchSelector.getSelectorContext(objectModel, resolvedParams);
+       
+        try {
+            for (int i = 0; i < this.whenTests.length; i++) {
+                if (this.executor.invokeSwitchSelector(this, 
+                        objectModel, 
+                        switchSelector, 
+                        whenTests[i].resolve(context, objectModel), 
+                        resolvedParams, 
+                        ctx)) {
+                    return invokeNodes(this.whenNodes[i], env, context);
+                }
+            }
+
+            if (this.otherwhiseNodes != null) {
+                return invokeNodes(this.otherwhiseNodes, env, context);
+            }
+
+            return false;
+        } finally {
+            releaseComponent(switchSelector);
+        }
+    }
+}

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

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/TransformNode.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/TransformNode.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/TransformNode.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/TransformNode.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.parameters.Parameters;
+import org.apache.cocoon.components.pipeline.ProcessingPipeline;
+import org.apache.cocoon.components.treeprocessor.InvokeContext;
+import org.apache.cocoon.components.treeprocessor.ParameterizableProcessingNode;
+import org.apache.cocoon.components.treeprocessor.PipelineEventComponentProcessingNode;
+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.SitemapExecutor;
+
+import java.util.Map;
+
+/**
+ *
+ * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
+ * @version CVS $Id: TransformNode.java 179045 2005-05-30 11:08:13Z cziegeler $
+ */
+
+public class TransformNode extends PipelineEventComponentProcessingNode implements ParameterizableProcessingNode {
+
+    private String transformerName;
+
+    private VariableResolver source;
+
+    private Map parameters;
+
+
+    public TransformNode(String name, VariableResolver source) {
+        this.transformerName = name;
+        this.source = source;
+    }
+
+    public void setParameters(Map parameterMap) {
+        this.parameters = parameterMap;
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.apache.cocoon.components.treeprocessor.ProcessingNode#invoke(org.apache.cocoon.environment.Environment, org.apache.cocoon.components.treeprocessor.InvokeContext)
+     */
+    public final boolean invoke(Environment env, InvokeContext context)
+    throws Exception {
+
+        final Map objectModel = env.getObjectModel();
+
+        final ProcessingPipeline pipeline = context.getProcessingPipeline();
+        
+        SitemapExecutor.PipelineComponentDescription desc = new SitemapExecutor.PipelineComponentDescription();
+        desc.type = this.transformerName;
+        desc.source = source.resolve(context, objectModel);
+        desc.parameters = VariableResolver.buildParameters(this.parameters, context, objectModel);
+        desc.hintParameters = this.pipelineHints == null
+                ? Parameters.EMPTY_PARAMETERS
+                : VariableResolver.buildParameters(this.pipelineHints, context, objectModel);
+
+        // inform executor
+        desc = this.executor.addTransformer(this, objectModel, desc);
+
+        pipeline.addTransformer(
+            desc.type,
+            desc.source,
+            desc.parameters,
+            desc.hintParameters
+        );
+
+        // Check view
+        if (this.views != null) {
+	   
+            //inform the pipeline that we have a branch point
+            pipeline.informBranchPoint();
+	    
+            String cocoonView = env.getView();
+            if (cocoonView != null) {
+
+                // Get view node
+                ProcessingNode viewNode = (ProcessingNode)this.views.get(cocoonView);
+
+                if (viewNode != null) {
+                    if (getLogger().isInfoEnabled()) {
+                        getLogger().info("Jumping to view " + cocoonView + " from transformer at " + this.getLocation());
+                    }
+                    return viewNode.invoke(env, context);
+                }
+            }
+        }
+
+        // Return false to contine sitemap invocation
+        return false;
+    }
+}

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

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/TransformNodeBuilder.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/TransformNodeBuilder.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/TransformNodeBuilder.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/TransformNodeBuilder.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,63 @@
+/*
+ * 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.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;
+import org.apache.cocoon.transformation.Transformer;
+
+import java.util.Collection;
+import java.util.Map;
+
+/**
+ *
+ * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
+ * @version CVS $Id: TransformNodeBuilder.java 30941 2004-07-29 19:56:58Z vgritsenko $
+ */
+
+public class TransformNodeBuilder extends AbstractProcessingNodeBuilder
+  implements LinkedProcessingNodeBuilder {
+
+    private TransformNode node;
+
+    private Collection views;
+    private Map  pipelineHints;
+
+    public ProcessingNode buildNode(Configuration config) throws Exception {
+
+        String type = this.treeBuilder.getTypeForStatement(config, Transformer.ROLE);
+
+        this.views = ((SitemapLanguage)this.treeBuilder).getViewsForStatement(Transformer.ROLE, type, config);
+        this.pipelineHints = ((SitemapLanguage)this.treeBuilder).getHintsForStatement(Transformer.ROLE, type, config);
+
+        this.node = new TransformNode(
+            type,
+            VariableResolverFactory.getResolver(config.getAttribute("src", null), this.manager)
+        );
+
+        this.node.setPipelineHints(this.pipelineHints);
+        return this.treeBuilder.setupNode(node, config);
+    }
+
+    public void linkNode() throws Exception {
+        this.node.setViews(
+            ((SitemapLanguage)this.treeBuilder).getViewNodes(this.views)
+        );
+    }
+}

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

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/VPCNode.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/VPCNode.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/VPCNode.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/VPCNode.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,40 @@
+/*
+ * 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.Set;
+
+import org.apache.cocoon.components.treeprocessor.NamedContainerNode;
+
+/**
+ * A VPC node that just invokes its children and store what parameters are sources.
+ *
+ * @version $Id: VPCNode.java 292282 2005-09-28 19:54:16Z vgritsenko $
+ */
+
+public class VPCNode extends NamedContainerNode {
+
+    Set sourceSet;
+
+    public VPCNode(String name, Set sourceSet) {
+        super(name);
+        this.sourceSet = sourceSet;
+    }
+
+    public Set getSources() {
+        return this.sourceSet;
+    }
+}

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

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/VPCNodeBuilder.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/VPCNodeBuilder.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/VPCNodeBuilder.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/VPCNodeBuilder.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,65 @@
+/*
+ * 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.HashSet;
+
+import org.apache.avalon.framework.configuration.Configuration;
+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.context.DefaultContext;
+import org.apache.cocoon.Constants;
+import org.apache.cocoon.components.treeprocessor.NamedContainerNodeBuilder;
+import org.apache.cocoon.components.treeprocessor.ProcessingNode;
+
+/**
+ * Handles a virtual sitemap component.
+ *
+ * @version $Id: VPCNodeBuilder.java 292282 2005-09-28 19:54:16Z vgritsenko $
+ */
+public class VPCNodeBuilder extends NamedContainerNodeBuilder
+    implements Contextualizable {
+
+    private DefaultContext context;
+
+    // FIXME: The class is thread safe, will that work with Contextualizable?
+    public void contextualize(Context context) throws ContextException {
+        this.context = (DefaultContext) context;
+    }
+
+    public ProcessingNode buildNode(Configuration config) throws Exception {
+        String type = config.getName();
+        String name = config.getAttribute(this.nameAttr);
+
+        // Find out which parameters that should be handled as sources
+        // and put the info in the context.
+        Configuration[] sources = config.getChildren("source");
+        HashSet sourceSet = new HashSet();
+        for (int j = 0; j < sources.length; j++)
+            sourceSet.add(sources[j].getAttribute("param"));
+        
+        VPCNode node = new VPCNode(name, sourceSet);
+        this.setupNode(node, config);
+
+        // Stuff this node into the context of current Sitemap so that
+        // VirtualPipelineComponent can find it. 
+        //
+        this.context.put(Constants.CONTEXT_VPC_PREFIX + type + "-" + name, node);
+
+        return node;
+    }
+}

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

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/VPCsNodeBuilder.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/VPCsNodeBuilder.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/VPCsNodeBuilder.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/VPCsNodeBuilder.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,63 @@
+/*
+ * 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.components.treeprocessor.ContainerNode;
+import org.apache.cocoon.components.treeprocessor.ContainerNodeBuilder;
+import org.apache.cocoon.components.treeprocessor.ProcessingNode;
+import org.apache.cocoon.generation.VirtualPipelineGenerator;
+import org.apache.cocoon.reading.VirtualPipelineReader;
+import org.apache.cocoon.serialization.VirtualPipelineSerializer;
+import org.apache.cocoon.transformation.VirtualPipelineTransformer;
+
+/**
+ * Handles a set of virtual sitemap components.
+ *
+ * @version $Id: VPCsNodeBuilder.java 292282 2005-09-28 19:54:16Z vgritsenko $
+ */
+public class VPCsNodeBuilder extends ContainerNodeBuilder {
+
+    /**
+     * Checks if a child element is a VPC, and if not throws a <code>ConfigurationException</code>.
+     *
+     * @param child the child configuration to check.
+     * @return <code>true</code> if this child should be considered or <code>false</code>
+     *         if it should be ignored.
+     * @throws ConfigurationException if this child isn't allowed.
+     */
+    protected boolean isChild(Configuration child) throws ConfigurationException {
+
+        checkNamespace(child);
+
+        String clazz = child.getAttribute("src");
+        return VirtualPipelineGenerator.class.getName().equals(clazz)
+            || VirtualPipelineSerializer.class.getName().equals(clazz)
+            || VirtualPipelineTransformer.class.getName().equals(clazz)
+            || VirtualPipelineReader.class.getName().equals(clazz);
+    }
+
+    protected void setupNode(ContainerNode node, Configuration config)throws Exception {
+
+        this.treeBuilder.setupNode(node, config);
+
+        ProcessingNode[] children = buildChildNodes(config);
+
+        node.setChildren(children);
+    }
+}

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

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/ViewNodeBuilder.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/ViewNodeBuilder.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/ViewNodeBuilder.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/ViewNodeBuilder.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,66 @@
+/*
+ * 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.NamedContainerNodeBuilder;
+import org.apache.cocoon.components.treeprocessor.NamedProcessingNode;
+import org.apache.cocoon.components.treeprocessor.ProcessingNode;
+
+/**
+ * Builds a &lt;map:view&gt;
+ *
+ * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
+ * @version CVS $Id: ViewNodeBuilder.java 30941 2004-07-29 19:56:58Z vgritsenko $
+ */
+
+public class ViewNodeBuilder extends NamedContainerNodeBuilder implements ThreadSafe {
+
+    public ProcessingNode buildNode(Configuration config) throws Exception {
+
+        // Get the label or position (pseudo-label) of this view.
+        String label = config.getAttribute("from-label", null);
+
+        if (label == null) {
+            String position = config.getAttribute("from-position");
+            if ("first".equals(position)) {
+                label = SitemapLanguage.FIRST_POS_LABEL;
+            } else if ("last".equals(position)) {
+                label = SitemapLanguage.LAST_POS_LABEL;
+            } else {
+                String msg = "Bad value for 'from-position' at " + config.getLocation();
+                throw new ConfigurationException(msg);
+            }
+        }
+
+        SitemapLanguage sitemapBuilder = (SitemapLanguage)this.treeBuilder;
+
+        // Indicate to child builders that we're in a view (they won't perform view branching)
+        sitemapBuilder.setBuildingView(true);
+
+        // Build children
+        NamedProcessingNode result = (NamedProcessingNode)super.buildNode(config);
+
+        sitemapBuilder.addViewForLabel(label, result.getName());
+
+        // Clear the flag
+        sitemapBuilder.setBuildingView(false);
+
+        return result;
+    }
+}

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

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/package.html
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/package.html?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/package.html (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/sitemap/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>Implemention of the Sitemap language</title>
+</head>
+<body>
+ <h1>Implemention of the Sitemap language</h1>
+ <p>
+ </p>
+</body>
+</html>

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

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/variables/NOPVariableResolver.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/variables/NOPVariableResolver.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/variables/NOPVariableResolver.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/variables/NOPVariableResolver.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,45 @@
+/*
+ * 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.variables;
+
+import org.apache.cocoon.components.treeprocessor.InvokeContext;
+
+import java.util.Map;
+
+/**
+ * No-op implementation of {@link VariableResolver} for constant expressions
+ *
+ * @version CVS $Id: NOPVariableResolver.java 30941 2004-07-29 19:56:58Z vgritsenko $
+ */
+public class NOPVariableResolver extends VariableResolver {
+
+    private String expression = null;
+
+    public NOPVariableResolver(String expression) {
+        super(expression);
+        if (expression != null) {
+            this.expression = VariableResolverFactory.unescape(expression);
+        }
+    }
+
+    public final String resolve(InvokeContext context, Map objectModel) {
+        return this.expression;
+    }
+    
+    public final void release() {
+        // Nothing to do
+    }
+}

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

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/variables/PreparedVariableResolver.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/variables/PreparedVariableResolver.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/variables/PreparedVariableResolver.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/variables/PreparedVariableResolver.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,390 @@
+/*
+ * 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.variables;
+
+import org.apache.avalon.framework.activity.Disposable;
+import org.apache.avalon.framework.configuration.ConfigurationException;
+import org.apache.avalon.framework.service.ServiceException;
+import org.apache.avalon.framework.service.ServiceManager;
+import org.apache.avalon.framework.service.ServiceSelector;
+import org.apache.avalon.framework.thread.ThreadSafe;
+
+import org.apache.cocoon.components.modules.input.InputModule;
+import org.apache.cocoon.components.treeprocessor.InvokeContext;
+import org.apache.cocoon.sitemap.PatternException;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Stack;
+
+/**
+ * Prepared implementation of {@link VariableResolver} for fast evaluation.
+ *
+ * @author <a href="mailto:uv@upaya.co.uk">Upayavira</a>
+ * @version CVS $Id: PreparedVariableResolver.java 179045 2005-05-30 11:08:13Z cziegeler $
+ */
+final public class PreparedVariableResolver extends VariableResolver implements Disposable {
+
+    private ServiceManager manager;
+    private ServiceSelector selector;
+    protected List tokens;
+    protected boolean needsMapStack;
+
+    private static final int OPEN = -2;
+    private static final int CLOSE = -3;
+    private static final int COLON = -4;
+    private static final int TEXT = -5;
+    private static final int EXPR = -7;
+    private static final int SITEMAP_VAR = -9;
+    private static final int THREADSAFE_MODULE = -10;
+    private static final int STATEFUL_MODULE = -11;
+    private static final int ROOT_SITEMAP_VARIABLE = 0;
+    private static final int ANCHOR_VAR = -1;
+
+    protected static Token COLON_TOKEN = new Token(COLON);
+    protected static Token OPEN_TOKEN = new Token(OPEN);
+    protected static Token CLOSE_TOKEN = new Token(CLOSE);
+    protected static Token EMPTY_TOKEN = new Token(EXPR);
+
+    public PreparedVariableResolver(String expr, ServiceManager manager) throws PatternException {
+        super(expr);
+        this.manager = manager;
+        this.tokens = new ArrayList();
+
+        VariableExpressionTokenizer.tokenize(expr, new VariableExpressionTokenizer.TokenReciever() {
+            public void addToken(int type, String value) throws PatternException {
+                switch (type) {
+                    case VariableExpressionTokenizer.TokenReciever.COLON:
+                        tokens.add(COLON_TOKEN);
+                        break;
+                    case VariableExpressionTokenizer.TokenReciever.OPEN:
+                        tokens.add(OPEN_TOKEN);
+                        break;
+                    case VariableExpressionTokenizer.TokenReciever.CLOSE:
+                        tokens.add(CLOSE_TOKEN);
+                        break;
+                    case VariableExpressionTokenizer.TokenReciever.TEXT:
+                        tokens.add(new Token(value));
+                        break;
+                    case VariableExpressionTokenizer.TokenReciever.MODULE:
+                        Token token;
+                        if (value.equals("sitemap")) {
+                            // Explicit prefix for sitemap variable
+                            needsMapStack = true;
+                            token = new Token(SITEMAP_VAR);
+                        } else if (value.startsWith("#")) {
+                            // anchor syntax refering to a name result level
+                            needsMapStack = true;
+                            token = new Token(ANCHOR_VAR, value.substring(1));
+                        } else {
+                            // Module used
+                            token = getNewModuleToken(value);
+                        }
+                        tokens.add(token);
+                        break;
+                    case VariableExpressionTokenizer.TokenReciever.VARIABLE:
+                        needsMapStack = true;
+                        tokens.add(getNewVariableToken(value));
+                        break;
+                    default:
+                        throw new IllegalArgumentException("Unknown token type: " + type);
+                }
+            }
+        });
+    }
+
+    protected Token getNewVariableToken(String variable) {
+        if (variable.startsWith("/")) {
+            return new Token(ROOT_SITEMAP_VARIABLE, variable.substring(1));
+        }
+        // Find level
+        int level = 1; // Start at 1 since it will be substracted from list.size()
+        int pos = 0;
+        while (variable.startsWith("../", pos)) {
+            level++;
+            pos += "../".length();
+        }
+        return new Token(level, variable.substring(pos));
+    }
+
+
+    protected Token getNewModuleToken(String moduleName) throws PatternException {
+        if (this.selector == null) {
+            try {
+                // First access to a module : lookup selector
+                this.selector = (ServiceSelector) this.manager.lookup(InputModule.ROLE + "Selector");
+            } catch(ServiceException ce) {
+                throw new PatternException("Cannot access input modules selector", ce);
+            }
+        }
+
+        // Get the module
+        InputModule module;
+        try {
+            module = (InputModule) this.selector.select(moduleName);
+        } catch (ServiceException e) {
+            throw new PatternException("Cannot get module named '" + moduleName +
+                                       "' in expression '" + this.originalExpr + "'", e);
+        }
+
+        Token token;
+        // Is this module threadsafe ?
+        if (module instanceof ThreadSafe) {
+            token = new Token(THREADSAFE_MODULE, module);
+        } else {
+            // Stateful module : release it and get a new one each time
+            this.selector.release(module);
+            token = new Token(STATEFUL_MODULE, moduleName);
+        }
+        return token;
+    }
+
+    public final String resolve(InvokeContext context, Map objectModel) throws PatternException {
+        List mapStack = null; // get the stack only when necessary - lazy inside the loop
+        int stackSize = 0;
+
+        if (needsMapStack) {
+            if (context == null) {
+                throw new PatternException("Need an invoke context to resolve " + this);
+            }
+            mapStack = context.getMapStack();
+            stackSize = mapStack.size();
+        }
+
+        Stack stack = new Stack();
+
+        for (Iterator i = tokens.iterator(); i.hasNext();) {
+            Token token = (Token) i.next();
+            Token last;
+            switch (token.getType()){
+                case TEXT:
+                    if (stack.empty()) {
+                        stack.push(new Token(EXPR, token.getStringValue()));
+                    } else {
+                        last = (Token)stack.peek();
+                        if (last.hasType(EXPR)) {
+                            last.merge(token);
+                        } else {
+                            stack.push(new Token(EXPR, token.getStringValue()));
+                        }
+                    }
+                    break;
+                case CLOSE:
+                    Token expr = (Token)stack.pop();
+                    Token lastButOne = (Token)stack.pop();
+                    Token result;
+                    if (expr.hasType(COLON)) { // i.e. nothing was specified after the colon
+                        stack.pop(); // Pop the OPEN
+                        result = processModule(lastButOne, EMPTY_TOKEN, objectModel, context, mapStack, stackSize);
+                    } else if (lastButOne.hasType(COLON)) {
+                        Token module = (Token)stack.pop();
+                        stack.pop(); // Pop the OPEN
+                        result = processModule(module, expr, objectModel, context, mapStack, stackSize);
+                    } else {
+                        result = processVariable(expr, mapStack, stackSize);
+                    }
+                    if (stack.empty()) {
+                        stack.push(result);
+                    } else {
+                        last = (Token)stack.peek();
+                        if (last.hasType(EXPR)) {
+                            last.merge(result);
+                        } else {
+                            stack.push(result);
+                        }
+                    }
+                    break;
+                case OPEN:
+                case COLON:
+                case ANCHOR_VAR:
+                case THREADSAFE_MODULE:
+                case STATEFUL_MODULE:
+                case ROOT_SITEMAP_VARIABLE:
+                default: {
+                    stack.push(token);
+                    break;
+                }
+            }
+        }
+        if (stack.size() !=1) {
+            throw new PatternException("Evaluation error in expression: " + originalExpr);
+        }
+        return ((Token)stack.pop()).getStringValue();
+    }
+
+    private Token processModule(Token module, Token expr, Map objectModel, InvokeContext context, List mapStack, int stackSize) throws PatternException {
+        int type = module.getType();
+
+        if (type == ANCHOR_VAR) {
+            Map levelResult = context.getMapByAnchor(module.getStringValue());
+
+            if (levelResult == null) {
+              throw new PatternException("Error while evaluating '" + this.originalExpr +
+                "' : no anchor '" + String.valueOf(module.getStringValue()) + "' found in context");
+            }
+
+            Object result = levelResult.get(expr.getStringValue());
+            return new Token(EXPR, result==null ? "" : result.toString());
+        } else if (type == THREADSAFE_MODULE) {
+            try {
+                InputModule im = module.getModule();
+                Object result = im.getAttribute(expr.getStringValue(), null, objectModel);
+                return new Token(EXPR, result==null ? "" : result.toString());
+
+            } catch(ConfigurationException confEx) {
+                throw new PatternException("Cannot get variable '" + expr.getStringValue() +
+                    "' in expression '" + this.originalExpr + "'", confEx);
+            }
+
+        } else if (type == STATEFUL_MODULE) {
+            InputModule im = null;
+            String moduleName = module.getStringValue();
+            try {
+                im = (InputModule) this.selector.select(moduleName);
+
+                Object result = im.getAttribute(expr.getStringValue(), null, objectModel);
+                return new Token(EXPR, result==null ? "" : result.toString());
+
+            } catch(ServiceException e) {
+                throw new PatternException("Cannot get module '" + moduleName +
+                                           "' in expression '" + this.originalExpr + "'", e);
+
+            } catch(ConfigurationException confEx) {
+                throw new PatternException("Cannot get variable '" + expr.getStringValue() +
+                    "' in expression '" + this.originalExpr + "'", confEx);
+
+            } finally {
+                this.selector.release(im);
+            }
+        } else if (type == SITEMAP_VAR) {
+            // Prefixed sitemap variable must be parsed at runtime
+            String variable = expr.getStringValue();
+            Token token;
+            if (variable.startsWith("/")) {
+                token = new Token(ROOT_SITEMAP_VARIABLE, variable.substring(1));
+            } else {
+                // Find level
+                int level = 1; // Start at 1 since it will be substracted from list.size()
+                int pos = 0;
+                while (variable.startsWith("../", pos)) {
+                    level++;
+                    pos += "../".length();
+                }
+                token = new Token(level, variable.substring(pos));
+            }
+            return processVariable(token, mapStack, stackSize);
+        } else {
+            throw new PatternException("Unknown token type: " + expr.getType());
+        }
+    }
+
+    private Token processVariable(Token expr, List mapStack, int stackSize) throws PatternException {
+        int type = expr.getType();
+        String value = expr.getStringValue();
+        if (type == ROOT_SITEMAP_VARIABLE) {
+            Object result = ((Map)mapStack.get(0)).get(value);
+            return new Token(EXPR, result==null ? "" : result.toString());
+        }
+        // relative sitemap variable
+        if (type > stackSize) {
+            throw new PatternException("Error while evaluating '" + this.originalExpr +
+                "' : not so many levels");
+        }
+
+        Object result = ((Map)mapStack.get(stackSize - type)).get(value);
+        return new Token(EXPR, result==null ? "" : result.toString());
+    }
+
+    public final void dispose() {
+        if (this.selector != null) {
+            for (Iterator i = tokens.iterator(); i.hasNext();) {
+                Token token = (Token)i.next();
+                if (token.hasType(THREADSAFE_MODULE)) {
+                    InputModule im = token.getModule();
+                    this.selector.release(im);
+                }
+            }
+            this.manager.release(this.selector);
+            this.selector = null;
+            this.manager = null;
+        }
+    }
+
+    private static class Token {
+
+        private Object value;
+        private int type;
+
+        public Token(int type) {
+            if (type==EXPR) {
+                this.value="";
+            } else {
+                this.value = null;
+            }
+            this.type = type;
+        }
+
+        public Token(int type, String value) {
+            this.value = value;
+            this.type = type;
+        }
+
+        public Token(int type, InputModule module) {
+            this.value = module;
+            this.type = type;
+        }
+
+        public Token(String value) {
+            this.type = TEXT;
+            this.value = value;
+        }
+
+        public int getType() {
+          return type;
+        }
+
+        public String getStringValue() {
+            if (value instanceof String) {
+                return (String)this.value;
+            }
+            return null;
+        }
+
+        public boolean hasType(int type){
+            return this.type == type;
+        }
+
+        public boolean equals(Object o) {
+            if (o instanceof Token) {
+                return ((Token)o).hasType(this.type);
+            }
+            return false;
+        }
+
+        public void merge(Token newToken) {
+            this.value = this.value + newToken.getStringValue();
+        }
+
+        public InputModule getModule() {
+            if (value instanceof InputModule) {
+                return (InputModule)value;
+            }
+            return null;
+        }
+    }
+}

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

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/variables/VariableExpressionTokenizer.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/variables/VariableExpressionTokenizer.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/variables/VariableExpressionTokenizer.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/variables/VariableExpressionTokenizer.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,140 @@
+/*
+ * 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.variables;
+
+import org.apache.cocoon.sitemap.PatternException;
+
+/**
+ * Parses "Text {module:{module:attribute}} more text {variable}" types of
+ * expressions. Supports escaping of braces with '\' character, and nested
+ * expressions.
+ *
+ * @version CVS $Id: VariableExpressionTokenizer.java 54080 2004-10-08 13:35:03Z vgritsenko $
+ */
+public final class VariableExpressionTokenizer {
+
+    /**
+     * Callback for tokenizer
+     */
+    public interface TokenReciever {
+        int OPEN = -2;
+        int CLOSE = -3;
+        int COLON = -4;
+        int TEXT = -5;
+        int MODULE = -6;
+        int VARIABLE = -8;
+
+        /**
+         * Reports parsed tokens.
+         */
+        void addToken(int type, String value) throws PatternException;
+    }
+
+    /**
+     * Tokenizes specified expression. Passes tokens to the
+     * reciever.
+     *
+     * @throws PatternException if expression is not valid
+     */
+    public static void tokenize(String expression, TokenReciever reciever) throws PatternException {
+
+        int lastTokenType = 0;
+
+        int openCount = 0;
+        int closeCount = 0;
+
+        int pos = 0;
+        int i;
+        boolean escape = false;
+
+        for (i = 0; i < expression.length(); i++) {
+            final char c = expression.charAt(i);
+
+            if (escape) {
+                escape = false;
+            } else if (c == '\\' && i < expression.length()) {
+                char nextChar = expression.charAt(i + 1);
+                if (nextChar == '{' || nextChar == '}') {
+                    expression = expression.substring(0, i) + expression.substring(i + 1);
+                    escape = true;
+                    i--;
+                }
+            } else if (c == '{') {
+                if (i > pos) {
+                    reciever.addToken(lastTokenType = TokenReciever.TEXT, expression.substring(pos, i));
+                }
+
+                openCount++;
+                reciever.addToken(lastTokenType = TokenReciever.OPEN, null);
+
+                int colonPos = indexOf(expression, ':', i);
+                int closePos = indexOf(expression, '}', i);
+                int openPos = indexOf(expression, '{', i);
+
+                if (openPos < colonPos && openPos < closePos) {
+                    throw new PatternException("Invalid '{' at position " + i +
+                                               " in expression \"" + expression + "\"");
+                }
+
+                if (colonPos < closePos) {
+                    // we've found a module
+                    String module = expression.substring(i + 1, colonPos);
+                    reciever.addToken(lastTokenType = TokenReciever.MODULE, module);
+                    i = colonPos - 1;
+                } else {
+                    // Unprefixed name: variable
+                    reciever.addToken(lastTokenType = TokenReciever.VARIABLE, expression.substring(i + 1, closePos));
+                    i = closePos - 1;
+                }
+
+                pos = i + 1;
+            } else if (c == '}') {
+                if (i > 0 && expression.charAt(i - 1) == '\\') {
+                    continue;
+                }
+                if (i > pos) {
+                    reciever.addToken(lastTokenType = TokenReciever.TEXT, expression.substring(pos, i));
+                }
+
+                closeCount++;
+                reciever.addToken(lastTokenType = TokenReciever.CLOSE, null);
+
+                pos = i + 1;
+            } else if (c == ':') {
+                if (lastTokenType != TokenReciever.MODULE || i != pos) {
+                    // this colon isn't part of a module reference
+                    continue;
+                }
+
+                reciever.addToken(lastTokenType = TokenReciever.COLON, null);
+                pos = i + 1;
+            }
+        }
+
+        if (i > pos) {
+            reciever.addToken(lastTokenType = TokenReciever.TEXT, expression.substring(pos, i));
+        }
+
+        if (openCount != closeCount) {
+            throw new PatternException("Mismatching braces in expression \"" + expression + "\"");
+        }
+    }
+
+    private static int indexOf(String expression, char chr, int pos) {
+        int location;
+        return (location = expression.indexOf(chr, pos + 1)) != -1? location : expression.length();
+    }
+}

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

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/variables/VariableResolver.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/variables/VariableResolver.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/variables/VariableResolver.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/components/treeprocessor/variables/VariableResolver.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,157 @@
+/*
+ * 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.variables;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.apache.avalon.framework.parameters.Parameters;
+import org.apache.cocoon.components.treeprocessor.InvokeContext;
+import org.apache.cocoon.sitemap.PatternException;
+import org.apache.cocoon.sitemap.SitemapParameters;
+import org.apache.cocoon.util.location.Locatable;
+import org.apache.cocoon.util.location.Location;
+
+/**
+ * Utility class for handling {...} pattern substitutions in sitemap statements.
+ *
+ * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
+ * @version CVS $Id: VariableResolver.java 233343 2005-08-18 18:06:44Z sylvain $
+ */
+public abstract class VariableResolver {
+
+    public static final Map EMPTY_MAP = Collections.unmodifiableMap(new java.util.HashMap(0));
+
+    protected final String originalExpr;
+    
+    protected VariableResolver(String expr) {
+        this.originalExpr = expr;
+    }
+
+    public final String toString() {
+        return this.originalExpr;
+    }
+
+    /**
+     * Compare two VariableResolvers
+     */
+    public boolean equals(Object object) {
+        if (object instanceof VariableResolver) {
+            VariableResolver other = (VariableResolver)object;
+            return (this.originalExpr == null && other.originalExpr == null) ||
+                   (this.originalExpr.equals(other.originalExpr));
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * generate HashCode
+     * needed to determine uniqueness within hashtables
+     */
+    public int hashCode() {
+        return this.originalExpr == null ? 0 : this.originalExpr.hashCode();
+    }
+
+    /**
+     * Resolve all {...} patterns using the values given in the object model.
+     */
+    public String resolve(Map objectModel) throws PatternException {
+        return resolve(null, objectModel);
+    }
+
+    /**
+     * Resolve all {...} patterns using the values given in the list of maps and the object model.
+     */
+    public abstract String resolve(InvokeContext context, Map objectModel) throws PatternException;
+
+    /**
+     * Build a <code>Parameters</code> object from a Map of named <code>VariableResolver</code>s and
+     * a list of Maps used for resolution.
+     *
+     * @return a fully resolved <code>Parameters</code>.
+     */
+    public static Parameters buildParameters(Map expressions, InvokeContext context, Map objectModel) throws PatternException {
+        Location location;
+        if (expressions instanceof Locatable) {
+            location = ((Locatable)expressions).getLocation();
+        } else {
+            location = Location.UNKNOWN;
+        }
+        
+        if ((expressions == null || expressions.size() == 0) && location.equals(Location.UNKNOWN)) {
+            return Parameters.EMPTY_PARAMETERS;
+        }
+
+        SitemapParameters result = new SitemapParameters(location);
+
+        Iterator iter = expressions.entrySet().iterator();
+        while (iter.hasNext()) {
+            Map.Entry entry = (Map.Entry)iter.next();
+            result.setParameter(
+                ((VariableResolver)entry.getKey()).resolve(context, objectModel),
+                ((VariableResolver)entry.getValue()).resolve(context, objectModel)
+            );
+        }
+
+        return result;
+    }
+
+    /**
+     * Build a <code>Map</code> from a Map of named <code>ListOfMapResolver</code>s and
+     * a list of Maps used for resolution.
+     *
+     * @return a fully resolved <code>Map</code>.
+     */
+    public static Map buildMap(Map expressions, InvokeContext context, Map objectModel) throws PatternException {
+        int size;
+        if (expressions == null || (size = expressions.size()) == 0) {
+            return EMPTY_MAP;
+        }
+
+        Map result;
+        if ( expressions instanceof Locatable ) {
+            result = new SitemapParameters.LocatedHashMap(((Locatable)expressions).getLocation(), size);   
+        } else {
+            result = new HashMap(size);
+        }
+
+        Iterator iter = expressions.entrySet().iterator();
+        while (iter.hasNext()) {
+            Map.Entry entry = (Map.Entry)iter.next();
+            result.put(
+                ((VariableResolver)entry.getKey()).resolve(context, objectModel),
+                ((VariableResolver)entry.getValue()).resolve(context, objectModel)
+            );
+        }
+
+        return result;
+    }
+
+//    /**
+//     * Release a <code>Map</code> of expressions.
+//     */
+//    public static void release(Map expressions) {
+//        Iterator iter = expressions.entrySet().iterator();
+//        while (iter.hasNext()) {
+//            Map.Entry entry = (Map.Entry)iter.next();
+//            ((VariableResolver)entry.getKey()).release();
+//            ((VariableResolver)entry.getValue()).release();
+//        }
+//    }
+}

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



Mime
View raw message