001: /* ====================================================================
002: The Jicarilla Software License
003:
004: Copyright (c) 2003 Leo Simons.
005: All rights reserved.
006:
007: Permission is hereby granted, free of charge, to any person obtaining
008: a copy of this software and associated documentation files (the
009: "Software"), to deal in the Software without restriction, including
010: without limitation the rights to use, copy, modify, merge, publish,
011: distribute, sublicense, and/or sell copies of the Software, and to
012: permit persons to whom the Software is furnished to do so, subject to
013: the following conditions:
014:
015: The above copyright notice and this permission notice shall be
016: included in all copies or substantial portions of the Software.
017:
018: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
019: EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
020: MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
021: IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
022: CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
023: TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
024: SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
025: ==================================================================== */
026: package org.jicarilla.container.factories;
027:
028: import org.jicarilla.container.Factory;
029: import org.jicarilla.container.JicarillaIllegalAccessException;
030: import org.jicarilla.container.JicarillaInstantiationException;
031: import org.jicarilla.container.JicarillaInvocationTargetException;
032: import org.jicarilla.container.NoPublicConstructorAvailableException;
033: import org.jicarilla.container.NoSatisfiableConstructorAvailableException;
034: import org.jicarilla.container.util.Type3Util;
035: import org.jicarilla.lang.Assert;
036: import org.jicarilla.lang.LifecycleUtil;
037:
038: import java.beans.BeanInfo;
039: import java.beans.IntrospectionException;
040: import java.beans.Introspector;
041: import java.beans.PropertyDescriptor;
042: import java.lang.reflect.Constructor;
043: import java.lang.reflect.InvocationTargetException;
044: import java.lang.reflect.Method;
045: import java.util.Arrays;
046: import java.util.HashSet;
047: import java.util.List;
048: import java.util.Map;
049:
050: /**
051: *
052: *
053: * @author <a href="lsimons at jicarilla dot org">Leo Simons</a>
054: * @version $Id: BeanFactory.java,v 1.2 2004/03/23 13:37:52 lsimons Exp $
055: */
056: public class BeanFactory implements Factory {
057: // ----------------------------------------------------------------------
058: // Properties
059: // ----------------------------------------------------------------------
060: protected final Class m_clazz;
061: protected final Map m_properties;
062: protected final List m_constructorParameters;
063: protected final BeanInfo m_beanInfo;
064:
065: // ----------------------------------------------------------------------
066: // Constructors
067: // ----------------------------------------------------------------------
068: public BeanFactory(final Class clazz) throws IntrospectionException {
069: this (clazz, null);
070: }
071:
072: public BeanFactory(final Class clazz, final Map properties)
073: throws IntrospectionException {
074: this (clazz, properties, null);
075: }
076:
077: public BeanFactory(final Class clazz, final Map properties,
078: final List constructorParameters)
079: throws IntrospectionException {
080: Assert.assertNotNull("clazz argument may not be null", clazz);
081:
082: m_clazz = clazz;
083: m_properties = properties;
084: m_constructorParameters = constructorParameters;
085:
086: m_beanInfo = Introspector.getBeanInfo(clazz);
087: }
088:
089: // ----------------------------------------------------------------------
090: // Interface: Factory
091: // ----------------------------------------------------------------------
092: public Object newInstance() {
093: final Constructor constructor = getGreediestSatisfiableConstructor(
094: m_clazz, m_constructorParameters);
095:
096: final Object instance;
097: if (m_constructorParameters != null) {
098: try {
099: instance = constructor
100: .newInstance(m_constructorParameters.toArray());
101: } catch (InstantiationException e) {
102: throw new JicarillaInstantiationException(e);
103: } catch (IllegalAccessException e) {
104: throw new JicarillaIllegalAccessException(e);
105: } catch (InvocationTargetException e) {
106: throw new JicarillaInvocationTargetException(e);
107: }
108: } else {
109: try {
110: instance = m_clazz.newInstance();
111: } catch (InstantiationException e) {
112: throw new JicarillaInstantiationException(e);
113: } catch (IllegalAccessException e) {
114: throw new JicarillaIllegalAccessException(e);
115: }
116: }
117:
118: try {
119: callSetterMethods(m_beanInfo, instance, m_properties);
120: } catch (IllegalAccessException e) {
121: throw new JicarillaIllegalAccessException(e);
122: } catch (InvocationTargetException e) {
123: throw new JicarillaInvocationTargetException(e);
124: }
125:
126: try {
127: LifecycleUtil.initialize(instance);
128: } catch (Throwable t) {
129: throw new JicarillaInstantiationException(t);
130: }
131:
132: return instance;
133: }
134:
135: public void releaseInstance(final Object o) throws Exception {
136: try {
137: LifecycleUtil.dispose(o);
138: } catch (Throwable t) {
139: }
140: }
141:
142: // ----------------------------------------------------------------------
143: // Helper Methods
144: // ----------------------------------------------------------------------
145: public static void callSetterMethods(final BeanInfo beanInfo,
146: final Object instance, final Map properties)
147: throws IllegalAccessException, InvocationTargetException {
148: if (properties == null)
149: return;
150:
151: final PropertyDescriptor[] pd = beanInfo
152: .getPropertyDescriptors();
153: for (int i = 0; i < pd.length; i++) {
154: final PropertyDescriptor descriptor = pd[i];
155: final String name = descriptor.getName();
156: if (!properties.containsKey(name))
157: continue;
158:
159: final Method m = descriptor.getWriteMethod();
160: if (m == null)
161: continue;
162:
163: final Object value = properties.get(name);
164: m.invoke(instance, new Object[] { value });
165: }
166: }
167:
168: public static Constructor getGreediestSatisfiableConstructor(
169: final Class clazz, final List constructorParameters) {
170: // this is the picocontainer algorithm, modified
171: // to use specified parameters, and modified
172: // to return the parameters that were not used
173: Assert.assertNotNull("clazz argument may not be null", clazz);
174:
175: final Constructor[] constructors = clazz.getConstructors();
176: Type3Util.sortConstructorsByGreediness(constructors);
177:
178: Constructor constructor = null;
179: if (constructorParameters == null) {
180: try {
181: constructor = clazz.getConstructor(new Class[0]);
182: } catch (NoSuchMethodException e) {
183: throw new NoPublicConstructorAvailableException(clazz);
184: }
185: } else {
186: final int size = constructorParameters.size();
187: for (int i = 0; i < constructors.length; i++) {
188: if (constructors[i].getParameterTypes().length == size) {
189: constructor = constructors[i];
190: break;
191: }
192: }
193: }
194:
195: if (constructor == null) {
196: final Constructor simplestConstructor = constructors[constructors.length - 1];
197:
198: final Class[] parameterTypes = simplestConstructor
199: .getParameterTypes();
200:
201: int unsatisfied = 0;
202: if (constructorParameters != null)
203: unsatisfied = constructorParameters.size()
204: - parameterTypes.length;
205:
206: final Class[] unsatisfiedDependencies = new Class[unsatisfied];
207: System.arraycopy(parameterTypes, constructorParameters
208: .size() - 1, unsatisfiedDependencies, 0,
209: unsatisfied);
210:
211: final HashSet set = new HashSet();
212: set.addAll(Arrays.asList(unsatisfiedDependencies));
213:
214: throw new NoSatisfiableConstructorAvailableException(clazz,
215: simplestConstructor, set);
216: }
217: return constructor;
218: }
219: }
|