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.support; 018 019 import java.io.InputStream; 020 import java.util.Properties; 021 import java.util.concurrent.atomic.AtomicBoolean; 022 023 import org.apache.camel.ServiceStatus; 024 import org.apache.camel.StatefulService; 025 import org.apache.camel.util.IOHelper; 026 import org.slf4j.Logger; 027 import org.slf4j.LoggerFactory; 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 * <p/> 033 * Implementations can extend this base class and implement {@link org.apache.camel.SuspendableService} 034 * in case they support suspend/resume. 035 * 036 * @version 037 */ 038 public abstract class ServiceSupport implements StatefulService { 039 private static final Logger LOG = LoggerFactory.getLogger(ServiceSupport.class); 040 041 protected final AtomicBoolean started = new AtomicBoolean(false); 042 protected final AtomicBoolean starting = new AtomicBoolean(false); 043 protected final AtomicBoolean stopping = new AtomicBoolean(false); 044 protected final AtomicBoolean stopped = new AtomicBoolean(false); 045 protected final AtomicBoolean suspending = new AtomicBoolean(false); 046 protected final AtomicBoolean suspended = new AtomicBoolean(false); 047 protected final AtomicBoolean shuttingdown = new AtomicBoolean(false); 048 protected final AtomicBoolean shutdown = new AtomicBoolean(false); 049 050 private String version; 051 052 public void start() throws Exception { 053 if (isStarting() || isStarted()) { 054 // only start service if not already started 055 LOG.trace("Service already started"); 056 return; 057 } 058 if (starting.compareAndSet(false, true)) { 059 LOG.trace("Starting service"); 060 try { 061 doStart(); 062 started.set(true); 063 starting.set(false); 064 stopping.set(false); 065 stopped.set(false); 066 suspending.set(false); 067 suspended.set(false); 068 shutdown.set(false); 069 shuttingdown.set(false); 070 } catch (Exception e) { 071 try { 072 stop(); 073 } catch (Exception e2) { 074 // Ignore exceptions as we want to show the original exception 075 } finally { 076 // ensure flags get reset to stopped as we failed during starting 077 stopping.set(false); 078 stopped.set(true); 079 starting.set(false); 080 started.set(false); 081 suspending.set(false); 082 suspended.set(false); 083 shutdown.set(false); 084 shuttingdown.set(false); 085 } 086 throw e; 087 } 088 } 089 } 090 091 public void stop() throws Exception { 092 if (isStopped()) { 093 LOG.trace("Service already stopped"); 094 return; 095 } 096 if (isStopping()) { 097 LOG.trace("Service already stopping"); 098 return; 099 } 100 stopping.set(true); 101 try { 102 doStop(); 103 } finally { 104 stopping.set(false); 105 stopped.set(true); 106 starting.set(false); 107 started.set(false); 108 suspending.set(false); 109 suspended.set(false); 110 shutdown.set(false); 111 shuttingdown.set(false); 112 } 113 } 114 115 @Override 116 public void suspend() throws Exception { 117 if (!suspended.get()) { 118 if (suspending.compareAndSet(false, true)) { 119 try { 120 starting.set(false); 121 stopping.set(false); 122 doSuspend(); 123 } finally { 124 stopped.set(false); 125 stopping.set(false); 126 starting.set(false); 127 started.set(false); 128 suspending.set(false); 129 suspended.set(true); 130 shutdown.set(false); 131 shuttingdown.set(false); 132 } 133 } 134 } 135 } 136 137 @Override 138 public void resume() throws Exception { 139 if (suspended.get()) { 140 if (starting.compareAndSet(false, true)) { 141 try { 142 doResume(); 143 } finally { 144 started.set(true); 145 starting.set(false); 146 stopping.set(false); 147 stopped.set(false); 148 suspending.set(false); 149 suspended.set(false); 150 shutdown.set(false); 151 shuttingdown.set(false); 152 } 153 } 154 } 155 } 156 157 @Override 158 public void shutdown() throws Exception { 159 if (shutdown.get()) { 160 LOG.trace("Service already shut down"); 161 return; 162 } 163 // ensure we are stopped first 164 stop(); 165 166 if (shuttingdown.compareAndSet(false, true)) { 167 try { 168 doShutdown(); 169 } finally { 170 // shutdown is also stopped so only set shutdown flags 171 shutdown.set(true); 172 shuttingdown.set(false); 173 } 174 } 175 } 176 177 @Override 178 public ServiceStatus getStatus() { 179 // we should check the ---ing states first, as this indicate the state is in the middle of doing that 180 if (isStarting()) { 181 return ServiceStatus.Starting; 182 } 183 if (isStopping()) { 184 return ServiceStatus.Stopping; 185 } 186 if (isSuspending()) { 187 return ServiceStatus.Suspending; 188 } 189 190 // then check for the regular states 191 if (isStarted()) { 192 return ServiceStatus.Started; 193 } 194 if (isStopped()) { 195 return ServiceStatus.Stopped; 196 } 197 if (isSuspended()) { 198 return ServiceStatus.Suspended; 199 } 200 201 // use stopped as fallback 202 return ServiceStatus.Stopped; 203 } 204 205 @Override 206 public boolean isStarted() { 207 return started.get(); 208 } 209 210 @Override 211 public boolean isStarting() { 212 return starting.get(); 213 } 214 215 @Override 216 public boolean isStopping() { 217 return stopping.get(); 218 } 219 220 @Override 221 public boolean isStopped() { 222 return stopped.get(); 223 } 224 225 @Override 226 public boolean isSuspending() { 227 return suspending.get(); 228 } 229 230 @Override 231 public boolean isSuspended() { 232 return suspended.get(); 233 } 234 235 @Override 236 public boolean isRunAllowed() { 237 return !isStoppingOrStopped(); 238 } 239 240 public boolean isStoppingOrStopped() { 241 return stopping.get() || stopped.get(); 242 } 243 244 /** 245 * Implementations override this method to support customized start/stop. 246 * <p/> 247 * <b>Important: </b> See {@link #doStop()} for more details. 248 * 249 * @see #doStop() 250 */ 251 protected abstract void doStart() throws Exception; 252 253 /** 254 * Implementations override this method to support customized start/stop. 255 * <p/> 256 * <b>Important:</b> Camel will invoke this {@link #doStop()} method when 257 * the service is being stopped. This method will <b>also</b> be invoked 258 * if the service is still in <i>uninitialized</i> state (eg has not 259 * been started). The method is <b>always</b> called to allow the service 260 * to do custom logic when the service is being stopped, such as when 261 * {@link org.apache.camel.CamelContext} is shutting down. 262 * 263 * @see #doStart() 264 */ 265 protected abstract void doStop() throws Exception; 266 267 /** 268 * Implementations override this method to support customized suspend/resume. 269 */ 270 protected void doSuspend() throws Exception { 271 // noop 272 } 273 274 /** 275 * Implementations override this method to support customized suspend/resume. 276 */ 277 protected void doResume() throws Exception { 278 // noop 279 } 280 281 /** 282 * Implementations override this method to perform customized shutdown. 283 */ 284 protected void doShutdown() throws Exception { 285 // noop 286 } 287 288 @Override 289 public synchronized String getVersion() { 290 if (version != null) { 291 return version; 292 } 293 InputStream is = null; 294 // try to load from maven properties first 295 try { 296 Properties p = new Properties(); 297 is = getClass().getResourceAsStream("/META-INF/maven/org.apache.camel/camel-core/pom.properties"); 298 if (is != null) { 299 p.load(is); 300 version = p.getProperty("version", ""); 301 } 302 } catch (Exception e) { 303 // ignore 304 } finally { 305 if (is != null) { 306 IOHelper.close(is); 307 } 308 } 309 310 // fallback to using Java API 311 if (version == null) { 312 Package aPackage = getClass().getPackage(); 313 if (aPackage != null) { 314 version = aPackage.getImplementationVersion(); 315 if (version == null) { 316 version = aPackage.getSpecificationVersion(); 317 } 318 } 319 } 320 321 if (version == null) { 322 // we could not compute the version so use a blank 323 version = ""; 324 } 325 326 return version; 327 } 328 }