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