001: /*
002: * Created on 04-Feb-2006
003: */
004:
005: // Some code in this file is subject to the ASF licence, terms follow:
006: /*
007: * Copyright 2002-2004 the original author or authors.
008: *
009: * Licensed under the Apache License, Version 2.0 (the "License");
010: * you may not use this file except in compliance with the License.
011: * You may obtain a copy of the License at
012: *
013: * http://www.apache.org/licenses/LICENSE-2.0
014: *
015: * Unless required by applicable law or agreed to in writing, software
016: * distributed under the License is distributed on an "AS IS" BASIS,
017: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
018: * See the License for the specific language governing permissions and
019: * limitations under the License.
020: */
021: // Under term 4c) of the licence, attribution details taken from the original
022: // source (AbstractBeanFactory.java) are as follows:
023: // * @author Rod Johnson
024: // * @author Juergen Hoeller
025: // * @since 15 April 2001
026: package uk.org.ponder.rsac;
027:
028: import java.lang.reflect.Method;
029: import java.util.List;
030: import java.util.Map;
031:
032: import org.springframework.beans.BeansException;
033: import org.springframework.beans.MutablePropertyValues;
034: import org.springframework.beans.PropertyValue;
035: import org.springframework.beans.factory.NoSuchBeanDefinitionException;
036: import org.springframework.beans.factory.config.BeanDefinition;
037: import org.springframework.beans.factory.config.BeanDefinitionHolder;
038: import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
039: import org.springframework.beans.factory.config.ConstructorArgumentValues;
040: import org.springframework.beans.factory.config.RuntimeBeanReference;
041: import org.springframework.beans.factory.config.TypedStringValue;
042: import org.springframework.beans.factory.support.AbstractBeanDefinition;
043: import org.springframework.beans.factory.support.ManagedList;
044: import org.springframework.beans.factory.support.RootBeanDefinition;
045:
046: import uk.org.ponder.conversion.StringArrayParser;
047: import uk.org.ponder.reflect.ClassGetter;
048: import uk.org.ponder.reflect.ReflectUtils;
049: import uk.org.ponder.saxalizer.AccessMethod;
050: import uk.org.ponder.saxalizer.MethodAnalyser;
051: import uk.org.ponder.saxalizer.SAXAccessMethod;
052: import uk.org.ponder.stringutil.StringList;
053: import uk.org.ponder.util.Logger;
054:
055: public class BeanDefUtil {
056:
057: // NB an IMPORTANT CHANGE from the ABF version is change of references to
058: // AbstractBeanFactory into ConfigurableListableBeanFactory. This considerably
059: // weakens the type generality of our system but is unavoidable since
060: // CLBF is the LOWEST level at which a getBeanDefinition() method is visible
061: // to us, since we are no longer members of ABF. Since in practice we plan
062: // to implement all RSAC using GenericApplicationContexts, this is not a
063: // problem, and anyone who wants to inherit bean definitions FROM application
064: // scope INTO request scope is i) deranged and ii) gets everything they
065: // deserve.
066: static AbstractBeanDefinition getMergedBeanDefinition(
067: ConfigurableListableBeanFactory factory, String beanName,
068: boolean includingAncestors) throws BeansException {
069: try {
070: return getMergedBeanDefinition(factory, beanName, factory
071: .getBeanDefinition(beanName));
072: } catch (NoSuchBeanDefinitionException ex) {
073: if (includingAncestors
074: && factory.getParentBeanFactory() instanceof ConfigurableListableBeanFactory) {
075: return getMergedBeanDefinition(
076: (ConfigurableListableBeanFactory) factory
077: .getParentBeanFactory(), beanName, true);
078: } else {
079: throw ex;
080: }
081: }
082: }
083:
084: // Need resistance for incompatibility in signature of BeanDefinition which
085: // has appeared in Spring 2.1 - this now features the getParentName method which
086: // used only to appear in ChildBeanDefinition. There is now also "GenericBeanDefinition"
087: // which is inherited off the common parent AbstractBeanDefinition.
088: static String getParentDefinitionName(BeanDefinition bd) {
089: try {
090: if (ReflectUtils.hasMethod(bd, "getParentName")) {
091: Method method = bd.getClass().getMethod(
092: "getParentName", SAXAccessMethod.emptyclazz);
093: return (String) method.invoke(bd,
094: SAXAccessMethod.emptyobj);
095: }
096: } catch (Exception e) {
097: }
098: return null;
099: }
100:
101: static AbstractBeanDefinition getMergedBeanDefinition(
102: ConfigurableListableBeanFactory factory, String beanName,
103: BeanDefinition bd) throws BeansException {
104:
105: if (!(bd instanceof AbstractBeanDefinition)) {
106: throw new IllegalArgumentException(
107: "Bean definition "
108: + beanName
109: + " of "
110: + bd.getClass()
111: + " which is not descended from AbstractBeanDefinition can not be recognised");
112: }
113: AbstractBeanDefinition abd = (AbstractBeanDefinition) bd;
114: String parentName = getParentDefinitionName(abd);
115: if (parentName == null) {
116: return abd;
117: } else {
118: AbstractBeanDefinition pbd = null;
119: if (!beanName.equals(parentName)) {
120: pbd = getMergedBeanDefinition(factory, parentName, true);
121: } else {
122: if (factory.getParentBeanFactory() instanceof ConfigurableListableBeanFactory) {
123: ConfigurableListableBeanFactory parentFactory = (ConfigurableListableBeanFactory) factory
124: .getParentBeanFactory();
125: pbd = getMergedBeanDefinition(parentFactory,
126: parentName, true);
127: } else {
128: throw new NoSuchBeanDefinitionException(
129: parentName,
130: "Parent name '"
131: + parentName
132: + "' is equal to bean name '"
133: + beanName
134: + "' - cannot be resolved without an AbstractBeanFactory parent");
135: }
136: }
137:
138: // deep copy with overridden values
139: pbd.overrideFrom(abd);
140: return pbd;
141: }
142:
143: }
144:
145: static RSACBeanInfo convertBeanDef(BeanDefinition origdef,
146: String beanname, ConfigurableListableBeanFactory factory,
147: MethodAnalyser abdAnalyser, BeanDefConverter converter) {
148: RSACBeanInfo rbi = new RSACBeanInfo();
149: AbstractBeanDefinition def = getMergedBeanDefinition(factory,
150: beanname, origdef);
151: MutablePropertyValues pvs = def.getPropertyValues();
152: PropertyValue[] values = pvs.getPropertyValues();
153: for (int j = 0; j < values.length; ++j) {
154: PropertyValue this pv = values[j];
155: Object beannames = BeanDefUtil.propertyValueToBeanName(
156: this pv.getValue(), converter);
157: boolean skip = false;
158: // skip recording the dependency if it was unresolvable (some
159: // unrecognised
160: // type) or was a single-valued type referring to a static dependency.
161: // NB - we now record ALL dependencies - bean-copying strategy
162: // discontinued.
163: if (beannames == null
164: // || beannames instanceof String
165: // && !blankcontext.containsBean((String) beannames)
166: ) {
167: skip = true;
168: }
169: if (!skip) {
170: rbi.recordDependency(this pv.getName(), beannames);
171: }
172: }
173: // NB - illegal cast here is unavoidable.
174: // Bit of a problem here with Spring flow - apparently the bean class
175: // will NOT be set for a "factory-method" bean UNTIL it has been
176: // instantiated
177: // via the logic in AbstractAutowireCapableBeanFactory l.376:
178: // protected BeanWrapper instantiateUsingFactoryMethod(
179: AbstractBeanDefinition abd = def;
180: rbi.factorybean = abd.getFactoryBeanName();
181: rbi.factorymethod = abd.getFactoryMethodName();
182: rbi.initmethod = abd.getInitMethodName();
183: rbi.destroymethod = abd.getDestroyMethodName();
184: rbi.islazyinit = abd.isLazyInit();
185: rbi.dependson = abd.getDependsOn();
186: rbi.issingleton = abd.isSingleton();
187: rbi.isabstract = abd.isAbstract();
188: rbi.aliases = factory.containsBeanDefinition(beanname) ? factory
189: .getAliases(beanname)
190: : StringArrayParser.EMPTY_STRINGL;
191: if (abd.hasConstructorArgumentValues()) {
192: ConstructorArgumentValues cav = abd
193: .getConstructorArgumentValues();
194: boolean hasgeneric = !cav.getGenericArgumentValues()
195: .isEmpty();
196: boolean hasindexed = !cav.getIndexedArgumentValues()
197: .isEmpty();
198: if (hasgeneric && hasindexed) {
199: throw new UnsupportedOperationException(
200: "RSAC Bean "
201: + beanname
202: + " has both indexed and generic constructor arguments, which is not supported");
203: }
204: if (hasgeneric) {
205: List cvalues = cav.getGenericArgumentValues();
206: rbi.constructorargvals = new ConstructorArgumentValues.ValueHolder[cvalues
207: .size()];
208: for (int i = 0; i < cvalues.size(); ++i) {
209: rbi.constructorargvals[i] = (ConstructorArgumentValues.ValueHolder) cvalues
210: .get(i);
211: }
212: } else if (hasindexed) {
213: Map cvalues = cav.getIndexedArgumentValues();
214: rbi.constructorargvals = new ConstructorArgumentValues.ValueHolder[cvalues
215: .size()];
216: for (int i = 0; i < cvalues.size(); ++i) {
217: rbi.constructorargvals[i] = (ConstructorArgumentValues.ValueHolder) cvalues
218: .get(new Integer(i));
219: }
220: }
221: }
222: if (rbi.factorymethod == null) {
223: // Core Spring change at 2.0M5 - ALL bean classes are now irrevocably
224: // lazy!!
225: // Package org.springframework.beans
226: // introduced lazy loading (and lazy validation) of bean classes in
227: // standard bean factories and bean definition readers
228: AccessMethod bcnaccess = abdAnalyser
229: .getAccessMethod("beanClassName");
230: if (bcnaccess != null) {
231: String bcn = (String) bcnaccess.getChildObject(abd);
232: if (bcn != null) {
233: rbi.beanclass = ClassGetter.forName(bcn);
234: }
235: } else {
236: // all right then BE like that! We'll work out the class later.
237: // NB - beandef.getBeanClass() was eliminated around 1.2, we must
238: // use the downcast even earlier now.
239: rbi.beanclass = abd.getBeanClass();
240: }
241: }
242: return rbi;
243: }
244:
245: // magic evil code from AbstractBeanFactory l.443 - this is the main reason
246: // I abandoned Spring Forms and the like, and it will return to plague us.
247: // Just take a look at the constructor for BeanWrapperImpl - one of these
248: // is created for EVERY BEAN IN A FACTORY!
249:
250: // protected BeanWrapper createBeanWrapper(Object beanInstance) {
251: // return (beanInstance != null ? new BeanWrapperImpl(beanInstance) : new
252: // BeanWrapperImpl());
253: // }
254:
255: // this method is really
256: // resolveValueIfNecessary **LITE**, we assume all other resolution
257: // is done by the parent factory and are ONLY interested in propertyvalues
258: // that refer to other beans IN THIS CONTAINER.
259: // org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory
260: // l.900:
261: // protected Object resolveValueIfNecessary(
262: // String beanName, RootBeanDefinition mergedBeanDefinition, String argName,
263: // Object value)
264: // throws BeansException {
265: // Since actual values are the rarer case, make THEM the composite ones.
266:
267: // returns either a String or StringList of bean names, or a ValueHolder
268: public static Object propertyValueToBeanName(Object value,
269: BeanDefConverter converter) {
270: Object beanspec = null;
271: if (value instanceof BeanDefinitionHolder) {
272: // Resolve BeanDefinitionHolder: contains BeanDefinition with name and
273: // aliases.
274: BeanDefinitionHolder bdHolder = (BeanDefinitionHolder) value;
275: String beanname = bdHolder.getBeanName();
276: converter.convertBeanDef(bdHolder.getBeanDefinition(),
277: beanname, true);
278: beanspec = beanname;
279: } else if (value instanceof BeanDefinition) {
280: throw new IllegalArgumentException(
281: "No idea what to do with bean definition!");
282: } else if (value instanceof RuntimeBeanReference) {
283: RuntimeBeanReference ref = (RuntimeBeanReference) value;
284: beanspec = ref.getBeanName();
285: } else if (value instanceof ManagedList) {
286: List valuelist = (List) value;
287: StringList togo = new StringList();
288: for (int i = 0; i < valuelist.size(); ++i) {
289: String this beanname = (String) propertyValueToBeanName(
290: valuelist.get(i), converter);
291: togo.add(this beanname);
292: }
293: beanspec = togo;
294: } else if (value instanceof String) {
295: beanspec = new ValueHolder((String) value);
296: } else if (value instanceof TypedStringValue) {
297: beanspec = new ValueHolder(((TypedStringValue) value)
298: .getValue());
299: } else {
300: Logger.log.warn("RSACBeanLocator Got value " + value
301: + " of unknown type " + value.getClass()
302: + ": ignoring");
303: }
304: return beanspec;
305: }
306:
307: }
|