001    /**
002     *
003     * Copyright 2003-2004 The Apache Software Foundation
004     *
005     *  Licensed under the Apache License, Version 2.0 (the "License");
006     *  you may not use this file except in compliance with the License.
007     *  You may obtain a copy of the License at
008     *
009     *     http://www.apache.org/licenses/LICENSE-2.0
010     *
011     *  Unless required by applicable law or agreed to in writing, software
012     *  distributed under the License is distributed on an "AS IS" BASIS,
013     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     *  See the License for the specific language governing permissions and
015     *  limitations under the License.
016     */
017    
018    package org.apache.geronimo.kernel.basic;
019    
020    import java.util.Collections;
021    import java.util.HashMap;
022    import java.util.HashSet;
023    import java.util.Iterator;
024    import java.util.Map;
025    import java.util.Set;
026    
027    import org.apache.commons.logging.Log;
028    import org.apache.commons.logging.LogFactory;
029    import org.apache.geronimo.kernel.Kernel;
030    import org.apache.geronimo.kernel.GBeanNotFoundException;
031    import org.apache.geronimo.kernel.lifecycle.LifecycleMonitor;
032    import org.apache.geronimo.kernel.lifecycle.LifecycleListener;
033    import org.apache.geronimo.gbean.runtime.LifecycleBroadcaster;
034    import org.apache.geronimo.gbean.AbstractNameQuery;
035    import org.apache.geronimo.gbean.AbstractName;
036    import org.apache.geronimo.gbean.GBeanData;
037    
038    /**
039     * @version $Rev: 430508 $ $Date: 2006-08-10 12:56:47 -0700 (Thu, 10 Aug 2006) $
040     */
041    public class BasicLifecycleMonitor implements LifecycleMonitor {
042        private static final Log log = LogFactory.getLog(BasicLifecycleMonitor.class);
043    
044    
045        // todo we should only hold weak references to the listeners
046        /**
047         * Map of AbstractName to set of Listeners interested in this name.
048         */
049        private final Map boundListeners = new HashMap();
050    
051        /**
052         * Map of listener to patterns they are interested in.
053         */
054        private final Map listenerPatterns = new HashMap();
055    
056        public BasicLifecycleMonitor(Kernel kernel) {
057    
058            // register for state change notifications with all mbeans that match the target patterns
059            Set names = kernel.listGBeans((AbstractNameQuery)null);
060            for (Iterator objectNameIterator = names.iterator(); objectNameIterator.hasNext();) {
061                AbstractName source = (AbstractName) objectNameIterator.next();
062                GBeanData gBeanData;
063                try {
064                    gBeanData = kernel.getGBeanData(source);
065                } catch (GBeanNotFoundException e) {
066                    //this should never happen
067                    throw new AssertionError(e);
068                }
069                addSource(source, gBeanData.getGBeanInfo().getInterfaces());
070            }
071        }
072    
073        public synchronized void destroy() {
074            boundListeners.clear();
075            listenerPatterns.clear();
076        }
077    
078        private synchronized void addSource(AbstractName source, Set interfaceTypes) {
079            if (boundListeners.containsKey(source)) {
080                // already registered
081                return;
082            }
083    
084            // find all listeners interested in events from this source
085            SourceInfo sourceInfo = new SourceInfo(interfaceTypes);
086            HashSet listeners = sourceInfo.getListeners();
087            for (Iterator listenerIterator = listenerPatterns.entrySet().iterator(); listenerIterator.hasNext();) {
088                Map.Entry entry = (Map.Entry) listenerIterator.next();
089                Set patterns = (Set) entry.getValue();
090                for (Iterator patternIterator = patterns.iterator(); patternIterator.hasNext();) {
091                    AbstractNameQuery pattern = (AbstractNameQuery) patternIterator.next();
092                    if (pattern.matches(source, interfaceTypes)) {
093                        LifecycleListener listener = (LifecycleListener) entry.getKey();
094                        listeners.add(listener);
095                    }
096                }
097            }
098    
099            boundListeners.put(source, sourceInfo);
100        }
101    
102        private synchronized void removeSource(AbstractName source) {
103            boundListeners.remove(source);
104        }
105    
106        public synchronized void addLifecycleListener(LifecycleListener listener, AbstractNameQuery pattern) {
107            addLifecycleListener(listener, Collections.singleton(pattern));
108        }
109    
110        public synchronized void addLifecycleListener(LifecycleListener listener, Set patterns) {
111            for (Iterator patternIterator = patterns.iterator(); patternIterator.hasNext();) {
112                AbstractNameQuery pattern = (AbstractNameQuery) patternIterator.next();
113                for (Iterator iterator = boundListeners.entrySet().iterator(); iterator.hasNext();) {
114                    Map.Entry entry = (Map.Entry) iterator.next();
115                    AbstractName source = (AbstractName) entry.getKey();
116                    SourceInfo sourceInfo = (SourceInfo) entry.getValue();
117                    if (pattern.matches(source, sourceInfo.getInterfaceTypes())) {
118                        Set listeners = sourceInfo.getListeners();
119                        listeners.add(listener);
120                    }
121                }
122            }
123            listenerPatterns.put(listener, patterns);
124        }
125    
126        public synchronized void removeLifecycleListener(LifecycleListener listener) {
127            for (Iterator iterator = boundListeners.values().iterator(); iterator.hasNext();) {
128                SourceInfo sourceInfo = (SourceInfo) iterator.next();
129                sourceInfo.getListeners().remove(listener);
130            }
131            listenerPatterns.remove(listener);
132        }
133    
134        private synchronized Set getTargets(AbstractName source) {
135            SourceInfo targets = (SourceInfo) boundListeners.get(source);
136            if (targets == null) {
137                // no one is interested in this event
138                return Collections.EMPTY_SET;
139            } else {
140                return new HashSet(targets.getListeners());
141            }
142        }
143    
144        private void fireLoadedEvent(AbstractName refInfoName) {
145            Set targets = getTargets(refInfoName);
146            for (Iterator iterator = targets.iterator(); iterator.hasNext();) {
147                LifecycleListener listener = (LifecycleListener) iterator.next();
148                try {
149                    listener.loaded(refInfoName);
150                } catch (Throwable e) {
151                    log.warn("Exception occured while notifying listener", e);
152                }
153            }
154        }
155    
156        private void fireStartingEvent(AbstractName source) {
157            Set targets = getTargets(source);
158            for (Iterator iterator = targets.iterator(); iterator.hasNext();) {
159                LifecycleListener listener = (LifecycleListener) iterator.next();
160                try {
161                    listener.starting(source);
162                } catch (Throwable e) {
163                    log.warn("Exception occured while notifying listener", e);
164                }
165            }
166        }
167    
168        private void fireRunningEvent(AbstractName source) {
169            Set targets = getTargets(source);
170            for (Iterator iterator = targets.iterator(); iterator.hasNext();) {
171                LifecycleListener listener = (LifecycleListener) iterator.next();
172                try {
173                    listener.running(source);
174                } catch (Throwable e) {
175                    log.warn("Exception occured while notifying listener", e);
176                }
177            }
178        }
179    
180        private void fireStoppingEvent(AbstractName source) {
181            Set targets = getTargets(source);
182            for (Iterator iterator = targets.iterator(); iterator.hasNext();) {
183                LifecycleListener listener = (LifecycleListener) iterator.next();
184                try {
185                    listener.stopping(source);
186                } catch (Throwable e) {
187                    log.warn("Exception occured while notifying listener", e);
188                }
189            }
190        }
191    
192        private void fireStoppedEvent(AbstractName source) {
193            Set targets = getTargets(source);
194            for (Iterator iterator = targets.iterator(); iterator.hasNext();) {
195                LifecycleListener listener = (LifecycleListener) iterator.next();
196                try {
197                    listener.stopped(source);
198                } catch (Throwable e) {
199                    log.warn("Exception occured while notifying listener", e);
200                }
201            }
202        }
203    
204        private void fireFailedEvent(AbstractName source) {
205            Set targets = getTargets(source);
206            for (Iterator iterator = targets.iterator(); iterator.hasNext();) {
207                LifecycleListener listener = (LifecycleListener) iterator.next();
208                try {
209                    listener.failed(source);
210                } catch (Throwable e) {
211                    log.warn("Exception occured while notifying listener", e);
212                }
213            }
214        }
215    
216        private void fireUnloadedEvent(AbstractName source) {
217            Set targets = getTargets(source);
218            for (Iterator iterator = targets.iterator(); iterator.hasNext();) {
219                LifecycleListener listener = (LifecycleListener) iterator.next();
220                try {
221                    listener.unloaded(source);
222                } catch (Throwable e) {
223                    log.warn("Exception occured while notifying listener", e);
224                }
225            }
226        }
227    
228        public LifecycleBroadcaster createLifecycleBroadcaster(AbstractName abstractName, Set interfaceTypes) {
229            return new RawLifecycleBroadcaster(abstractName, interfaceTypes);
230        }
231    
232        private class RawLifecycleBroadcaster implements LifecycleBroadcaster {
233            private final AbstractName abstractName;
234            private final Set interfaceTypes;
235    
236            public RawLifecycleBroadcaster(AbstractName abstractName, Set interfaceTypes) {
237                this.abstractName = abstractName;
238                this.interfaceTypes = interfaceTypes;
239            }
240    
241            public void fireLoadedEvent() {
242                addSource(abstractName, interfaceTypes);
243                BasicLifecycleMonitor.this.fireLoadedEvent(abstractName);
244            }
245    
246            public void fireStartingEvent() {
247                BasicLifecycleMonitor.this.fireStartingEvent(abstractName);
248            }
249    
250            public void fireRunningEvent() {
251                BasicLifecycleMonitor.this.fireRunningEvent(abstractName);
252            }
253    
254            public void fireStoppingEvent() {
255                BasicLifecycleMonitor.this.fireStoppingEvent(abstractName);
256            }
257    
258            public void fireStoppedEvent() {
259                BasicLifecycleMonitor.this.fireStoppedEvent(abstractName);
260            }
261    
262            public void fireFailedEvent() {
263                BasicLifecycleMonitor.this.fireFailedEvent(abstractName);
264            }
265    
266            public void fireUnloadedEvent() {
267                BasicLifecycleMonitor.this.fireUnloadedEvent(abstractName);
268                removeSource(abstractName);
269            }
270        }
271    
272        private final class SourceInfo {
273            private final Set interfaceTypes;
274            private final HashSet listeners = new HashSet();
275    
276            public SourceInfo(Set interfaceTypes) {
277                this.interfaceTypes = interfaceTypes;
278            }
279    
280            public Set getInterfaceTypes() {
281                return interfaceTypes;
282            }
283    
284            public HashSet getListeners() {
285                return listeners;
286            }
287        }
288    
289    }