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.util;
018    
019    import java.util.Arrays;
020    import java.util.Collection;
021    import java.util.LinkedHashSet;
022    import java.util.List;
023    import java.util.Set;
024    
025    import org.apache.camel.Navigate;
026    import org.apache.camel.Service;
027    import org.apache.camel.ShutdownableService;
028    import org.apache.camel.StatefulService;
029    import org.apache.camel.SuspendableService;
030    import org.slf4j.Logger;
031    import org.slf4j.LoggerFactory;
032    
033    /**
034     * A collection of helper methods for working with {@link Service} objects
035     *
036     * @version 
037     */
038    public final class ServiceHelper {
039        private static final transient Logger LOG = LoggerFactory.getLogger(ServiceHelper.class);
040    
041        /**
042         * Utility classes should not have a public constructor.
043         */
044        private ServiceHelper() {
045        }
046    
047        /**
048         * Starts all of the given services
049         */
050        public static void startService(Object value) throws Exception {
051            if (value instanceof Service) {
052                startService((Service)value);
053            } else if (value instanceof Collection) {
054                startServices((Collection<?>)value);
055            }
056        }
057        
058        /**
059         * Starts all of the given services
060         */
061        public static void startService(Service service) throws Exception {
062            service.start();
063        }
064    
065        /**
066         * Starts all of the given services
067         */
068        public static void startServices(Object... services) throws Exception {
069            if (services == null) {
070                return;
071            }
072            for (Object value : services) {
073                startService(value);
074            }
075        }
076    
077        /**
078         * Starts all of the given services
079         */
080        public static void startServices(Collection<?> services) throws Exception {
081            if (services == null) {
082                return;
083            }
084            for (Object value : services) {
085                startService(value);
086            }
087        }
088    
089        /**
090         * Stops all of the given services, throwing the first exception caught
091         */
092        public static void stopServices(Object... services) throws Exception {
093            if (services == null) {
094                return;
095            }
096            List<Object> list = Arrays.asList(services);
097            stopServices(list);
098        }
099    
100        /**
101         * Stops all of the given services, throwing the first exception caught
102         */
103        public static void stopService(Object value) throws Exception {
104            if (isStopped(value)) {
105                // only stop service if not already stopped
106                LOG.trace("Service already stopped: {}", value);
107                return;
108            }
109            if (value instanceof Service) {
110                Service service = (Service)value;
111                LOG.trace("Stopping service {}", value);
112                service.stop();
113            } else if (value instanceof Collection) {
114                stopServices((Collection<?>)value);
115            }
116        }
117    
118        /**
119         * Stops all of the given services, throwing the first exception caught
120         */
121        public static void stopServices(Collection<?> services) throws Exception {
122            if (services == null) {
123                return;
124            }
125            Exception firstException = null;
126            for (Object value : services) {
127                try {
128                    stopService(value);
129                } catch (Exception e) {
130                    if (LOG.isDebugEnabled()) {
131                        LOG.debug("Caught exception stopping service: " + value, e);
132                    }
133                    if (firstException == null) {
134                        firstException = e;
135                    }
136                }
137            }
138            if (firstException != null) {
139                throw firstException;
140            }
141        }
142    
143        /**
144         * Stops and shutdowns all of the given services, throwing the first exception caught
145         */
146        public static void stopAndShutdownServices(Object... services) throws Exception {
147            if (services == null) {
148                return;
149            }
150            List<Object> list = Arrays.asList(services);
151            stopAndShutdownServices(list);
152        }
153    
154        /**
155         * Stops and shutdowns all of the given services, throwing the first exception caught
156         */
157        public static void stopAndShutdownService(Object value) throws Exception {
158            stopService(value);
159    
160            // then try to shutdown
161            if (value instanceof ShutdownableService) {
162                ShutdownableService service = (ShutdownableService)value;
163                LOG.trace("Shutting down service {}", value);
164                service.shutdown();
165            }
166        }
167    
168        /**
169         * Stops and shutdowns all of the given services, throwing the first exception caught
170         */
171        public static void stopAndShutdownServices(Collection<?> services) throws Exception {
172            if (services == null) {
173                return;
174            }
175            Exception firstException = null;
176    
177            for (Object value : services) {
178    
179                // must stop it first
180                stopService(value);
181    
182                // then try to shutdown
183                if (value instanceof ShutdownableService) {
184                    ShutdownableService service = (ShutdownableService)value;
185                    try {
186                        LOG.trace("Shutting down service: {}", service);
187                        service.shutdown();
188                    } catch (Exception e) {
189                        if (LOG.isDebugEnabled()) {
190                            LOG.debug("Caught exception shutting down service: " + service, e);
191                        }
192                        if (firstException == null) {
193                            firstException = e;
194                        }
195                    }
196                }
197            }
198            if (firstException != null) {
199                throw firstException;
200            }
201        }
202    
203        public static void resumeServices(Collection<?> services) throws Exception {
204            if (services == null) {
205                return;
206            }
207            Exception firstException = null;
208            for (Object value : services) {
209                if (value instanceof Service) {
210                    Service service = (Service)value;
211                    try {
212                        resumeService(service);
213                    } catch (Exception e) {
214                        if (LOG.isDebugEnabled()) {
215                            LOG.debug("Caught exception resuming service: " + service, e);
216                        }
217                        if (firstException == null) {
218                            firstException = e;
219                        }
220                    }
221                }
222            }
223            if (firstException != null) {
224                throw firstException;
225            }
226        }
227    
228        /**
229         * Resumes the given service.
230         * <p/>
231         * If the service is a {@link org.apache.camel.SuspendableService} then the <tt>resume</tt>
232         * operation is <b>only</b> invoked if the service is suspended.
233         * <p/>
234         * If the service is a {@link org.apache.camel.support.ServiceSupport} then the <tt>start</tt>
235         * operation is <b>only</b> invoked if the service is startable.
236         * <p/>
237         * Otherwise the service is started.
238         *
239         * @param service the service
240         * @return <tt>true</tt> if either <tt>resume</tt> or <tt>start</tt> was invoked,
241         * <tt>false</tt> if the service is already in the desired state.
242         * @throws Exception is thrown if error occurred
243         */
244        public static boolean resumeService(Service service) throws Exception {
245            if (service instanceof SuspendableService) {
246                SuspendableService ss = (SuspendableService) service;
247                if (ss.isSuspended()) {
248                    LOG.debug("Resuming service {}", service);
249                    ss.resume();
250                    return true;
251                } else {
252                    return false;
253                }
254            } else {
255                startService(service);
256                return true;
257            }
258        }
259    
260        public static void suspendServices(Collection<?> services) throws Exception {
261            if (services == null) {
262                return;
263            }
264            Exception firstException = null;
265            for (Object value : services) {
266                if (value instanceof Service) {
267                    Service service = (Service)value;
268                    try {
269                        suspendService(service);
270                    } catch (Exception e) {
271                        if (LOG.isDebugEnabled()) {
272                            LOG.debug("Caught exception suspending service: " + service, e);
273                        }
274                        if (firstException == null) {
275                            firstException = e;
276                        }
277                    }
278                }
279            }
280            if (firstException != null) {
281                throw firstException;
282            }
283        }
284    
285        /**
286         * Suspends the given service.
287         * <p/>
288         * If the service is a {@link org.apache.camel.SuspendableService} then the <tt>suspend</tt>
289         * operation is <b>only</b> invoked if the service is <b>not</b> suspended.
290         * <p/>
291         * If the service is a {@link org.apache.camel.support.ServiceSupport} then the <tt>stop</tt>
292         * operation is <b>only</b> invoked if the service is stoppable.
293         * <p/>
294         * Otherwise the service is stopped.
295         *
296         * @param service the service
297         * @return <tt>true</tt> if either <tt>suspend</tt> or <tt>stop</tt> was invoked,
298         * <tt>false</tt> if the service is already in the desired state.
299         * @throws Exception is thrown if error occurred
300         */
301        public static boolean suspendService(Service service) throws Exception {
302            if (service instanceof SuspendableService) {
303                SuspendableService ss = (SuspendableService) service;
304                if (!ss.isSuspended()) {
305                    LOG.trace("Suspending service {}", service);
306                    ss.suspend();
307                    return true;
308                } else {
309                    return false;
310                }
311            } else {
312                stopService(service);
313                return true;
314            }
315        }
316    
317        /**
318         * Is the given service stopping or stopped?
319         *
320         * @return <tt>true</tt> if already stopped, otherwise <tt>false</tt>
321         */
322        public static boolean isStopped(Object value) {
323            if (value instanceof StatefulService) {
324                StatefulService service = (StatefulService) value;
325                if (service.isStopping() || service.isStopped()) {
326                    return true;
327                }
328            }
329            return false;
330        }
331    
332        /**
333         * Is the given service starting or started?
334         *
335         * @return <tt>true</tt> if already started, otherwise <tt>false</tt>
336         */
337        public static boolean isStarted(Object value) {
338            if (value instanceof StatefulService) {
339                StatefulService service = (StatefulService) value;
340                if (service.isStarting() || service.isStarted()) {
341                    return true;
342                }
343            }
344            return false;
345        }
346        
347        /**
348         * Is the given service suspended
349         *
350         * @return <tt>true</tt> if already suspended, otherwise <tt>false</tt>
351         */
352        public static boolean isSuspended(Object value) {
353            if (value instanceof StatefulService) {
354                StatefulService service = (StatefulService) value;
355                if (service.isSuspended() || service.isSuspending()) {
356                    return true;
357                }
358            }
359            return false;
360        }
361    
362        /**
363         * Gather all child services by navigating the service to recursively gather all child services.
364         *
365         * @param service the service
366         * @return the services, including the parent service, and all its children
367         */
368        public static Set<Service> getChildServices(Service service) {
369            Set<Service> answer = new LinkedHashSet<Service>();
370            doGetChildServices(answer, service);
371            return answer;
372        }
373    
374        private static void doGetChildServices(Set<Service> services, Service service) {
375            services.add(service);
376            if (service instanceof Navigate) {
377                Navigate<?> nav = (Navigate<?>) service;
378                if (nav.hasNext()) {
379                    List<?> children = nav.next();
380                    for (Object child : children) {
381                        if (child instanceof Service) {
382                            doGetChildServices(services, (Service) child);
383                        }
384                    }
385                }
386            }
387        }
388        
389    }