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: 17329 $
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    }