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/13 13:37:18 UTC

svn commit: r377366 - in /cocoon/trunk/cocoon-core: ./ src/main/java/org/apache/cocoon/ src/main/java/org/apache/cocoon/components/source/impl/ src/main/java/org/apache/cocoon/core/container/spring/

Author: cziegeler
Date: Mon Feb 13 04:37:14 2006
New Revision: 377366

URL: http://svn.apache.org/viewcvs?rev=377366&view=rev
Log:
Adding prototype for spring based container

Added:
    cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/
    cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/ApplicationContextFactory.java   (with props)
    cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/AvalonEnvironment.java   (with props)
    cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/AvalonServiceManager.java   (with props)
    cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/AvalonServiceSelector.java   (with props)
    cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/CocoonSettingsConfigurer.java   (with props)
    cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/CocoonXmlWebApplicationContext.java   (with props)
    cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/ComponentInfo.java   (with props)
    cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/ConfigReader.java   (with props)
    cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/ConfigurationInfo.java   (with props)
    cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/PoolableFactoryBean.java   (with props)
    cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/XmlConfigCreator.java   (with props)
Modified:
    cocoon/trunk/cocoon-core/pom.xml
    cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/Cocoon.java
    cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/components/source/impl/ContextSourceFactory.java

Modified: cocoon/trunk/cocoon-core/pom.xml
URL: http://svn.apache.org/viewcvs/cocoon/trunk/cocoon-core/pom.xml?rev=377366&r1=377365&r2=377366&view=diff
==============================================================================
--- cocoon/trunk/cocoon-core/pom.xml (original)
+++ cocoon/trunk/cocoon-core/pom.xml Mon Feb 13 04:37:14 2006
@@ -305,6 +305,11 @@
       <artifactId>jakarta-bcel</artifactId>
       <version>20040329</version>
     </dependency>
+    <dependency>
+      <groupId>springframework</groupId>
+      <artifactId>spring</artifactId>
+      <version>1.2.6</version>
+    </dependency>
   </dependencies>
   <profiles>
     <profile>

Modified: cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/Cocoon.java
URL: http://svn.apache.org/viewcvs/cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/Cocoon.java?rev=377366&r1=377365&r2=377366&view=diff
==============================================================================
--- cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/Cocoon.java (original)
+++ cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/Cocoon.java Mon Feb 13 04:37:14 2006
@@ -42,11 +42,16 @@
 import org.apache.cocoon.core.Core;
 import org.apache.cocoon.core.Settings;
 import org.apache.cocoon.core.container.RoleManager;
+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.environment.Environment;
 import org.apache.cocoon.environment.ObjectModelHelper;
 import org.apache.cocoon.environment.Request;
 import org.apache.cocoon.environment.Session;
 import org.apache.cocoon.environment.internal.EnvironmentHelper;
+import org.apache.cocoon.servlet.CocoonServlet;
 import org.apache.cocoon.util.location.Location;
 import org.apache.cocoon.util.location.LocationImpl;
 import org.apache.cocoon.util.location.LocationUtils;
@@ -55,6 +60,7 @@
 import org.apache.excalibur.source.Source;
 import org.apache.excalibur.source.SourceResolver;
 import org.apache.excalibur.source.impl.URLSource;
+import org.springframework.context.ApplicationContext;
 import org.xml.sax.InputSource;
 
 import java.io.BufferedInputStream;
@@ -64,6 +70,8 @@
 import java.util.HashMap;
 import java.util.Map;
 
+import javax.servlet.ServletConfig;
+
 /**
  * The Cocoon Object is the main Kernel for the entire Cocoon system.
  *
@@ -223,7 +231,7 @@
         this.loggerManager = loggerManager;
     }
 
-    /* (non-Javadoc)
+    /**
      * @see org.apache.avalon.framework.activity.Initializable#initialize()
      */
     public void initialize() throws Exception {
@@ -239,6 +247,20 @@
             throw new ConfigurationException(
                     "Could not open configuration file: " + settings.getConfiguration(), e);
         }
+
+        // Test setup spring container
+        System.out.println("Setting up test Spring container");
+        AvalonEnvironment env = new AvalonEnvironment();
+        env.context = this.context;
+        env.core = this.core;
+        env.logger = this.getLogger();
+        env.servletContext = ((ServletConfig)this.context.get(CocoonServlet.CONTEXT_SERVLET_CONFIG)).getServletContext();
+        env.settings = this.core.getSettings();
+        ApplicationContext rootContext = ApplicationContextFactory.createRootApplicationContext(env);
+        ConfigurationInfo result = ConfigReader.readConfiguration(this.configurationFile.getURI(), env);
+        ApplicationContext mainContext = ApplicationContextFactory.createApplicationContext(env, result, rootContext);
+        System.out.println("Getting something from mainContext: " + mainContext.getBean(Core.ROLE));
+        // END Test setup
 
         this.serviceManager = new CocoonServiceManager(this.parentServiceManager);
         ContainerUtil.enableLogging(this.serviceManager, this.rootLogger.getChildLogger("manager"));

Modified: cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/components/source/impl/ContextSourceFactory.java
URL: http://svn.apache.org/viewcvs/cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/components/source/impl/ContextSourceFactory.java?rev=377366&r1=377365&r2=377366&view=diff
==============================================================================
--- cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/components/source/impl/ContextSourceFactory.java (original)
+++ cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/components/source/impl/ContextSourceFactory.java Mon Feb 13 04:37:14 2006
@@ -34,6 +34,7 @@
 import org.apache.avalon.framework.thread.ThreadSafe;
 import org.apache.cocoon.Constants;
 import org.apache.cocoon.environment.Context;
+import org.apache.cocoon.servlet.CocoonServlet;
 import org.apache.commons.lang.BooleanUtils;
 import org.apache.excalibur.source.Source;
 import org.apache.excalibur.source.SourceException;
