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    }