View Javadoc

1   /*
2    * Created on May 20, 2005
3    *
4    * An embeddable IoC/dependcy-inject container (similar to <a
5    * href="http://www.picocontainer.org">PicoContainer </a>).
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             // only one possible constructor found, use that
151             constructor = (Constructor) possibleConstructors.get(possibleConstructors.size() - 1);
152         } else if (possibleConstructors.size() > 0) {
153             // more than one possible constructor found... hmmn...
154             // try and use default constructor
155             // TODO something else
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 }