001    /**
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.xbean.server.spring.loader;
018    
019    import java.io.File;
020    import java.util.Collections;
021    import java.util.Iterator;
022    import java.util.List;
023    
024    import org.apache.xbean.kernel.Kernel;
025    import org.apache.xbean.kernel.ServiceFactory;
026    import org.apache.xbean.kernel.ServiceName;
027    import org.apache.xbean.kernel.StringServiceName;
028    import org.apache.xbean.server.loader.Loader;
029    import org.apache.xbean.server.spring.configuration.SpringConfigurationServiceFactory;
030    import org.apache.xbean.spring.context.FileSystemXmlApplicationContext;
031    import org.apache.xbean.spring.context.SpringApplicationContext;
032    import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
033    import org.springframework.context.support.AbstractXmlApplicationContext;
034    
035    /**
036     * SpringLoader loads Spring xml configurations into a Kernel.  This service uses the XBean version of
037     * FileSystemXmlApplicationContext so custom XML extensions are available.  This loader also support the specification
038     * of SpringXmlPreprocessors and BeanFactoryPostProcessors to apply to the configuration.
039     *
040     * @org.apache.xbean.XBean namespace="http://xbean.apache.org/schemas/server" element="spring-loader"
041     *     description="Loads Spring xml configurations into a Kernel"
042     *
043     * @author Dain Sundstrom
044     * @version $Id$
045     * @since 2.0
046     */
047    public class SpringLoader implements Loader {
048        private Kernel kernel;
049        private File baseDir = new File(".").getAbsoluteFile();
050        private List beanFactoryPostProcessors = Collections.EMPTY_LIST;
051        private List xmlPreprocessors = Collections.EMPTY_LIST;
052        private AbstractXmlApplicationContext applicationContext;  
053    
054        /**
055         * Creates an empty SpringLoader.  Note this loader is not usable until a kernel is specified.
056         */
057        public SpringLoader() {
058        }
059    
060        /**
061         * {@inheritDoc}
062         */
063        public Kernel getKernel() {
064            return kernel;
065        }
066    
067        /**
068         * Sets the kernel in which configurations are loaded.
069         * @param kernel the kernel in which configurations are loaded
070         */
071        public void setKernel(Kernel kernel) {
072            this.kernel = kernel;
073        }
074    
075        /**
076         * Gets the BeanFactoryPostProcessors to apply to the configuration.
077         * @return the BeanFactoryPostProcessors to apply to the configuration
078         */
079        public List getBeanFactoryPostProcessors() {
080            return beanFactoryPostProcessors;
081        }
082    
083        /**
084         * Sets the BeanFactoryPostProcessors to apply to the configuration.
085         * @param beanFactoryPostProcessors the BeanFactoryPostProcessors to apply to the configuration
086         */
087        public void setBeanFactoryPostProcessors(List beanFactoryPostProcessors) {
088            this.beanFactoryPostProcessors = beanFactoryPostProcessors;
089        }
090    
091        /**
092         * Gets the base directory from which configuration locations are resolved.
093         * @return the base directory from which configuration locations are resolved
094         */
095        public File getBaseDir() {
096            return baseDir;
097        }
098    
099        /**
100         * Sets the base directory from which configuration locations are resolved.
101         * @param baseDir the base directory from which configuration locations are resolved
102         */
103        public void setBaseDir(File baseDir) {
104            this.baseDir = baseDir;
105        }
106    
107        /**
108         * Gets the SpringXmlPreprocessors applied to the configuration.
109         * @return the SpringXmlPreprocessors applied to the configuration
110         */
111        public List getXmlPreprocessors() {
112            return xmlPreprocessors;
113        }
114    
115        /**
116         * Sets the SpringXmlPreprocessors applied to the configuration.
117         * @param xmlPreprocessors the SpringXmlPreprocessors applied to the configuration
118         */
119        public void setXmlPreprocessors(List xmlPreprocessors) {
120            this.xmlPreprocessors = xmlPreprocessors;
121        }
122    
123        /**
124         * Loads the specified configuration into the kernel.  The location specifies a file relative to the baseDir using
125         * baseDir.toURI().resolve(location).getPath() + ".xml".  This service uses the XBean version of
126         * FileSystemXmlApplicationContext so custom XML extensions are available.
127         * @param location the location of the configuration file relative to the base directory without the .xml extension
128         * @return the name of the SpringConfiguration service for this location
129         * @throws Exception if a problem occurs while loading the Spring configuration file
130         */
131        public ServiceName load(String location) throws Exception {
132            String resolvedLocation = baseDir.toURI().resolve(location).getPath();
133            String configLocation = "/" + resolvedLocation + ".xml";
134            applicationContext = createXmlApplicationContext(configLocation);
135    
136            for (Iterator iter = beanFactoryPostProcessors.iterator(); iter.hasNext();) {
137                BeanFactoryPostProcessor processor = (BeanFactoryPostProcessor) iter.next();
138                applicationContext.addBeanFactoryPostProcessor(processor);
139            }
140            applicationContext.setDisplayName(location);
141    
142            ClassLoader classLoader = applicationContext.getClassLoader();
143            if (classLoader == null) {
144                classLoader = Thread.currentThread().getContextClassLoader();
145            }
146            if (classLoader == null) {
147                classLoader = SpringLoader.class.getClassLoader();
148            }
149    
150            ServiceName serviceName = new StringServiceName("configuration:" + location);
151            ServiceFactory springConfigurationServiceFactory = new SpringConfigurationServiceFactory(applicationContext);
152            kernel.registerService(serviceName, springConfigurationServiceFactory);
153            return serviceName;
154        }
155    
156        /**
157         * Returns the last Spring application context that was read via the call to {@link #load(String)}
158         */
159        public AbstractXmlApplicationContext getApplicationContext() {
160            return applicationContext;
161        }
162    
163        /**
164         * A factory method for creating the application context
165         */
166        protected AbstractXmlApplicationContext createXmlApplicationContext(String configLocation) {
167            return new FileSystemXmlApplicationContext(
168                    new String[] {configLocation},
169                    false,
170                    xmlPreprocessors);
171        }
172    }