001/*
002 * Copyright 2002-2012 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.context.access;
018
019import javax.naming.NamingException;
020
021import org.springframework.beans.BeansException;
022import org.springframework.beans.factory.access.BeanFactoryLocator;
023import org.springframework.beans.factory.access.BeanFactoryReference;
024import org.springframework.beans.factory.access.BootstrapException;
025import org.springframework.context.ApplicationContext;
026import org.springframework.context.support.ClassPathXmlApplicationContext;
027import org.springframework.jndi.JndiLocatorSupport;
028import org.springframework.util.StringUtils;
029
030/**
031 * BeanFactoryLocator implementation that creates the BeanFactory from one or
032 * more classpath locations specified in a JNDI environment variable.
033 *
034 * <p>This default implementation creates a
035 * {@link org.springframework.context.support.ClassPathXmlApplicationContext}.
036 * Subclasses may override {@link #createBeanFactory} for custom instantiation.
037 *
038 * @author Colin Sampaleanu
039 * @author Juergen Hoeller
040 * @see #createBeanFactory
041 */
042public class ContextJndiBeanFactoryLocator extends JndiLocatorSupport implements BeanFactoryLocator {
043
044        /**
045         * Any number of these characters are considered delimiters between
046         * multiple bean factory config paths in a single String value.
047         */
048        public static final String BEAN_FACTORY_PATH_DELIMITERS = ",; \t\n";
049
050
051        /**
052         * Load/use a bean factory, as specified by a factory key which is a JNDI
053         * address, of the form {@code java:comp/env/ejb/BeanFactoryPath}. The
054         * contents of this JNDI location must be a string containing one or more
055         * classpath resource names (separated by any of the delimiters '{@code ,; \t\n}'
056         * if there is more than one. The resulting BeanFactory (or ApplicationContext)
057         * will be created from the combined resources.
058         * @see #createBeanFactory
059         */
060        @Override
061        public BeanFactoryReference useBeanFactory(String factoryKey) throws BeansException {
062                try {
063                        String beanFactoryPath = lookup(factoryKey, String.class);
064                        if (logger.isTraceEnabled()) {
065                                logger.trace("Bean factory path from JNDI environment variable [" + factoryKey +
066                                                "] is: " + beanFactoryPath);
067                        }
068                        String[] paths = StringUtils.tokenizeToStringArray(beanFactoryPath, BEAN_FACTORY_PATH_DELIMITERS);
069                        return createBeanFactory(paths);
070                }
071                catch (NamingException ex) {
072                        throw new BootstrapException("Define an environment variable [" + factoryKey + "] containing " +
073                                        "the class path locations of XML bean definition files", ex);
074                }
075        }
076
077        /**
078         * Create the BeanFactory instance, given an array of class path resource Strings
079         * which should be combined. This is split out as a separate method so that
080         * subclasses can override the actual BeanFactory implementation class.
081         * <p>Delegates to {@code createApplicationContext} by default,
082         * wrapping the result in a ContextBeanFactoryReference.
083         * @param resources an array of Strings representing classpath resource names
084         * @return the created BeanFactory, wrapped in a BeanFactoryReference
085         * (for example, a ContextBeanFactoryReference wrapping an ApplicationContext)
086         * @throws BeansException if factory creation failed
087         * @see #createApplicationContext
088         * @see ContextBeanFactoryReference
089         */
090        protected BeanFactoryReference createBeanFactory(String[] resources) throws BeansException {
091                ApplicationContext ctx = createApplicationContext(resources);
092                return new ContextBeanFactoryReference(ctx);
093        }
094
095        /**
096         * Create the ApplicationContext instance, given an array of class path resource
097         * Strings which should be combined
098         * @param resources an array of Strings representing classpath resource names
099         * @return the created ApplicationContext
100         * @throws BeansException if context creation failed
101         */
102        protected ApplicationContext createApplicationContext(String[] resources) throws BeansException {
103                return new ClassPathXmlApplicationContext(resources);
104        }
105
106}