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    package org.apache.xbean.kernel.standard;
018    
019    import java.util.ArrayList;
020    import java.util.Collections;
021    import java.util.Iterator;
022    import java.util.LinkedHashMap;
023    import java.util.LinkedHashSet;
024    import java.util.List;
025    import java.util.Map;
026    import java.util.Set;
027    
028    import org.apache.xbean.kernel.ServiceMonitor;
029    import org.apache.xbean.kernel.KernelMonitor;
030    import org.apache.xbean.kernel.ServiceName;
031    import org.apache.xbean.kernel.ServiceEvent;
032    import org.apache.xbean.kernel.KernelErrorsError;
033    
034    /**
035     * The ServiceMonitorBroadcaster broadcasts kernel events to registered service monitors.
036     *
037     * @author Dain Sundstrom
038     * @version $Id$
039     * @since 2.0
040     */
041    public class ServiceMonitorBroadcaster implements ServiceMonitor {
042        /**
043         * The monitors for service events.
044         */
045        private final Map serviceMonitors = new LinkedHashMap();
046    
047        /**
048         * The monitor we notify when we get an exception from a service monitor.
049         */
050        private final KernelMonitor kernelMonitor;
051    
052        /**
053         * Creates a ServiceMonitorBroadcaster that notifies the specified kernel monitor when an error occurs while
054         * notifying the registered service monitors.
055         *
056         * @param kernelMonitor the monitor to notify when an error occurs while notifying the registered service monitors
057         */
058        public ServiceMonitorBroadcaster(KernelMonitor kernelMonitor) {
059            if (kernelMonitor == null) throw new NullPointerException("kernelMonitor is null");
060            this.kernelMonitor = kernelMonitor;
061        }
062    
063        /**
064         * Adds a service monitor for a specific service, or if the specified service name is null, a global monitor.
065         * <p/>
066         * Note: the order in which service monitors are notified is not specified.
067         *
068         * @param serviceMonitor the service monitor to add
069         * @param serviceName the unique name of the service to monitor or null to monitor all services
070         */
071        public void addServiceMonitor(ServiceMonitor serviceMonitor, ServiceName serviceName) {
072            if (serviceMonitor == null) throw new NullPointerException("serviceMonitor is null");
073            synchronized (serviceMonitors) {
074                Set monitors = (Set) serviceMonitors.get(serviceName);
075                if (monitors == null) {
076                    monitors = new LinkedHashSet();
077                    serviceMonitors.put(serviceName, monitors);
078                }
079                monitors.add(serviceMonitor);
080            }
081        }
082    
083        /**
084         * Removes a service monitor.
085         *
086         * @param serviceMonitor the service monitor to remove
087         */
088        public void removeServiceMonitor(ServiceMonitor serviceMonitor) {
089            if (serviceMonitor == null) throw new NullPointerException("serviceMonitor is null");
090            synchronized (serviceMonitors) {
091                for (Iterator iterator = serviceMonitors.values().iterator(); iterator.hasNext();) {
092                    Set monitors = (Set) iterator.next();
093                    monitors.remove(serviceMonitor);
094                    if (monitors.isEmpty()) {
095                        iterator.remove();
096                    }
097                }
098            }
099        }
100    
101        /**
102         * Gets the service monitors registered to recieve events for the specified service.  This will include all global
103         * monitors and service specific monitors.
104         *
105         * @param serviceName the name of the service
106         * @return the monitors registerd to recieve events for the specified service
107         */
108        private Set getServiceMonitors(ServiceName serviceName) {
109            synchronized (serviceMonitors) {
110                Set monitors = new LinkedHashSet();
111                Set globalMonitors = (Set) serviceMonitors.get(null);
112                if (globalMonitors != null) {
113                    monitors.addAll(globalMonitors);
114                }
115                Set specificMonitors = (Set) serviceMonitors.get(serviceName);
116                if (specificMonitors != null) {
117                    monitors.addAll(specificMonitors);
118                }
119                return monitors;
120            }
121        }
122    
123        /**
124         * {@inheritDoc}
125         */
126        public void serviceRegistered(ServiceEvent serviceEvent) {
127            List errors = new ArrayList();
128            Set serviceMonitors = getServiceMonitors(serviceEvent.getServiceName());
129            for (Iterator iterator = serviceMonitors.iterator(); iterator.hasNext();) {
130                ServiceMonitor serviceMonitor = (ServiceMonitor) iterator.next();
131                try {
132                    serviceMonitor.serviceRegistered(serviceEvent);
133                } catch (Throwable e) {
134                    errors.addAll(fireServiceNotificationError(serviceMonitor, serviceEvent, e));
135                }
136            }
137            if (!errors.isEmpty()) {
138                throw new KernelErrorsError(errors);
139            }
140        }
141    
142        /**
143         * {@inheritDoc}
144         */
145        public void serviceStarting(ServiceEvent serviceEvent) {
146            List errors = new ArrayList();
147            Set serviceMonitors = getServiceMonitors(serviceEvent.getServiceName());
148            for (Iterator iterator = serviceMonitors.iterator(); iterator.hasNext();) {
149                ServiceMonitor serviceMonitor = (ServiceMonitor) iterator.next();
150                try {
151                    serviceMonitor.serviceStarting(serviceEvent);
152                } catch (Throwable e) {
153                    errors.addAll(fireServiceNotificationError(serviceMonitor, serviceEvent, e));
154                }
155            }
156            if (!errors.isEmpty()) {
157                throw new KernelErrorsError(errors);
158            }
159        }
160    
161        /**
162         * {@inheritDoc}
163         */
164        public void serviceWaitingToStart(ServiceEvent serviceEvent) {
165            List errors = new ArrayList();
166            Set serviceMonitors = getServiceMonitors(serviceEvent.getServiceName());
167            for (Iterator iterator = serviceMonitors.iterator(); iterator.hasNext();) {
168                ServiceMonitor serviceMonitor = (ServiceMonitor) iterator.next();
169                try {
170                    serviceMonitor.serviceWaitingToStart(serviceEvent);
171                } catch (Throwable e) {
172                    errors.addAll(fireServiceNotificationError(serviceMonitor, serviceEvent, e));
173                }
174            }
175            if (!errors.isEmpty()) {
176                throw new KernelErrorsError(errors);
177            }
178        }
179    
180        /**
181         * {@inheritDoc}
182         */
183        public void serviceStartError(ServiceEvent serviceEvent) {
184            List errors = new ArrayList();
185            Set serviceMonitors = getServiceMonitors(serviceEvent.getServiceName());
186            for (Iterator iterator = serviceMonitors.iterator(); iterator.hasNext();) {
187                ServiceMonitor serviceMonitor = (ServiceMonitor) iterator.next();
188                try {
189                    serviceMonitor.serviceStartError(serviceEvent);
190                } catch (Throwable e) {
191                    errors.addAll(fireServiceNotificationError(serviceMonitor, serviceEvent, e));
192                }
193            }
194            if (!errors.isEmpty()) {
195                throw new KernelErrorsError(errors);
196            }
197        }
198    
199        /**
200         * {@inheritDoc}
201         */
202        public void serviceRunning(ServiceEvent serviceEvent) {
203            List errors = new ArrayList();
204            Set serviceMonitors = getServiceMonitors(serviceEvent.getServiceName());
205            for (Iterator iterator = serviceMonitors.iterator(); iterator.hasNext();) {
206                ServiceMonitor serviceMonitor = (ServiceMonitor) iterator.next();
207                try {
208                    serviceMonitor.serviceRunning(serviceEvent);
209                } catch (Throwable e) {
210                    errors.addAll(fireServiceNotificationError(serviceMonitor, serviceEvent, e));
211                }
212            }
213            if (!errors.isEmpty()) {
214                throw new KernelErrorsError(errors);
215            }
216        }
217    
218        /**
219         * {@inheritDoc}
220         */
221        public void serviceStopping(ServiceEvent serviceEvent) {
222            List errors = new ArrayList();
223            Set serviceMonitors = getServiceMonitors(serviceEvent.getServiceName());
224            for (Iterator iterator = serviceMonitors.iterator(); iterator.hasNext();) {
225                ServiceMonitor serviceMonitor = (ServiceMonitor) iterator.next();
226                try {
227                    serviceMonitor.serviceStopping(serviceEvent);
228                } catch (Throwable e) {
229                    errors.addAll(fireServiceNotificationError(serviceMonitor, serviceEvent, e));
230                }
231            }
232            if (!errors.isEmpty()) {
233                throw new KernelErrorsError(errors);
234            }
235        }
236    
237        /**
238         * {@inheritDoc}
239         */
240        public void serviceWaitingToStop(ServiceEvent serviceEvent) {
241            List errors = new ArrayList();
242            Set serviceMonitors = getServiceMonitors(serviceEvent.getServiceName());
243            for (Iterator iterator = serviceMonitors.iterator(); iterator.hasNext();) {
244                ServiceMonitor serviceMonitor = (ServiceMonitor) iterator.next();
245                try {
246                    serviceMonitor.serviceWaitingToStop(serviceEvent);
247                } catch (Throwable e) {
248                    errors.addAll(fireServiceNotificationError(serviceMonitor, serviceEvent, e));
249                }
250            }
251            if (!errors.isEmpty()) {
252                throw new KernelErrorsError(errors);
253            }
254        }
255    
256        /**
257         * {@inheritDoc}
258         */
259        public void serviceStopError(ServiceEvent serviceEvent) {
260            List errors = new ArrayList();
261            Set serviceMonitors = getServiceMonitors(serviceEvent.getServiceName());
262            for (Iterator iterator = serviceMonitors.iterator(); iterator.hasNext();) {
263                ServiceMonitor serviceMonitor = (ServiceMonitor) iterator.next();
264                try {
265                    serviceMonitor.serviceStopError(serviceEvent);
266                } catch (Throwable e) {
267                    errors.addAll(fireServiceNotificationError(serviceMonitor, serviceEvent, e));
268                }
269            }
270            if (!errors.isEmpty()) {
271                throw new KernelErrorsError(errors);
272            }
273        }
274    
275        /**
276         * {@inheritDoc}
277         */
278        public void serviceStopped(ServiceEvent serviceEvent) {
279            List errors = new ArrayList();
280            Set serviceMonitors = getServiceMonitors(serviceEvent.getServiceName());
281            for (Iterator iterator = serviceMonitors.iterator(); iterator.hasNext();) {
282                ServiceMonitor serviceMonitor = (ServiceMonitor) iterator.next();
283                try {
284                    serviceMonitor.serviceStopped(serviceEvent);
285                } catch (Throwable e) {
286                    errors.addAll(fireServiceNotificationError(serviceMonitor, serviceEvent, e));
287                }
288            }
289            if (!errors.isEmpty()) {
290                throw new KernelErrorsError(errors);
291            }
292        }
293    
294        /**
295         * {@inheritDoc}
296         */
297        public void serviceUnregistered(ServiceEvent serviceEvent) {
298            List errors = new ArrayList();
299            Set serviceMonitors = getServiceMonitors(serviceEvent.getServiceName());
300            for (Iterator iterator = serviceMonitors.iterator(); iterator.hasNext();) {
301                ServiceMonitor serviceMonitor = (ServiceMonitor) iterator.next();
302                try {
303                    serviceMonitor.serviceUnregistered(serviceEvent);
304                } catch (Throwable e) {
305                    errors.addAll(fireServiceNotificationError(serviceMonitor, serviceEvent, e));
306                }
307            }
308            if (!errors.isEmpty()) {
309                throw new KernelErrorsError(errors);
310            }
311        }
312    
313        private List fireServiceNotificationError(ServiceMonitor serviceMonitor, ServiceEvent serviceEvent, Throwable throwable) {
314            try {
315                kernelMonitor.serviceNotificationError(serviceMonitor, serviceEvent, throwable);
316            } catch (RuntimeException ignored) {
317                // ignore - we did our best to notify the world
318            } catch (KernelErrorsError e) {
319                return e.getErrors();
320            } catch (Error e) {
321                return Collections.singletonList(e);
322            }
323            return Collections.EMPTY_LIST;
324        }
325    }