001    package biz.hammurapi.config;
002    
003    public abstract class ServiceBase extends ComponentBase implements Service {
004            
005            private String status;
006            
007            private ThreadLocal prevServiceTL = new ThreadLocal();
008            
009            ServiceBase prevService;
010            ServiceBase nextService;
011            
012            /**
013             * Services shall implement initialization sequence in this method.
014             * @throws ConfigurationException
015             */
016            protected abstract void startInternal() throws ConfigurationException;
017    
018            /**
019             * This implementation can be invoked multiple times. ServiceBase class maintains internal started flag to ensure
020             * that startInternal() method is invoked only once. The naming bus invokes this method every time before returning
021             * service from get() method.
022             */
023            public final synchronized void start() throws ConfigurationException {
024                    if (!"Started".equals(status)) {
025                            if ("Starting".equals(status)) {
026                                    throw new ConfigurationException("Circular dependency: start() method reentered by the same thread");
027                            }
028                            startInternal();
029                            
030                            prevService = (ServiceBase) prevServiceTL.get();
031                            prevServiceTL.set(this);
032                            if (prevService!=null) {
033                                    prevService.nextService=this;
034                            }
035                    }
036            }
037            
038            protected abstract void stopInternal() throws ConfigurationException;
039            
040            /**
041             *  Invokes stopInternal if all dependent services has been stopped.
042             *  Otherwise goes into "stoppable" state. When stops, also stops all
043             *  stoppable previous services.
044             */
045            public final synchronized void stop() throws ConfigurationException {
046                    if (nextService==null || nextService.status==null) {
047                            stopInternal();
048                            status = null;
049                            if (prevService!=null && "Stoppable".equals(prevService.status)) {
050                                    prevService.stop();
051                            }
052                    } else {
053                            status = "Stoppable";
054                    }
055            }
056    
057    }