001: /*
002: * Copyright 2002-2007 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: * http://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:
017: package org.springframework.context.access;
018:
019: import java.util.HashMap;
020: import java.util.Map;
021:
022: import org.springframework.beans.BeansException;
023: import org.springframework.beans.factory.BeanFactory;
024: import org.springframework.beans.factory.access.BeanFactoryLocator;
025: import org.springframework.beans.factory.access.SingletonBeanFactoryLocator;
026: import org.springframework.context.ConfigurableApplicationContext;
027: import org.springframework.context.support.ClassPathXmlApplicationContext;
028: import org.springframework.core.io.support.ResourcePatternResolver;
029: import org.springframework.core.io.support.ResourcePatternUtils;
030:
031: /**
032: * <p>Variant of {@link org.springframework.beans.factory.access.SingletonBeanFactoryLocator}
033: * which creates its internal bean factory reference as an
034: * {@link org.springframework.context.ApplicationContext} instead of
035: * SingletonBeanFactoryLocator's simple BeanFactory. For almost all usage scenarios,
036: * this will not make a difference, since within that ApplicationContext or BeanFactory
037: * you are still free to define either BeanFactory or ApplicationContext instances.
038: * The main reason one would need to use this class is if bean post-processing
039: * (or other ApplicationContext specific features are needed in the bean reference
040: * definition itself).
041: *
042: * <p><strong>Note:</strong> This class uses <strong>classpath*:beanRefContext.xml</strong>
043: * as the default resource location for the bean factory reference definition files.
044: * It is not possible nor legal to share definitions with SingletonBeanFactoryLocator
045: * at the same time.
046: *
047: * @author Colin Sampaleanu
048: * @author Juergen Hoeller
049: * @see org.springframework.beans.factory.access.SingletonBeanFactoryLocator
050: * @see org.springframework.context.access.DefaultLocatorFactory
051: */
052: public class ContextSingletonBeanFactoryLocator extends
053: SingletonBeanFactoryLocator {
054:
055: private static final String DEFAULT_RESOURCE_LOCATION = "classpath*:beanRefContext.xml";
056:
057: /** The keyed singleton instances */
058: private static final Map instances = new HashMap();
059:
060: /**
061: * Returns an instance which uses the default "classpath*:beanRefContext.xml", as
062: * the name of the definition file(s). All resources returned by the current
063: * thread's context class loader's <code>getResources</code> method with this
064: * name will be combined to create a definition, which is just a BeanFactory.
065: * @return the corresponding BeanFactoryLocator instance
066: * @throws BeansException in case of factory loading failure
067: */
068: public static BeanFactoryLocator getInstance()
069: throws BeansException {
070: return getInstance(null);
071: }
072:
073: /**
074: * Returns an instance which uses the the specified selector, as the name of the
075: * definition file(s). In the case of a name with a Spring "classpath*:" prefix,
076: * or with no prefix, which is treated the same, the current thread's context class
077: * loader's <code>getResources</code> method will be called with this value to get
078: * all resources having that name. These resources will then be combined to form a
079: * definition. In the case where the name uses a Spring "classpath:" prefix, or
080: * a standard URL prefix, then only one resource file will be loaded as the
081: * definition.
082: * @param selector the location of the resource(s) which will be read and
083: * combined to form the definition for the BeanFactoryLocator instance.
084: * Any such files must form a valid ApplicationContext definition.
085: * @return the corresponding BeanFactoryLocator instance
086: * @throws BeansException in case of factory loading failure
087: */
088: public static BeanFactoryLocator getInstance(String selector)
089: throws BeansException {
090: String resourceLocation = selector;
091: if (resourceLocation == null) {
092: resourceLocation = DEFAULT_RESOURCE_LOCATION;
093: }
094:
095: // For backwards compatibility, we prepend "classpath*:" to the selector name if there
096: // is no other prefix (i.e. "classpath*:", "classpath:", or some URL prefix).
097: if (!ResourcePatternUtils.isUrl(resourceLocation)) {
098: resourceLocation = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX
099: + resourceLocation;
100: }
101:
102: synchronized (instances) {
103: if (logger.isTraceEnabled()) {
104: logger
105: .trace("ContextSingletonBeanFactoryLocator.getInstance(): instances.hashCode="
106: + instances.hashCode()
107: + ", instances="
108: + instances);
109: }
110: BeanFactoryLocator bfl = (BeanFactoryLocator) instances
111: .get(resourceLocation);
112: if (bfl == null) {
113: bfl = new ContextSingletonBeanFactoryLocator(
114: resourceLocation);
115: instances.put(resourceLocation, bfl);
116: }
117: return bfl;
118: }
119: }
120:
121: /**
122: * Constructor which uses the the specified name as the resource name
123: * of the definition file(s).
124: * @param resourceLocation the Spring resource location to use
125: * (either a URL or a "classpath:" / "classpath*:" pseudo URL)
126: */
127: protected ContextSingletonBeanFactoryLocator(String resourceLocation) {
128: super (resourceLocation);
129: }
130:
131: /**
132: * Overrides the default method to create definition object as an ApplicationContext
133: * instead of the default BeanFactory. This does not affect what can actually
134: * be loaded by that definition.
135: * <p>The default implementation simply builds a
136: * {@link org.springframework.context.support.ClassPathXmlApplicationContext}.
137: */
138: protected BeanFactory createDefinition(String resourceLocation,
139: String factoryKey) {
140: return new ClassPathXmlApplicationContext(
141: new String[] { resourceLocation }, false);
142: }
143:
144: /**
145: * Overrides the default method to refresh the ApplicationContext, invoking
146: * {@link ConfigurableApplicationContext#refresh ConfigurableApplicationContext.refresh()}.
147: */
148: protected void initializeDefinition(BeanFactory groupDef) {
149: if (groupDef instanceof ConfigurableApplicationContext) {
150: ((ConfigurableApplicationContext) groupDef).refresh();
151: }
152: }
153:
154: /**
155: * Overrides the default method to operate on an ApplicationContext, invoking
156: * {@link ConfigurableApplicationContext#refresh ConfigurableApplicationContext.close()}.
157: */
158: protected void destroyDefinition(BeanFactory groupDef,
159: String selector) {
160: if (groupDef instanceof ConfigurableApplicationContext) {
161: if (logger.isTraceEnabled()) {
162: logger
163: .trace("Context group with selector '"
164: + selector
165: + "' being released, as there are no more references to it");
166: }
167: ((ConfigurableApplicationContext) groupDef).close();
168: }
169: }
170:
171: }
|