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.integration.pico;
027:
028: import org.jicarilla.container.Adapter;
029: import org.jicarilla.container.Container;
030: import org.jicarilla.container.JicarillaClassNotFoundException;
031: import org.jicarilla.container.NoPublicConstructorAvailableException;
032: import org.jicarilla.container.NoSatisfiableConstructorAvailableException;
033: import org.jicarilla.container.Resolver;
034: import org.jicarilla.container.factories.AbstractFactory;
035: import org.jicarilla.container.util.ReflectionUtil;
036: import org.jicarilla.container.util.Type3Util;
037: import org.jicarilla.lang.Assert;
038: import org.jicarilla.lang.Selector;
039: import org.picocontainer.Parameter;
040: import org.picocontainer.PicoException;
041:
042: import java.lang.reflect.Constructor;
043: import java.lang.reflect.InvocationTargetException;
044: import java.util.HashSet;
045: import java.util.Set;
046:
047: /**
048: * @author <a href="lsimons at jicarilla dot org">Leo Simons</a>
049: * @version $Id: PicoBasedJicarillaComponentFactory.java,v 1.3 2004/03/23 13:37:56 lsimons Exp $
050: */
051: public class PicoBasedJicarillaComponentFactory extends AbstractFactory {
052: protected Constructor m_constructor;
053: protected final Parameter[] m_parameters;
054: protected final JicarillaBasedPicoContainer m_picoContainer;
055:
056: public PicoBasedJicarillaComponentFactory(
057: final JicarillaBasedPicoContainer container,
058: final String className, final Parameter[] parameters) {
059: super (container.getResolver(), className);
060: m_parameters = parameters;
061: //m_resolver = new PicoComponentFactoryContainer(
062: // container, parameters );
063: m_picoContainer = container;
064: }
065:
066: protected Object doNewInstance() throws IllegalAccessException,
067: InvocationTargetException, InstantiationException {
068: if (m_clazz == null)
069: try {
070: m_clazz = ReflectionUtil.loadClass(m_className);
071: } catch (ClassNotFoundException e) {
072: throw new JicarillaClassNotFoundException(e);
073: }
074: if (m_constructor == null) {
075: m_constructor = getGreediestSatisfiableConstructor(m_clazz,
076: m_picoContainer, m_parameters);
077: }
078:
079: final Class[] parameterTypes = m_constructor
080: .getParameterTypes();
081: super .checkCyclicDependency(parameterTypes);
082: super .enableCyclicDependencyChecking();
083:
084: final Object[] parameters = new Object[parameterTypes.length];
085:
086: if (parameterTypes.length > 0) {
087: for (int i = 0; i < parameters.length; i++) {
088: if (i < m_parameters.length && m_parameters[i] != null)
089: parameters[i] = m_parameters[i].resolveAdapter(
090: m_picoContainer).getComponentInstance(
091: m_picoContainer);
092: else
093: // this should not throw an exception, since
094: // the container said it contained the parameter type!
095: parameters[i] = m_resolver.get(parameterTypes[i]);
096: }
097: return m_constructor.newInstance(parameters);
098: } else {
099: return m_clazz.newInstance();
100: }
101: }
102:
103: public class PicoComponentFactoryContainer implements Container {
104: protected final JicarillaBasedPicoContainer m_delegate;
105: protected final Parameter[] m_parameters;
106: protected final Resolver m_resolver;
107:
108: public PicoComponentFactoryContainer(
109: final JicarillaBasedPicoContainer delegate,
110: final Parameter[] parameters) {
111: m_delegate = delegate;
112: m_parameters = parameters;
113: m_resolver = new PicoComponentFactoryResolver(m_delegate
114: .getResolver(), delegate);
115: }
116:
117: public Container registerAdapter(final Selector selector,
118: final Adapter adapter) {
119: m_delegate.registerAdapter(selector, adapter);
120: return this ;
121: }
122:
123: public Container registerAdapter(final Object key,
124: final Adapter adapter) {
125: m_delegate.registerAdapter(key, adapter);
126: return this ;
127: }
128:
129: public Resolver getResolver() {
130: return m_resolver;
131: }
132: }
133:
134: protected class PicoComponentFactoryResolver implements Resolver {
135: protected final Resolver m_delegate;
136: private final JicarillaBasedPicoContainer m_container;
137:
138: public PicoComponentFactoryResolver(final Resolver delegate,
139: final JicarillaBasedPicoContainer container) {
140: m_delegate = delegate;
141: m_container = container;
142: }
143:
144: public Object get(final Object key) {
145: // try and fetch the dependency from the parameter set
146: for (int i = 0; i < m_parameters.length; i++) {
147: if (m_parameters[i] == null)
148: continue;
149:
150: try {
151: final org.picocontainer.ComponentAdapter adapter = m_parameters[i]
152: .resolveAdapter(m_container);
153: final Object currentKey = adapter.getComponentKey();
154: if (currentKey.equals(key)) {
155: final Object instance = adapter
156: .getComponentInstance(m_container);
157: // use a parameter only once!
158: m_parameters[i] = null;
159: return instance;
160: }
161: } catch (PicoException pe) {
162: // continue
163: }
164: }
165:
166: // that didn't work, so do the 'regular type 3' thing
167: return m_delegate.get(key);
168: }
169:
170: public Object[] getAll(final Object key) {
171: return m_delegate.getAll(key);
172: }
173:
174: public boolean contains(final Object key) {
175: return m_delegate.contains(key);
176: }
177:
178: public void releaseInstance(final Object component)
179: throws Exception {
180: m_delegate.releaseInstance(component);
181: }
182:
183: }
184:
185: public static Constructor getGreediestSatisfiableConstructor(
186: final Class clazz,
187: final JicarillaBasedPicoContainer dependencyProvider,
188: final Parameter[] parameters) {
189: // this is the picocontainer algorithm, modified
190: // to support specified parameters
191: Assert.assertNotNull("clazz argument may not be null", clazz);
192: final Constructor[] constructors = clazz.getConstructors();
193:
194: final Class[] providedParameterTypes = new Class[parameters.length];
195: for (int i = 0; i < parameters.length; i++) {
196: final Parameter p = parameters[i];
197: final Class c = p.resolveAdapter(dependencyProvider)
198: .getComponentImplementation();
199: providedParameterTypes[i] = c;
200: }
201:
202: if (constructors.length == 0)
203: throw new NoPublicConstructorAvailableException(clazz);
204:
205: Type3Util.sortConstructorsByGreediness(constructors);
206:
207: final Set unsatisfiedDependencies = new HashSet();
208: for (int i = 0; i < constructors.length; i++) {
209: final Constructor constructor = constructors[i];
210: final Class[] parameterTypes = constructor
211: .getParameterTypes();
212:
213: boolean found = true;
214: for (int j = 0; j < parameterTypes.length; j++) {
215: final Class parameterType = parameterTypes[j];
216:
217: boolean alreadyFound = false;
218: for (int k = 0; k < providedParameterTypes.length; k++) {
219: final Class type = providedParameterTypes[k];
220: if (type != null
221: && parameterType.isAssignableFrom(type)) {
222: alreadyFound = true;
223: providedParameterTypes[k] = null; // use only once
224: break;
225: }
226: }
227: if (alreadyFound)
228: continue;
229:
230: if (!dependencyProvider.getResolver().contains(
231: parameterType)) {
232: unsatisfiedDependencies.add(parameterType);
233: found = false;
234: // get all of them -- break;
235: }
236: }
237: if (!found)
238: continue;
239:
240: return constructor;
241: }
242:
243: throw new NoSatisfiableConstructorAvailableException(clazz,
244: constructors[constructors.length - 1],
245: unsatisfiedDependencies);
246: }
247:
248: }
|