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 }