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.CamelException;
024    import org.apache.camel.Service;
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: 763092 $
033     */
034    public abstract class ServiceSupport implements Service {
035        private static int threadCounter;
036        private AtomicBoolean started = new AtomicBoolean(false);
037        private AtomicBoolean starting = new AtomicBoolean(false);
038        private AtomicBoolean stopping = new AtomicBoolean(false);
039        private AtomicBoolean stopped = new AtomicBoolean(false);
040        private Collection 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                            stop(childrenStarted);
059                            throw ex;
060                        } else {
061                            started.set(true);
062                            starting.set(false);
063                        }
064                    }
065                }
066            }
067        }
068        
069        private void stop(boolean childrenStarted) throws Exception {
070            if (stopping.compareAndSet(false, true)) {
071                try {
072                    try {
073                        starting.set(false);
074                        if (childrenStarted) {
075                            doStop();
076                        }
077                    } finally {
078                        started.set(false);
079                        if (childServices != null) {
080                            ServiceHelper.stopServices(childServices);
081                        }
082                    }
083                } finally {
084                    stopped.set(true);
085                    stopping.set(false);
086                }
087            }
088        }
089    
090        public void stop() throws Exception {
091            if (started.get()) {
092                stop(true);
093            }
094        }
095    
096        /**
097         * @return true if this service has been started
098         */
099        public boolean isStarted() {
100            return started.get();
101        }
102    
103        /**
104         * @return true if this service is
105         */
106        public boolean isStarting() {
107            return starting.get();
108        }
109    
110        /**
111         * @return true if this service is in the process of closing
112         */
113        public boolean isStopping() {
114            return stopping.get();
115        }
116    
117        /**
118         * @return true if this service is closed
119         */
120        public boolean isStopped() {
121            return stopped.get();
122        }
123    
124        /**
125         * Helper methods so the service knows if it should keep running.
126         * Returns false if the service is being stopped or is stopped.
127         *
128         * @return true if the service should continue to run.
129         */
130        protected boolean isRunAllowed() {
131            return !(stopping.get() || stopped.get());
132        }
133    
134        protected abstract void doStart() throws Exception;
135    
136        protected abstract void doStop() throws Exception;
137    
138        /**
139         * Creates a new thread name with the given prefix
140         */
141        protected String getThreadName(String prefix) {
142            return prefix + " thread:" + nextThreadCounter();
143        }
144    
145        protected static synchronized int nextThreadCounter() {
146            return ++threadCounter;
147        }
148    
149        protected void addChildService(Object childService) {
150            synchronized (this) {
151                if (childServices == null) {
152                    childServices = new CopyOnWriteArrayList();
153                }
154            }
155            childServices.add(childService);
156        }
157    
158        protected boolean removeChildService(Object childService) {
159            return childServices != null ? childServices.remove(childService) : false;
160        }
161        
162        protected synchronized String getVersion() {
163            if (ObjectHelper.isNotNullAndNonEmpty(version)) {
164                return version;
165            }
166            
167            Package aPackage = getClass().getPackage();
168            if (aPackage != null) {
169                version = aPackage.getImplementationVersion();
170                if (version == null) {
171                    version = aPackage.getSpecificationVersion();
172                }
173            }
174            return version != null ? version : "";
175        }
176    }