@@ -82,7 +83,7 @@
     throws ContextException {
         this.envContext = (Context)context.get(Constants.CONTEXT_ENVIRONMENT_CONTEXT);
         try {
-            this.servletContext = ((ServletConfig) context.get("servlet-config")).getServletContext();
+            this.servletContext = ((ServletConfig) context.get(CocoonServlet.CONTEXT_SERVLET_CONFIG)).getServletContext();
         } catch (ContextException ignore) {
             // in other environments (CLI etc.), we don't have a servlet context
         }

Added: 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=377366&view=auto
==============================================================================
--- cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/ApplicationContextFactory.java (added)
+++ cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/ApplicationContextFactory.java Mon Feb 13 04:37:14 2006
@@ -0,0 +1,192 @@
+/*
+ * Copyright 2006 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.container.spring;
+
+import java.util.Map;
+
+
+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.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;
+import org.springframework.web.context.WebApplicationContext;
+
+/**
+ * This factory creates new Spring {@link ApplicationContext} objects which support
+ * the Avalon style component configuration.
+ *
+ * @since 2.2
+ * @version $Id$
+ */
+public class ApplicationContextFactory {
+
+    /**
+     * Create a new (sub) application context.
+     *
+     * @param env
+     * @param info
+     * @param parent The parent application context or null.
+     * @return A new application context
+     * @throws Exception
+     */
+    public static ApplicationContext createApplicationContext(AvalonEnvironment  env,
+                                                              ConfigurationInfo  info,
+                                                              ApplicationContext parent)
+    throws Exception {
+        final String xmlConfig = (new XmlConfigCreator()).createConfig(info.getComponents());
+        Resource rsc = new ByteArrayResource(xmlConfig.getBytes("utf-8"));
+        CocoonXmlWebApplicationContext context = new CocoonXmlWebApplicationContext(rsc, parent);
+        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);
+        }
+        return context;
+    }
+
+    /**
+     * Create the root application context.
+     * This context is the root of all Cocoon based Spring application contexts. If
+     * the default Spring context is created using the Spring context listener, that
+     * default context will be the parent of this root context.
+     *
+     * @param env
+     * @return A new root application context.
+     * @throws Exception
+     */
+    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);
+        context.refresh();
+        final ConfigurableListableBeanFactory factory = context.getBeanFactory();
+        factory.registerSingleton(Context.class.getName(), env.context);
+        factory.registerSingleton(Logger.class.getName(), env.logger);
+        factory.registerSingleton(Core.class.getName(), env.core);
+        factory.registerSingleton(Settings.class.getName(), env.settings);
+        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);
+            if ( info == null ) {
+                // no info so just return as this is not an Avalon component
+                return bean;
+            }
+            try {
+                if ( info.getLoggerCategory() != null ) {
+                    ContainerUtil.enableLogging(bean, this.logger.getChildLogger(info.getLoggerCategory()));
+                } else {
+                    ContainerUtil.enableLogging(bean, this.logger);
+                }
+                ContainerUtil.contextualize(bean, 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);
+        }
+    }
+}

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

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

Added: cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/AvalonEnvironment.java
URL: http://svn.apache.org/viewcvs/cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/AvalonEnvironment.java?rev=377366&view=auto
==============================================================================
--- cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/AvalonEnvironment.java (added)
+++ cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/AvalonEnvironment.java Mon Feb 13 04:37:14 2006
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2006 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.container.spring;
+
+import javax.servlet.ServletContext;
+
+import org.apache.avalon.framework.context.Context;
+import org.apache.avalon.framework.logger.Logger;
+import org.apache.cocoon.core.Core;
+import org.apache.cocoon.core.Settings;
+
+/**
+ * This is a simple bean used to pass all Avalon related environment information
+ * to the application context.
+ *
+ * @since 2.2
+ * @version $Id$
+ */
+public final class AvalonEnvironment {
+    public ServletContext servletContext;
+    public Context  context;
+    public Logger   logger;
+    public Core     core;
+    public Settings settings;
+}
\ No newline at end of file

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

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

Added: cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/AvalonServiceManager.java
URL: http://svn.apache.org/viewcvs/cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/AvalonServiceManager.java?rev=377366&view=auto
==============================================================================
--- cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/AvalonServiceManager.java (added)
+++ cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/AvalonServiceManager.java Mon Feb 13 04:37:14 2006
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2006 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.container.spring;
+
+import org.apache.avalon.framework.service.ServiceException;
+import org.apache.avalon.framework.service.ServiceManager;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.beans.factory.BeanFactoryAware;
+
+/**
+ * This bean acts like a Avalon {@link ServiceManager}.
+ *
+ * @since 2.2
+ * @version $Id$
+ */
+final class AvalonServiceManager
+    implements ServiceManager, BeanFactoryAware {
+
+
+    protected BeanFactory beanFactory;
+
+    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
+        this.beanFactory = beanFactory;
+    }
+
+    /**
+     * @see org.apache.avalon.framework.service.ServiceManager#hasService(java.lang.String)
+     */
+    public boolean hasService(String role) {
+        return this.beanFactory.containsBean(role);
+    }
+
+    /**
+     * @see org.apache.avalon.framework.service.ServiceManager#lookup(java.lang.String)
+     */
+    public Object lookup(String role) throws ServiceException {
+        if ( !this.hasService(role) ) {
+            throw new ServiceException("AvalonServiceManager",
+                                       "Component with '" + role + "' is not defined in this service manager.");
+        }
+        return this.beanFactory.getBean(role);
+    }
+
+    /**
+     * @see org.apache.avalon.framework.service.ServiceManager#release(java.lang.Object)
+     */
+    public void release(Object component) {
+        // we never release
+    }
+}
\ No newline at end of file

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

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

Added: cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/AvalonServiceSelector.java
URL: http://svn.apache.org/viewcvs/cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/AvalonServiceSelector.java?rev=377366&view=auto
==============================================================================
--- cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/AvalonServiceSelector.java (added)
+++ cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/AvalonServiceSelector.java Mon Feb 13 04:37:14 2006
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2006 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.container.spring;
+
+import org.apache.avalon.framework.service.ServiceException;
+import org.apache.avalon.framework.service.ServiceManager;
+import org.apache.avalon.framework.service.ServiceSelector;
+
+/**
+ * This bean acts like a Avalon {@link ServiceSelector}.
+ *
+ * @since 2.2
+ * @version $Id$
+ */
+public class AvalonServiceSelector implements ServiceSelector {
+
+    protected final String role;
+    protected final ServiceManager manager;
+    protected String defaultKey;
+
+    public AvalonServiceSelector(ServiceManager manager, String r) {
+        this.role = r + '/';
+        this.manager = manager;
+    }
+
+    public void setDefault(String value) {
+        this.defaultKey = value;
+    }
+
+    /**
+     * @see org.apache.avalon.framework.service.ServiceSelector#select(java.lang.Object)
+     */
+    public Object select(Object key) throws ServiceException {
+        if ( key == null || key.toString().length() == 0 ) {
+            key = this.defaultKey;
+        }
+        return this.manager.lookup(this.role + key);
+    }
+
+    /**
+     * @see org.apache.avalon.framework.service.ServiceSelector#isSelectable(java.lang.Object)
+     */
+    public boolean isSelectable(Object key) {
+        return this.manager.hasService(this.role + key);
+    }
+
+    /**
+     * @see org.apache.avalon.framework.service.ServiceSelector#release(java.lang.Object)
+     */
+    public void release(Object component) {
+        this.manager.release(component);
+    }
+}

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

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

