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 */
017package org.apache.camel.support;
018
019import java.util.LinkedHashSet;
020import java.util.Set;
021
022import org.apache.camel.util.ServiceHelper;
023
024/**
025 * Base class to control lifecycle for a set of child {@link org.apache.camel.Service}s.
026 */
027public abstract class ChildServiceSupport extends ServiceSupport {
028    private Set<Object> childServices;
029    
030    public void start() throws Exception {
031        start(true);
032    }
033
034    public void start(boolean startChildren) throws Exception {
035        if (!started.get()) {
036            if (starting.compareAndSet(false, true)) {
037                boolean childrenStarted = false;
038                Exception ex = null;
039                try {
040                    if (childServices != null && startChildren) {
041                        ServiceHelper.startServices(childServices);
042                    }
043                    childrenStarted = true;
044                    doStart();
045                } catch (Exception e) {
046                    ex = e;
047                } finally {
048                    if (ex != null) {
049                        try {
050                            stop(childrenStarted);
051                        } catch (Exception e) {
052                            // Ignore exceptions as we want to show the original exception
053                        }
054                        throw ex;
055                    } else {
056                        started.set(true);
057                        starting.set(false);
058                        stopping.set(false);
059                        stopped.set(false);
060                        suspending.set(false);
061                        suspended.set(false);
062                        shutdown.set(false);
063                        shuttingdown.set(false);
064                    }
065                }
066            }
067        }
068    }
069    
070    private void stop(boolean childrenStarted) throws Exception {
071        if (stopping.compareAndSet(false, true)) {
072            try {
073                try {
074                    starting.set(false);
075                    suspending.set(false);
076                    if (childrenStarted) {
077                        doStop();
078                    }
079                } finally {
080                    started.set(false);
081                    suspended.set(false);
082                    if (childServices != null) {
083                        ServiceHelper.stopServices(childServices);
084                    }
085                }
086            } finally {
087                stopped.set(true);
088                stopping.set(false);
089                starting.set(false);
090                started.set(false);
091                suspending.set(false);
092                suspended.set(false);
093                shutdown.set(false);
094                shuttingdown.set(false);
095            }
096        }
097    }
098
099    public void stop() throws Exception {
100        if (!stopped.get()) {
101            stop(true);
102        }
103    }
104    
105    public void shutdown() throws Exception {
106        // ensure we are stopped first
107        stop();
108
109        if (shuttingdown.compareAndSet(false, true)) {
110            try {
111                try {
112                    doShutdown();
113                } finally {
114                    if (childServices != null) {
115                        ServiceHelper.stopAndShutdownServices(childServices);
116                    }
117                }
118            } finally {
119                // shutdown is also stopped so only set shutdown flags
120                shutdown.set(true);
121                shuttingdown.set(false);
122            }
123        }
124    }
125    
126    protected void addChildService(Object childService) {
127        synchronized (this) {
128            if (childServices == null) {
129                childServices = new LinkedHashSet<Object>();
130            }
131        }
132        childServices.add(childService);
133    }
134
135    protected boolean removeChildService(Object childService) {
136        return childServices != null && childServices.remove(childService);
137    }
138
139}