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.List;
020    import java.util.ArrayList;
021    import java.util.Iterator;
022    
023    import java.util.concurrent.Executors;
024    import java.util.concurrent.ExecutorService;
025    import java.util.concurrent.TimeUnit;
026    import java.util.concurrent.locks.Lock;
027    import java.util.concurrent.locks.ReentrantLock;
028    import java.util.concurrent.locks.Condition;
029    import org.apache.xbean.kernel.IllegalServiceStateException;
030    import org.apache.xbean.kernel.Kernel;
031    import org.apache.xbean.kernel.KernelErrorsError;
032    import org.apache.xbean.kernel.KernelMonitor;
033    import org.apache.xbean.kernel.ServiceAlreadyExistsException;
034    import org.apache.xbean.kernel.ServiceFactory;
035    import org.apache.xbean.kernel.ServiceMonitor;
036    import org.apache.xbean.kernel.ServiceName;
037    import org.apache.xbean.kernel.ServiceNotFoundException;
038    import org.apache.xbean.kernel.ServiceRegistrationException;
039    import org.apache.xbean.kernel.ServiceState;
040    import org.apache.xbean.kernel.StartStrategies;
041    import org.apache.xbean.kernel.StartStrategy;
042    import org.apache.xbean.kernel.StopStrategies;
043    import org.apache.xbean.kernel.StopStrategy;
044    import org.apache.xbean.kernel.UnregisterServiceException;
045    import org.apache.xbean.kernel.UnsatisfiedConditionsException;
046    import org.apache.xbean.kernel.KernelFactory;
047    
048    /**
049     * The standard kernel implementation.
050     *
051     * @author Dain Sundstrom
052     * @version $Id$
053     * @since 2.0
054     */
055    public class StandardKernel implements Kernel {
056        /**
057         * The unique name of this kernel.
058         */
059        private final String kernelName;
060    
061        /**
062         * The registered service managers.
063         */
064        private final ServiceManagerRegistry serviceManagerRegistry;
065    
066        /**
067         * Tracks and broadcasts kernel evnents to the registered listeners.
068         */
069        private final KernelMonitorBroadcaster kernelMonitor = new KernelMonitorBroadcaster();
070    
071        /**
072         * This monitor broadcasts events to the listeners registered for service.
073         */
074        private final ServiceMonitorBroadcaster serviceMonitor = new ServiceMonitorBroadcaster(kernelMonitor);
075    
076        /**
077         * If true, the kernel is still running.
078         */
079        private boolean running = true;
080    
081        /**
082         * Lock that should be acquired before accessing the running boolean flag.
083         */
084        private final Lock destroyLock = new ReentrantLock();
085    
086        /**
087         * The condition that is notified when the kernel has been destroyed.
088         */
089        private final Condition destroyCondition = destroyLock.newCondition();
090    
091        /**
092         * Creates the service managers with handle service lifecycle.
093         */
094        private ServiceManagerFactory serviceManagerFactory;
095        
096        /**
097         * The service executor for this kernel
098         */         
099        private ExecutorService serviceExecutor;
100        
101        /**
102         * True if the executor is owned by this kernel and should be shutdown
103         * when the kernel is destroyed     
104         */         
105        private boolean ownsServiceExecutor;
106    
107        /**
108         * Creates a kernel using the specified name.
109         *
110         * @param kernelName the unique name of this kernel
111         */
112        public StandardKernel(String kernelName) {
113            this(kernelName, Executors.newCachedThreadPool(), 30, TimeUnit.SECONDS);
114            ownsServiceExecutor = true;
115        }
116    
117        /**
118         * Creates a kernel using the specified name.
119         *
120         * @param kernelName the unique name of this kernel
121         * @param serviceExecutor the executor to use for asynchronous service operations
122         * @param timeoutDuration the maximum duration to wait for a service event to complete
123         * @param timeoutUnits the unit of measure for the timeoutDuration
124         */
125        public StandardKernel(String kernelName, ExecutorService serviceExecutor, long timeoutDuration, TimeUnit timeoutUnits) {
126            if (kernelName == null) throw new NullPointerException("kernelName is null");
127            if (kernelName.length() ==0) throw new IllegalArgumentException("kernelName must be atleast one character long");
128            if (serviceExecutor == null) throw new NullPointerException("serviceExecutor is null");
129            if (timeoutUnits == null) throw new NullPointerException("timeoutUnits is null");
130    
131            this.kernelName = kernelName;
132            this.serviceExecutor = serviceExecutor;
133            serviceManagerFactory = new ServiceManagerFactory(this, serviceMonitor, serviceExecutor, timeoutDuration, timeoutUnits);
134            serviceManagerRegistry = new ServiceManagerRegistry(serviceManagerFactory);
135        }
136    
137        /**
138         * {@inheritDoc}
139         */
140        public void destroy() throws KernelErrorsError {
141            destroyLock.lock();
142            try {
143                // if we are already stopped simply return
144                if (!running) {
145                    return;
146                }
147                running = false;
148            } finally {
149                destroyLock.unlock();
150            }
151    
152            // destroy all services
153            serviceManagerRegistry.destroy();
154            
155            // shutdown service executor
156            if (ownsServiceExecutor) {
157                serviceExecutor.shutdown();
158            }
159    
160            // remove this kernel from the kernel factory registry
161            KernelFactory.destroyInstance(this);
162    
163            // notify threads waiting for destroy to complete
164            destroyLock.lock();
165            try {
166                destroyCondition.signalAll();
167            } finally {
168                destroyLock.unlock();
169            }
170        }
171    
172        /**
173         * {@inheritDoc}
174         */
175        public void waitForDestruction() {
176            destroyLock.lock();
177            try {
178                // if we are already stopped simply return
179                if (!running) {
180                    return;
181                }
182    
183                // wait until destroy completes
184                destroyCondition.awaitUninterruptibly();
185            } finally {
186                destroyLock.unlock();
187            }
188    
189        }
190    
191        /**
192         * {@inheritDoc}
193         */
194        public boolean isRunning() {
195            destroyLock.lock();
196            try {
197                return running;
198            } finally {
199                destroyLock.unlock();
200            }
201        }
202    
203        /**
204         * {@inheritDoc}
205         */
206        public String getKernelName() {
207            return kernelName;
208        }
209    
210        /**
211         * {@inheritDoc}
212         */
213        public void registerService(ServiceName serviceName, ServiceFactory serviceFactory) throws ServiceAlreadyExistsException, ServiceRegistrationException {
214            if (serviceName == null) throw new NullPointerException("serviceName is null");
215            if (serviceFactory == null) throw new NullPointerException("serviceFactory is null");
216            if (!isRunning()) {
217                throw new ServiceRegistrationException(serviceName, new IllegalStateException("Kernel is destroyed"));
218            }
219    
220            serviceManagerRegistry.registerService(serviceName, serviceFactory);
221        }
222    
223        /**
224         * {@inheritDoc}
225         */
226        public void unregisterService(ServiceName serviceName) throws ServiceNotFoundException, ServiceRegistrationException {
227            if (serviceName == null) throw new NullPointerException("serviceName is null");
228            unregisterService(serviceName, StopStrategies.SYNCHRONOUS);
229        }
230    
231        /**
232         * {@inheritDoc}
233         */
234        public void unregisterService(ServiceName serviceName, StopStrategy stopStrategy) throws ServiceNotFoundException, ServiceRegistrationException {
235            if (serviceName == null) throw new NullPointerException("serviceName is null");
236            if (stopStrategy == null) throw new NullPointerException("stopStrategy is null");
237            if (!isRunning()) {
238                return;
239            }
240    
241            serviceManagerRegistry.unregisterService(serviceName, stopStrategy);
242        }
243    
244        /**
245         * {@inheritDoc}
246         */
247        public boolean isRegistered(ServiceName serviceName) {
248            if (serviceName == null) throw new NullPointerException("serviceName is null");
249            if (!isRunning()) {
250                return false;
251            }
252    
253            return serviceManagerRegistry.isRegistered(serviceName);
254        }
255    
256        /**
257         * {@inheritDoc}
258         */
259        public ServiceState getServiceState(ServiceName serviceName) throws ServiceNotFoundException {
260            if (serviceName == null) throw new NullPointerException("serviceName is null");
261            ServiceManager serviceManager = getServiceManager(serviceName);
262            return serviceManager.getState();
263        }
264    
265        /**
266         * {@inheritDoc}
267         */
268        public long getServiceStartTime(ServiceName serviceName) throws ServiceNotFoundException {
269            if (serviceName == null) throw new NullPointerException("serviceName is null");
270            ServiceManager serviceManager = getServiceManager(serviceName);
271            return serviceManager.getStartTime();
272        }
273    
274        /**
275         * {@inheritDoc}
276         */
277        public void startService(ServiceName serviceName) throws ServiceNotFoundException, IllegalServiceStateException, UnsatisfiedConditionsException, Exception {
278            if (serviceName == null) throw new NullPointerException("serviceName is null");
279            startService(serviceName, false, StartStrategies.SYNCHRONOUS);
280        }
281    
282        /**
283         * {@inheritDoc}
284         */
285        public void startService(ServiceName serviceName, StartStrategy startStrategy) throws ServiceNotFoundException, IllegalServiceStateException, UnsatisfiedConditionsException, Exception {
286            if (serviceName == null) throw new NullPointerException("serviceName is null");
287            if (startStrategy == null) throw new NullPointerException("startStrategy is null");
288            startService(serviceName, false, startStrategy);
289        }
290    
291        /**
292         * {@inheritDoc}
293         */
294        public void startServiceRecursive(ServiceName serviceName) throws ServiceNotFoundException, IllegalServiceStateException, UnsatisfiedConditionsException, Exception {
295            if (serviceName == null) throw new NullPointerException("serviceName is null");
296            startService(serviceName, true, StartStrategies.SYNCHRONOUS);
297        }
298    
299        /**
300         * {@inheritDoc}
301         */
302        public void startServiceRecursive(ServiceName serviceName, StartStrategy startStrategy) throws ServiceNotFoundException, IllegalServiceStateException, UnsatisfiedConditionsException, Exception {
303            if (serviceName == null) throw new NullPointerException("serviceName is null");
304            if (startStrategy == null) throw new NullPointerException("startStrategy is null");
305            startService(serviceName, true, startStrategy);
306        }
307    
308        private void startService(ServiceName serviceName, boolean recursive, StartStrategy startStrategy) throws Exception {
309            if (startStrategy == null) throw new NullPointerException("startStrategy is null");
310            ServiceManager serviceManager = getServiceManager(serviceName);
311            try {
312                serviceManager.start(recursive, startStrategy);
313            } catch (UnregisterServiceException e) {
314                try {
315                    unregisterService(serviceName, StopStrategies.FORCE);
316                } catch (ServiceNotFoundException ignored) {
317                    // that is weird, but what ever
318                } catch (ServiceRegistrationException ignored) {
319                    // we are alredy throwing an exception so ignore this one
320                }
321                Throwable cause = e.getCause();
322                if (cause instanceof Exception) {
323                    throw (Exception) cause;
324                } else if (cause instanceof Error) {
325                    throw (Error) cause;
326                } else {
327                    throw new AssertionError(cause);
328                }
329            }
330        }
331    
332        /**
333         * {@inheritDoc}
334         */
335        public void stopService(ServiceName serviceName) throws ServiceNotFoundException, UnsatisfiedConditionsException {
336            if (serviceName == null) throw new NullPointerException("serviceName is null");
337            stopService(serviceName, StopStrategies.SYNCHRONOUS);
338        }
339    
340        /**
341         * {@inheritDoc}
342         */
343        public void stopService(ServiceName serviceName, StopStrategy stopStrategy) throws ServiceNotFoundException, UnsatisfiedConditionsException {
344            if (serviceName == null) throw new NullPointerException("serviceName is null");
345            if (stopStrategy == null) throw new NullPointerException("stopStrategy is null");
346            ServiceManager serviceManager = getServiceManager(serviceName);
347            serviceManager.stop(stopStrategy);
348        }
349    
350        /**
351         * {@inheritDoc}
352         */
353        public boolean isServiceEnabled(ServiceName serviceName) throws ServiceNotFoundException {
354            if (serviceName == null) throw new NullPointerException("serviceName is null");
355            ServiceManager serviceManager = getServiceManager(serviceName);
356            ServiceFactory serviceFactory = serviceManager.getServiceFactory();
357            return serviceFactory.isEnabled();
358        }
359    
360        /**
361         * {@inheritDoc}
362         */
363        public void setServiceEnabled(ServiceName serviceName, boolean enabled) throws ServiceNotFoundException {
364            if (serviceName == null) throw new NullPointerException("serviceName is null");
365            ServiceManager serviceManager = getServiceManager(serviceName);
366            ServiceFactory serviceFactory = serviceManager.getServiceFactory();
367            serviceFactory.setEnabled(enabled);
368        }
369    
370        /**
371         * {@inheritDoc}
372         */
373        public Object getService(ServiceName serviceName) throws ServiceNotFoundException, IllegalArgumentException {
374            if (serviceName == null) throw new NullPointerException("serviceName is null");
375            ServiceManager serviceManager = getServiceManager(serviceName);
376            return serviceManager.getService();
377        }
378    
379        /**
380         * {@inheritDoc}
381         */
382        public Object getService(Class type) {
383            if (type == null) throw new NullPointerException("type is null");
384            if (!isRunning()) {
385                return null;
386            }
387    
388            Object service = serviceManagerRegistry.getService(type);
389            return service;
390        }
391    
392        /**
393         * {@inheritDoc}
394         */
395        public List getServices(Class type) {
396            if (type == null) throw new NullPointerException("type is null");
397            if (!isRunning()) {
398                return null;
399            }
400    
401            List services = serviceManagerRegistry.getServices(type);
402            return services;
403        }
404    
405        /**
406         * {@inheritDoc}
407         */
408        public ServiceFactory getServiceFactory(ServiceName serviceName) throws ServiceNotFoundException {
409            if (serviceName == null) throw new NullPointerException("serviceName is null");
410            ServiceManager serviceManager = getServiceManager(serviceName);
411            return serviceManager.getServiceFactory();
412        }
413    
414        /**
415         * {@inheritDoc}
416         */
417        public ServiceFactory getServiceFactory(Class type) {
418            if (type == null) throw new NullPointerException("type is null");
419            if (!isRunning()) {
420                return null;
421            }
422    
423            ServiceManager serviceManager = serviceManagerRegistry.getServiceManager(type);
424            return serviceManager.getServiceFactory();
425        }
426    
427        /**
428         * {@inheritDoc}
429         */
430        public List getServiceFactories(Class type) {
431            if (type == null) throw new NullPointerException("type is null");
432            if (!isRunning()) {
433                return null;
434            }
435    
436            List serviceManagers = serviceManagerRegistry.getServiceManagers(type);
437            List serviceFactories = new ArrayList(serviceManagers.size());
438            for (Iterator iterator = serviceManagers.iterator(); iterator.hasNext();) {
439                ServiceManager serviceManager = (ServiceManager) iterator.next();
440                serviceFactories.add(serviceManager.getServiceFactory());
441            }
442            return serviceFactories;
443        }
444    
445        /**
446         * {@inheritDoc}
447         */
448        public ClassLoader getClassLoaderFor(ServiceName serviceName) throws ServiceNotFoundException {
449            if (serviceName == null) throw new NullPointerException("serviceName is null");
450            ServiceManager serviceManager = getServiceManager(serviceName);
451            return serviceManager.getClassLoader();
452        }
453    
454        private ServiceManager getServiceManager(ServiceName serviceName) throws ServiceNotFoundException {
455            if (!isRunning()) {
456                throw new ServiceNotFoundException(serviceName);
457            }
458    
459            ServiceManager serviceManager = serviceManagerRegistry.getServiceManager(serviceName);
460            return serviceManager;
461        }
462    
463        /**
464         * {@inheritDoc}
465         */
466        public void addKernelMonitor(KernelMonitor kernelMonitor) {
467            if (kernelMonitor == null) throw new NullPointerException("kernelMonitor is null");
468            if (!isRunning()) {
469                throw new IllegalStateException("Kernel is stopped");
470            }
471            this.kernelMonitor.addKernelMonitor(kernelMonitor);
472        }
473    
474        /**
475         * {@inheritDoc}
476         */
477        public void removeKernelMonitor(KernelMonitor kernelMonitor) {
478            if (kernelMonitor == null) throw new NullPointerException("kernelMonitor is null");
479            this.kernelMonitor.removeKernelMonitor(kernelMonitor);
480        }
481    
482        /**
483         * {@inheritDoc}
484         */
485        public void addServiceMonitor(ServiceMonitor serviceMonitor) {
486            if (serviceMonitor == null) throw new NullPointerException("serviceMonitor is null");
487            if (!isRunning()) {
488                throw new IllegalStateException("Kernel is stopped");
489            }
490            addServiceMonitor(serviceMonitor, null);
491        }
492    
493        /**
494         * {@inheritDoc}
495         */
496        public void addServiceMonitor(ServiceMonitor serviceMonitor, ServiceName serviceName) {
497            if (serviceMonitor == null) throw new NullPointerException("serviceMonitor is null");
498            if (serviceName == null) throw new NullPointerException("serviceName is null");
499            if (!isRunning()) {
500                throw new IllegalStateException("Kernel is stopped");
501            }
502            this.serviceMonitor.addServiceMonitor(serviceMonitor, serviceName);
503        }
504    
505        /**
506         * {@inheritDoc}
507         */
508        public void removeServiceMonitor(ServiceMonitor serviceMonitor) {
509            if (serviceMonitor == null) throw new NullPointerException("serviceMonitor is null");
510            this.serviceMonitor.removeServiceMonitor(serviceMonitor);
511        }
512    }