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