Package org.apache.cocoon.treeprocessor

Source Code of org.apache.cocoon.treeprocessor.TreeProcessor

/*****************************************************************************
* Copyright (C) The Apache Software Foundation. All rights reserved.        *
* ------------------------------------------------------------------------- *
* This software is published under the terms of the Apache Software License *
* version 1.1, a copy of which has been included  with this distribution in *
* the LICENSE file.                                                         *
*****************************************************************************/

package org.apache.cocoon.treeprocessor;

import org.apache.avalon.excalibur.component.RoleManageable;
import org.apache.avalon.excalibur.component.RoleManager;
import org.apache.avalon.excalibur.logger.LogKitManageable;
import org.apache.avalon.excalibur.logger.LogKitManager;

import org.apache.avalon.framework.activity.Disposable;
import org.apache.avalon.framework.activity.Initializable;

import org.apache.avalon.framework.component.Component;
import org.apache.avalon.framework.component.ComponentException;
import org.apache.avalon.framework.component.ComponentManager;
import org.apache.avalon.framework.component.ComponentSelector;
import org.apache.avalon.framework.component.Composable;

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.context.Context;
import org.apache.avalon.framework.context.ContextException;
import org.apache.avalon.framework.context.Contextualizable;

import org.apache.avalon.framework.logger.AbstractLoggable;
import org.apache.avalon.framework.thread.ThreadSafe;

import org.apache.cocoon.Processor;
import org.apache.cocoon.components.LifecycleHelper;
import org.apache.cocoon.components.pipeline.EventPipeline;
import org.apache.cocoon.components.pipeline.StreamPipeline;
import org.apache.cocoon.components.source.CocoonSourceFactory;
import org.apache.cocoon.components.source.DelayedRefreshSourceWrapper;
import org.apache.cocoon.components.source.SourceHandler;
import org.apache.cocoon.components.source.URLSource;
import org.apache.cocoon.components.url.URLFactory;
import org.apache.cocoon.environment.Environment;
import org.apache.cocoon.environment.Source;

import java.io.InputStream;
import java.util.*;

/**
* Interpreted tree-traversal implementation of a pipeline assembly language.
*
* @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
* @version CVS $Revision: 1.3 $ $Date: 2002/01/30 14:35:07 $
*/