Added: cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/CocoonSettingsConfigurer.java
URL: http://svn.apache.org/viewcvs/cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/CocoonSettingsConfigurer.java?rev=377366&view=auto
==============================================================================
--- cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/CocoonSettingsConfigurer.java (added)
+++ cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/CocoonSettingsConfigurer.java Mon Feb 13 04:37:14 2006
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2005-2006 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.container.spring;
+
+import java.util.List;
+import java.util.Properties;
+
+import org.apache.cocoon.core.Settings;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.BeanDefinitionStoreException;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.config.BeanDefinitionVisitor;
+import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
+
+/**
+ * Make the properties of the Cocoon settings available within Spring configuration.
+ *
+ * @since 2.2
+ * @version $Id$
+ */
+public class CocoonSettingsConfigurer
+    extends PropertyPlaceholderConfigurer
+    implements BeanFactoryPostProcessor {
+
+    protected final Settings settings;
+
+    public CocoonSettingsConfigurer(Settings settings) {
+        this.settings = settings;
+    }
+
+    /**
+     * @see org.springframework.beans.factory.config.PropertyPlaceholderConfigurer#processProperties(org.springframework.beans.factory.config.ConfigurableListableBeanFactory, java.util.Properties)
+     */
+    protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess,
+                                     Properties props)
+    throws BeansException {
+        final BeanDefinitionVisitor visitor = new CocoonSettingsResolvingBeanDefinitionVisitor(this.settings);
+        String[] beanNames = beanFactoryToProcess.getBeanDefinitionNames();
+        for (int i = 0; i < beanNames.length; i++) {
+            BeanDefinition bd = beanFactoryToProcess.getBeanDefinition(beanNames[i]);
+            try {
+                visitor.visitBeanDefinition(bd);
+            } catch (BeanDefinitionStoreException ex) {
+                throw new BeanDefinitionStoreException(bd
+                        .getResourceDescription(), beanNames[i], ex
+                        .getMessage());
+            }
+        }
+    }
+
+    protected class CocoonSettingsResolvingBeanDefinitionVisitor
+        extends BeanDefinitionVisitor {
+
+        protected final Properties props;
+
+        public CocoonSettingsResolvingBeanDefinitionVisitor(Settings settings) {
+            this.props = new Properties();
+
+            List propsList = settings.getProperties();
+            for (int i = 0; i < propsList.size(); i++) {
+                String propName = (String) propsList.get(i);
+                props.put(propName, settings.getProperty(propName));
+            }
+        }
+
+        protected String resolveStringValue(String strVal) {
+            return parseStringValue(strVal, this.props, null);
+        }
+    }
+
+}

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

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

Added: 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=377366&view=auto
==============================================================================
--- cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/CocoonXmlWebApplicationContext.java (added)
+++ cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/CocoonXmlWebApplicationContext.java Mon Feb 13 04:37:14 2006
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2006 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.container.spring;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+
+import org.apache.avalon.framework.CascadingRuntimeException;
+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.xml.XmlBeanDefinitionReader;
+import org.springframework.context.ApplicationContext;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.UrlResource;
+import org.springframework.web.context.support.XmlWebApplicationContext;
+
+/**
+ * This is a Cocoon specific implementation of a Spring {@link ApplicationContext}.
+ *
+ * @since 2.2
+ * @version $Id$
+ */
+public class CocoonXmlWebApplicationContext extends XmlWebApplicationContext {
+
+    public static final String DEFAULT_SPRING_CONFIG = "conf/applicationContext.xml";
+
+    final private Resource avalonResource;
+    protected SourceResolver resolver;
+    protected String baseURL;
+
+
+    public CocoonXmlWebApplicationContext(Resource avalonResource,
+                                          ApplicationContext parent) {
+        this.setParent(parent);
+        this.avalonResource = avalonResource;
+    }
+
+    /**
+     * @see org.springframework.web.context.support.XmlWebApplicationContext#loadBeanDefinitions(org.springframework.beans.factory.xml.XmlBeanDefinitionReader)
+     */
+    protected void loadBeanDefinitions(XmlBeanDefinitionReader reader)
+    throws BeansException, IOException {
+        super.loadBeanDefinitions(reader);
+        if ( this.avalonResource != null ) {
+            reader.loadBeanDefinitions(this.avalonResource);
+        }
+    }
+
+    public void setSourceResolver(SourceResolver aResolver) {
+        this.resolver = aResolver;
+    }
+
+    public void setEnvironmentHelper(EnvironmentHelper eh) {
+        this.baseURL = eh.getContext();
+        if ( !this.baseURL.endsWith("/") ) {
+            this.baseURL = this.baseURL + '/';
+        }
+    }
+
+    /**
+     * Resolve file paths beneath the root of the web application.
+     * <p>Note: Even if a given path starts with a slash, it will get
+     * interpreted as relative to the web application root directory
+     * (which is the way most servlet containers handle such paths).
+     * @see org.springframework.web.context.support.ServletContextResource
+     */
+    protected Resource getResourceByPath(String path) {
+        if ( path.startsWith("/") ) {
+            path = path.substring(1);
+        }
+        path = this.baseURL + path;
+        try {
+            return new UrlResource(path);
+        } catch (MalformedURLException mue) {
+            // FIXME - for now, we simply call super
+            return super.getResourceByPath(path);
+        }
+    }
+    
+    /**
+     * The default location for the context is "conf/applicationContext.xml"
+     * which is searched relative to the current sitemap.
+     * @return The default config locations if they exist otherwise an empty array.
+     */
+    protected String[] getDefaultConfigLocations() {
+        if ( this.resolver != null ) {
+            Source testSource = null;
+            try {
+                testSource = this.resolver.resolveURI(DEFAULT_SPRING_CONFIG);
+                if (testSource.exists()) {
+                    return new String[] {DEFAULT_SPRING_CONFIG};
+                }
+            } catch(MalformedURLException e) {
+                throw new CascadingRuntimeException("Malformed URL when resolving Spring default config location [ " + DEFAULT_SPRING_CONFIG + "]. This is an unrecoverable programming error. Check the code where this exception was thrown.", e);
+            } catch(IOException e) {
+                throw new CascadingRuntimeException("Cannot resolve default config location ["+ DEFAULT_SPRING_CONFIG + "] due to an IOException. See cause for details.", e);
+            } finally {
+                this.resolver.release(testSource);
+            }
+        }        
+        return new String[]{};
+    }
+
+}

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

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

