001    package biz.hammurapi.config;
002    
003    import java.util.ArrayList;
004    import java.util.Collection;
005    import java.util.Collections;
006    import java.util.Iterator;
007    import java.util.LinkedHashMap;
008    import java.util.List;
009    import java.util.Map;
010    import java.util.Set;
011    
012    import biz.hammurapi.metrics.MeasurementCollector;
013    import biz.hammurapi.metrics.MeasurementConsumer;
014    import biz.hammurapi.util.Attributable;
015    import biz.hammurapi.util.CollectionVisitable;
016    import biz.hammurapi.util.VisitableBase;
017    import biz.hammurapi.util.Visitor;
018    
019    public class GenericContainer extends VisitableBase implements Component, Command, Attributable, Context, MeasurementCollector, MeasurementConsumer {
020    
021            private Map componentMap = new LinkedHashMap();
022    
023            protected Map getComponentMap() {
024                    return componentMap;
025            }
026    
027            private boolean started;
028            private Object owner;
029            
030            private PathNavigator pathNavigator = new PathNavigator(this) {
031            
032                            protected Object getParent() {
033                                    return owner;
034                            }
035            
036                            protected Object getChild(String name) {
037                                    return componentMap.get(name);
038                            }
039                            
040                    };
041                    
042            private LinkedHashMap attributes = new LinkedHashMap();
043            private MeasurementConsumer measurementConsumer;
044    
045            /**
046             * Looks up component in component tree.
047             * @param name
048             * @return
049             */
050            public Object get(String name) {                
051                    return pathNavigator.get(name);
052            }
053    
054            /**
055             * Adds component and starts it.
056             * @param name
057             * @param component
058             * @throws ConfigurationException 
059             */
060            public void addComponent(String name, Object component) throws ConfigurationException {
061                    if (name==null) {
062                            name = "Anonymous component "+componentMap.size();
063                    }
064                    
065                    // Remove previous component
066                    Object prevComponent=componentMap.remove(name);
067                    if (prevComponent!=null) {
068                            if (prevComponent instanceof Component) {
069                                    if (started) {
070                                            ((Component) prevComponent).stop();
071                                    }
072                                    ((Component) prevComponent).setOwner(null);
073                            }
074                            
075                            if (prevComponent instanceof MeasurementCollector) {
076                                    ((MeasurementCollector) prevComponent).setMeasurementConsumer(null);
077                            }
078                    }
079                    
080                    if (component!=null) {
081                            if (component instanceof MeasurementCollector) {
082                                    final String componentName = name;
083                                    MeasurementConsumer cmc = new MeasurementConsumer() {
084                                            public void addMeasurement(String mName, double value, long time) {
085                                                    if (measurementConsumer!=null) {
086                                                            measurementConsumer.addMeasurement(componentName+"."+mName, value, time==0 ? System.currentTimeMillis() : time);
087                                                    }                                               
088                                            }
089                                    };
090                                    ((MeasurementCollector) component).setMeasurementConsumer(cmc);
091                            }
092                            
093                            if (component instanceof NamedComponent) {
094                                    ((NamedComponent) component).setName(name);
095                            }
096                            
097                            // Add new component
098                            if (component instanceof Component) {
099                                    Component theComponent = (Component) component;
100                                    theComponent.setOwner(this);
101                                    if (started) {
102                                            theComponent.start();
103                                    }
104                            }
105            
106                            if (name!=null) {
107                                    componentMap.put(name, component);
108                            }
109                            
110                    }
111            }
112    
113            public void start() throws ConfigurationException {
114                    if (getMeasurementConsumer() instanceof Component) {
115                            ((Component) getMeasurementConsumer()).start();
116                    }
117                    
118                    Iterator it=componentMap.values().iterator();
119                    while (it.hasNext()) {
120                            Object component = it.next();
121                            if (component instanceof Component) {
122                                    ((Component) component).start();
123                            }                       
124                    }
125                    started=true;
126            }
127    
128            public void stop() throws ConfigurationException {
129                    started=false;
130                    List reverseComponentList=new ArrayList(componentMap.values());
131                    Collections.reverse(reverseComponentList);
132                    Iterator it=reverseComponentList.iterator();
133                    while (it.hasNext()) {
134                            Object component = it.next();
135                            if (component instanceof Component) {
136                                    ((Component) component).stop();
137                            }                       
138                    }
139                    if (getMeasurementConsumer() instanceof Component) {
140                            ((Component) getMeasurementConsumer()).stop();
141                    }
142            }
143    
144            public void setOwner(Object owner) {
145                    this.owner=owner;               
146            }
147    
148            /**
149             * Invokes execute() of executable components sequentially.
150             */
151            public void execute(Object executionContext) {
152                    Iterator it=componentMap.values().iterator();
153                    while (it.hasNext()) {
154                            Object component = it.next();
155                            if (component instanceof Command) {
156                                    ((Command) component).execute(executionContext);
157                            }                       
158                    }
159            }
160    
161            protected void acceptChildren(Visitor visitor) {
162                    new CollectionVisitable(componentMap.values(), false).accept(visitor);
163            }
164    
165            protected Collection getComponents() {
166                    return componentMap.values();
167            }
168    
169            public Set getComponentNames() {
170                    return Collections.unmodifiableSet(componentMap.keySet());
171            }
172    
173            public void setAttribute(Object key, Object value) {
174                    attributes.put(key, value);
175            }
176    
177            public Object getAttribute(Object key) {
178                    return attributes.get(key);
179            }
180    
181            public Object removeAttribute(Object key) {
182                    return attributes.remove(key);
183            }
184    
185            public void setMeasurementConsumer(MeasurementConsumer measurementConsumer) {
186                    this.measurementConsumer = measurementConsumer;         
187                    if (measurementConsumer instanceof Component) {
188                            ((Component) measurementConsumer).setOwner(this);
189                    }
190            }
191            
192            public MeasurementConsumer getMeasurementConsumer() {
193                    return measurementConsumer;
194            }
195    
196            public void addMeasurement(String name, double value, long time) {
197                    if (measurementConsumer!=null) {
198                            measurementConsumer.addMeasurement(name, value, time);
199                    }               
200            }               
201    
202            /**
203             * Finds component owner of particular type.
204             * @param ownerType
205             * @return Owner which is an instance of specified type or null if no such owner is found.
206             */
207            public Object getOwner(Class ownerType) {
208                    if (owner==null || ownerType.isInstance(owner)) {
209                            return owner;
210                    }
211                    
212                    if (owner instanceof ComponentBase) {
213                            return ((ComponentBase) owner).getOwner(ownerType);
214                    }
215                    
216                    if (owner instanceof GenericContainer) {
217                            return ((GenericContainer) owner).getOwner(ownerType);
218                    }
219                    
220                    return null;
221            }
222    }