001    /*
002    @license.text@
003     */
004    package biz.hammurapi.util;
005    
006    import java.util.ArrayList;
007    import java.util.Collections;
008    import java.util.HashMap;
009    import java.util.Iterator;
010    import java.util.List;
011    import java.util.Map;
012    
013    import org.w3c.dom.Element;
014    import org.w3c.dom.Node;
015    import org.w3c.dom.NodeList;
016    
017    import biz.hammurapi.config.ClassAcceptor;
018    import biz.hammurapi.config.Component;
019    import biz.hammurapi.config.ConfigurationException;
020    import biz.hammurapi.config.Context;
021    import biz.hammurapi.config.DomConfigFactory;
022    import biz.hammurapi.config.DomConfigurable;
023    import biz.hammurapi.config.PathNavigator;
024    import biz.hammurapi.xml.dom.DOMUtils;
025    
026    
027    /**
028     * Simple container
029     * @author Pavel Vlasov
030     * @revision $Revision$
031     */
032    public class CompositeWorkerContainer implements Component, DomConfigurable, Worker, Context {
033            private Map workerMap=new HashMap(); 
034            private List workers=new ArrayList();
035            private boolean started;
036            private Object parent;
037            
038            private PathNavigator pathNavigator=new PathNavigator(this) {
039    
040                    protected Object getParent() {
041                            return parent;
042                    }
043    
044                    protected Object getChild(String name) {
045                            return workerMap.get(name);
046                    }
047                    
048            };
049            
050            
051            public CompositeWorkerContainer() {
052                    // Default constructor
053            }
054            
055            /**
056             * Looks up component in component tree.
057             * @param name
058             * @return
059             */
060            public Object get(String name) {                
061                    return pathNavigator.get(name);
062            }
063            
064            /**
065             * Adds component and starts it.
066             * @param name
067             * @param worker
068             * @throws ConfigurationException 
069             */
070            private void addWorker(String name, Worker worker) throws ConfigurationException {
071                    if (name!=null) {
072                            // Remove previous worker
073                            Object prevWorkerWithSameName=workerMap.remove(name);
074                            if (prevWorkerWithSameName!=null) {
075                                    workers.remove(prevWorkerWithSameName);
076                                    if (prevWorkerWithSameName instanceof Component) {
077                                            if (started) {
078                                                    ((Component) prevWorkerWithSameName).stop();
079                                            }
080                                            ((Component) prevWorkerWithSameName).setOwner(null);
081                                    }
082                            }
083                    }
084                    
085                    if (worker!=null) {
086                            // Add new worker
087                            if (worker instanceof Component) {
088                                    Component theComponent = (Component) worker;
089                                    theComponent.setOwner(this);
090                                    if (started) {
091                                            theComponent.start();
092                                    }
093                            }
094            
095                            if (name!=null) {
096                                    workerMap.put(name, worker);
097                            }
098                            
099                            workers.add(worker);
100                    }
101            }
102            
103            public void start() throws ConfigurationException {
104                    Iterator it=workers.iterator();
105                    while (it.hasNext()) {
106                            Object worker = it.next();
107                            if (worker instanceof Component) {
108                                    ((Component) worker).start();
109                            }                       
110                    }
111                    started=true;
112            }
113            
114            public void stop() throws ConfigurationException {
115                    started=false;
116                    List reverseWorkerList=new ArrayList(workers);
117                    Collections.reverse(reverseWorkerList);
118                    Iterator it=reverseWorkerList.iterator();
119                    while (it.hasNext()) {
120                            Object worker = it.next();
121                            if (worker instanceof Component) {
122                                    ((Component) worker).stop();
123                            }                       
124                    }
125            }
126    
127            public void setOwner(Object owner) {
128                    parent=owner;           
129            }
130            
131            public void configure(Node configNode, Context context) throws ConfigurationException {
132                    DomConfigFactory factory=new DomConfigFactory(context);
133                    try {
134                            NodeList nl = DOMUtils.selectNodeList(configNode, "worker|worker-ref");
135                            for (int i=0, l=nl.getLength(); i<l; ++i) {
136                                    Element we = (Element) nl.item(i);
137                                    if ("worker".equals(we.getNodeName())) {
138                                            addWorker(
139                                                            we.hasAttribute("name") ? we.getAttribute("name") : null, 
140                                                            (Worker)factory.create(
141                                                                            we,
142                                                                            new ClassAcceptor() {
143    
144                                                                                    public void accept(Class clazz) throws ConfigurationException {
145                                                                                            if (!(Worker.class.isAssignableFrom(clazz))) {
146                                                                                                    throw new ConfigurationException(clazz.getName()+" does not implement "+Worker.class+" interface.");
147                                                                                            }
148                                                                                    }
149                                                                                    
150                                                                            },
151                                                                            null));
152                                    } else {
153                                            String ref = DOMUtils.getElementText(we);
154                                            Object referencedWorker=get(ref);
155                                            if (referencedWorker==null) {
156                                                    throw new ConfigurationException("Invalid worker reference: "+ref);
157                                            }
158                                            
159                                            if (!(referencedWorker instanceof Worker)) {
160                                                    throw new ConfigurationException(referencedWorker.getClass().getName()+" does not implement "+Worker.class+" interface.");                                              
161                                            }
162                                            
163                                            addWorker(we.hasAttribute("name") ? we.getAttribute("name") : null, (Worker) referencedWorker); 
164                                    }
165                            } 
166                    } catch (Exception e) {
167                            throw new ConfigurationException(e);
168                    }
169            }
170            
171            /**
172             * Gives job to workers until one of them accepts it.
173             */
174            public boolean post(Runnable job) {
175                    Iterator it=workers.iterator();
176                    while (it.hasNext()) {
177                            Worker worker=(Worker)  it.next();
178                            if (worker.post(job)) {
179                                    return true;
180                            }                       
181                    }
182                    return false;
183            }       
184    }