Added: cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/ComponentInfo.java
URL: http://svn.apache.org/viewcvs/cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/ComponentInfo.java?rev=377366&view=auto
==============================================================================
--- cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/ComponentInfo.java (added)
+++ cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/ComponentInfo.java Mon Feb 13 04:37:14 2006
@@ -0,0 +1,221 @@
+/*
+ * Copyright 2006 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.container.spring;
+
+import org.apache.avalon.framework.configuration.Configuration;
+import org.apache.avalon.framework.parameters.Parameters;
+
+/**
+ * Meta-information about a component.
+ *
+ * @since 2.2
+ * @version $Id$
+ */
+public final class ComponentInfo {
+
+    public static final int MODEL_UNKNOWN   = -1;
+    public static final int MODEL_PRIMITIVE = 0;
+    public static final int MODEL_SINGLETON = 1;
+    public static final int MODEL_POOLED    = 2;
+    public static final int MODEL_NON_THREAD_SAFE_POOLED = 3;
+
+    public static final String TYPE_SINGLETON = "singleton";
+    public static final String TYPE_POOLED = "pooled";
+    public static final String TYPE_NON_THREAD_SAFE_POOLED = "non-thread-safe-pooled";
+
+    private int model;
+    private String initMethodName;
+    private String destroyMethodName;
+    private String poolInMethodName;
+    private String poolOutMethodName;
+    private String serviceClassName;
+    private Configuration configuration;
+    private Parameters parameters;
+    private String loggerCategory;
+    private String role;
+
+    public ComponentInfo() {
+        this.model = MODEL_PRIMITIVE;
+    }
+
+    /**
+     * @return Returns the model.
+     */
+    public int getModel() {
+        return model;
+    }
+
+    /**
+     * @param model The model to set.
+     */
+    public void setModel(int model) {
+        this.model = model;
+    }
+
+    /**
+     * @return Returns the destroyMethod.
+     */
+    public String getDestroyMethodName() {
+        return destroyMethodName;
+    }
+
+    /**
+     * @param destroyMethod The destroyMethod to set.
+     */
+    public void setDestroyMethodName(String destroyMethod) {
+        this.destroyMethodName = destroyMethod;
+    }
+
+    /**
+     * @return Returns the initMethod.
+     */
+    public String getInitMethodName() {
+        return initMethodName;
+    }
+
+    /**
+     * @param initMethod The initMethod to set.
+     */
+    public void setInitMethodName(String initMethod) {
+        this.initMethodName = initMethod;
+    }
+
+    /**
+     * @return Returns the poolInMethodName
+     */
+    public String getPoolInMethodName() {
+        return this.poolInMethodName;
+    }
+
+    /**
+     * @param poolMethod The poolInMethod name to set.
+     */
+    public void setPoolInMethodName(String poolMethod) {
+        this.poolInMethodName = poolMethod;
+    }
+
+    /**
+     * @return Returns the poolOutMethodName
+     */
+    public String getPoolOutMethodName() {
+        return this.poolOutMethodName;
+    }
+
+    /**
+     * @param poolMethod The poolOutMethod name to set.
+     */
+    public void setPoolOutMethodName(String poolMethod) {
+        this.poolOutMethodName = poolMethod;
+    }
+
+    /**
+     * @return Returns the serviceClassName.
+     */
+    public String getServiceClassName() {
+        return serviceClassName;
+    }
+
+    /**
+     * @param serviceClassName The serviceClassName to set.
+     */
+    public void setServiceClassName(String serviceClassName) {
+        this.serviceClassName = serviceClassName;
+    }
+
+    /**
+     * @return Returns the configuration.
+     */
+    public Configuration getConfiguration() {
+        return configuration;
+    }
+
+    /**
+     * @param configuration The configuration to set.
+     */
+    public void setConfiguration(Configuration configuration) {
+        this.configuration = configuration;
+    }
+
+    public String getLocation() {
+        return this.configuration.getLocation();
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.Object#toString()
+     */
+    public String toString() {
+        return "ServiceInfo: {class=" + this.getServiceClassName()+"}";
+    }
+
+    public void fill(Configuration attr) {
+        // test model
+        final String model = attr.getAttribute("model", null);
+        if ( TYPE_POOLED.equals(model) ) {
+            this.setModel(ComponentInfo.MODEL_POOLED);
+            this.setPoolInMethodName(attr.getAttribute("pool-in", null));
+            this.setPoolOutMethodName(attr.getAttribute("pool-out", null));
+        } else if (TYPE_NON_THREAD_SAFE_POOLED.equals(model)) {
+            this.setModel(ComponentInfo.MODEL_NON_THREAD_SAFE_POOLED);
+            this.setPoolInMethodName(attr.getAttribute("pool-in", null));
+            this.setPoolOutMethodName(attr.getAttribute("pool-out", null));
+        } else if ( TYPE_SINGLETON.equals(model) ) {
+            this.setModel(ComponentInfo.MODEL_SINGLETON);
+        }
+        // init/destroy methods
+        this.setInitMethodName(attr.getAttribute("init", null));
+        this.setDestroyMethodName(attr.getAttribute("destroy", null));
+        // logging
+        this.setLoggerCategory(attr.getAttribute("logger", null));
+        this.setRole(attr.getAttribute("role", null));
+    }
+
+    /**
+     * @return Returns the loggerCategory.
+     */
+    public String getLoggerCategory() {
+        return this.loggerCategory;
+    }
+
+    /**
+     * @param loggerCategory The loggerCategory to set.
+     */
+    public void setLoggerCategory(String loggerCategory) {
+        this.loggerCategory = loggerCategory;
+    }
+    
+    /**
+     * @param role The role to set.
+     */
+    public void setRole( String role ) {
+        this.role = role;
+    }
+
+    /**
+     * @return Returns the role.
+     */
+    public String getRole() {
+        return role;
+    }
+
+    public Parameters getParameters() {
+        return parameters;
+    }
+
+    public void setParameters(Parameters parameters) {
+        this.parameters = parameters;
+    }
+
+}

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

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

Added: cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/ConfigReader.java
URL: http://svn.apache.org/viewcvs/cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/ConfigReader.java?rev=377366&view=auto
==============================================================================
--- cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/ConfigReader.java (added)
+++ cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/ConfigReader.java Mon Feb 13 04:37:14 2006
@@ -0,0 +1,392 @@
+/*
+ * Copyright 2006 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.container.spring;
+
+import java.io.IOException;
+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.DefaultConfigurationSerializer;
+import org.apache.cocoon.configuration.ConfigurationBuilder;
+import org.apache.cocoon.core.source.SimpleSourceResolver;
+import org.apache.cocoon.matching.helpers.WildcardHelper;
+import org.apache.excalibur.source.Source;
+import org.apache.excalibur.source.SourceResolver;
+import org.apache.excalibur.source.TraversableSource;
+
+/**
+ * This component reads in Avalon style configuration files and returns all
+ * contained components and their configurations.
+ *
+ * @since 2.2
+ * @version $Id$
+ */
+public class ConfigReader {
+
+    /** Parameter map for the context protocol */
+    protected static final Map CONTEXT_PARAMETERS = Collections.singletonMap("force-traversable", Boolean.TRUE);
+
+    protected SourceResolver resolver;
+
+    /** Map for shorthand to role mapping. */
+    private final Map shorthands = new HashMap();
+
+    /** Map for role to default classname mapping. */
+    private final Map classNames = new HashMap();
+
+    /** Map for role->key to classname mapping. */
+    private final Map keyClassNames = new HashMap();
+
+    /** List of components. */
+    private final Map components = new HashMap();
+
+    /** Root logger. */
+    private String rootLogger;
+
+    /** Avalon environment. */
+    private AvalonEnvironment environment;
+
+    public static ConfigurationInfo readConfiguration(String source, AvalonEnvironment env)
+    throws Exception {
+        final SimpleSourceResolver sourceResolver = new SimpleSourceResolver();
+        sourceResolver.enableLogging(env.logger);
+        sourceResolver.contextualize(env.context);
+
+        ConfigReader converter = new ConfigReader();
+        converter.resolver = sourceResolver;
+        converter.environment = env;
+
+        converter.convert(source);
+
+        ConfigurationInfo info = new ConfigurationInfo();
+        info.setComponents(converter.components);
+        info.setRootLogger(converter.rootLogger);
+        return info;
+    }
+
+    public ConfigReader() {
+        // nothing to do
+    }
+
+    protected void convert(String relativePath)
+    throws Exception {
+        final Source root = this.resolver.resolveURI(relativePath);
+        try {
+            ConfigurationBuilder b = new ConfigurationBuilder(this.environment.settings);
+            Configuration config = b.build(root.getInputStream());
+            
+            // It's possible to define a logger on a per sitemap/service manager base.
+            // This is the default logger for all components defined with this sitemap/manager.
+            this.rootLogger = config.getAttribute("logger", null);
+
+            // and load configuration with a empty list of loaded configurations
+            parseConfiguration(config, root.getURI(), new HashSet());
+            final Iterator i = this.classNames.values().iterator();
+            while ( i.hasNext() ) {
+                final ComponentInfo current = (ComponentInfo)i.next();
+                this.components.put(current.getRole(), current);
+            }
+        } finally {
+            this.resolver.release(root);
+        }
+    }
+
+    protected void parseConfiguration(final Configuration configuration,
+                                      String contextURI,
+                                      Set loadedURIs) 
+    throws ConfigurationException {
+        final Configuration[] configurations = configuration.getChildren();
+
+        for( int i = 0; i < configurations.length; i++ ) {
+            final Configuration componentConfig = configurations[i];
+
+            final String componentName = componentConfig.getName();
+
+            if ("include".equals(componentName)) {
+                this.handleInclude(contextURI, loadedURIs, componentConfig);
+
+            } else {
+                // Component declaration
+                // Find the role
+                String role = componentConfig.getAttribute("role", null);
+                if (role == null) {
+                    // Get the role from the role manager if not explicitely specified
+                    role = (String)this.shorthands.get( componentName );
+                    if (role == null) {
+                        // Unknown role
+                        throw new ConfigurationException("Unknown component type '" + componentName +
+                            "' at " + componentConfig.getLocation());
+                    }
+                }
+
+                // Find the className
+                String className = componentConfig.getAttribute("class", null);
+                ComponentInfo info;
+                if (className == null) {
+                    // Get the default class name for this role
+                    info = (ComponentInfo)this.classNames.get( role );
+                    if (info == null) {
+                        throw new ConfigurationException("Cannot find a class for role " + role + " at " + componentConfig.getLocation());
+                    }
+                    this.classNames.remove(info);
+                    className = info.getServiceClassName();
+                } else {                    
+                    info = new ComponentInfo();
+                }
+                // If it has a "name" attribute, add it to the role (similar to the
+                // declaration within a service selector)
+                // Note: this has to be done *after* finding the className above as we change the role
+                String name = componentConfig.getAttribute("name", null);
+                if (name != null) {
+                    role = role + "/" + name;
+                }
+                info.fill(componentConfig);
+                info.setServiceClassName(className);
+                info.setRole(role);
+                info.setConfiguration(componentConfig);
+
+                this.components.put(info.getRole(), info);
+                // now if this is a selector, then we have to register the single components
+                if ( info.getConfiguration() != null && className.endsWith("Selector") ) {
+                    String classAttribute = null;
+                    if ( className.equals("org.apache.cocoon.core.container.DefaultServiceSelector") ) {
+                        classAttribute = "class";
+                    } else if (className.equals("org.apache.cocoon.components.treeprocessor.sitemap.ComponentsSelector") ) {
+                        classAttribute = "src";
+                    } 
+                    if ( classAttribute == null ) {
+                        // TODO: Unknown selector
+                        try {
+                            System.out.println("** Found unknown selector: " + className);
+                            DefaultConfigurationSerializer dcs = new DefaultConfigurationSerializer();
+                            System.out.println(dcs.serialize(info.getConfiguration()));
+                            System.out.println("----------------------------------------------------");
+                        } catch (Exception ignore) {
+                        }
+                    } else {
+                        String componentRole = role;
+                        if ( componentRole.endsWith("Selector") ) {
+                            componentRole = componentRole.substring(0, componentRole.length() - 8);
+                        }
+                        componentRole += '/';
+                        Configuration[] children = info.getConfiguration().getChildren();
+                        for (int j=0; j<children.length; j++) {
+                            final Configuration current = children[j];
+                            final ComponentInfo childInfo = new ComponentInfo();
+                            childInfo.fill(current);
+                            childInfo.setConfiguration(current);
+                            childInfo.setServiceClassName(current.getAttribute(classAttribute));
+                            childInfo.setRole(componentRole + current.getAttribute("name"));
+                            this.components.put(childInfo.getRole(), childInfo);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    protected void handleInclude(final String contextURI,
+                                 final Set loadedURIs,
+                                 final Configuration includeStatement)
+    throws ConfigurationException {
+        final String includeURI = includeStatement.getAttribute("src", null);
+        String directoryURI = null;
+        if ( includeURI == null ) {
+            // check for directories
+            directoryURI = includeStatement.getAttribute("dir", null);                    
+        }
+        if ( includeURI == null && directoryURI == null ) {
+            throw new ConfigurationException("Include statement must either have a 'src' or 'dir' attribute, at " +
+                    includeStatement.getLocation());
+        }
+
+        if ( includeURI != null ) {
+            Source src = null;
+            try {
+                src = this.resolver.resolveURI(includeURI, contextURI, null);
+
+                this.loadURI(src, loadedURIs, includeStatement);
+            } catch (Exception e) {
+                throw new ConfigurationException("Cannot load '" + includeURI + "' at " + includeStatement.getLocation(), e);
+            } finally {
+                this.resolver.release(src);
+            }
+            
+        } else {
+            final String pattern = includeStatement.getAttribute("pattern", null);
+            int[] parsedPattern = null;
+            if ( pattern != null ) {
+                parsedPattern = WildcardHelper.compilePattern(pattern);
+            }
+            Source directory = null;
+            try {
+                directory = this.resolver.resolveURI(directoryURI, contextURI, CONTEXT_PARAMETERS);
+                if ( directory instanceof TraversableSource ) {
+                    final Iterator children = ((TraversableSource)directory).getChildren().iterator();
+                    while ( children.hasNext() ) {
+                        final Source s = (Source)children.next();
+                        try {
+                            if ( parsedPattern == null || this.match(s.getURI(), parsedPattern)) {
+                                this.loadURI(s, loadedURIs, includeStatement);
+                            }
+                        } finally {
+                            this.resolver.release(s);
+                        }
+                    }
+                } else {
+                    throw new ConfigurationException("Include.dir must point to a directory, '" + directory.getURI() + "' is not a directory.'");
+                }
+            } catch (IOException ioe) {
+                throw new ConfigurationException("Unable to read configurations from " + directoryURI);
+            } finally {
+                this.resolver.release(directory);
+            }
+        }
+    }
+
+    protected void loadURI(final Source src,
+                           final Set loadedURIs,
+                           final Configuration includeStatement) 
+    throws ConfigurationException {
+        // If already loaded: do nothing
+        final String uri = src.getURI();
+
+        if (!loadedURIs.contains(uri)) {
+            // load it and store it in the read set
+            Configuration includeConfig = null;
+            try {
+                ConfigurationBuilder builder = new ConfigurationBuilder(this.environment.settings);
+                includeConfig = builder.build(src.getInputStream(), uri);
+            } catch (Exception e) {
+                throw new ConfigurationException("Cannot load '" + uri + "' at " + includeStatement.getLocation(), e);
+            }
+            loadedURIs.add(uri);
+
+            // what is it?
+            String includeKind = includeConfig.getName();
+            if (includeKind.equals("components")) {
+                // more components
+                this.parseConfiguration(includeConfig, uri, loadedURIs);
+            } else if (includeKind.equals("role-list")) {
+                // more roles
+                this.configureRoles(includeConfig);
+            } else {
+                throw new ConfigurationException("Unknow document '" + includeKind + "' included at " +
+                        includeStatement.getLocation());
+            }
+        }
+    }
+
+    private boolean match(String uri, int[] parsedPattern ) {
+        int pos = uri.lastIndexOf('/');
+        if ( pos != -1 ) {
+            uri = uri.substring(pos+1);
+        }
+        return WildcardHelper.match(null, uri, parsedPattern);      
+    }
+
+    /**
+     * Reads a configuration object and creates the role, shorthand,
+     * and class name mapping.
+     *
+     * @param configuration  The configuration object.
+     * @throws ConfigurationException if the configuration is malformed
+     */
+    protected final void configureRoles( final Configuration configuration )
+    throws ConfigurationException {
+        final Configuration[] roles = configuration.getChildren();
+
+        for( int i = 0; i < roles.length; i++ ) {
+            Configuration role = roles[i];
+            
+            if (!"role".equals(role.getName())) {
+                throw new ConfigurationException("Unexpected '" + role.getName() + "' element at " + role.getLocation());
+            }
+            
+            final String roleName = role.getAttribute("name");
+            final String shorthand = role.getAttribute("shorthand", null);
+            final String defaultClassName = role.getAttribute("default-class", null);
+
+            if (shorthand != null) {
+                // Store the shorthand and check that its consistent with any previous one
+                Object previous = this.shorthands.put( shorthand, roleName );
+                if (previous != null && !previous.equals(roleName)) {
+                    throw new ConfigurationException("Shorthand '" + shorthand + "' already used for role " +
+                            previous + ": inconsistent declaration at " + role.getLocation());
+                }
+            }
+
+            if ( defaultClassName != null ) {
+                ComponentInfo info = (ComponentInfo)this.classNames.get(roleName);
+                if (info == null) {
+                    // Create a new info and store it
+                    info = new ComponentInfo();
+                    info.setServiceClassName(defaultClassName);
+                    info.fill(role);
+                    info.setRole(roleName);
+                    info.setConfiguration(role);
+                    this.classNames.put(roleName, info);
+                } else {
+                    // Check that it's consistent with the existing info
+                    if (!defaultClassName.equals(info.getServiceClassName())) {
+                        throw new ConfigurationException("Invalid redeclaration: default class already set to " + info.getServiceClassName() +
+                                " for role " + roleName + " at " + role.getLocation());
+                    }
+                    //FIXME: should check also other ServiceInfo members
+                }
+            }
+
+            final Configuration[] keys = role.getChildren( "hint" );
+            if( keys.length > 0 ) {
+                Map keyMap = (Map)this.keyClassNames.get(roleName);
+                if (keyMap == null) {
+                    keyMap = new HashMap();
+                    this.keyClassNames.put(roleName, keyMap);
+                }
+
+                for( int j = 0; j < keys.length; j++ ) {
+                    Configuration key = keys[j];
+                    
+                    final String shortHand = key.getAttribute( "shorthand" ).trim();
+                    final String className = key.getAttribute( "class" ).trim();
+
+                    ComponentInfo info = (ComponentInfo)keyMap.get(shortHand);
+                    if (info == null) {       
+                        info = new ComponentInfo();
+                        info.setServiceClassName(className);
+                        info.fill(key);
+                        info.setConfiguration(key);
+                        keyMap.put( shortHand, info );
+                    } else {
+                        // Check that it's consistent with the existing info
+                        if (!className.equals(info.getServiceClassName())) {
+                            throw new ConfigurationException("Invalid redeclaration: class already set to " + info.getServiceClassName() +
+                                    " for hint " + shortHand + " at " + key.getLocation());
+                        }
+                        //FIXME: should check also other ServiceInfo members
+                    }
+                }
+            }
+        }
+    }
+}

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

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

Added: cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/ConfigurationInfo.java
URL: http://svn.apache.org/viewcvs/cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/ConfigurationInfo.java?rev=377366&view=auto
==============================================================================
--- cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/ConfigurationInfo.java (added)
+++ cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/ConfigurationInfo.java Mon Feb 13 04:37:14 2006
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2006 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.container.spring;
+
+import java.util.Map;
+
+/**
+ * This bean stores information about a complete Avalon style configuration.
+ * It can be passed to an {@link XmlConfigCreator} to create a Spring like
+ * configuration.
+ *
+ * @since 2.2
+ * @version $Id$
+ */
+public class ConfigurationInfo {
+
+    protected Map components;
+    
+    protected String rootLogger;
+
+    public Map getComponents() {
+        return components;
+    }
+
+    public void setComponents(Map components) {
+        this.components = components;
+    }
+
+    public String getRootLogger() {
+        return rootLogger;
+    }
+
+    public void setRootLogger(String rootLogger) {
+        this.rootLogger = rootLogger;
+    }
+
+
+}

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

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

Added: cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/PoolableFactoryBean.java
URL: http://svn.apache.org/viewcvs/cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/PoolableFactoryBean.java?rev=377366&view=auto
==============================================================================
--- cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/PoolableFactoryBean.java (added)
+++ cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/PoolableFactoryBean.java Mon Feb 13 04:37:14 2006
@@ -0,0 +1,361 @@
+/* 
+ * Copyright 2002-2005 The Apache Software Foundation
+ * Licensed  under the  Apache License,  Version 2.0  (the "License");
+ * you may not use  this file  except in  compliance with the License.
+ * You may obtain a copy of the License at 
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed  under the  License is distributed on an "AS IS" BASIS,
+ * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
+ * implied.
+ * 
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cocoon.core.container.spring;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.Set;
+
+import org.apache.avalon.excalibur.pool.Recyclable;
+import org.apache.cocoon.core.Core;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.beans.factory.BeanFactoryAware;
+import org.springframework.beans.factory.FactoryBean;
+
+/**
+ * This factory bean adds simple pooling support to Spring.
+ *
+ * @since 2.2
+ * @version $Id$
+ */
+public class PoolableFactoryBean
+    implements FactoryBean, BeanFactoryAware {
+    
+    /** The default max size of the pool. */
+    public static final int DEFAULT_MAX_POOL_SIZE = 64;
+
+    /** All the interfaces for the proxy. */
+    protected final Class[] interfaces;
+
+    /** The pooled component. */
+    protected final String name;
+
+    /** The class. */
+    protected final Class beanClass;
+
+    /** The corresponding bean factory. */
+    protected BeanFactory beanFactory;
+
+    /**
+     * Object used to synchronize access to the get and put methods
+     */
+    protected final Object semaphore = new Object();
+
+    /**
+     * The maximum size of the pool.
+     */
+    private final int max;
+
+    /**
+     * List of the Poolable instances which are available for use.
+     */
+    private LinkedList ready;
+
+    /**
+     * Store the size of the ready list to optimize operations which require this value.
+     */
+    private int readySize;
+
+    /**
+     * Total number of Poolable instances in the pool
+     */
+    private int size;
+
+    /**
+     * Total number of Poolable instances created 
+     */
+    private int highWaterMark;
+
+    /** Pool-in-method-name. */
+    protected String poolInMethodName;
+
+    /** Pool-out-method-name. */
+    protected String poolOutMethodName;
+
+    protected Method poolInMethod;
+    protected Method poolOutMethod;
+
+    /**
+     * Create a PoolableComponentHandler which manages a pool of Components
+     * created by the specified factory object.
+     *
+     * @param name The name of the bean which should be pooled.
+     */
+    public PoolableFactoryBean( String name, String className )
+    throws Exception {
+        this(name, className, DEFAULT_MAX_POOL_SIZE);
+    }
+    
+    /**
+     * Create a PoolableComponentHandler which manages a pool of Components
+     * created by the specified factory object.
+     *
+     * @param name The name of the bean which should be pooled.
+     */
+    public PoolableFactoryBean( String name, String className, int poolMax )
+    throws Exception {
+        this.name = name;
+        this.max = ( poolMax <= 0 ? Integer.MAX_VALUE : poolMax );
+        this.beanClass = Class.forName(className);
+        final HashSet workInterfaces = new HashSet();
+
+        // Get *all* interfaces
+        this.guessWorkInterfaces( this.beanClass, workInterfaces );
+
+        this.interfaces = (Class[]) workInterfaces.toArray( new Class[workInterfaces.size()] );
+
+        // Create the pool lists.
+        this.ready = new LinkedList();
+    }
+
+    public void setPoolInMethodName(String poolInMethodName) {
+        this.poolInMethodName = poolInMethodName;
+    }
+
+    public void setPoolOutMethodName(String poolOutMethodName) {
+        this.poolOutMethodName = poolOutMethodName;
+    }
+
+    public void initialize() throws Exception {
+        if ( this.poolInMethodName != null ) {
+            this.poolInMethod = this.beanClass.getMethod(this.poolInMethodName, null);
+        } else {
+            this.poolInMethod = null;
+        }
+        if ( this.poolOutMethodName != null ) {
+            this.poolOutMethod = this.beanClass.getMethod(this.poolOutMethodName, null);
+        } else {
+            this.poolOutMethod = null;
+        }
+    }
+    /**
+     * Dispose of associated Pools and Factories.
+     */
+    public void dispose() {
+        // Any Poolables in the ready list need to be disposed of
+        synchronized( this.semaphore ) {
+            // Remove objects in the ready list.
+            for( Iterator iter = this.ready.iterator(); iter.hasNext(); ) {
+                Object poolable = iter.next();
+                iter.remove();
+                this.readySize--;
+                this.permanentlyRemovePoolable( poolable );
+            }
+        }
+    }
+    
+    /**
+     * Permanently removes a poolable from the pool's active list and
+     *  destroys it so that it will not ever be reused.
+     * <p>
+     * This method is only called by threads that have m_semaphore locked.
+     */
+    protected void permanentlyRemovePoolable( Object poolable ) {
+        this.size--;
+    }
+
+    /**
+     * Gets a Poolable from the pool.  If there is room in the pool, a new Poolable will be
+     *  created.  Depending on the parameters to the constructor, the method may block or throw
+     *  an exception if a Poolable is not available on the pool.
+     *
+     * @return Always returns a Poolable.  Contract requires that put must always be called with
+     *  the Poolable returned.
+     * @throws Exception An exception may be thrown as described above or if there is an exception
+     *  thrown by the ObjectFactory's newInstance() method.
+     */
+    protected Object getFromPool() throws Exception {
+        Object poolable;
+        synchronized( this.semaphore ) {
+            // Look for a Poolable at the end of the m_ready list
+            if ( this.readySize > 0 ){
+                // A poolable is ready and waiting in the pool
+                poolable = this.ready.removeLast();
+                this.readySize--;
+            } else {
+                // Create a new poolable.  May throw an exception if the poolable can not be
+                //  instantiated.
+                poolable = this.beanFactory.getBean(this.name);
+                this.size++;
+                this.highWaterMark = (this.highWaterMark < this.size ? this.size : this.highWaterMark);
+            }
+        }
+
+        this.exitingPool(poolable);
+
+        return poolable;
+    }
+
+    /**
+     * Returns a poolable to the pool 
+     *
+     * @param poolable Poolable to return to the pool.
+     */
+    protected void putIntoPool( final Object poolable ) {
+        try {
+            this.enteringPool(poolable);
+        } catch (Exception ignore) {
+            // ignore this
+        }
+
+        synchronized( this.semaphore ) {
+            if( this.size <= this.max ) {
+                this.ready.addLast( poolable );
+                this.readySize++;
+            } else {
+                // More Poolables were created than can be held in the pool, so remove.
+                this.permanentlyRemovePoolable( poolable );
+            }
+        }
+    }
+
+    /**
+     * Handle service specific methods for getting it out of the pool
+     */
+    public void exitingPool( final Object component )
+    throws Exception {
+        if ( this.poolOutMethod != null ) {
+            this.poolOutMethod.invoke(component, null);
+        }         
+    }
+
+    /**
+     * Handle service specific methods for putting it into the pool
+     */
+    public void enteringPool( final Object component )
+    throws Exception {
+        // Handle Recyclable objects
+        if( component instanceof Recyclable ) {
+            ( (Recyclable)component ).recycle();
+        }
+        if ( this.poolInMethod != null ) {
+            this.poolInMethod.invoke(component, null);
+        }         
+    }
+
+    /**
+     * @see org.springframework.beans.factory.BeanFactoryAware#setBeanFactory(org.springframework.beans.factory.BeanFactory)
+     */
+    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
+        this.beanFactory = beanFactory; 
+    }
+
+    /**
+     * @see org.springframework.beans.factory.FactoryBean#getObject()
+     */
+    public Object getObject() throws Exception {
+        return Proxy.newProxyInstance(this.getClass().getClassLoader(),
+                                      this.interfaces, 
+                                      new ProxyHandler(this));
+    }
+
+    /**
+     * @see org.springframework.beans.factory.FactoryBean#getObjectType()
+     */
+    public Class getObjectType() {
+        return this.beanClass;
+    }
+
+    /**
+     * @see org.springframework.beans.factory.FactoryBean#isSingleton()
+     */
+    public boolean isSingleton() {
+        return false;
+    }
+
+    /**
+     * Get a list of interfaces to proxy by scanning through
+     * all interfaces a class implements.
+     *
+     * @param clazz           the class
+     * @param workInterfaces  the set of current work interfaces
+     */
+    private void guessWorkInterfaces( final Class clazz,
+                                      final Set workInterfaces ) {
+        if ( null != clazz ) {
+            this.addInterfaces( clazz.getInterfaces(), workInterfaces );
+
+            this.guessWorkInterfaces( clazz.getSuperclass(), workInterfaces );
+        }
+    }
+
+    /**
+     * Get a list of interfaces to proxy by scanning through
+     * all interfaces a class implements.
+     *
+     * @param interfaces      the array of interfaces
+     * @param workInterfaces  the set of current work interfaces
+     */
+    private void addInterfaces( final Class[] interfaces,
+                                final Set workInterfaces ) {
+        for ( int i = 0; i < interfaces.length; i++ ) {
+            workInterfaces.add( interfaces[i] );
+            this.addInterfaces(interfaces[i].getInterfaces(), workInterfaces);
+        }
+    }
+
+    protected static final class ProxyHandler implements InvocationHandler, Core.CleanupTask {
+        
+        private final ThreadLocal componentHolder = new ThreadLocal();
+        private final PoolableFactoryBean handler;
+
+        public ProxyHandler(PoolableFactoryBean handler) {
+            this.handler = handler;
+        }
+        
+        /**
+         * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])
+         */
+        public Object invoke(Object proxy, Method method, Object[] args)
+        throws Throwable {
+            if ( method.getName().equals("hashCode") && args == null ) {
+                return new Integer(this.hashCode());
+            }
+            if ( this.componentHolder.get() == null ) {
+                this.componentHolder.set(this.handler.getFromPool());
+                Core.addCleanupTask(this);
+            }
+            try {
+                return method.invoke(this.componentHolder.get(), args);
+            } catch (InvocationTargetException ite) {
+                throw ite.getTargetException();
+            }
+        }
+        
+        
+        /**
+         * @see org.apache.cocoon.core.Core.CleanupTask#invoke()
+         */
+        public void invoke() {
+            try {
+                final Object o = this.componentHolder.get();
+                this.handler.putIntoPool(o);
+            } catch (Exception ignore) {
+                // we ignore this
+            }
+            this.componentHolder.set(null);
+        }
+    }
+    
+    
+}

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

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

Added: 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=377366&view=auto
==============================================================================
--- cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/XmlConfigCreator.java (added)
+++ cocoon/trunk/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/XmlConfigCreator.java Mon Feb 13 04:37:14 2006
@@ -0,0 +1,174 @@
+/*
+ * Copyright 2006 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.container.spring;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.avalon.framework.service.ServiceManager;
+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
+ * @version $Id$
+ */
+public class XmlConfigCreator {
+
+    protected static final String XMLHEADER = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
+    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) 
+    throws Exception {
+        final List pooledRoles = new ArrayList();
+        final StringBuffer buffer = new StringBuffer();
+        buffer.append(XMLHEADER);
+        buffer.append(DOCTYPE);
+        buffer.append("<beans>\n");
+
+        // start with "static" components: ServiceManager
+        buffer.append("<bean");
+        this.appendAttribute(buffer, "id", ServiceManager.class.getName());
+        this.appendAttribute(buffer, "class", AvalonServiceManager.class.getName());
+        buffer.append("/>\n");
+
+        final Iterator i = components.entrySet().iterator();
+        while ( i.hasNext() ) {
+            final Map.Entry entry = (Map.Entry)i.next();
+            final ComponentInfo current = (ComponentInfo)entry.getValue();
+            final String role = current.getRole();
+    
+            String className = current.getServiceClassName();
+            boolean isSelector = false;
+            boolean singleton = true;
+            boolean poolable = false;
+            // Test for Selector - we skip them
+            if ( className.equals("org.apache.cocoon.core.container.DefaultServiceSelector")
+                 || className.equals("org.apache.cocoon.components.treeprocessor.sitemap.ComponentsSelector") ) {
+                // Add selector
+                className = AvalonServiceSelector.class.getName();
+                isSelector = true;
+            } else {
+                if ( current.getModel() == ComponentInfo.MODEL_NON_THREAD_SAFE_POOLED 
+                    || current.getModel() == ComponentInfo.MODEL_POOLED ) {
+                    poolable = true;
+                    singleton = false;
+                } else if ( current.getModel() != ComponentInfo.MODEL_SINGLETON ) {
+                    singleton = false;
+                }
+            }
+            buffer.append("<bean");
+            if ( !poolable ) {
+                this.appendAttribute(buffer, "name", this.xml(role));
+            } else {
+                this.appendAttribute(buffer, "name", this.xml(role + "Pooled"));                
+            }
+            this.appendAttribute(buffer, "class", className);
+            this.appendAttribute(buffer, "init-method", current.getInitMethodName());
+            this.appendAttribute(buffer, "destroy-method", current.getDestroyMethodName());
+            this.appendAttribute(buffer, "singleton", String.valueOf(singleton));
+            if ( !isSelector ) {
+                buffer.append("/>\n");
+            } else {
+                buffer.append(">\n");
+                buffer.append("  <constructor-arg ref=\"");
+                buffer.append(ServiceManager.class.getName());
+                buffer.append("\"/>\n");
+                buffer.append("  <constructor-arg type=\"java.lang.String\"><value>");
+                buffer.append(role.substring(0, role.length()-8));
+                buffer.append("</value></constructor-arg>\n");
+                if ( current.getConfiguration() != null
+                     && current.getConfiguration().getAttribute("default", null) != null ) {
+                    buffer.append("  <property name=\"default\"><value>");
+                    buffer.append(current.getConfiguration().getAttribute("default"));
+                    buffer.append("</value></property>\n");
+                }
+                buffer.append("</bean>\n");
+            }
+            if ( poolable ) {
+                // add the factory for poolables
+                buffer.append("<bean");
+                this.appendAttribute(buffer, "name", this.xml(role));
+                this.appendAttribute(buffer, "class", PoolableFactoryBean.class.getName());
+                this.appendAttribute(buffer, "singleton", "true");
+                this.appendAttribute(buffer, "init-method", "initialize");
+                this.appendAttribute(buffer, "destroy-method", "dispose");
+                buffer.append(">\n");
+                buffer.append("  <constructor-arg type=\"java.lang.String\"><value>");
+                buffer.append(this.xml(role) + "Pooled");
+                buffer.append("</value></constructor-arg>\n");
+                buffer.append("  <constructor-arg type=\"java.lang.String\"><value>");
+                buffer.append(className);
+                buffer.append("</value></constructor-arg>\n");
+                if ( current.getConfiguration() != null ) {
+                    final String poolMax = current.getConfiguration().getAttribute("pool-max", null);
+                    if ( poolMax != null ) {
+                        buffer.append("  <constructor-arg><value>");
+                        buffer.append(poolMax);
+                        buffer.append("</value></constructor-arg>\n");
+                    }
+                }
+                if ( current.getPoolInMethodName() != null ) {
+                    buffer.append("  <property name=\"poolInMethodName\"><value>");
+                    buffer.append(current.getPoolInMethodName());
+                    buffer.append("</value></property>\n");
+                }
+                if ( current.getPoolOutMethodName() != null ) {
+                    buffer.append("<property name=\"poolOutMethodName\"><value>");
+                    buffer.append(current.getPoolOutMethodName());
+                    buffer.append("</property>\n");
+                }
+                buffer.append("</bean>\n");
+                pooledRoles.add(role);
+            }
+        }
+        buffer.append("</beans>\n");
+
+        // now change roles for pooled components (from {role} to {role}Pooled
+        final Iterator prI = pooledRoles.iterator();
+        while ( prI.hasNext() ) {
+            final String role = (String)prI.next();
+            final Object info = components.remove(role);
+            components.put(role + "Pooled", info);
+        }
+        return buffer.toString();
+    }
+
+    protected String xml(String value) {
+        value = StringUtils.replace(value, "&", "&amp;");
+        value = StringUtils.replace(value, "<", "&lt;");
+        value = StringUtils.replace(value, ">", "&gt;");
+        return value;
+    }
+
+    protected void appendAttribute(StringBuffer buffer, String attr, String value) {
+        if ( value != null ) {
+            buffer.append(' ');
+            buffer.append(attr);
+            buffer.append("=\"");
+            buffer.append(value);
+            buffer.append("\"");
+        }
+    }
+}

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

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