public class TreeProcessor extends AbstractLoggable implements ThreadSafe, Processor,
  Composable, Configurable, LogKitManageable, RoleManageable, Initializable, Contextualizable, Disposable {
   
    private static final String XCONF_URL = "resource://org/apache/cocoon/treeprocessor/treeprocessor.xconf";
   
    /** The parent TreeProcessor, if any */
    protected TreeProcessor parent;
   
    /** The context */
    protected Context context;
   
    /** The component manager */
    protected ComponentManager manager;
   
    /** The logkit manager to get Loggers */
    protected LogKitManager logKit;
   
    /** The role manager */
    protected RoleManager roleManager;
   
    /** The language used by this processor */
    protected String language;
   
    /** The configuration for each language */
    protected Map languageConfigs;
   
    /** The root node of the processing tree */
    protected ProcessingNode rootNode;
   
    /** The list of processing nodes that should be disposed when disposing this processor */
    protected List disposableNodes;
   
    /** Last modification time */
    protected long lastModified = 0;
   
    /** The relative file name of the tree definition */
    protected String sourceName;
   
    /** The source of the tree definition */
    protected Source source;
   
    /** Delay for <code>sourceLastModified</code>. */
    protected long lastModifiedDelay;
   
    /** The current language configuration */
    protected Configuration currentLanguage;
   
    protected SourceHandler sourceHandler;
   
    protected Class treeBuilderClass;
   
    /**
     * Create a TreeProcessor.
     */
    public TreeProcessor() {
        // Language can be overriden in the configuration.
        this.language = "sitemap";
    }
       
    /**
     * Create a child processor for a given language
     */
    protected TreeProcessor(TreeProcessor parent, ComponentManager manager, String language) {
        this.parent = parent;
        this.language = (language == null) ? parent.language : language;
       
        // Copy all that can be copied from the parent
        this.context = parent.context;
        this.logKit = parent.logKit;
        this.languageConfigs = parent.languageConfigs;
       
        // We have our own CM
        this.manager = manager;
       
        // Other fields are setup in initialize()
    }
   
    /**
     * Create a new child of this processor (used for mounting submaps).
     *
     * @param manager the component manager to be used by the child processor.
     * @param language the language to be used by the child processor.
     * @return a new child processor.
     */
    public TreeProcessor createChildProcessor(ComponentManager manager, String language) throws Exception {
        TreeProcessor child = new TreeProcessor(this, manager, language);
        child.setLogger(getLogger());
        child.initialize();
        return child;
    }

    public void contextualize(Context context) throws ContextException {
        this.context = context;
    }
   
    public void compose(ComponentManager manager) throws ComponentException {
        this.manager = manager;
    }

    public void setLogKitManager(LogKitManager logKit) {
        this.logKit = logKit;
    }
   
    public void setRoleManager(RoleManager rm) {
        this.roleManager = rm;
    }


/*
  <processor>
    <reload delay="10"/>
    <root-language name="sitemap"/>
    <language>...</language>
  </processor>
*/
    public void configure(Configuration config) throws ConfigurationException {
       
        Configuration rootLangConfig = config.getChild("root-language", false);
        if (rootLangConfig != null) {
            this.language = rootLangConfig.getAttribute("name");
        }
       
        // Reload check delay. Default is 1 second.
        this.lastModifiedDelay = config.getChild("reload").getAttributeAsLong("delay", 1000L);
       
        // Read the builtin languages definition file
        Configuration builtin;
       
        try {
            URLFactory factory = (URLFactory)this.manager.lookup(URLFactory.ROLE);
            URLSource source = new URLSource(factory.getURL(XCONF_URL), this.manager);
            try {
                SAXConfigurationHandler handler = new SAXConfigurationHandler();
                source.toSAX(handler);
                builtin = handler.getConfiguration();
            } finally {
                this.manager.release((Component)factory);
                if (source != null) {
                    source.recycle();
                }
            }
        } catch(Exception e) {
            String msg = "Error while reading treeprocessor.xconf : " + e.getMessage();
            getLogger().error(msg, e);
            throw new ConfigurationException(msg, e);
        }
       
        this.languageConfigs = new HashMap();

        // Add builtin languages
        addLanguages("builtin", builtin.getChildren("language"));
       
        // Add additional languages from the configuration
        addLanguages("additional", config.getChildren("language"));
    }
   
    private void addLanguages(String type, Configuration[] languages)
      throws ConfigurationException {
       
        for (int i = 0; i < languages.length; i++) {
           
            String name = languages[i].getAttribute("name");
           
            if (this.languageConfigs.containsKey(name)) {
                getLogger().info("Redefining language '" + name + "' in " + type + " configuration.");
            } else {
                getLogger().debug("Adding " + type + " language '" + name + "'");
            }

            this.languageConfigs.put(name, languages[i]);
        }
    }

    public void initialize() throws Exception {

        this.currentLanguage = (Configuration)this.languageConfigs.get(this.language);
        if (this.currentLanguage == null) {
            throw new ConfigurationException("No configuration defined for language '" + this.language + "'");
        }
       
        Configuration fileConfig = this.currentLanguage.getChild("file", false);
        if (fileConfig == null) {
            throw new ConfigurationException("Missing 'file' configuration for language '" + this.language + "', at " +
                this.currentLanguage.getLocation());
        }
       
        this.sourceName = fileConfig.getAttribute("name");

        // Get a new Source handler
        this.sourceHandler = (SourceHandler)this.manager.lookup(SourceHandler.ROLE);
       
        // and add the special "cocoon:" source factory
        this.sourceHandler.addFactory("cocoon", new CocoonSourceFactory(this, this.manager));
       
        // Get the TreeBuider class
        String builderClassName =
            this.currentLanguage.getAttribute("class", TreeBuilder.class.getName());

        try {
            this.treeBuilderClass = Thread.currentThread().getContextClassLoader().loadClass(builderClassName);
        } catch(Exception e) {
            String msg = "Cannot create class '" + builderClassName + "' at " +
                this.currentLanguage.getLocation();
            getLogger().error(msg, e);
            throw new ConfigurationException(msg, e);
        }
    }
   
    public boolean process(Environment environment) throws Exception {
        InvokeContext context = new InvokeContext();
        try {
            return process(environment, context);
        } finally {
            context.dispose();
        }
    }

    public boolean process(Environment environment, StreamPipeline pipeline, EventPipeline eventPipeline)
      throws Exception {
        InvokeContext context = new InvokeContext(pipeline, eventPipeline);
        try {
            return process(environment, context);
        } finally {
            context.dispose();
        }
    }

    protected boolean process(Environment environment, InvokeContext context)
      throws Exception {

        SourceHandler oldSourceHandler = environment.getSourceHandler();

        try {
            environment.setSourceHandler(this.sourceHandler);
            if (this.rootNode == null || this.source.getLastModified() > this.lastModified) {
                setupRootNode(environment);
            }
            return this.rootNode.invoke(environment, context);
        } finally {
            environment.setSourceHandler(oldSourceHandler);
        }
    }
   
    protected synchronized void setupRootNode(Environment env) throws Exception {
       
        // Now that we entered the synchronized area, recheck what's already
        // been checked in process().
        if (this.rootNode != null && source.getLastModified() <= this.lastModified) {
            // Nothing changed
            return;
        }
       
        long startTime = System.currentTimeMillis();
       
        if (this.rootNode == null) {
            // First call : create source
            // FIXME : make the delay configurable
            this.source = new DelayedRefreshSourceWrapper(env.resolve(this.sourceName), 1000L);
           
        } else {
            // Dispose existing tree, we will build a new one.
            disposeTree();
        }
       
        // Read the tree definition file as a Configuration
        getLogger().debug("Building " + this.language + " from " + source.getSystemId());
       
        // Build a namespace-aware configuration object
        SAXConfigurationHandler handler = new NamespacedSAXConfigurationHandler();
        source.toSAX(handler);
        Configuration treeConfig = handler.getConfiguration();
       
        TreeBuilder treeBuilder = (TreeBuilder)this.treeBuilderClass.newInstance();
        LifecycleHelper.setupComponent(treeBuilder,
            getLogger(),
            this.context,
            this.manager,
            this.roleManager,
            this.logKit,
            this.currentLanguage);

        treeBuilder.setProcessor(this);
       
        // Build the tree
        ProcessingNode root;
        try {
            root = treeBuilder.build(treeConfig);
        } catch(Exception e) {
            getLogger().debug("Failed to build processing tree from " + source.getSystemId(), e);
            throw e;
        }
       
        LifecycleHelper.decommission(treeBuilder);
           
        this.lastModified = System.currentTimeMillis();
       
        if (getLogger().isDebugEnabled()) {
            double time = (this.lastModified - startTime) / 1000.0;
            getLogger().debug("TreeProcessor built in " + time + " secs from " + source.getSystemId());
            //System.out.println("TreeProcessor built in " + time + " secs from " + source.getSystemId());
        }
       
        // Finished
        this.rootNode = root;
    }

    public void dispose() {
        disposeTree();       
        this.manager.release(this.sourceHandler);
    }
   
    /**
     * Dispose all nodes in the tree that are disposable
     */
    protected void disposeTree() {
        if (this.disposableNodes != null) {
            Iterator iter = this.disposableNodes.iterator();
            while (iter.hasNext()) {
                ((Disposable)iter.next()).dispose();
            }
        }
    }
}
TOP

Related Classes of org.apache.cocoon.treeprocessor.TreeProcessor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.