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.beans.factory.support;
018:
019: import org.springframework.beans.MutablePropertyValues;
020: import org.springframework.beans.factory.BeanDefinitionStoreException;
021: import org.springframework.beans.factory.BeanFactoryUtils;
022: import org.springframework.beans.factory.config.BeanDefinition;
023: import org.springframework.beans.factory.config.BeanDefinitionHolder;
024: import org.springframework.beans.factory.config.ConstructorArgumentValues;
025: import org.springframework.util.ClassUtils;
026: import org.springframework.util.ObjectUtils;
027: import org.springframework.util.StringUtils;
028:
029: /**
030: * Utility methods that are useful for bean definition reader implementations.
031: * Mainly intended for internal use.
032: *
033: * @author Juergen Hoeller
034: * @author Rob Harrop
035: * @since 1.1
036: * @see PropertiesBeanDefinitionReader
037: * @see org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader
038: */
039: public class BeanDefinitionReaderUtils {
040:
041: /**
042: * Separator for generated bean names. If a class name or parent name is not
043: * unique, "#1", "#2" etc will be appended, until the name becomes unique.
044: */
045: public static final String GENERATED_BEAN_NAME_SEPARATOR = BeanFactoryUtils.GENERATED_BEAN_NAME_SEPARATOR;
046:
047: /**
048: * Create a new GenericBeanDefinition for the given
049: * class name, parent, constructor arguments, and property values.
050: * @param className the name of the bean class, if any
051: * @param parentName the name of the parent bean, if any
052: * @param cargs the constructor arguments, if any
053: * @param pvs the property values, if any
054: * @param classLoader the ClassLoader to use for loading bean classes
055: * (can be <code>null</code> to just register bean classes by name)
056: * @return the bean definition
057: * @throws ClassNotFoundException if the bean class could not be loaded
058: * @deprecated in favor of <code>createBeanDefinition(String, String, ClassLoader)</code>
059: * @see #createBeanDefinition(String, String, ClassLoader)
060: */
061: public static AbstractBeanDefinition createBeanDefinition(
062: String className, String parentName,
063: ConstructorArgumentValues cargs, MutablePropertyValues pvs,
064: ClassLoader classLoader) throws ClassNotFoundException {
065:
066: AbstractBeanDefinition bd = createBeanDefinition(parentName,
067: className, classLoader);
068: bd.setConstructorArgumentValues(cargs);
069: bd.setPropertyValues(pvs);
070: return bd;
071: }
072:
073: /**
074: * Create a new GenericBeanDefinition for the given parent name and class name,
075: * eagerly loading the bean class if a ClassLoader has been specified.
076: * @param parentName the name of the parent bean, if any
077: * @param className the name of the bean class, if any
078: * @param classLoader the ClassLoader to use for loading bean classes
079: * (can be <code>null</code> to just register bean classes by name)
080: * @return the bean definition
081: * @throws ClassNotFoundException if the bean class could not be loaded
082: */
083: public static AbstractBeanDefinition createBeanDefinition(
084: String parentName, String className, ClassLoader classLoader)
085: throws ClassNotFoundException {
086:
087: GenericBeanDefinition bd = new GenericBeanDefinition();
088: bd.setParentName(parentName);
089: if (className != null) {
090: if (classLoader != null) {
091: bd.setBeanClass(ClassUtils.forName(className,
092: classLoader));
093: } else {
094: bd.setBeanClassName(className);
095: }
096: }
097: return bd;
098: }
099:
100: /**
101: * Generate a bean name for the given bean definition, unique within the
102: * given bean factory.
103: * @param definition the bean definition to generate a bean name for
104: * @param registry the bean factory that the definition is going to be
105: * registered with (to check for existing bean names)
106: * @param isInnerBean whether the given bean definition will be registered
107: * as inner bean or as top-level bean (allowing for special name generation
108: * for inner beans versus top-level beans)
109: * @return the generated bean name
110: * @throws BeanDefinitionStoreException if no unique name can be generated
111: * for the given bean definition
112: */
113: public static String generateBeanName(BeanDefinition definition,
114: BeanDefinitionRegistry registry, boolean isInnerBean)
115: throws BeanDefinitionStoreException {
116:
117: String generatedBeanName = definition.getBeanClassName();
118: if (generatedBeanName == null) {
119: if (definition.getParentName() != null) {
120: generatedBeanName = definition.getParentName()
121: + "$child";
122: } else if (definition.getFactoryBeanName() != null) {
123: generatedBeanName = definition.getFactoryBeanName()
124: + "$created";
125: }
126: }
127: if (!StringUtils.hasText(generatedBeanName)) {
128: throw new BeanDefinitionStoreException(
129: "Unnamed bean definition specifies neither "
130: + "'class' nor 'parent' nor 'factory-bean' - can't generate bean name");
131: }
132:
133: String id = generatedBeanName;
134: if (isInnerBean) {
135: // Inner bean: generate identity hashcode suffix.
136: id = generatedBeanName + GENERATED_BEAN_NAME_SEPARATOR
137: + ObjectUtils.getIdentityHexString(definition);
138: } else {
139: // Top-level bean: use plain class name.
140: // Increase counter until the id is unique.
141: int counter = -1;
142: while (counter == -1 || registry.containsBeanDefinition(id)) {
143: counter++;
144: id = generatedBeanName + GENERATED_BEAN_NAME_SEPARATOR
145: + counter;
146: }
147: }
148: return id;
149: }
150:
151: /**
152: * Generate a bean name for the given top-level bean definition,
153: * unique within the given bean factory.
154: * @param beanDefinition the bean definition to generate a bean name for
155: * @param registry the bean factory that the definition is going to be
156: * registered with (to check for existing bean names)
157: * @return the generated bean name
158: * @throws BeanDefinitionStoreException if no unique name can be generated
159: * for the given bean definition
160: */
161: public static String generateBeanName(
162: BeanDefinition beanDefinition,
163: BeanDefinitionRegistry registry)
164: throws BeanDefinitionStoreException {
165:
166: return generateBeanName(beanDefinition, registry, false);
167: }
168:
169: /**
170: * Register the given bean definition with the given bean factory.
171: * @param definitionHolder the bean definition including name and aliases
172: * @param registry the bean factory to register with
173: * @throws BeanDefinitionStoreException if registration failed
174: */
175: public static void registerBeanDefinition(
176: BeanDefinitionHolder definitionHolder,
177: BeanDefinitionRegistry registry)
178: throws BeanDefinitionStoreException {
179:
180: // Register bean definition under primary name.
181: String beanName = definitionHolder.getBeanName();
182: registry.registerBeanDefinition(beanName, definitionHolder
183: .getBeanDefinition());
184:
185: // Register aliases for bean name, if any.
186: String[] aliases = definitionHolder.getAliases();
187: if (aliases != null) {
188: for (int i = 0; i < aliases.length; i++) {
189: registry.registerAlias(beanName, aliases[i]);
190: }
191: }
192: }
193:
194: /**
195: * Register the given bean definition with a generated name,
196: * unique within the given bean factory.
197: * @param definition the bean definition to generate a bean name for
198: * @param registry the bean factory to register with
199: * @return the generated bean name
200: * @throws BeanDefinitionStoreException if no unique name can be generated
201: * for the given bean definition or the definition cannot be registered
202: */
203: public static String registerWithGeneratedName(
204: AbstractBeanDefinition definition,
205: BeanDefinitionRegistry registry)
206: throws BeanDefinitionStoreException {
207:
208: String generatedName = generateBeanName(definition, registry,
209: false);
210: registry.registerBeanDefinition(generatedName, definition);
211: return generatedName;
212: }
213:
214: }
|