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/08/22 22:33:31 UTC

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

Author: cziegeler
Date: Tue Aug 22 13:33:30 2006
New Revision: 433740

URL: http://svn.apache.org/viewvc?rev=433740&view=rev
Log:
Add factory bean to create avalon context
New implementation to read avalon style configuration files
Update settings handling

Added:
    cocoon/trunk/core/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/avalon/AvalonContextFactoryBean.java   (with props)
    cocoon/trunk/core/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/avalon/ConfigReader.java   (with props)
Modified:
    cocoon/trunk/core/cocoon-core/src/main/java/org/apache/cocoon/core/CoreUtil.java
    cocoon/trunk/core/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/SettingsBeanFactoryPostProcessor.java

Modified: cocoon/trunk/core/cocoon-core/src/main/java/org/apache/cocoon/core/CoreUtil.java
URL: http://svn.apache.org/viewvc/cocoon/trunk/core/cocoon-core/src/main/java/org/apache/cocoon/core/CoreUtil.java?rev=433740&r1=433739&r2=433740&view=diff
==============================================================================
--- cocoon/trunk/core/cocoon-core/src/main/java/org/apache/cocoon/core/CoreUtil.java (original)
+++ cocoon/trunk/core/cocoon-core/src/main/java/org/apache/cocoon/core/CoreUtil.java Tue Aug 22 13:33:30 2006
@@ -247,7 +247,7 @@
      * @param servletContext the Cocoon context
      * @param contextUrl URL for the context
      */
