View Javadoc
1   /*
2    * Created on May 1, 2004
3    * 
4    * This library is free software; you can redistribute it and/or
5    * modify it under the terms of the GNU Lesser General Public
6    * License as published by the Free Software Foundation; either
7    * version 2.1 of the License, or (at your option) any later version.
8    * 
9    * This library is distributed in the hope that it will be useful,
10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12   * Lesser General Public License for more details.
13   * 
14   * Full GNU LGPL license terms : http://www.gnu.org/copyleft/lesser.txt
15   * 
16   * Project : iky-container
17   * Package : net.wmind.container
18   * Author : mchaplin@users.sourceforge.net
19   */
20  package net.mchaplin.ioc;
21  
22  import java.lang.reflect.Constructor;
23  import java.lang.reflect.InvocationTargetException;
24  import java.lang.reflect.Method;
25  import java.util.Hashtable;
26  import java.util.Iterator;
27  import java.util.List;
28  import java.util.Map;
29  import java.util.Set;
30  import java.util.Vector;
31  
32  import net.mchaplin.commons.StackTraceUtils;
33  import net.mchaplin.commons.WmindObject;
34  import net.mchaplin.ioc.component.ComponentFactoryI;
35  import net.mchaplin.ioc.component.ComponentI;
36  import net.mchaplin.ioc.exp.ContainerException;
37  
38  /***
39   * Default, ready-to-use ContainerI implementation
40   * Provides Component registration & management 
41   * services.
42   * 
43   * @author mchaplin@users.sourceforge.net
44   *
45   * TODO Handle interfaces use in constructors
46   * TODO Move component lookup services to a ServiceLocator
47   * 
48   * $Header: 
49   * $Revision: 
50   * $Date:
51   *  
52   */
53  public class DefaultContainer extends WmindObject implements ContainerI {
54  
55      /***
56       * container instance name
57       */
58      private String instanceName = "";
59      
60      /*** Known containers */
61      private List<ContainerI> containers = null;
62      /***
63       * container parent instance
64       */
65      private ContainerI parent = null;
66      /***
67       * containers registering this container as parent
68       */
69      private transient ContainerI[] sons = null;
70      
71      /***
72       * registered components in this container
73       */
74      private transient Map<String, List<ComponentI>> regTypes = null;
75      
76      /***
77       * registered component factories in this container
78       */
79      private transient Map<String, List<ComponentFactoryI>> regTypesFact = null;
80      
81      /***
82       * reference this container
83       */
84      public static final int HERE = 0;
85  
86      /***
87       * reference this container parent
88       */
89      public static final int PARENT = 1;
90  
91      /***
92       * reference this container sons
93       */
94      public static final int SONS = 2;
95      
96      /***
97       * registered sons count
98       */
99      public transient int sonsCount = 0;
100     
101     /***
102      * default lentgh for sons array
103      */
104     public static final int SONS_DEFAULT_LENTGH = 5;
105 
106     /***
107      * Instanciate a container.
108      *  
109      */
110     public DefaultContainer(String name) {
111         super();
112         log.info("Creating container [" + name + "]");
113         instanceName = name;
114         regTypes = new Hashtable<String, List<ComponentI>>();
115         regTypesFact = new Hashtable<String, List<ComponentFactoryI>>();
116         sons = new ContainerI[SONS_DEFAULT_LENTGH];
117         parent = this;
118         // TODO customizable
119         //addComponentToContainer(this, this.getClass().getName());
120         addComponentToContainer(this, "net.mchaplin.ioc.ContainerI");
121     }
122 
123     /***
124      * Instanciate & register this container as child of another container
125      * 
126      * @param parent
127      */
128     public DefaultContainer(ContainerI parent, String name) {
129         super();
130         log.info("Creating container [" + name + "] with parent [" + parent.getInstanceName() + "]");
131         instanceName = name;
132         this.setParent(parent);
133         sons = new ContainerI[SONS_DEFAULT_LENTGH];
134         parent.addSon(this);
135         regTypes = new Hashtable<String, List<ComponentI>>();
136         regTypesFact = new Hashtable<String, List<ComponentFactoryI>>();
137         // TODO customizable
138         //addComponentToContainer(this, this.getClass().getName());
139         addComponentToContainer(this, "net.mchaplin.ioc.ContainerI");
140     }
141 
142 
143     
144     /***
145      * Register a Component into the Container
146      * 
147      * @param component the component to register
148      */
149     public void registerComponentImplementation(Class component) {
150         this.registerComponentImplementation(component, "");
151 
152     }
153 
154     /***
155      * Register a Factory for later use.
156      * 
157      * @param factory the factory to register
158      */
159     public void registerFactoryImplementation(Class factory) {
160         log.debug(METHOD_CALL+"registerFactoryImplementation("+factory.getName()+")");
161         Object instance = instanciateComponent(factory);
162         if (isInterfaceImplemented(factory, ComponentI.CMP_I)) {
163             addFactoryToContainer((ComponentFactoryI) instance, "");
164         } else {
165             log.warn("Factory ["+factory.getName()+"] does not implements ComponentI, registration skipped !");
166         }
167     }
168 
169     /***
170      * Component registration. Will try a newInstance() call on it &
171      * register if not already present.
172      * 
173      * @param component the component Class to register
174      * @param type optional, the type to register this instance as. If set, the
175      *             Component will be registered under its fully qualified class
176      *             name
177      */
178 
179     public void registerComponentImplementation(Class component, String type) {
180 
181         Object instance = instanciateComponent(component);
182             
183         if (instance != null && isInterfaceImplemented(component, ComponentI.CMP_I)) {
184             ComponentI cmp = (ComponentI) instance;
185             cmp.setContainer(this);
186             addComponentToContainer(cmp, type);
187         }
188         
189     }   
190 
191     /***
192      * Custom component registration. The factory will be instanciated through a
193      * Factory() Constructor. The component will then be instanciated
194      * through the Factory.retrieveInstance() method
195      * 
196      * @param component the component to register
197      * @param factory the factory to register
198      * 
199      * @see net.mchaplin.ioc.ContainerI#registerComponentImplementation(java.lang.Class,
200      *      java.lang.Class)
201      */
202     public void registerComponentImplementation(Class component, Class factory) throws ContainerException {
203         this.registerComponentImplementation(component, factory, null);
204     }
205 
206     /***
207      * Custom component registration. The factory will be instanciated through a
208      * Factory() Constructor. The component will then be instanciated
209      * through the Factory.retrieveInstance() method
210      * 
211      * @param component the component to register
212      * @param factory the factory to register
213      * @param type the type to register this instance as. If set, the
214      *             Component will be registered under its fully qualified class
215      *             name
216      * 
217      * @see net.mchaplin.ioc.ContainerI#registerComponentImplementation(java.lang.Class,
218      *      java.lang.Class)
219      */
220     public void registerComponentImplementation(Class component, Class factory, String type) throws ContainerException {
221 
222         // check if the component is not already registered
223         if (lookupComponent(component) == null) {
224             ComponentFactoryI oFactory = null;
225             String sFactoryType = null;
226             Object oComponent = null;
227             Method method = null;
228 
229             // Check if factory already exists
230             String sLocation = lookupComponent(factory);
231             if (sLocation == null) {
232                 // Else instanciate & register it
233                 this.registerFactoryImplementation(factory);
234             }
235             // Retrieve back the factory instance
236             oFactory = retrieveFactoryInstance(factory);
237             sFactoryType = oFactory.toString().substring(6);
238             // Instanciate & register the component
239             try {
240                 method = oFactory.getClass().getDeclaredMethod("retrieveInstance", (Class[]) null);
241                 oComponent = method.invoke(oFactory, (Object[]) null);
242             } catch (IllegalArgumentException e) {
243                 StackTraceUtils.printExtendedStackTrace("IllegalArgumentException thrown while instanciating : ", component, e);
244                 throw new ContainerException(e.getCause());
245             } catch (NoSuchMethodException e) {
246                 StackTraceUtils.printExtendedStackTrace("NoSuchMethodException thrown while instanciating : ", component, e);
247                 throw new ContainerException(e.getCause());
248             } catch (IllegalAccessException e) {
249                 StackTraceUtils.printExtendedStackTrace("IllegalAccessException thrown while instanciating : ", component, e);
250                 throw new ContainerException(e.getCause());
251             } catch (InvocationTargetException e) {
252                 StackTraceUtils.printExtendedStackTrace("InvocationTargetException thrown while instanciating : ", component, e);
253                 throw new ContainerException(e.getCause());
254             }
255             addComponentToContainer((ComponentI) oComponent, type);
256             
257         } else {
258             log.info("Component : "+component.getClass()+" is already registered");
259         }
260     }
261 
262     /***
263      * Instanciate a component. Constructor dependencies
264      * are looked up inside the container hierarchy.
265      * 
266      * @param component the component to instanciate
267      * @return an instance of component
268      */
269     private Object instanciateComponent(Class component) {
270 
271         boolean emtyCnstr = false;
272         String constrLoc = null;
273         int params = 0;
274         Constructor curConstr = null;
275         Constructor targetConstr = null; // the constructor that will be
276                                               // used for this component
277                                               // instanciation
278         Class[] constrParams = null;
279         Class curParam = null;
280         Object instance = null;
281 
282         Constructor[] cmpConstr = component.getDeclaredConstructors();
283 
284         // introspect object constructors : for each constructor
285         for (int i = 0; i < cmpConstr.length; i++) {
286             curConstr = cmpConstr[i];
287             constrParams = curConstr.getParameterTypes();
288             // if it's not an empty parameter one
289             if (constrParams.length != 0) {
290                 log.debug("Introspecting a " + constrParams.length + " parameters Constructor");
291                 // check if the container knows about constructor parameter types
292                 for (int j = 0; j < constrParams.length; j++) {
293                     curParam = constrParams[j];
294                     constrLoc = this.lookupComponent(curParam);
295                     // if not found, check if the parent container knows about
296                     // constructor parameter types
297                     if (constrLoc == null) {
298                         constrLoc = this.getParent().lookupComponent(curParam);
299                     }
300                 }
301                 // check if this is the biggest constructor we know
302                 if (constrLoc != null && constrParams.length > params) {
303                     params = constrParams.length;
304                     targetConstr = curConstr;
305                 }
306             } else {
307                 emtyCnstr = true;
308             }
309         }
310         if (!emtyCnstr && targetConstr != null) {
311             instance = parameterizedConstructorInstanciation(targetConstr);
312         } else { // the component has an empty constructor only.
313             instance = emptyConstructorInstanciation(component);
314         }
315 
316         return instance;
317     }
318     
319     /***
320      * @param component
321      * @param instance
322      * @return
323      */
324     private Object emptyConstructorInstanciation(Class component) {
325         Object instance = null;
326         try {
327             instance = component.newInstance();
328         } catch (InstantiationException e) {
329             log.error("InstantiationException thrown while instanciating : " + component.toString().substring(6));
330             log.error(WmindObject.EX_CAUSE);
331             StackTraceUtils.printStackTrace(e.getCause());
332             log.error(WmindObject.EX_STACK);
333         } catch (IllegalAccessException e) {
334             log.error("IllegalAccessException thrown while instanciating : " + component.toString().substring(6));
335             StackTraceUtils.printStackTrace(e);
336         }
337         
338         return instance;
339     }
340 
341     /***
342      * @param component
343      * @param curConstructor
344      * @param constr
345      * @param instance
346      * @return
347      */
348     private Object parameterizedConstructorInstanciation(Constructor constr) {
349         Class[] cnstrPrms = null;
350         Object[] oParams = null;
351         Object instance = null;
352         /* instanciate the component, injecting instances from container
353          * into constructor 
354          */ 
355         
356         cnstrPrms = constr.getParameterTypes();
357         oParams = new Object[cnstrPrms.length];
358         for (int k = 0; k < cnstrPrms.length; k++) {
359             oParams[k] = this.retrieveComponentInstance(cnstrPrms[k]);
360         }
361         try {
362             instance = constr.newInstance(oParams);
363         } catch (IllegalArgumentException e) {
364             log.error("IllegalArgumentException thrown while instanciating : " + constr.getName());
365             StackTraceUtils.printStackTrace(e);
366         } catch (InstantiationException e) {
367             log.error(WmindObject.EX_CAUSE);
368             StackTraceUtils.printStackTrace(e.getCause());
369             log.error(WmindObject.EX_STACK);
370             log.error("InstantiationException thrown while instanciating : " +  constr.getName());
371             StackTraceUtils.printStackTrace(e);
372         } catch (IllegalAccessException e) {
373             log.error("IllegalAccessException thrown while instanciating : " +  constr.getName());
374             StackTraceUtils.printStackTrace(e);
375         } catch (InvocationTargetException e) {
376             log.error("InvocationTargetException thrown while instanciating : " +  constr.getName());
377             log.error(WmindObject.EX_CAUSE);
378             StackTraceUtils.printStackTrace(e.getCause());
379             log.error(WmindObject.EX_STACK);
380             StackTraceUtils.printStackTrace(e);
381         }
382         return instance;
383     }
384 
385     /***
386      * Recursively check in a class implements
387      * a given interface
388      * 
389      * @param component the class to introspect
390      * @param name the interface fully-qualified name to look for
391      * @return 
392      */
393     private boolean isInterfaceImplemented(Class component, String name) {
394         log.debug(METHOD_CALL+"isInterfaceImplemented("+component.getName()+", "+name+")");
395         boolean found = false;
396         Class[] interfaces = null;
397         
398         // check in component's interface
399         if (component.getInterfaces().length != 0) {
400             interfaces = component.getInterfaces();
401             found = introspectInterfaces(interfaces, name);
402             
403         } else {
404             log.debug("Class : "+component.getName()+" has no interfaces.");
405         }
406         
407         // then, try in component's inheritance
408         while (!found && component.getSuperclass() != null) {
409             if (component.getSuperclass().getInterfaces().length != 0) {
410                 interfaces = component.getSuperclass().getInterfaces();
411                 found = introspectInterfaces(interfaces, name);
412             }
413             // recurse
414             component = component.getSuperclass();
415         }
416         
417         if (found) {
418             log.debug("Class ["+component.getName()+"] implements ["+name+"]");
419         } else {
420             log.debug("Class ["+component.getName()+"] does not implements ["+name+"]");
421         }
422         
423         return found;
424     }
425 
426     /***
427      * @param component
428      * @param name
429      * @param found
430      * @param ct
431      * @return
432      */
433     private boolean introspectInterfaces(Class[] interfaces, String name) {
434         
435         boolean found = false;
436         int ct = 0;
437         Class curInterface = null;
438         
439         while (!found && ct<interfaces.length) {
440             curInterface = interfaces[ct];
441             // check if match
442             if (curInterface.getName().equals(name)) {
443                 found = true;
444             }
445             //recurse if we don't have a match
446             if (!found) {
447                 isInterfaceImplemented(curInterface, name);
448             }
449             ct++;
450         }
451         return found;
452     }
453 
454     /***
455      * Add an instance of ComponentI to this Container
456      * 
457      * @param oComponent the component to add to this container
458      * @param type optionnal, the type to register this component as
459      */
460     private void addComponentToContainer(ComponentI oComponent, String type) {
461         String cmpName = null;
462         List<ComponentI> lInstances = null;
463         if (oComponent != null) {
464 	        if (type != null && !type.equals("")) {
465 	            cmpName = type;
466 	        } else {
467 	            cmpName = oComponent.getClass().getName();
468 	        }
469 	        log.info("Adding component : [" + cmpName + "] to container ["+this.instanceName+"]");
470 	        // check if component is registered
471             if (regTypes.containsKey(cmpName)) {
472                 lInstances = regTypes.get(cmpName);
473             } else {
474                 lInstances = new Vector<ComponentI>();
475             }
476             lInstances.add(oComponent);
477             this.regTypes.put(cmpName, lInstances);
478             log.debug("Component registered under name : " + cmpName);
479         }
480     }
481 
482     /***
483      * Add an instance of ComponentFactoryI to this Container
484      * 
485      * @param oComponent the component to add to this container
486      * @param type optionnal, the type to register this component as
487      */
488     private void addFactoryToContainer(ComponentFactoryI oComponent, String type) {
489         String cmpName = null;
490         if (oComponent != null) {
491             cmpName = oComponent.getClass().getName();
492             log.debug("Adding factory : [" + cmpName + "] to container ["+this.instanceName+"]");
493             List<ComponentFactoryI> lInstances = new Vector<ComponentFactoryI>();
494             lInstances.add(oComponent);
495             if (type != null && !type.equals("")) {
496                 log.debug("Factory registered under name : " + type);
497                 this.regTypesFact.put(type, lInstances);
498             } else {
499                 this.regTypesFact.put(cmpName, lInstances);
500             }
501         }
502     }
503 
504     public void registerComponentInstance(ComponentI instance) {
505         addComponentToContainer(instance, instance.getClass().getName());
506     }
507 
508     public void registerComponentInstance(ComponentI instance, String key) {
509         addComponentToContainer(instance, key);
510     }
511 
512 
513 
514     /***
515      * Retrieve the first instance in List of given type.
516      * 
517      * @param classType the Class type to retrieve an instance of.
518      * @return an instance of ComponentI, whose Class match classType
519      */
520     public ComponentI retrieveComponentInstance(Class classType) {
521         String key = classType.getName();
522         return retrieveComponentInstance(key, null);
523     }
524 
525     /***
526      * Retrieve the first instance in List of given type.
527      * 
528      * @param key the component type to retrieve an instance of
529      * @return an instance of ComponentI, whose full name match key
530      */
531     public ComponentI retrieveComponentInstance(String key) {
532         return retrieveComponentInstance(key, null);
533     }
534 
535     /***
536      * Retrieve the first instance in List of given type.
537      * 
538      * @param key the component type to retrieve an instance of
539      * @param location the location of the container where the component
540      * 		  should be retrieved from.
541      * @return an instance of ComponentI, whose full name match key
542      */
543     public ComponentI retrieveComponentInstance(String key, String location) {
544         //logger.debug(METHOD_CALL + "retrieveComponentInstance(" + key + ")");
545         ComponentI oComponent = null;
546         ContainerI[] arrSon = null;
547         ContainerI curSon = null;
548         Vector lObjects = null;
549         boolean found = false;
550         int i=0;
551         int ct=0;
552         
553         if (this.regTypes.containsKey(key)) {
554             lObjects = (Vector) this.regTypes.get(key);
555             oComponent = (ComponentI) lObjects.firstElement();
556             //lObjects.remove(0);
557         } else if (this.getParent() != null && this.getParent().getRegisteredTypes().containsKey(key)) {
558             lObjects = (Vector) this.getParent().getRegisteredTypes().get(key);
559             oComponent = (ComponentI) lObjects.firstElement();
560         } else {
561             // looking into root container sons (unoptimized!)
562                 arrSon = parent.getSons();
563                 ct = arrSon.length;
564                 while (!found && i<ct) {
565                     if (arrSon[i] != null) {
566                     curSon = arrSon[i];
567                     if (curSon.getRegisteredTypes().containsKey(key)) {
568                         lObjects = (Vector) curSon.getRegisteredTypes().get(key);
569                         oComponent = (ComponentI) lObjects.firstElement();
570                         found = true;
571                     }
572                     }
573                     i++;
574                 }                
575         }
576         if (oComponent == null) {
577             log.warn("Container does not contain objects of type : [" + key + "]");
578         }
579         return oComponent;
580     }
581     /***
582      * Retrieve the first instance in List of given type.
583      * 
584      * @param classType the Class type to retrieve an instance of.
585      * @return an instance of ComponentI, whose Class match classType
586      */
587     public ComponentFactoryI retrieveFactoryInstance(Class classType) {
588         String key = classType.getName();
589         return retrieveFactoryInstance(key);
590     }
591 
592     /***
593      * Retrieve the first instance in List of given type.
594      * 
595      * @param key the key to retrieve associated Factory instance.
596      * @return an instance of ComponentI, whose full name match key
597      */
598     public ComponentFactoryI retrieveFactoryInstance(String key) {
599         //logger.debug(METHOD_CALL + "retrieveFactoryInstance(" + key + ")");
600         ComponentFactoryI oComponent = null;
601         Vector lObjects = null;
602         // FIXME Factory can be registered as a factory OR a type !
603         if (this.regTypesFact.containsKey(key)) {
604             lObjects = (Vector) this.regTypesFact.get(key);
605             oComponent = (ComponentFactoryI) lObjects.firstElement();
606             //lObjects.remove(0);
607         } else if (this.regTypes.containsKey(key)) {
608             lObjects = (Vector) this.regTypes.get(key);
609             oComponent = (ComponentFactoryI) lObjects.firstElement();
610         } else {
611             log.warn("Container does not contain objects of type : [" + key + "]");
612         }
613         return oComponent;
614     }
615 
616     /***
617      * Retrieve a list of registered components for the given key
618      *  
619      */
620     public List retrieveComponentInstances(String key) {
621         List ret = null;
622         if (regTypes.containsKey(key)) {
623             ret = (List) regTypes.get(key);
624         } else {
625             log.warn("Container does not contain objects of type : [" + key + "]");
626         }
627         return ret;
628     }
629 
630     /***
631      * Retrieve a list of all registered components
632      *  
633      */
634     public void retrieveComponentInstances() {
635         // TODO Implement DefaultContainer.retrieveComponentInstances
636     }
637 
638     /***
639      * Gives back a Component when you stop using it. 
640      * TODO : manage component lock/unlock mode
641      *  
642      */
643     public void makeComponentAvailable() {
644         // TODO Implement DefaultContainer.makeComponentAvailable
645     }
646 
647     public void unregisterComponentInstance(ComponentI instance) {
648         // TODO Implement DefaultContainer.unregisterComponentInstance
649     }
650 
651 
652 
653     /***
654      * @see net.mchaplin.ioc.ComponentI#getContainer()
655      */
656     public ContainerI getContainer() {
657         return this;
658     }
659     
660 
661     /***
662      * Lookup for to see if a given component is currently registered in this
663      * Container, its parent or sons. Use if you have no knowledge of where the
664      * component is located
665      * 
666      * @param classType
667      *            the Class type to lookup for.
668      * @return the name of the container where a Component instance has been
669      *         found or null.
670      */
671     public String lookupComponent(Class classType) {
672         //logger.debug(METHOD_CALL + "lookupComponent(" + classType.getName() + ")");
673 
674         String location = null;
675         boolean found = false;
676         ContainerI curSon = null;
677 
678         // lookup in local container, parent container or iterate any sons
679         // container
680         if (this.regTypes.containsKey(classType.getName())) {
681             location = this.getInstanceName();
682         } else if (this.getParent() != null && this.getParent().getRegisteredTypes().containsKey(classType.getName())) {
683             location = this.getParent().getInstanceName();
684         } else {
685             int i = 0;
686             while (!found && i < sons.length) {
687                 curSon = sons[i];
688                 if (curSon != null && curSon.getRegisteredTypes().containsKey(classType.getName())) {
689                     found = true;
690                     location = curSon.getInstanceName();
691                 }
692                 i++;
693             }
694             if (!found) {
695                 log.debug("Component " + classType.getName() + " lookup failed.");
696             }
697         }
698         if (location != null) {
699             log.debug("Component location : " + location);
700         }
701         return location;
702     }
703 
704     /***
705      * Lookup for to see if a given component is currently registered.
706      * 
707      * 
708      * @param classType the Class type to lookup for.
709      * @param where where to lookup the component : here, parent or sons
710      * 
711      * @return the name of the container where a Component instance has been
712      *         found or null.
713      */
714     public String lookupComponent(Class classType, int where) {
715         String location = null;
716         boolean found = false;
717         ContainerI curSon = null;
718         switch (where) {
719         case HERE:
720             if (this.regTypes.containsKey(classType.getName())) {
721                 location = this.getInstanceName();
722             }
723             break;
724 
725         case PARENT:
726             if (this.getParent() != null && this.getParent().getRegisteredTypes().containsKey(classType.getName())) {
727                 location = this.getParent().getInstanceName();
728             }
729             break;
730 
731         case SONS:
732             int i = 0;
733             while (!found && i < sons.length) {
734                 curSon = sons[i];
735                 if (curSon.getRegisteredTypes().containsKey(classType.getName())) {
736                     found = true;
737                     location = curSon.getInstanceName();
738                 }
739                 i++;
740             }
741             break;
742 
743         default:
744             location = lookupComponent(classType);
745             break;
746         }
747 
748         return location;
749     }
750 
751     /***
752      * @return Returns the containers.
753      */
754     public List<ContainerI> getContainers() {
755         return containers;
756     }
757     /***
758      * @param containers The containers to set.
759      */
760     public void setContainers(List<ContainerI> containers) {
761         this.containers = containers;
762     }
763     
764     /***
765      * @return Returns the instanceName.
766      */
767     public String getInstanceName() {
768         return instanceName;
769     }
770 
771     /***
772      * @param instanceName
773      *            The instanceName to set.
774      */
775     public void setInstanceName(String instanceName) {
776         this.instanceName = instanceName;
777     }
778 
779     /***
780      *
781      * @see net.mchaplin.ioc.ContainerI#getParent()
782      */
783     public ContainerI getParent() {
784         return this.parent;
785     }
786     
787     /*** 
788     *
789     * @see net.mchaplin.ioc.ContainerI#setParent(net.mchaplin.ioc.ContainerI)
790     */
791    public final void setParent(ContainerI aParent) {
792        this.parent = aParent;
793    }
794 
795 
796 
797    /***
798     * @return Returns the registeredTypes.
799     */
800    public Map<String,List<ComponentI>> getRegisteredTypes() {
801        return regTypes;
802    }
803 
804    /***
805     * @return Returns the sons.
806     */
807    public ContainerI[] getSons() {
808        return sons;
809    }
810    
811    /***
812     * Return the current state of a Container instance, as formatted text.
813     * 
814     * @return the current Container State as formatted text.
815     */
816    public String getState() {
817        StringBuffer state = new StringBuffer();
818        Iterator it = null;
819        Set kSet = null;
820        ContainerI curSon = null;
821 
822        state.append("Container : [").append(this.getInstanceName()).append("] has parent [");
823        state.append(this.parent != null && this.parent.getInstanceName() != null ? this.parent.getInstanceName() : "").append("]").append(
824                " \n");
825 
826        if (regTypes.isEmpty()) {
827            state.append("Container is empty.");
828        } else {
829            kSet = regTypes.keySet();
830            it = kSet.iterator();
831            state.append("Registered types : \n");
832            while (it.hasNext()) {
833                state.append("\t -> [").append((String) it.next()).append("]").append("\n");
834            }
835 
836        }
837        state.append("Registered sons : \n");
838        if (this.sons != null) {
839            for (int i = 0; i < sonsCount; i++) {
840                curSon = sons[i];
841                state.append("\t -> [").append(curSon.getInstanceName()).append("]").append("\n");
842            }
843        }
844 
845        return state.toString();
846    }
847 
848    /***
849     * @return Returns the sons.
850     */
851    public void addSon(ContainerI container) {
852        ContainerI[] bigger = null;
853        if (sonsCount < SONS_DEFAULT_LENTGH) {
854            sons[sonsCount] = container;
855        } else {
856            // ehe... copying the array ...
857            bigger = new ContainerI[sonsCount + 1];
858            for (int i = 0; i < sons.length; i++) {
859                bigger[i] = sons[i];
860            }
861            bigger[sonsCount] = container;
862            sons = bigger;
863        }
864        log.info(container.getInstanceName() + " registered as son of " + this.instanceName);
865        sonsCount++;
866    }
867     
868 
869     /***
870      * @see net.mchaplin.ioc.component.ComponentI#setContainer(net.mchaplin.ioc.ContainerI)
871      */
872     public void setContainer(ContainerI container) {
873         setParent(container);
874     }
875     /***
876      * @see net.mchaplin.ioc.ComponentI#reset()
877      */
878     public void reset() {
879         regTypes = null;
880         regTypesFact = null;
881         sons = null;
882     }
883 }