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 }