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