You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@cocoon.apache.org by cz...@apache.org on 2006/02/17 18:20:05 UTC

svn commit: r378575 - in /cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon: ./ core/ core/container/spring/

Author: cziegeler
Date: Fri Feb 17 09:20:03 2006
New Revision: 378575

URL: http://svn.apache.org/viewcvs?rev=378575&view=rev
Log:
Spring based container works now for core (apart from tree processor)

Added:
    cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/SpringCoreUtil.java   (with props)
Modified:
    cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/SpringCocoon.java
    cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/CoreUtil.java
    cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/ApplicationContextFactory.java
    cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/CocoonXmlWebApplicationContext.java
    cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/XmlConfigCreator.java

Modified: cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/SpringCocoon.java
URL: http://svn.apache.org/viewcvs/cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/SpringCocoon.java?rev=378575&r1=378574&r2=378575&view=diff
==============================================================================
--- cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/SpringCocoon.java (original)
+++ cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/SpringCocoon.java Fri Feb 17 09:20:03 2006
@@ -33,6 +33,9 @@
 import org.apache.cocoon.environment.Session;
 import org.apache.cocoon.environment.internal.EnvironmentHelper;
 import org.apache.commons.lang.SystemUtils;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.beans.factory.BeanFactoryAware;
 
 /**
  * The Cocoon Object is the main Kernel for the entire Cocoon system.
@@ -40,7 +43,7 @@
  * @version $Id$
  */
 public class SpringCocoon
