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