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.activemq.util;
018    
019    import java.util.List;
020    import java.util.concurrent.CopyOnWriteArrayList;
021    import java.util.concurrent.atomic.AtomicBoolean;
022    
023    import org.apache.activemq.Service;
024    import org.slf4j.Logger;
025    import org.slf4j.LoggerFactory;
026    
027    /**
028     * A helper class for working with services together with a useful base class
029     * for service implementations.
030     * 
031     * 
032     */
033    public abstract class ServiceSupport implements Service {
034        private static final Logger LOG = LoggerFactory.getLogger(ServiceSupport.class);
035    
036        private AtomicBoolean started = new AtomicBoolean(false);
037        private AtomicBoolean stopping = new AtomicBoolean(false);
038        private AtomicBoolean stopped = new AtomicBoolean(false);
039        private List<ServiceListener>serviceListeners = new CopyOnWriteArrayList<ServiceListener>();
040    
041        public static void dispose(Service service) {
042            try {
043                service.stop();
044            } catch (Exception e) {
045                LOG.debug("Could not stop service: " + service + ". Reason: " + e, e);
046            }
047        }
048    
049        public void start() throws Exception {
050            if (started.compareAndSet(false, true)) {
051                boolean success = false;
052                stopped.set(false);
053                try {
054                    preStart();
055                    doStart();
056                    success = true;
057                } finally {
058                    started.set(success);
059                }
060                for(ServiceListener l:this.serviceListeners) {
061                    l.started(this);
062                }
063            }
064        }
065    
066        public void stop() throws Exception {
067            if (stopped.compareAndSet(false, true)) {
068                stopping.set(true);
069                ServiceStopper stopper = new ServiceStopper();
070                try {
071                    doStop(stopper);
072                } catch (Exception e) {
073                    stopper.onException(this, e);
074                } finally {
075                    postStop(stopper);
076                }
077                stopped.set(true);
078                started.set(false);
079                stopping.set(false);
080                for(ServiceListener l:this.serviceListeners) {
081                    l.stopped(this);
082                }
083                stopper.throwFirstException();
084            }
085        }
086    
087        /**
088         * @return true if this service has been started
089         */
090        public boolean isStarted() {
091            return started.get();
092        }
093    
094        /**
095         * @return true if this service is in the process of closing
096         */
097        public boolean isStopping() {
098            return stopping.get();
099        }
100    
101        /**
102         * @return true if this service is closed
103         */
104        public boolean isStopped() {
105            return stopped.get();
106        }
107        
108        public void addServiceListener(ServiceListener l) {
109            this.serviceListeners.add(l);
110        }
111        
112        public void removeServiceListener(ServiceListener l) {
113            this.serviceListeners.remove(l);
114        }
115    
116        /**
117         *
118         * handle for various operations after stopping the service (like locking)
119         *
120         * @throws Exception
121         */
122        protected void postStop(ServiceStopper stopper) throws Exception {}
123    
124        protected abstract void doStop(ServiceStopper stopper) throws Exception;
125    
126        /**
127         *
128         * handle for various operations before starting the service (like locking)
129         *
130         * @throws Exception
131         */
132        protected void preStart() throws Exception {}
133    
134        protected abstract void doStart() throws Exception;
135    }