-       implements Processor {
+       implements Processor, BeanFactoryAware {
 
     /** Active request count. */
     private volatile int activeRequestCount;
@@ -51,11 +54,8 @@
     /** The environment helper. */
     protected final EnvironmentHelper environmentHelper;
 
-    /** An optional component that is called before and after processing all requests. */
-    protected RequestListener requestListener;
-
     /** Processor attributes. */
-    protected Map processorAttributes = new HashMap();
+    protected final Map processorAttributes = new HashMap();
 
     /** The service manager. */
     protected final ServiceManager serviceManager;
@@ -63,6 +63,9 @@
     /** The logger. */
     protected final Logger logger;
 
+    /** An optional component that is called before and after processing all requests. */
+    protected RequestListener requestListener;
+
     /**
      * Creates a new <code>Cocoon</code> instance.
      */
@@ -81,10 +84,13 @@
     }
 
     /**
-     * Set the (optional) request listener.
+     * @see org.springframework.beans.factory.BeanFactoryAware#setBeanFactory(org.springframework.beans.factory.BeanFactory)
      */
-    public void setRequestListener(RequestListener listener) {
-        this.requestListener = listener;
+    public void setBeanFactory(BeanFactory factory) throws BeansException {
+        // get the optional request listener
+        if ( factory.containsBean(RequestListener.ROLE) ) {
+            this.requestListener = (RequestListener)factory.getBean(RequestListener.ROLE);
+        }
     }
 
     /**
@@ -191,8 +197,7 @@
     throws Exception {
         environment.startingProcessing();
         final int environmentDepth = EnvironmentHelper.markEnvironment();
-        // FIXME
-        //EnvironmentHelper.enterProcessor(this, this.serviceManager, environment);
+        EnvironmentHelper.enterProcessor(this, this.serviceManager, environment);
         try {
             boolean result;
             if (this.logger.isDebugEnabled()) {

Modified: cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/CoreUtil.java
URL: http://svn.apache.org/viewcvs/cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/CoreUtil.java?rev=378575&r1=378574&r2=378575&view=diff
==============================================================================
--- cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/CoreUtil.java (original)
+++ cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/CoreUtil.java Fri Feb 17 09:20:03 2006
@@ -31,8 +31,6 @@
 import java.util.Map;
 import java.util.Properties;
 
-import javax.servlet.ServletConfig;
-
 import org.apache.avalon.excalibur.logger.Log4JConfLoggerManager;
 import org.apache.avalon.excalibur.logger.LoggerManageable;
 import org.apache.avalon.excalibur.logger.LoggerManager;
@@ -54,17 +52,12 @@
 import org.apache.cocoon.components.container.ComponentContext;
 import org.apache.cocoon.configuration.ConfigurationBuilder;
 import org.apache.cocoon.core.container.SingleComponentServiceManager;
-import org.apache.cocoon.core.container.spring.ApplicationContextFactory;
-import org.apache.cocoon.core.container.spring.AvalonEnvironment;
-import org.apache.cocoon.core.container.spring.ConfigReader;
-import org.apache.cocoon.core.container.spring.ConfigurationInfo;
 import org.apache.cocoon.core.logging.CocoonLogKitLoggerManager;
 import org.apache.cocoon.core.logging.PerRequestLoggerManager;
 import org.apache.cocoon.core.logging.SettingsContext;
 import org.apache.cocoon.core.source.SimpleSourceResolver;
 import org.apache.cocoon.environment.Environment;
 import org.apache.cocoon.matching.helpers.WildcardHelper;
-import org.apache.cocoon.servlet.CocoonServlet;
 import org.apache.cocoon.util.ClassUtils;
 import org.apache.cocoon.util.StringUtils;
 import org.apache.cocoon.util.location.Location;
@@ -73,7 +66,6 @@
 import org.apache.excalibur.source.Source;
 import org.apache.excalibur.source.SourceResolver;
 import org.apache.excalibur.source.TraversableSource;
-import org.springframework.context.ApplicationContext;
 
 /**
  * This is an utility class to create a new Cocoon instance.
@@ -335,9 +327,6 @@
         // The Cocoon container fetches the Core object using the context.
         // FIXME - We shouldn't need this - check where it is used
         this.appContext.put(Core.ROLE, core);
-
-        // test the setup of the spring based container
-        this.testSpringContainer();
     }
 
     /**
@@ -920,20 +909,6 @@
             return this.loggerManager.getLoggerForCategory(rootlogger);
         }
         return this.log;
-    }
-
-    protected void testSpringContainer() throws Exception {
-        System.out.println("Setting up test Spring container...");
-        AvalonEnvironment env = new AvalonEnvironment();
-        env.context = this.appContext;
-        env.core = this.core;
-        env.logger = this.log;
-        env.servletContext = ((ServletConfig)this.appContext.get(CocoonServlet.CONTEXT_SERVLET_CONFIG)).getServletContext();
-        env.settings = this.core.getSettings();
-        ApplicationContext rootContext = ApplicationContextFactory.createRootApplicationContext(env);
-        ConfigurationInfo result = ConfigReader.readConfiguration(settings.getConfiguration(), env);
-        ApplicationContext mainContext = ApplicationContextFactory.createApplicationContext(env, result, rootContext);
-        System.out.println("Getting core cocoon processor context: " + mainContext.getBean(Core.ROLE));
     }
 
     /**

Added: cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/SpringCoreUtil.java
URL: http://svn.apache.org/viewcvs/cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/SpringCoreUtil.java?rev=378575&view=auto
==============================================================================
--- cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/SpringCoreUtil.java (added)
+++ cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/SpringCoreUtil.java Fri Feb 17 09:20:03 2006
@@ -0,0 +1,909 @@
+/*
+ * Copyright 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.core;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+
+import org.apache.avalon.framework.configuration.Configuration;
+import org.apache.avalon.framework.configuration.ConfigurationException;
+import org.apache.avalon.framework.configuration.DefaultConfigurationBuilder;
+import org.apache.avalon.framework.context.ContextException;
+import org.apache.avalon.framework.context.DefaultContext;
+import org.apache.avalon.framework.logger.Logger;
+import org.apache.cocoon.Cocoon;
+import org.apache.cocoon.Constants;
+import org.apache.cocoon.Modifiable;
+import org.apache.cocoon.Processor;
+import org.apache.cocoon.components.ContextHelper;
+import org.apache.cocoon.components.container.ComponentContext;
+import org.apache.cocoon.core.container.spring.ApplicationContextFactory;
+import org.apache.cocoon.core.container.spring.AvalonEnvironment;
+import org.apache.cocoon.core.container.spring.ConfigReader;
+import org.apache.cocoon.core.container.spring.ConfigurationInfo;
+import org.apache.cocoon.core.source.SimpleSourceResolver;
+import org.apache.cocoon.servlet.CocoonServlet;
+import org.apache.cocoon.util.ClassUtils;
+import org.apache.cocoon.util.StringUtils;
+import org.apache.cocoon.util.location.Location;
+import org.apache.cocoon.util.location.LocationImpl;
+import org.apache.cocoon.util.location.LocationUtils;
+import org.apache.excalibur.source.Source;
+import org.apache.excalibur.source.SourceResolver;
+import org.apache.excalibur.source.TraversableSource;
+import org.springframework.context.ApplicationContext;
+
+/**
+ * This is an utility class to create a new Cocoon instance.
+ * 
+ * @version $Id$
+ * @since 2.2
+ */
+public class SpringCoreUtil {
+
+    /** Parameter map for the context protocol */
+    protected static final Map CONTEXT_PARAMETERS = Collections.singletonMap("force-traversable", Boolean.TRUE);
+
+    /** The callback to the real environment. */
+    protected final BootstrapEnvironment env;
+
+    /** "legacy" support: create an avalon context. */
+    protected final DefaultContext appContext = new ComponentContext();
+
+    /** The settings. */
+    protected MutableSettings settings;
+
+    /** The root logger. */
+    protected Logger log;
+
+    /** The Root processor instance */
+    protected Processor processor;
+
+    protected ClassLoader classloader;
+
+    /** The core object. */
+    protected Core core;
+
+    /** The servlet context. */
+    protected final ServletContext servletContext;
+
+    /** The container. */
+    protected ApplicationContext container;
+
+    // Register the location finder for Avalon configuration objects and exceptions
+    // and keep a strong reference to it.
+    private static final LocationUtils.LocationFinder confLocFinder = new LocationUtils.LocationFinder() {
+        public Location getLocation(Object obj, String description) {
+            if (obj instanceof Configuration) {
+                Configuration config = (Configuration)obj;
+                String locString = config.getLocation();
+                Location result = LocationUtils.parse(locString);
+                if (LocationUtils.isKnown(result)) {
+                    // Add description
+                    StringBuffer desc = new StringBuffer().append('<');
+                    // Unfortunately Configuration.getPrefix() is not public
+                    try {
+                        if (config.getNamespace().startsWith("http://apache.org/cocoon/sitemap/")) {
+                            desc.append("map:");
+                        }
+                    } catch (ConfigurationException e) {
+                        // no namespace: ignore
+                    }
+                    desc.append(config.getName()).append('>');
+                    return new LocationImpl(desc.toString(), result);
+                } else {
+                    return result;
+                }
+            }
+            
+            if (obj instanceof Exception) {
+                // Many exceptions in Cocoon have a message like "blah blah at file://foo/bar.xml:12:1"
+                String msg = ((Exception)obj).getMessage();
+                if (msg == null) return null;
+                
+                int pos = msg.lastIndexOf(" at ");
+                if (pos != -1) {
+                    return LocationUtils.parse(msg.substring(pos + 4));
+                } else {
+                    // Will try other finders
+                    return null;
+                }
+            }
+            
+            // Try next finders.
+            return null;
+        }
+    };
+    
+    static {
+        LocationUtils.addFinder(confLocFinder);
+    }
+    
+    /**
+     * Setup a new instance.
+     * @param environment The hook back to the environment.
+     * @throws Exception
+     */
+    public SpringCoreUtil(BootstrapEnvironment environment,
+                          ServletContext context)
+    throws Exception {
+        this.servletContext = context;
+        this.env = environment;
+        this.init();
+        this.createClassloader();        
+    }
+
+    protected void init()
+    throws Exception {
+        // first let's set up the appContext with some values to make
+        // the simple source resolver work
+
+        // add root url
+        try {
+            appContext.put(ContextHelper.CONTEXT_ROOT_URL,
+                           new URL(this.env.getContextURL()));
+        } catch (MalformedURLException ignore) {
+            // we simply ignore this
+        }
+
+        // add environment context
+        this.appContext.put(Constants.CONTEXT_ENVIRONMENT_CONTEXT,
+                            this.env.getEnvironmentContext());
+
+        // now add environment specific information
+        this.env.configure(appContext);
+
+        // create settings
+        this.settings = this.createSettings();
+
+        // first init the work-directory for the logger.
+        // this is required if we are running inside a war file!
+        final String workDirParam = this.settings.getWorkDirectory();
+        File workDir;
+        if (workDirParam != null) {
+            if (this.env.getContextForWriting() == null) {
+                // No context path : consider work-directory as absolute
+                workDir = new File(workDirParam);
+            } else {
+                // Context path exists : is work-directory absolute ?
+                File workDirParamFile = new File(workDirParam);
+                if (workDirParamFile.isAbsolute()) {
+                    // Yes : keep it as is
+                    workDir = workDirParamFile;
+                } else {
+                    // No : consider it relative to context path
+                    workDir = new File(this.env.getContextForWriting(), workDirParam);
+                }
+            }
+        } else {
+            workDir = new File("cocoon-files");
+        }
+        workDir.mkdirs();
+        this.appContext.put(Constants.CONTEXT_WORK_DIR, workDir);
+        this.settings.setWorkDirectory(workDir.getAbsolutePath());
+
+        // Init logger
+        this.log = ApplicationContextFactory.createRootLogger(servletContext, this.settings.getCocoonLogger());
+        this.env.setLogger(this.log);
+
+        // Output some debug info
+        if (this.log.isDebugEnabled()) {
+            this.log.debug("Context URL: " + this.env.getContextURL());
+            this.log.debug("Writeable Context: " + this.env.getContextForWriting());
+            if (workDirParam != null) {
+                this.log.debug("Using work-directory " + workDir);
+            } else {
+                this.log.debug("Using default work-directory " + workDir);
+            }
+        }
+
+        final String uploadDirParam = this.settings.getUploadDirectory();
+        File uploadDir;
+        if (uploadDirParam != null) {
+            if (this.env.getContextForWriting() == null) {
+                uploadDir = new File(uploadDirParam);
+            } else {
+                // Context path exists : is upload-directory absolute ?
+                File uploadDirParamFile = new File(uploadDirParam);
+                if (uploadDirParamFile.isAbsolute()) {
+                    // Yes : keep it as is
+                    uploadDir = uploadDirParamFile;
+                } else {
+                    // No : consider it relative to context path
+                    uploadDir = new File(this.env.getContextForWriting(), uploadDirParam);
+                }
+            }
+            if (this.log.isDebugEnabled()) {
+                this.log.debug("Using upload-directory " + uploadDir);
+            }
+        } else {
+            uploadDir = new File(workDir, "upload-dir" + File.separator);
+            if (this.log.isDebugEnabled()) {
+                this.log.debug("Using default upload-directory " + uploadDir);
+            }
+        }
+        uploadDir.mkdirs();
+        appContext.put(Constants.CONTEXT_UPLOAD_DIR, uploadDir);
+        this.settings.setUploadDirectory(uploadDir.getAbsolutePath());
+
+        String cacheDirParam = this.settings.getCacheDirectory();
+        File cacheDir;
+        if (cacheDirParam != null) {
+            if (this.env.getContextForWriting() == null) {
+                cacheDir = new File(cacheDirParam);
+            } else {
+                // Context path exists : is cache-directory absolute ?
+                File cacheDirParamFile = new File(cacheDirParam);
+                if (cacheDirParamFile.isAbsolute()) {
+                    // Yes : keep it as is
+                    cacheDir = cacheDirParamFile;
+                } else {
+                    // No : consider it relative to context path
+                    cacheDir = new File(this.env.getContextForWriting(), cacheDirParam);
+                }
+            }
+            if (this.log.isDebugEnabled()) {
+                this.log.debug("Using cache-directory " + cacheDir);
+            }
+        } else {
+            cacheDir = new File(workDir, "cache-dir" + File.separator);
+            File parent = cacheDir.getParentFile();
+            if (parent != null) {
+                parent.mkdirs();
+            }
+            if (this.log.isDebugEnabled()) {
+                this.log.debug("cache-directory was not set - defaulting to " + cacheDir);
+            }
+        }
+        cacheDir.mkdirs();
+        appContext.put(Constants.CONTEXT_CACHE_DIR, cacheDir);
+        this.settings.setCacheDirectory(cacheDir.getAbsolutePath());
+
+        // update configuration
+        final URL u = this.env.getConfigFile(this.settings.getConfiguration());
+        this.settings.setConfiguration(u.toExternalForm());
+        this.appContext.put(Constants.CONTEXT_CONFIG_URL, u);
+
+        // set encoding
+        this.appContext.put(Constants.CONTEXT_DEFAULT_ENCODING, settings.getFormEncoding());
+
+        // set class loader
+        this.appContext.put(Constants.CONTEXT_CLASS_LOADER, this.classloader);
+
+        // Set the system properties needed by Xalan2.
+        // FIXME Do we still need this?
+        this.setSystemProperties();
+
+        // dump system properties
+        this.dumpSystemProperties();
+
+        // create the Core object
+        this.core = this.createCore();
+
+        // settings can't be changed anymore
+        settings.makeReadOnly();
+
+        // put the core into the context - this is for internal use only
+        // The Cocoon container fetches the Core object using the context.
+        // FIXME - We shouldn't need this - check where it is used
+        this.appContext.put(Core.ROLE, core);
+
+        // test the setup of the spring based container
+        this.container = this.setupSpringContainer();
+    }
+
+    /**
+     * Return the core object.
+     */
+    public Core getCore() {
+        return this.core;
+    }
+
+    /**
+     * Create a new core instance.
+     * This method can be overwritten in sub classes.
+     * @return A new core object.
+     */
+    protected Core createCore() {
+        final Core c = new Core(this.settings, this.appContext);
+        return c;
+    }
+
+    /**
+     * Return the settings object.
+     */
+    public Settings getSettings() {
+        return this.settings;
+    }
+
+    /**
+     * Get the settings for Cocoon.
+     * This method reads several property files and merges the result. If there
+     * is more than one definition for a property, the last one wins.
+     * The property files are read in the following order:
+     * 1) context://WEB-INF/properties/*.properties
+     *    Default values for the core and each block - the order in which the files are read is not guaranteed.
+     * 2) context://WEB-INF/properties/[RUNNING_MODE]/*.properties
+     *    Default values for the running mode - the order in which the files are read is not guaranteed.
+     * 3) Property providers (ToBeDocumented)
+     * 4) The environment (CLI, Servlet etc.) adds own properties (e.g. from web.xml)
+     * 5) Additional property file specified by the "org.apache.cocoon.settings" system property or
+     *    if the property is not found, the file ".cocoon/settings.properties" is tried to be read from
+     *    the user directory.
+     * 6) System properties
+     *
+     * @return A new Settings object
+     */
+    protected MutableSettings createSettings() {
+        // get the running mode
+        final String mode = System.getProperty(Settings.PROPERTY_RUNNING_MODE, Settings.DEFAULT_RUNNING_MODE);
+        this.env.log("Running in mode: " + mode);
+
+        // create an empty settings objects
+        final MutableSettings s = new MutableSettings();
+
+        // we need our own resolver
+        final SourceResolver resolver = this.createSourceResolver(new LoggerWrapper(this.env));
+
+        // now read all properties from the properties directory
+        this.readProperties("context://WEB-INF/properties", s, resolver);
+        // read all properties from the mode dependent directory
+        this.readProperties("context://WEB-INF/properties/" + mode, s, resolver);
+
+        // Next look for custom property providers
+        Iterator i = s.getPropertyProviders().iterator();
+        while ( i.hasNext() ) {
+            final String className = (String)i.next();
+            try {
+                PropertyProvider provider = (PropertyProvider)ClassUtils.newInstance(className);
+                s.fill(provider.getProperties());
+            } catch (Exception ignore) {
+                env.log("Unable to get property provider for class " + className, ignore);
+                env.log("Continuing initialization.");            
+            }
+        }
+        // fill from the environment configuration, like web.xml etc.
+        env.configure(s);
+
+        // read additional properties file
+        String additionalPropertyFile = s.getProperty(Settings.PROPERTY_USER_SETTINGS, 
+                                                      System.getProperty(Settings.PROPERTY_USER_SETTINGS));
+        // if there is no property defining the addition file, we try it in the home directory
+        if ( additionalPropertyFile == null ) {
+            additionalPropertyFile = System.getProperty("user.home") + File.separator + ".cocoon/settings.properties";
+            final File testFile = new File(additionalPropertyFile);
+            if ( !testFile.exists() ) {
+                additionalPropertyFile = null;
+            }
+        }
+        if ( additionalPropertyFile != null ) {
+            env.log("Reading user settings from '" + additionalPropertyFile + "'");
+            final Properties p = new Properties();
+            try {
+                FileInputStream fis = new FileInputStream(additionalPropertyFile);
+                p.load(fis);
+                fis.close();
+            } catch (IOException ignore) {
+                env.log("Unable to read '" + additionalPropertyFile + "'.", ignore);
+                env.log("Continuing initialization.");
+            }
+        }
+        // now overwrite with system properties
+        s.fill(System.getProperties());
+
+        return s;
+    }
+
+    /**
+     * Dump System Properties.
+     */
+    protected void dumpSystemProperties() {
+        if (this.log.isDebugEnabled()) {
+            try {
+                Enumeration e = System.getProperties().propertyNames();
+                this.log.debug("===== System Properties Start =====");
+                for (; e.hasMoreElements();) {
+                    String key = (String) e.nextElement();
+                    this.log.debug(key + "=" + System.getProperty(key));
+                }
+                this.log.debug("===== System Properties End =====");
+            } catch (SecurityException se) {
+                // Ignore Exceptions.
+            }
+        }
+    }
+
+    /**
+     * Sets required system properties.
+     */
+    protected void setSystemProperties() {
+        try {
+            // FIXME We shouldn't have to specify the SAXParser...
+            // This is needed by Xalan2, it is used by org.xml.sax.helpers.XMLReaderFactory
+            // to locate the SAX2 driver.
+            if (getSystemProperty("org.xml.sax.driver", null) == null) {
+                System.setProperty("org.xml.sax.driver", "org.apache.xerces.parsers.SAXParser");
+            }
+        } catch (SecurityException e) {
+            // Ignore security exceptions
+            System.out.println("Caught a SecurityException writing the system property: " + e);
+        }
+
+        try {
+            // FIXME We shouldn't have to specify these. Needed to override jaxp implementation of weblogic.
+            if (getSystemProperty("javax.xml.parsers.DocumentBuilderFactory", "").startsWith("weblogic")) {
+                System.setProperty("javax.xml.parsers.DocumentBuilderFactory", "org.apache.xerces.jaxp.DocumentBuilderFactoryImpl");
+                System.setProperty("javax.xml.parsers.SAXParserFactory","org.apache.xerces.jaxp.SAXParserFactoryImpl");
+            }
+        } catch (SecurityException e) {
+            // Ignore security exceptions
+            System.out.println("Caught a SecurityException writing the system property: " + e);
+        }
+    }
+
+    /**
+     * Helper method to retrieve system property.
+     * Returns default value if SecurityException is caught.
+     */
+    protected String getSystemProperty(String property, String value) {
+        try {
+            return System.getProperty(property, value);
+        } catch (SecurityException e) {
+            System.err.println("Caught a SecurityException reading the system property '" + property + "';" +
+                               " Cocoon will default to '" + value + "' value.");
+            return value;
+        }
+    }
+
+    /**
+     * Read all property files from the given directory and apply them to the settings.
+     */
+    protected void readProperties(String directoryName,
+                                  MutableSettings s,
+                                  SourceResolver resolver) {
+        Source directory = null;
+        try {
+            directory = resolver.resolveURI(directoryName, null, CONTEXT_PARAMETERS);
+            if (directory.exists() && directory instanceof TraversableSource) {
+                final Iterator c = ((TraversableSource) directory).getChildren().iterator();
+                while (c.hasNext()) {
+                    final Source src = (Source) c.next();
+                    if ( src.getURI().endsWith(".properties") ) {
+                        final InputStream propsIS = src.getInputStream();
+                        env.log("Reading settings from '" + src.getURI() + "'.");
+                        final Properties p = new Properties();
+                        p.load(propsIS);
+                        propsIS.close();
+                        s.fill(p);
+                    }
+                }
+            }
+        } catch (IOException ignore) {
+            env.log("Unable to read from directory 'WEB-INF/properties'.", ignore);
+            env.log("Continuing initialization.");            
+        } finally {
+            resolver.release(directory);
+        }
+    }
+
+    /**
+     * Create a simple source resolver.
+     */
+    protected SourceResolver createSourceResolver(Logger logger) {
+        // Create our own resolver
+        final SimpleSourceResolver resolver = new SimpleSourceResolver();
+        resolver.enableLogging(logger);
+        try {
+            resolver.contextualize(this.appContext);
+        } catch (ContextException ce) {
+            throw new CoreInitializationException(
+                    "Cannot setup source resolver.", ce);
+        }
+        return resolver;        
+    }
+
+    /**
+     * Create the classloader that inlcudes all the [block]/BLOCK-INF/classes directories. 
+     * @throws Exception
+     */
+    protected void createClassloader() throws Exception {
+        // get the wiring
+        final SourceResolver resolver = this.createSourceResolver(this.log);    
+        Source wiringSource = null;
+        final Configuration wiring;
+        try {
+            wiringSource = resolver.resolveURI(Constants.WIRING);
+            DefaultConfigurationBuilder builder = new DefaultConfigurationBuilder();
+            wiring = builder.build( wiringSource.getInputStream() );            
+        } catch(org.apache.excalibur.source.SourceNotFoundException snfe) {
+            throw new WiringNotFoundException("wiring.xml not found in the root directory of your Cocoon application.");
+        } finally {
+            resolver.release(wiringSource);
+        }
+        
+        // get all wired blocks and add their classed directory to the classloader
+        List urlList = new ArrayList();        
+        Configuration[] blocks = wiring.getChildren("block");
+        for(int i = 0; i < blocks.length; i++) {
+            String location = blocks[i].getAttribute("location");
+            if(this.log.isDebugEnabled()) {
+                this.log.debug("Found block " + blocks[i].getAttribute("id") + " at " + location);
+            }
+            Source classesDir = null;
+            try {
+               classesDir = resolver.resolveURI(location + "/" + Constants.BLOCK_META_DIR + "/classes");
+               if(classesDir.exists()) {
+                   String classesDirURI = classesDir.getURI();
+                   urlList.add(new URL(classesDirURI));
+                   if(this.log.isDebugEnabled()) {
+                       this.log.debug("added " + classesDir.getURI());
+                   }
+               }               
+            } finally {
+                resolver.release(classesDir);
+            }
+        }
+    
+        // setup the classloader using the current classloader as parent
+        ClassLoader parentClassloader = Thread.currentThread().getContextClassLoader();
+        URL[] urls = (URL[]) urlList.toArray(new URL[urlList.size()]);        
+        URLClassLoader classloader = new URLClassLoader(urls, parentClassloader);
+        Thread.currentThread().setContextClassLoader(classloader);
+        this.classloader = Thread.currentThread().getContextClassLoader();
+    }
+
+    /**
+     * Creates the Cocoon object and handles exception handling.
+     */
+    public synchronized Cocoon createCocoon()
+    throws Exception {        
+        this.createProcessor();
+        return (Cocoon)this.processor;
+    }
+
+    /**
+     * Gets the current cocoon object.
+     * Reload cocoon if configuration changed or we are reloading.
+     * Ensure that the correct classloader is set.
+     */
+    public Cocoon getCocoon(final String pathInfo, final String reloadParam)
+    throws Exception {
+        this.getProcessor(pathInfo, reloadParam);
+        return (Cocoon)this.processor;
+    }
+
+    /**
+     * Creates the root processor object and handles exception handling.
+     */
+    public synchronized Processor createProcessor()
+    throws Exception {
+
+        this.updateEnvironment();
+        this.forceLoad();
+        this.forceProperty();
+
+        try {
+            if (this.log.isInfoEnabled()) {
+                this.log.info("Reloading from: " + this.settings.getConfiguration());
+            }
+            Processor p = (Processor)this.container.getBean("org.apache.cocoon.Cocoon");
+
+            this.settings.setCreationTime(System.currentTimeMillis());
+            this.processor = p;
+        } catch (Exception e) {
+            this.log.error("Exception reloading root processor.", e);
+            throw e;
+        }
+        return this.processor;
+    }
+
+    /**
+     * Gets the current root processor object.
+     * Reload the root processor if configuration changed or we are reloading.
+     * Ensure that the correct classloader is set.
+     */
+    public Processor getProcessor(final String pathInfo, final String reloadParam)
+    throws Exception {
+        // set the blocks classloader for this thread
+        Thread.currentThread().setContextClassLoader(this.classloader);        
+        
+        if (this.settings.isReloadingEnabled("config")) {
+            boolean reload = false;
+
+            if (this.processor != null) {
+                if (this.processor instanceof Modifiable && ((Modifiable)this.processor).modifiedSince(this.settings.getCreationTime())) {
+                    if (this.log.isInfoEnabled()) {
+                        this.log.info("Configuration changed reload attempt");
+                    }
+                    reload = true;
+                } else if (pathInfo == null && reloadParam != null) {
+                    if (this.log.isInfoEnabled()) {
+                        this.log.info("Forced reload attempt");
+                    }
+                    reload = true;
+                }
+            } else if (pathInfo == null && reloadParam != null) {
+                if (this.log.isInfoEnabled()) {
+                    this.log.info("Invalid configurations reload");
+                }
+                reload = true;
+            }
+
+            if (reload) {
+                if (this.container != null) {
+                    this.container = null;
+                }
+                this.init();
+                this.createProcessor();
+            }
+        }
+        return this.processor;
+    }
+
+    protected ApplicationContext setupSpringContainer() throws Exception {
+        System.out.println("Setting up test Spring container...");
+        AvalonEnvironment env = new AvalonEnvironment();
+        env.context = this.appContext;
+        env.core = this.core;
+        env.logger = this.log;
+        env.servletContext = ((ServletConfig)this.appContext.get(CocoonServlet.CONTEXT_SERVLET_CONFIG)).getServletContext();
+        env.settings = this.core.getSettings();
+        ApplicationContext rootContext = ApplicationContextFactory.createRootApplicationContext(env);
+        ConfigurationInfo result = ConfigReader.readConfiguration(settings.getConfiguration(), env);
+        ApplicationContext mainContext = ApplicationContextFactory.createApplicationContext(env, result, rootContext, true);
+        System.out.println("Getting core cocoon processor context: " + mainContext.getBean(Core.ROLE));
+        return mainContext;
+    }
+
+    /**
+     * Handle the <code>load-class</code> parameter. This overcomes
+     * limits in many classpath issues. One of the more notorious
+     * ones is a bug in WebSphere that does not load the URL handler
+     * for the <code>classloader://</code> protocol. In order to
+     * overcome that bug, set <code>load-class</code> parameter to
+     * the <code>com.ibm.servlet.classloader.Handler</code> value.
+     *
+     * <p>If you need to load more than one class, then separate each
+     * entry with whitespace, a comma, or a semi-colon. Cocoon will
+     * strip any whitespace from the entry.</p>
+     */
+    protected void forceLoad() {
+        final Iterator i = this.settings.getLoadClasses().iterator();
+        while (i.hasNext()) {
+            final String fqcn = (String)i.next();
+            try {
+                if (this.log.isDebugEnabled()) {
+                    this.log.debug("Loading: " + fqcn);
+                }
+                ClassUtils.loadClass(fqcn).newInstance();
+            } catch (Exception e) {
+                if (this.log.isWarnEnabled()) {
+                    this.log.warn("Could not load class: " + fqcn, e);
+                }
+                // Do not throw an exception, because it is not a fatal error.
+            }
+        }
+    }
+
+    /**
+     * Handle the "force-property" parameter.
+     *
+     * If you need to force more than one property to load, then
+     * separate each entry with whitespace, a comma, or a semi-colon.
+     * Cocoon will strip any whitespace from the entry.
+     */
+    protected void forceProperty() {
+        if (this.settings.getForceProperties().size() > 0) {
+            final Iterator i = this.settings.getForceProperties().entrySet().iterator();
+            while (i.hasNext()) {
+                final Map.Entry current = (Map.Entry)i.next();
+                try {
+                    if (this.log.isDebugEnabled()) {
+                        this.log.debug("Setting: " + current.getKey() + "=" + current.getValue());
+                    }
+                    System.setProperty(current.getKey().toString(), current.getValue().toString());
+                } catch (Exception e) {
+                    if (this.log.isWarnEnabled()) {
+                        this.log.warn("Could not set property: " + current.getKey(), e);
+                    }
+                    // Do not throw an exception, because it is not a fatal error.
+                }
+            }
+        }
+    }
+
+    /**
+     * Method to update the environment before Cocoon instances are created.
+     *
+     * This is also useful if you wish to customize any of the 'protected'
+     * variables from this class before a Cocoon instance is built in a derivative
+     * of this class (eg. Cocoon Context).
+     */
+    protected void updateEnvironment() throws Exception {
+//        // concatenate the class path and the extra class path
+//        String classPath = this.env.getClassPath(this.settings);
+//        StringBuffer buffer = new StringBuffer();
+//        if ( classPath != null && classPath.length() > 0 ) {
+//            buffer.append(classPath);
+//        }
+//        classPath = this.getExtraClassPath();
+//        if ( classPath != null && classPath.length() > 0 ) {
+//            if ( buffer.length() > 0 ) {
+//                buffer.append(File.pathSeparatorChar);
+//            }
+//            buffer.append(classPath);
+//        }
+        // FIXME - for now we just set an empty string as this information is looked up
+        //         by other components
+        this.appContext.put(Constants.CONTEXT_CLASSPATH, "");
+    }
+
+    /**
+     * Dispose the root processor when environment is destroyed
+     */
+    public void destroy() {
+        // FIXME - we have to clean up here!
+        if ( this.container != null ) {
+            this.container = null;
+        }
+    }
+
+    /**
+     * Retreives the "extra-classpath" attribute, that needs to be
+     * added to the class path.
+     */
+    protected String getExtraClassPath() {
+        if (this.settings.getExtraClasspaths().size() > 0) {
+            StringBuffer sb = new StringBuffer();
+            final Iterator iter = this.settings.getExtraClasspaths().iterator();
+            int i = 0;
+            while (iter.hasNext()) {
+                String s = (String)iter.next();
+                if (i++ > 0) {
+                    sb.append(File.pathSeparatorChar);
+                }
+                if ((s.charAt(0) == File.separatorChar) ||
+                        (s.charAt(1) == ':')) {
+                    if (this.log.isDebugEnabled()) {
+                        this.log.debug("extraClassPath is absolute: " + s);
+                    }
+                    sb.append(s);
+
+                } else {
+                    if (s.indexOf("${") != -1) {
+                        String path = StringUtils.replaceToken(s);
+                        sb.append(path);
+                        if (this.log.isDebugEnabled()) {
+                            this.log.debug("extraClassPath is not absolute replacing using token: [" + s + "] : " + path);
+                        }
+                    } else {
+                        String path = null;
+                        if (this.env.getContextForWriting() != null) {
+                            path = this.env.getContextForWriting() + s;
+                            if (this.log.isDebugEnabled()) {
+                                this.log.debug("extraClassPath is not absolute pre-pending context path: " + path);
+                            }
+                        } else {
+                            path = this.settings.getWorkDirectory() + s;
+                            if (this.log.isDebugEnabled()) {
+                                this.log.debug("extraClassPath is not absolute pre-pending work-directory: " + path);
+                            }
+                        }
+                        sb.append(path);
+                    }
+                }
+            }
+            return sb.toString();
+        }
+        return "";
+    }
+
+    protected static final class LoggerWrapper implements Logger {
+        private final BootstrapEnvironment env;
+
+        public LoggerWrapper(BootstrapEnvironment env) {
+            this.env = env;
+        }
+
+        protected void text(String arg0, Throwable arg1) {
+            if ( arg1 != null ) {
+                this.env.log(arg0, arg1);
+            } else {
+                this.env.log(arg0);
+            }
+        }
+
+        public void debug(String arg0, Throwable arg1) {
+            // we ignore debug
+        }
+
+        public void debug(String arg0) {
+            // we ignore debug
+        }
+
+        public void error(String arg0, Throwable arg1) {
+            this.text(arg0, arg1);
+        }
+
+        public void error(String arg0) {
+            this.text(arg0, null);
+        }
+
+        public void fatalError(String arg0, Throwable arg1) {
+            this.text(arg0, arg1);
+        }
+
+        public void fatalError(String arg0) {
+            this.text(arg0, null);
+        }
+
+        public Logger getChildLogger(String arg0) {
+            return this;
+        }
+
+        public void info(String arg0, Throwable arg1) {
+            // we ignore info
+        }
+
+        public void info(String arg0) {
+            // we ignore info
+        }
+
+        public boolean isDebugEnabled() {
+            return false;
+        }
+
+        public boolean isErrorEnabled() {
+            return true;
+        }
+
+        public boolean isFatalErrorEnabled() {
+            return true;
+        }
+
+        public boolean isInfoEnabled() {
+            return false;
+        }
+
+        public boolean isWarnEnabled() {
+            return false;
+        }
+
+        public void warn(String arg0, Throwable arg1) {
+            // we ignore warn
+        }
+
+        public void warn(String arg0) {
+            // we ignore warn
+        }
+    }
+}

Propchange: cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/SpringCoreUtil.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/SpringCoreUtil.java
------------------------------------------------------------------------------
    svn:keywords = Id

Modified: cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/ApplicationContextFactory.java
URL: http://svn.apache.org/viewcvs/cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/ApplicationContextFactory.java?rev=378575&r1=378574&r2=378575&view=diff
==============================================================================
--- cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/ApplicationContextFactory.java (original)
+++ cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/ApplicationContextFactory.java Fri Feb 17 09:20:03 2006
@@ -15,26 +15,14 @@
  */
 package org.apache.cocoon.core.container.spring;
 
-import java.util.Map;
+import javax.servlet.ServletContext;
 
-
-import org.apache.avalon.framework.configuration.Configurable;
-import org.apache.avalon.framework.configuration.Configuration;
-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.logger.Log4JLogger;
 import org.apache.avalon.framework.logger.Logger;
-import org.apache.avalon.framework.parameters.Parameterizable;
-import org.apache.avalon.framework.parameters.Parameters;
-import org.apache.avalon.framework.service.ServiceManager;
 import org.apache.cocoon.core.Core;
 import org.apache.cocoon.core.Settings;
-import org.springframework.beans.BeansException;
-import org.springframework.beans.factory.BeanCreationException;
-import org.springframework.beans.factory.BeanFactory;
-import org.springframework.beans.factory.BeanInitializationException;
 import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
-import org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor;
 import org.springframework.context.ApplicationContext;
 import org.springframework.core.io.ByteArrayResource;
 import org.springframework.core.io.Resource;
@@ -60,29 +48,29 @@
      */
     public static ApplicationContext createApplicationContext(AvalonEnvironment  env,
                                                               ConfigurationInfo  info,
-                                                              ApplicationContext parent)
+                                                              ApplicationContext parent,
+                                                              boolean            addCocoon)
     throws Exception {
-        final String xmlConfig = (new XmlConfigCreator()).createConfig(info.getComponents());
+        final String xmlConfig = (new XmlConfigCreator()).createConfig(info.getComponents(), addCocoon);
         Resource rsc = new ByteArrayResource(xmlConfig.getBytes("utf-8"));
-        CocoonXmlWebApplicationContext context = new CocoonXmlWebApplicationContext(rsc, parent);
+        Logger logger = env.logger;
+        if ( info.rootLogger != null ) {
+            logger = env.logger.getChildLogger(info.rootLogger);
+        }
+        CocoonXmlWebApplicationContext context = new CocoonXmlWebApplicationContext(rsc, 
+                                                                                    parent,
+                                                                                    logger,
+                                                                                    info.getComponents(),
+                                                                                    env.context);
         context.addBeanFactoryPostProcessor(new CocoonSettingsConfigurer(env.settings));
 
         // TODO: Add context specific information
         //context.setSourceResolver(this.resolver);
         //context.setEnvironmentHelper(this.environmentHelper);
         context.setServletContext(env.servletContext);
-        AvalonPostProcessor processor = new AvalonPostProcessor();
-        processor.components = info.getComponents();
-        processor.logger = env.logger;
-        if ( info.rootLogger != null ) {
-            processor.logger = env.logger.getChildLogger(info.rootLogger);
-        }
-        processor.context = env.context;
         context.refresh();
-        processor.beanFactory = context.getBeanFactory();
-        context.getBeanFactory().addBeanPostProcessor(processor);
         if ( info.rootLogger != null ) {
-            context.getBeanFactory().registerSingleton(Logger.class.getName(), processor.logger);
+            context.getBeanFactory().registerSingleton(Logger.class.getName(), logger);
         }
         return context;
     }
@@ -100,7 +88,7 @@
     public static ApplicationContext createRootApplicationContext(AvalonEnvironment  env)
     throws Exception {
         final ApplicationContext parent = (ApplicationContext)env.servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
-        CocoonXmlWebApplicationContext context = new CocoonXmlWebApplicationContext(null, parent);
+        CocoonXmlWebApplicationContext context = new CocoonXmlWebApplicationContext(parent);
         context.refresh();
         final ConfigurableListableBeanFactory factory = context.getBeanFactory();
         factory.registerSingleton(Context.class.getName(), env.context);
@@ -110,83 +98,17 @@
         return context;
     }
 
-    /**
-     * This is a Spring BeanPostProcessor adding support for the Avalon lifecycle interfaces.
-     */
-    protected static final class AvalonPostProcessor implements DestructionAwareBeanPostProcessor {
-
-        protected static final Configuration EMPTY_CONFIG = new DefaultConfiguration("empty");
-
-        protected Logger logger;
-        protected Context context;
-        protected BeanFactory beanFactory;
-        protected Map components;
-
-        /**
-         * @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization(java.lang.Object, java.lang.String)
-         */
-        public Object postProcessAfterInitialization(Object bean, String beanName)
-        throws BeansException {
-            try {
-                ContainerUtil.start(bean);
-            } catch (Exception e) {
-                throw new BeanInitializationException("Unable to start bean " + beanName, e);
-            }
-            return bean;
-        }
-
-        /**
-         * @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessBeforeInitialization(java.lang.Object, java.lang.String)
-         */
-        public Object postProcessBeforeInitialization(Object bean, String beanName)
-        throws BeansException {
-            final ComponentInfo info = (ComponentInfo)this.components.get(beanName);
-            try {
-                if ( info == null ) {
-                    // no info so we just return the bean and don't apply any lifecycle interfaces
-                    return bean;
-                }
-                if ( info.getLoggerCategory() != null ) {
-                    ContainerUtil.enableLogging(bean, this.logger.getChildLogger(info.getLoggerCategory()));
-                } else {
-                    ContainerUtil.enableLogging(bean, this.logger);
-                }
-                ContainerUtil.contextualize(bean, this.context);
-                ContainerUtil.service(bean, (ServiceManager)this.beanFactory.getBean(ServiceManager.class.getName()));
-                if ( info != null ) {
-                    Configuration config = info.getConfiguration();
-                    if ( config == null ) {
-                        config = EMPTY_CONFIG;
-                    }
-                    if ( bean instanceof Configurable ) {
-                        ContainerUtil.configure(bean, config);
-                    } else if ( bean instanceof Parameterizable ) {
-                        Parameters p = info.getParameters();
-                        if ( p == null ) {
-                            p = Parameters.fromConfiguration(config);
-                            info.setParameters(p);
-                        }
-                        ContainerUtil.parameterize(bean, p);
-                    }
-                }
-                ContainerUtil.initialize(bean);
-            } catch (Exception e) {
-                throw new BeanCreationException("Unable to initialize Avalon component with role " + beanName, e);
-            }
-            return bean;
-        }
-
-        /**
-         * @see org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor#postProcessBeforeDestruction(java.lang.Object, java.lang.String)
-         */
-        public void postProcessBeforeDestruction(Object bean, String beanName)
-        throws BeansException {
-            try {
-                ContainerUtil.stop(bean);
-            } catch (Exception e) {
-                throw new BeanInitializationException("Unable to stop bean " + beanName, e);
+    public static Logger createRootLogger(ServletContext context, String category) {
+        final ApplicationContext parent = (ApplicationContext)context.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
+        // test for a logger in the parent context
+        if ( parent != null && parent.containsBean(Logger.class.getName()) ) {
+            if ( category == null || category.length() == 0 ) {
+                return (Logger)parent.getBean(Logger.class.getName());
             }
-            ContainerUtil.dispose(bean);
+            return ((Logger)parent.getBean(Logger.class.getName())).getChildLogger(category);
         }
+        // create a new log4j logger
+        org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger(category);
+        return new Log4JLogger(logger);
     }
 }

Modified: cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/CocoonXmlWebApplicationContext.java
URL: http://svn.apache.org/viewcvs/cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/CocoonXmlWebApplicationContext.java?rev=378575&r1=378574&r2=378575&view=diff
==============================================================================
--- cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/CocoonXmlWebApplicationContext.java (original)
+++ cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/CocoonXmlWebApplicationContext.java Fri Feb 17 09:20:03 2006
@@ -17,12 +17,27 @@
 
 import java.io.IOException;
 import java.net.MalformedURLException;
+import java.util.Map;
 
 import org.apache.avalon.framework.CascadingRuntimeException;
+import org.apache.avalon.framework.configuration.Configurable;
+import org.apache.avalon.framework.configuration.Configuration;
+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.logger.Logger;
+import org.apache.avalon.framework.parameters.Parameterizable;
+import org.apache.avalon.framework.parameters.Parameters;
+import org.apache.avalon.framework.service.ServiceManager;
 import org.apache.cocoon.environment.internal.EnvironmentHelper;
 import org.apache.excalibur.source.Source;
 import org.apache.excalibur.source.SourceResolver;
 import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.BeanCreationException;
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.beans.factory.BeanInitializationException;
+import org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor;
+import org.springframework.beans.factory.support.DefaultListableBeanFactory;
 import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
 import org.springframework.context.ApplicationContext;
 import org.springframework.core.io.Resource;
@@ -43,11 +58,24 @@
     protected SourceResolver resolver;
     protected String baseURL;
 
+    protected final Logger avalonLogger;
+    protected final Context avalonContext;
+    protected final Map avalonComponentDefinitions;
+
+    public CocoonXmlWebApplicationContext(ApplicationContext parent) {
+        this(null, parent, null, null, null);
+    }
 
     public CocoonXmlWebApplicationContext(Resource avalonResource,
-                                          ApplicationContext parent) {
+                                          ApplicationContext parent,
+                                          Logger             avalonLogger,
+                                          Map                avalonComponentDefs,
+                                          Context            avalonContext) {
         this.setParent(parent);
         this.avalonResource = avalonResource;
+        this.avalonLogger = avalonLogger;
+        this.avalonComponentDefinitions = avalonComponentDefs;
+        this.avalonContext = avalonContext;
     }
 
     /**
@@ -61,6 +89,21 @@
         }
     }
 
+    /**
+     * @see org.springframework.context.support.AbstractRefreshableApplicationContext#createBeanFactory()
+     */
+    protected DefaultListableBeanFactory createBeanFactory() {
+        DefaultListableBeanFactory beanFactory = super.createBeanFactory();
+        if ( this.avalonComponentDefinitions != null ) {
+            AvalonPostProcessor processor = new AvalonPostProcessor(this.avalonComponentDefinitions,
+                                                                    this.avalonContext,
+                                                                    this.avalonLogger,
+                                                                    beanFactory);
+            beanFactory.addBeanPostProcessor(processor);
+        }
+        return beanFactory;
+    }
+
     public void setSourceResolver(SourceResolver aResolver) {
         this.resolver = aResolver;
     }
@@ -116,4 +159,93 @@
         return new String[]{};
     }
 
+    /**
+     * This is a Spring BeanPostProcessor adding support for the Avalon lifecycle interfaces.
+     */
+    protected static final class AvalonPostProcessor implements DestructionAwareBeanPostProcessor {
+
+        protected static final Configuration EMPTY_CONFIG = new DefaultConfiguration("empty");
+
+        protected final Logger logger;
+        protected final Context context;
+        protected final BeanFactory beanFactory;
+        protected final Map components;
+
+        public AvalonPostProcessor(Map         components,
+                                   Context     context,
+                                   Logger      logger,
+                                   BeanFactory factory) {
+            this.components = components;
+            this.context = context;
+            this.logger = logger;
+            this.beanFactory = factory;
+        }
+
+        /**
+         * @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization(java.lang.Object, java.lang.String)
+         */
+        public Object postProcessAfterInitialization(Object bean, String beanName)
+        throws BeansException {
+            try {
+                ContainerUtil.start(bean);
+            } catch (Exception e) {
+                throw new BeanInitializationException("Unable to start bean " + beanName, e);
+            }
+            return bean;
+        }
+
+        /**
+         * @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessBeforeInitialization(java.lang.Object, java.lang.String)
+         */
+        public Object postProcessBeforeInitialization(Object bean, String beanName)
+        throws BeansException {
+            final ComponentInfo info = (ComponentInfo)this.components.get(beanName);
+            try {
+                if ( info == null ) {
+                    // no info so we just return the bean and don't apply any lifecycle interfaces
+                    return bean;
+                }
+                if ( info.getLoggerCategory() != null ) {
+                    ContainerUtil.enableLogging(bean, this.logger.getChildLogger(info.getLoggerCategory()));
+                } else {
+                    ContainerUtil.enableLogging(bean, this.logger);
+                }
+                ContainerUtil.contextualize(bean, this.context);
+                ContainerUtil.service(bean, (ServiceManager)this.beanFactory.getBean(ServiceManager.class.getName()));
+                if ( info != null ) {
+                    Configuration config = info.getConfiguration();
+                    if ( config == null ) {
+                        config = EMPTY_CONFIG;
+                    }
+                    if ( bean instanceof Configurable ) {
+                        ContainerUtil.configure(bean, config);
+                    } else if ( bean instanceof Parameterizable ) {
+                        Parameters p = info.getParameters();
+                        if ( p == null ) {
+                            p = Parameters.fromConfiguration(config);
+                            info.setParameters(p);
+                        }
+                        ContainerUtil.parameterize(bean, p);
+                    }
+                }
+                ContainerUtil.initialize(bean);
+            } catch (Exception e) {
+                throw new BeanCreationException("Unable to initialize Avalon component with role " + beanName, e);
+            }
+            return bean;
+        }
+
+        /**
+         * @see org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor#postProcessBeforeDestruction(java.lang.Object, java.lang.String)
+         */
+        public void postProcessBeforeDestruction(Object bean, String beanName)
+        throws BeansException {
+            try {
+                ContainerUtil.stop(bean);
+            } catch (Exception e) {
+                throw new BeanInitializationException("Unable to stop bean " + beanName, e);
+            }
+            ContainerUtil.dispose(bean);
+        }
+    }
 }

Modified: cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/XmlConfigCreator.java
URL: http://svn.apache.org/viewcvs/cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/XmlConfigCreator.java?rev=378575&r1=378574&r2=378575&view=diff
==============================================================================
--- cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/XmlConfigCreator.java (original)
+++ cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/XmlConfigCreator.java Fri Feb 17 09:20:03 2006
@@ -20,14 +20,20 @@
 import java.util.List;
 import java.util.Map;
 
+import org.apache.avalon.excalibur.pool.Poolable;
+import org.apache.avalon.framework.context.Context;
+import org.apache.avalon.framework.logger.Logger;
 import org.apache.avalon.framework.service.ServiceManager;
+import org.apache.avalon.framework.thread.ThreadSafe;
+import org.apache.cocoon.Cocoon;
+import org.apache.cocoon.Processor;
+import org.apache.cocoon.SpringCocoon;
 import org.springframework.util.StringUtils;
 
 /**
  * This is a simple component that uses a {@link  ConfigurationInfo} to create
  * a Spring like configuration xml document.
  *
- * TODO: LogManager?
  * TODO: configure(Core)
  * TODO: register aliases for shorthands
  * @since 2.2
@@ -39,7 +45,7 @@
     protected static final String DOCTYPE =
         "<!DOCTYPE beans PUBLIC \"-//SPRING//DTD BEAN//EN\" \"http://www.springframework.org/dtd/spring-beans.dtd\">\n";
 
-    public String createConfig(Map components) 
+    public String createConfig(Map components, boolean addCocoon) 
     throws Exception {
         final List pooledRoles = new ArrayList();
         final StringBuffer buffer = new StringBuffer();
@@ -51,6 +57,7 @@
         buffer.append("<bean");
         this.appendAttribute(buffer, "id", ServiceManager.class.getName());
         this.appendAttribute(buffer, "class", AvalonServiceManager.class.getName());
+        this.appendAttribute(buffer, "singleton", "true");
         buffer.append("/>\n");
 
         final Iterator i = components.entrySet().iterator();
@@ -70,6 +77,15 @@
                 className = AvalonServiceSelector.class.getName();
                 isSelector = true;
             } else {
+                // test for unknown model
+                if ( current.getModel() == ComponentInfo.MODEL_UNKNOWN ) {
+                    final Class serviceClass = Class.forName(className);
+                    if ( ThreadSafe.class.isAssignableFrom(serviceClass) ) {
+                        current.setModel(ComponentInfo.MODEL_SINGLETON);
+                    } else if ( Poolable.class.isAssignableFrom(serviceClass) ) {
+                        current.setModel(ComponentInfo.MODEL_POOLED);
+                    }
+                }
                 if ( current.getModel() == ComponentInfo.MODEL_NON_THREAD_SAFE_POOLED 
                     || current.getModel() == ComponentInfo.MODEL_POOLED ) {
                     poolable = true;
@@ -142,6 +158,27 @@
                 buffer.append("</bean>\n");
                 pooledRoles.add(role);
             }
+        }
+        // add the Cocoon object to the root
+        if ( addCocoon ) {
+            buffer.append("<bean");
+            this.appendAttribute(buffer, "id", Cocoon.class.getName());
+            this.appendAttribute(buffer, "class", SpringCocoon.class.getName());
+            this.appendAttribute(buffer, "singleton", "true");
+            buffer.append(">\n");
+            buffer.append("  <constructor-arg ref=\"");
+            buffer.append(Processor.ROLE);
+            buffer.append("\"/>\n");
+            buffer.append("  <constructor-arg ref=\"");
+            buffer.append(ServiceManager.class.getName());
+            buffer.append("\"/>\n");
+            buffer.append("  <constructor-arg ref=\"");
+            buffer.append(Context.class.getName());
+            buffer.append("\"/>\n");
+            buffer.append("  <constructor-arg ref=\"");
+            buffer.append(Logger.class.getName());
+            buffer.append("\"/>\n");
+            buffer.append("</bean>\n");
         }
         buffer.append("</beans>\n");