-    private static void addSourceResolverContext(DefaultContext appContext,
+    public static void addSourceResolverContext(DefaultContext appContext,
                                                  ServletContext servletContext,
                                                  String         contextUrl) {
         try {
@@ -267,7 +267,7 @@
      * @param classloader 
      * @throws MalformedURLException
      */
-    private static void addSettingsContext(DefaultContext appContext, Settings settings)
+    public static void addSettingsContext(DefaultContext appContext, Settings settings)
     throws MalformedURLException {
         appContext.put(Constants.CONTEXT_WORK_DIR, new File(settings.getWorkDirectory()));
         appContext.put(Constants.CONTEXT_UPLOAD_DIR, new File(settings.getUploadDirectory()));

Modified: cocoon/trunk/core/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/SettingsBeanFactoryPostProcessor.java
URL: http://svn.apache.org/viewvc/cocoon/trunk/core/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/SettingsBeanFactoryPostProcessor.java?rev=433740&r1=433739&r2=433740&view=diff
==============================================================================
--- cocoon/trunk/core/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/SettingsBeanFactoryPostProcessor.java (original)
+++ cocoon/trunk/core/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/SettingsBeanFactoryPostProcessor.java Tue Aug 22 13:33:30 2006
@@ -20,6 +20,7 @@
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.net.URL;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -34,6 +35,7 @@
 import org.apache.cocoon.configuration.SettingsDefaults;
 import org.apache.cocoon.configuration.impl.MutableSettings;
 import org.apache.cocoon.configuration.impl.PropertyHelper;
+import org.apache.cocoon.core.CoreInitializationException;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.springframework.beans.BeansException;
@@ -76,10 +78,61 @@
         this.servletContext = sContext;
     }
 
-    public void init() {
+    public void init()
+    throws Exception {
         final MutableSettings s = this.createSettings();
         this.initSettingsFiles(s);
+        // update configuration
+        final URL u = this.getConfigFile(s.getConfiguration());
+        s.setConfiguration(u.toExternalForm());
+
+        // settings can't be changed anymore
+        s.makeReadOnly();
         this.settings = s;
+    }
+
+    /**
+     * Get the URL of the main Cocoon configuration file.
+     */
+    protected URL getConfigFile(final String configFileName)
+    throws Exception {
+        if (this.logger.isDebugEnabled()) {
+            this.logger.debug("Using configuration file: " + configFileName);
+        }
+
+        URL result;
+        try {
+            // test if this is a qualified url
+            if (configFileName.indexOf(':') == -1) {
+                result = this.servletContext.getResource(configFileName);
+            } else {
+                result = new URL(configFileName);
+            }
+        } catch (Exception mue) {
+            String msg = "Setting for 'configuration' is invalid : " + configFileName;
+            this.logger.error(msg, mue);
+            throw new CoreInitializationException(msg, mue);
+        }
+
+        if (result == null) {
+            File resultFile = new File(configFileName);
+            if (resultFile.isFile()) {
+                try {
+                    result = resultFile.getCanonicalFile().toURL();
+                } catch (Exception e) {
+                    String msg = "Setting for 'configuration' is invalid : " + configFileName;
+                    this.logger.error(msg, e);
+                    throw new CoreInitializationException(msg, e);
+                }
+            }
+        }
+
+        if (result == null) {
+            String msg = "Setting for 'configuration' doesn't name an existing resource : " + configFileName;
+            this.logger.error(msg);
+            throw new CoreInitializationException(msg);
+        }
+        return result;
     }
 
     /**

Added: cocoon/trunk/core/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/avalon/AvalonContextFactoryBean.java
URL: http://svn.apache.org/viewvc/cocoon/trunk/core/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/avalon/AvalonContextFactoryBean.java?rev=433740&view=auto
==============================================================================
--- cocoon/trunk/core/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/avalon/AvalonContextFactoryBean.java (added)
+++ cocoon/trunk/core/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/avalon/AvalonContextFactoryBean.java Tue Aug 22 13:33:30 2006
@@ -0,0 +1,92 @@
+/*
+ * 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.avalon;
+
+import javax.servlet.ServletContext;
+
+import org.apache.avalon.framework.context.Context;
+import org.apache.avalon.framework.context.DefaultContext;
+import org.apache.cocoon.configuration.Settings;
+import org.apache.cocoon.core.CoreUtil;
+import org.apache.cocoon.core.container.util.ComponentContext;
+import org.springframework.beans.factory.FactoryBean;
+import org.springframework.web.context.ServletContextAware;
+
+/**
+ *
+ * @since 2.2
+ * @version $Id$
+ */
+public class AvalonContextFactoryBean
+    implements FactoryBean, ServletContextAware {
+
+    /** The servlet context. */
+    protected ServletContext servletContext;
+
+    /** The settings. */
+    protected Settings settings;
+
+    protected Context context;
+
+    /**
+     * @see org.springframework.web.context.ServletContextAware#setServletContext(javax.servlet.ServletContext)
+     */
+    public void setServletContext(ServletContext sContext) {
+        this.servletContext = sContext;
+    }
+
+    protected void init()
+    throws Exception {
+        final DefaultContext appContext = new ComponentContext();
+
+        // add root url
+        String contextUrl = CoreUtil.getContextUrl(this.servletContext, "/WEB-INF/web.xml");
+        CoreUtil.addSourceResolverContext(appContext, servletContext, contextUrl);
+
+        // add the Avalon context attributes that are contained in the settings
+        CoreUtil.addSettingsContext(appContext, settings);
+        this.context = appContext;
+    }
+
+    /**
+     * @see org.springframework.beans.factory.FactoryBean#getObject()
+     */
+    public Object getObject() throws Exception {
+        return this.context;
+    }
+
+    /**
+     * @see org.springframework.beans.factory.FactoryBean#getObjectType()
+     */
+    public Class getObjectType() {
+        return Context.class;
+    }
+
+    /**
+     * @see org.springframework.beans.factory.FactoryBean#isSingleton()
+     */
+    public boolean isSingleton() {
+        return true;
+    }
+
+    public Settings getSettings() {
+        return settings;
+    }
+
+    public void setSettings(Settings settings) {
+        this.settings = settings;
+    }
+}

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

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

Added: cocoon/trunk/core/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/avalon/ConfigReader.java
URL: http://svn.apache.org/viewvc/cocoon/trunk/core/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/avalon/ConfigReader.java?rev=433740&view=auto
==============================================================================
--- cocoon/trunk/core/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/avalon/ConfigReader.java (added)
+++ cocoon/trunk/core/cocoon-core/src/main/java/org/apache/cocoon/core/container/spring/avalon/ConfigReader.java Tue Aug 22 13:33:30 2006
@@ -0,0 +1,550 @@
+/*
+ * 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.avalon;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+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.cocoon.core.container.spring.AvalonEnvironment;
+import org.apache.cocoon.core.container.spring.ComponentInfo;
+import org.apache.cocoon.core.container.spring.ConfigurationInfo;
+import org.apache.cocoon.core.container.util.ConfigurationBuilder;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.ResourceLoader;
+import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
+import org.xml.sax.InputSource;
+
+/**
+ * This component reads in Avalon style configuration files and returns all
+ * contained components and their configurations.
+ *
+ * @since 2.2
+ * @version $Id$
+ */
+public class ConfigReader {
+
+    /** Logger (we use the same logging mechanism as Spring!) */
+    protected final Log logger = LogFactory.getLog(getClass());
+
+    /** Resolver for reading configuration files. */
+    protected final PathMatchingResourcePatternResolver resolver;
+
+    /** The configuration info. */
+    protected final ConfigurationInfo configInfo;
+
+    /** Avalon environment. */
+    protected final AvalonEnvironment environment;
+
+    /** All component configurations. */
+    protected final List componentConfigs = new ArrayList();
+
+    public static ConfigurationInfo readConfiguration(String source, AvalonEnvironment env)
+    throws Exception {
+        final ConfigReader converter = new ConfigReader(env, null, null);
+        converter.convert(source);
+        return converter.configInfo;
+    }
+
+    public static ConfigurationInfo readConfiguration(Configuration     config,
+                                                      ConfigurationInfo parentInfo,
+                                                      AvalonEnvironment env,
+                                                      ResourceLoader    resourceLoader)
+    throws Exception {
+        return readConfiguration(config, null, parentInfo, env, resourceLoader);
+    }
+//         PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(new ServletContextResourceLoader(this.servletContext));
+
+    public static ConfigurationInfo readConfiguration(Configuration     rolesConfig,
+                                                      Configuration     componentConfig,
+                                                      ConfigurationInfo parentInfo,
+                                                      AvalonEnvironment env,
+                                                      ResourceLoader    resourceLoader)
+    throws Exception {
+        final ConfigReader converter = new ConfigReader(env, parentInfo, resourceLoader);
+        converter.convert(rolesConfig, componentConfig, null);
+        return converter.configInfo;        
+    }
+
+    private ConfigReader(AvalonEnvironment env,
+                         ConfigurationInfo parentInfo,
+                         ResourceLoader    resourceLoader)
+    throws Exception {
+        if ( resourceLoader != null ) {
+            this.resolver = new PathMatchingResourcePatternResolver(resourceLoader);
+        } else {
+            this.resolver = new PathMatchingResourcePatternResolver();
+        }
+        this.environment = env;
+
+        // now add selectors from parent
+        if ( parentInfo != null ) {
+            this.configInfo = new ConfigurationInfo(parentInfo);
+            final Iterator i = parentInfo.getComponents().values().iterator();
+            while ( i.hasNext() ) {
+                final ComponentInfo current = (ComponentInfo)i.next();
+                if ( current.isSelector() ) {
+                    this.configInfo.addRole(current.getRole(), current.copy());
+                }
+            }
+            // TODO - we should add the processor to each container
+            //        This would avoid the hacky getting of the current container in the tree processor
+            /*
+            ComponentInfo processorInfo = (ComponentInfo) parentInfo.getComponents().get(Processor.ROLE);
+            if ( processorInfo != null ) {
+                this.configInfo.getComponents().put(Processor.ROLE, processorInfo.copy());
+            }
+            */
+        } else {
+            this.configInfo = new ConfigurationInfo();
+        }
+    }
+
+    protected String convertUrl(String url) {
+        if ( url == null ) {
+            return null;
+        }
+        if ( url.startsWith("context:") ) {
+            return url.substring(10);
+        }
+        if ( url.startsWith("resource:") ) {
+            return "classpath:" + url.substring(10);
+        }
+        if ( url.indexOf(':') == -1 && !url.startsWith("/")) {
+            return '/' + url;
+        }
+        return url;
+    }
+
+    protected InputSource getInputSource(Resource rsrc)
+    throws Exception {
+        final InputSource is = new InputSource(rsrc.getInputStream());
+        is.setSystemId(rsrc.getURL().toExternalForm());
+        return is;
+    }
+
+    protected String getUrl(String url, String base) {
+        return url;
+    }
+
+    protected void convert(String relativePath)
+    throws Exception {
+        if ( this.logger.isInfoEnabled() ) {
+            this.logger.info("Reading Avalon configuration from " + relativePath);
+        }
+        Resource root = this.resolver.getResource(this.convertUrl(relativePath));
+        final ConfigurationBuilder b = new ConfigurationBuilder(this.environment.settings);
+        
+        final Configuration config = b.build(this.getInputSource(root));
+            
+        this.convert(config, null, root.getURL().toExternalForm());
+    }
+
+    protected void convert(Configuration config, Configuration additionalConfig, String rootUri)
+    throws Exception {
+        if ( this.logger.isInfoEnabled() ) {
+            this.logger.info("Converting Avalon configuration from configuration object: " + config);
+        }
+        // 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.configInfo.setRootLogger(config.getAttribute("logger", null));
+
+        // and load configuration with a empty list of loaded configurations
+        final Set loadedConfigs = new HashSet();
+        // what is it?
+        if ( "role-list".equals(config.getName()) || "roles".equals(config.getName())) {
+            this.configureRoles(config);
+        } else {
+            this.parseConfiguration(config, null, loadedConfigs);
+        }
+
+        // test for optional user-roles attribute
+        if ( rootUri != null ) {
+            final String userRoles = config.getAttribute("user-roles", null);
+            if (userRoles != null) {
+                if ( this.logger.isInfoEnabled() ) {
+                    this.logger.info("Reading additional user roles: " + userRoles);
+                }
+                final Resource userRolesSource = this.resolver.getResource(this.getUrl(userRoles, rootUri));
+                final ConfigurationBuilder b = new ConfigurationBuilder(this.environment.settings);
+                final Configuration userRolesConfig = b.build(this.getInputSource(userRolesSource));
+                this.parseConfiguration(userRolesConfig, userRolesSource.getURL().toExternalForm(), loadedConfigs);
+            }
+        }
+        if ( additionalConfig != null ) {
+            if ( "role-list".equals(additionalConfig.getName()) || "roles".equals(additionalConfig.getName())) {
+                this.configureRoles(additionalConfig);
+            } else {
+                this.parseConfiguration(additionalConfig, null, loadedConfigs);
+            }
+        }
+
+        // now process all component configurations
+        this.processComponents();
+
+        // add roles as components
+        final Iterator i = this.configInfo.getRoles().iterator();
+        while ( i.hasNext() ) {
+            final ComponentInfo current = (ComponentInfo)i.next();
+            current.setLazyInit(true);
+            this.configInfo.addComponent(current);
+        }
+        this.configInfo.clearRoles();
+    }
+
+    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 if ( "include-beans".equals(componentName) ) {
+                this.handleBeanInclude(contextURI, componentConfig);
+            } else {
+                // Component declaration, add it to list
+                this.componentConfigs.add(componentConfig);
+            }
+        }
+    }
+
+    protected void processComponents()
+    throws ConfigurationException {
+        final Iterator i = this.componentConfigs.iterator();
+        while ( i.hasNext() ) {
+            final Configuration componentConfig = (Configuration)i.next(); 
+            final String componentName = componentConfig.getName();
+
+            // Find the role
+            String role = componentConfig.getAttribute("role", null);
+            String alias = null;
+            if (role == null) {
+                // Get the role from the role manager if not explicitely specified
+                role = (String)this.configInfo.getShorthands().get( componentName );
+                alias = 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);
+            // 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);
+            ComponentInfo info;
+            if (className == null) {
+                // Get the default class name for this role
+                info = this.configInfo.getRole( role );
+                if (info == null) {
+                    if ( this.configInfo.getComponents().get( role) != null ) {
+                        throw new ConfigurationException("Duplicate component definition for role " + role + " at " + componentConfig.getLocation());
+                    }
+                    throw new ConfigurationException("Cannot find a class for role " + role + " at " + componentConfig.getLocation());
+                }
+                className = info.getComponentClassName();
+                if ( name != null ) {
+                    info = info.copy();                    
+                } else if ( !className.endsWith("Selector") ) {
+                    this.configInfo.removeRole(role);
+                }
+            } else {                    
+                info = new ComponentInfo();
+            }
+            // check for name attribute
+            // Note: this has to be done *after* finding the className above as we change the role
+            if (name != null) {
+                role = role + "/" + name;
+                if ( alias != null ) {
+                    alias = alias + '-' + name;
+                }
+            }
+            info.fill(componentConfig);
+            info.setComponentClassName(className);
+            info.setRole(role);
+            if ( alias != null ) {
+                info.setAlias(alias);
+            }
+            info.setConfiguration(componentConfig);
+
+            this.configInfo.addComponent(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 ) {
+                    this.logger.warn("Found unknown selector type (continuing anyway: " + className);
+                } else {
+                    String componentRole = role;
+                    if ( componentRole.endsWith("Selector") ) {
+                        componentRole = componentRole.substring(0, componentRole.length() - 8);
+                    }
+                    componentRole += '/';
+                    Configuration[] children = info.getConfiguration().getChildren();
+                    final Map hintConfigs = (Map)this.configInfo.getKeyClassNames().get(role);                       
+                    for (int j=0; j<children.length; j++) {
+                        final Configuration current = children[j];
+                        final ComponentInfo childInfo = new ComponentInfo();
+                        childInfo.fill(current);
+                        childInfo.setConfiguration(current);
+                        final ComponentInfo hintInfo = (hintConfigs == null ? null : (ComponentInfo)hintConfigs.get(current.getName()));
+                        if ( current.getAttribute(classAttribute, null ) != null 
+                             || hintInfo == null ) {
+                            childInfo.setComponentClassName(current.getAttribute(classAttribute));
+                        } else {
+                            childInfo.setComponentClassName(hintInfo.getComponentClassName());
+                        }
+                        childInfo.setRole(componentRole + current.getAttribute("name"));
+                        this.configInfo.addComponent(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 ) {
+            Resource src = null;
+            try {
+                src = this.resolver.getResource(this.getUrl(includeURI, contextURI));
+
+                this.loadURI(src, loadedURIs, includeStatement);
+            } catch (Exception e) {
+                throw new ConfigurationException("Cannot load '" + includeURI + "' at " + includeStatement.getLocation(), e);
+            }
+            
+        } else {
+            final String pattern = includeStatement.getAttribute("pattern", null);
+            try {
+                Resource[] resources = this.resolver.getResources(this.getUrl(directoryURI + '/' + pattern, contextURI));
+                if ( resources != null ) {
+                    for(int i=0; i < resources.length; i++) {
+                       this.loadURI(resources[i], loadedURIs, includeStatement);
+                    }
+                }
+            } catch (Exception e) {
+                throw new ConfigurationException("Cannot load from directory '" + directoryURI + "' at " + includeStatement.getLocation(), e);
+            }
+        }
+    }
+
+    protected void loadURI(final Resource      src,
+                           final Set           loadedURIs,
+                           final Configuration includeStatement) 
+    throws ConfigurationException, IOException {
+        // If already loaded: do nothing
+        final String uri = src.getURL().toExternalForm();
+
+        if (!loadedURIs.contains(uri)) {
+            if ( this.logger.isInfoEnabled() ) {
+                this.logger.info("Loading configuration: " + 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?
+            final 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());
+            }
+        }
+    }
+
+    protected void handleBeanInclude(final String contextURI,
+                                     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) {
+            Resource src = null;
+            try {
+                src = this.resolver.getResource(this.getUrl(includeURI, contextURI));
+
+                this.configInfo.addImport(src.getURL().toExternalForm());
+            } catch (Exception e) {
+                throw new ConfigurationException("Cannot load '" + includeURI + "' at "
+                        + includeStatement.getLocation(), e);
+            }
+
+        } else {
+            final String pattern = includeStatement.getAttribute("pattern", null);
+            try {
+                Resource[] resources = this.resolver.getResources(this.getUrl(directoryURI + '/' + pattern, contextURI));
+                if ( resources != null ) {
+                    for(int i=0; i < resources.length; i++) {
+                       this.configInfo.addImport(resources[i].getURL().toExternalForm());
+                    }
+                }
+            } catch (IOException ioe) {
+                throw new ConfigurationException("Unable to read configurations from "
+                        + directoryURI);
+            }
+        }
+    }
+
+    /**
+     * 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++ ) {
+            final Configuration role = roles[i];
+
+            if ( "alias".equals(role.getName()) ) {
+                final String roleName = role.getAttribute("role");
+                final String shorthand = role.getAttribute("shorthand");
+                this.configInfo.getShorthands().put(shorthand, roleName);
+                continue;
+            }
+            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.configInfo.getShorthands().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 = this.configInfo.getRole(roleName);
+                if (info == null) {
+                    // Create a new info and store it
+                    info = new ComponentInfo();
+                    info.setComponentClassName(defaultClassName);
+                    info.fill(role);
+                    info.setRole(roleName);
+                    info.setConfiguration(role);
+                    info.setAlias(shorthand);
+                    this.configInfo.addRole(roleName, info);
+                } else {
+                    // Check that it's consistent with the existing info
+                    if (!defaultClassName.equals(info.getComponentClassName())) {
+                        throw new ConfigurationException("Invalid redeclaration: default class already set to " + info.getComponentClassName() +
+                                " 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.configInfo.getKeyClassNames().get(roleName);
+                if (keyMap == null) {
+                    keyMap = new HashMap();
+                    this.configInfo.getKeyClassNames().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.setComponentClassName(className);
+                        info.fill(key);
+                        info.setConfiguration(key);
+                        info.setAlias(shortHand);
+                        keyMap.put( shortHand, info );
+                    } else {
+                        // Check that it's consistent with the existing info
+                        if (!className.equals(info.getComponentClassName())) {
+                            throw new ConfigurationException("Invalid redeclaration: class already set to " + info.getComponentClassName() +
+                                    " for hint " + shortHand + " at " + key.getLocation());
+                        }
+                        //FIXME: should check also other ServiceInfo members
+                    }
+                }
+            }
+        }
+    }
+}

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

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