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.camel.impl;
018
019 import java.util.Collection;
020 import java.util.concurrent.CopyOnWriteArrayList;
021 import java.util.concurrent.atomic.AtomicBoolean;
022
023 import org.apache.camel.Service;
024 import org.apache.camel.ServiceStatus;
025 import org.apache.camel.util.ObjectHelper;
026 import org.apache.camel.util.ServiceHelper;
027
028 /**
029 * A useful base class which ensures that a service is only initialized once and
030 * provides some helper methods for enquiring of its status
031 *
032 * @version $Revision: 772276 $
033 */
034 public abstract class ServiceSupport implements Service {
035 private final AtomicBoolean started = new AtomicBoolean(false);
036 private final AtomicBoolean starting = new AtomicBoolean(false);
037 private final AtomicBoolean stopping = new AtomicBoolean(false);
038 private final AtomicBoolean stopped = new AtomicBoolean(false);
039 private Collection childServices;
040 private String version;
041
042 public void start() throws Exception {
043 if (!started.get()) {
044 if (starting.compareAndSet(false, true)) {
045 boolean childrenStarted = false;
046 Exception ex = null;
047 try {
048 if (childServices != null) {
049 ServiceHelper.startServices(childServices);
050 }
051 childrenStarted = true;
052 doStart();
053 } catch (Exception e) {
054 ex = e;
055 } finally {
056 if (ex != null) {
057 stop(childrenStarted);
058 throw ex;
059 } else {
060 started.set(true);
061 starting.set(false);
062 }
063 }
064 }
065 }
066 }
067
068 private void stop(boolean childrenStarted) throws Exception {
069 if (stopping.compareAndSet(false, true)) {
070 try {
071 try {
072 starting.set(false);
073 if (childrenStarted) {
074 doStop();
075 }
076 } finally {
077 started.set(false);
078 if (childServices != null) {
079 ServiceHelper.stopServices(childServices);
080 }
081 }
082 } finally {
083 stopped.set(true);
084 stopping.set(false);
085 }
086 }
087 }
088
089 public void stop() throws Exception {
090 if (started.get()) {
091 stop(true);
092 }
093 }
094
095 /**
096 * Returns the current status
097 */
098 public ServiceStatus getStatus() {
099 // lets check these in oldest first as these flags can be changing in a concurrent world
100 if (isStarting()) {
101 return ServiceStatus.Starting;
102 }
103 if (isStarted()) {
104 return ServiceStatus.Started;
105 }
106 if (isStopping()) {
107 return ServiceStatus.Stopping;
108 }
109 if (isStopped()) {
110 return ServiceStatus.Stopped;
111 }
112 return ServiceStatus.Created;
113 }
114
115 /**
116 * @return true if this service has been started
117 */
118 public boolean isStarted() {
119 return started.get();
120 }
121
122 /**
123 * @return true if this service is
124 */
125 public boolean isStarting() {
126 return starting.get();
127 }
128
129 /**
130 * @return true if this service is in the process of closing
131 */
132 public boolean isStopping() {
133 return stopping.get();
134 }
135
136 /**
137 * @return true if this service is closed
138 */
139 public boolean isStopped() {
140 return stopped.get();
141 }
142
143 /**
144 * Helper methods so the service knows if it should keep running.
145 * Returns false if the service is being stopped or is stopped.
146 *
147 * @return true if the service should continue to run.
148 */
149 protected boolean isRunAllowed() {
150 return !(stopping.get() || stopped.get());
151 }
152
153 protected abstract void doStart() throws Exception;
154
155 protected abstract void doStop() throws Exception;
156
157 @SuppressWarnings("unchecked")
158 protected void addChildService(Object childService) {
159 synchronized (this) {
160 if (childServices == null) {
161 childServices = new CopyOnWriteArrayList();
162 }
163 }
164 childServices.add(childService);
165 }
166
167 protected boolean removeChildService(Object childService) {
168 return childServices != null && childServices.remove(childService);
169 }
170
171 /**
172 * Returns the version of this service
173 */
174 public synchronized String getVersion() {
175 if (ObjectHelper.isNotEmpty(version)) {
176 return version;
177 }
178
179 Package aPackage = getClass().getPackage();
180 if (aPackage != null) {
181 version = aPackage.getImplementationVersion();
182 if (version == null) {
183 version = aPackage.getSpecificationVersion();
184 }
185 }
186 return version != null ? version : "";
187 }
188 }