1
2
3
4
5
6
7 package net.sf.tlc.ioc.impl;
8
9 import java.lang.reflect.Constructor;
10 import java.lang.reflect.InvocationTargetException;
11 import java.util.ArrayList;
12 import java.util.Iterator;
13 import java.util.LinkedHashSet;
14 import java.util.Set;
15
16 import net.sf.tlc.ioc.IocContainer;
17 import net.sf.tlc.util.ClassUtils;
18
19 /***
20 * An embeddable IoC/dependcy-inject container (similar to <a
21 * href="http://www.picocontainer.org">PicoContainer </a>).
22 *
23 * @author aisrael
24 */
25 public class EmbeddableContainer implements IocContainer {
26
27 private final DependencyManager dependencyManager;
28
29 private final Set objects;
30
31 /***
32 * Constructor
33 *
34 * @param dependencyManager
35 * DependencyManager
36 */
37 public EmbeddableContainer(final DependencyManager dependencyManager) {
38 this.dependencyManager = dependencyManager;
39 objects = new LinkedHashSet();
40 }
41
42 /***
43 * Default constructor
44 */
45 public EmbeddableContainer() {
46 this(new DefaultDependencyManager());
47 }
48
49 /***
50 * (non-Javadoc)
51 *
52 * @see net.sf.tlc.ioc.IocContainer#register(java.lang.Class)
53 */
54 public final void register(final Class c) {
55 dependencyManager.registerClass(c);
56 }
57
58 /***
59 * (non-Javadoc)
60 *
61 * @see net.sf.tlc.ioc.IocContainer#add(java.lang.Object)
62 */
63 public final void add(final Object o) {
64 if (null != o) {
65 if (Class.class.equals(o.getClass())) {
66 throw new IllegalArgumentException(
67 "WARNING: adding a Class, maybe you should call register()?");
68 }
69 objects.add(o);
70 dependencyManager.registerClass(o.getClass());
71 }
72 }
73
74 /***
75 * @param c
76 * Class
77 * @return Object
78 */
79 private Object findObjectOfType(final Class c) {
80 for (final Iterator i = objects.iterator(); i.hasNext();) {
81 final Object o = i.next();
82 if (c.isAssignableFrom(o.getClass())) {
83 return o;
84 }
85 }
86 return null;
87 }
88
89 /***
90 * (non-Javadoc)
91 *
92 * @see net.sf.tlc.ioc.IocContainer#getInstance(java.lang.Class)
93 */
94 public final Object getInstance(final Class c) {
95 Object result = null;
96
97 result = findObjectOfType(c);
98 if (null == result) {
99 if (ClassUtils.isAbstractClass(c) || c.isInterface()) {
100 result = createConcreteObjectFor(c);
101 } else {
102 result = createObjectOfType(c);
103 }
104 }
105
106 return result;
107 }
108
109 /***
110 * @param c
111 * Class
112 * @return Object that extends or implements the class
113 */
114 private Object createConcreteObjectFor(final Class c) {
115 Object result = null;
116 final Class[] classes = dependencyManager.listAllImplementingClasses(c);
117 final ArrayList possibleClasses = new ArrayList();
118 for (int i = 0; i < classes.length; ++i) {
119 if (dependencyManager.canConstructClass(classes[i])) {
120 possibleClasses.add(classes[i]);
121 }
122 }
123 if (possibleClasses.size() == 1) {
124 final Class d = (Class) possibleClasses.get(0);
125 result = createObjectOfType(d);
126 } else if (possibleClasses.size() > 1) {
127 throw new RuntimeException("More than one possible class! What to choose?!");
128 }
129 return result;
130 }
131
132 /***
133 * @param c
134 * Class
135 * @return Object
136 */
137 private Object createObjectOfType(final Class c) {
138 Object result = null;
139 final ArrayList possibleConstructors = new ArrayList();
140 final Constructor[] constructors = c.getConstructors();
141 for (int i = 0; i < constructors.length; ++i) {
142 final Constructor constructor = constructors[i];
143 if (dependencyManager.canConstructClass(c, constructor)) {
144 possibleConstructors.add(constructor);
145 }
146 }
147
148 Constructor constructor = null;
149 if (possibleConstructors.size() == 1) {
150
151 constructor = (Constructor) possibleConstructors.get(possibleConstructors.size() - 1);
152 } else if (possibleConstructors.size() > 0) {
153
154
155
156 Constructor defaultConstructor = null;
157 for (final Iterator i = possibleConstructors.iterator(); i.hasNext();) {
158 final Constructor cons = (Constructor) i.next();
159 if (0 == cons.getParameterTypes().length) {
160 constructor = cons;
161 }
162 }
163 }
164
165 if (null != constructor) {
166 result = construct(c, constructor);
167 add(result);
168 }
169 return result;
170 }
171
172 /***
173 * @param c
174 * Class
175 * @param constructor
176 * Constructor
177 * @return Object
178 */
179 private Object construct(final Class c, final Constructor constructor) {
180 Object result;
181 final Class[] parameters = constructor.getParameterTypes();
182 final Object[] args = new Object[parameters.length];
183 for (int i = 0; i < parameters.length; ++i) {
184 args[i] = getInstance(parameters[i]);
185 }
186 final StringBuffer sb = new StringBuffer();
187 sb.append("Constructing ").append(c.getName()).append("(");
188 for (int i = 0; i < args.length;) {
189 sb.append(args[i].toString());
190 ++i;
191 if (i < args.length) {
192 sb.append(", ");
193 }
194 }
195 sb.append(")");
196 System.out.println(sb.toString());
197 try {
198 result = constructor.newInstance(args);
199 } catch (IllegalArgumentException e) {
200 throw new RuntimeException(e);
201 } catch (InstantiationException e) {
202 throw new RuntimeException(e);
203 } catch (IllegalAccessException e) {
204 throw new RuntimeException(e);
205 } catch (InvocationTargetException e) {
206 throw new RuntimeException(e);
207 }
208 return result;
209 }
210 }