1 package org.apache.tomcat.maven.common.run;
2
3 /*
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
19 * under the License.
20 */
21
22 import org.apache.maven.plugin.logging.Log;
23
24 import java.lang.reflect.InvocationTargetException;
25 import java.lang.reflect.Method;
26 import java.util.HashSet;
27 import java.util.Iterator;
28 import java.util.Set;
29
30 /**
31 * Registry which collects all embedded Tomcat Servers so that they will be shutdown
32 * through a shutdown hook when the JVM terminates or you can ask the registry to
33 * shutdown all started servers.
34 *
35 * @author Mark Michaelis
36 * @since 1.1
37 */
38 public final class EmbeddedRegistry
39 {
40 private static EmbeddedRegistry instance;
41
42 private Set<Object> containers = new HashSet<Object>( 1 );
43
44 /**
45 * Don't instantiate - use the instance through {@link #getInstance()}.
46 */
47 private EmbeddedRegistry()
48 {
49 // no op
50 }
51
52 /**
53 * Retrieve the lazily initialized instance of the registry.
54 *
55 * @return singleton instance of the registry
56 */
57 public static EmbeddedRegistry getInstance()
58 {
59 if ( instance == null )
60 {
61 instance = new EmbeddedRegistry();
62 Runtime.getRuntime().addShutdownHook( new Thread()
63 {
64 @Override
65 public void run()
66 {
67 try
68 {
69 getInstance().shutdownAll( null );
70 }
71 catch ( Exception e )
72 {
73 // ignore, the exception should already have been reported
74 }
75 }
76 } );
77 }
78 return instance;
79 }
80
81 /**
82 * Adds the given container to the registry which automatically registers it for the shutdown
83 * hook.
84 *
85 * @param container the container to register
86 * @return true if it got added; false if not
87 */
88 public synchronized boolean register( final Object container )
89 {
90 return containers.add( container );
91 }
92
93 /**
94 * Shuts down all registered embedded tomcats. All tomcats which successfully shut down will be
95 * removed from the registry.
96 *
97 * @param log the log to write possible shutdown exceptions to
98 * @throws Exception the first exception which occurred will be rethrown
99 */
100 public synchronized void shutdownAll( final Log log )
101 throws Exception
102 {
103 Exception firstException = null;
104 for ( Iterator<Object> iterator = containers.iterator(); iterator.hasNext(); )
105 {
106 Object embedded = iterator.next();
107 try
108 {
109 Method method = embedded.getClass().getMethod( "stop", null );
110 method.invoke( embedded, null );
111 iterator.remove();
112 }
113 catch ( NoSuchMethodException e )
114 {
115 if ( firstException == null )
116 {
117 firstException = e;
118 error( log, e, "no stop method in class " + embedded.getClass().getName() );
119 }
120 else
121 {
122 error( log, e, "Error while shutting down embedded Tomcat." );
123 }
124 }
125 catch ( IllegalAccessException e )
126 {
127 if ( firstException == null )
128 {
129 firstException = e;
130 error( log, e, "IllegalAccessException for stop method in class " + embedded.getClass().getName() );
131 }
132 else
133 {
134 error( log, e, "Error while shutting down embedded Tomcat." );
135 }
136 }
137 catch ( InvocationTargetException e )
138 {
139
140 if ( firstException == null )
141 {
142 firstException = e;
143 error( log, e, "IllegalAccessException for stop method in class " + embedded.getClass().getName() );
144 }
145 else
146 {
147 error( log, e, "Error while shutting down embedded Tomcat." );
148 }
149 }
150 }
151 if ( firstException != null )
152 {
153 throw firstException;
154 }
155 }
156
157 /**
158 * Reports the exception. If a log is given (typically when called from within a Mojo) the
159 * message will be printed to the log. Otherwise it will be printed to StdErr.
160 *
161 * @param log the log to write the message to; null to write to stderr
162 * @param e exception which shall be reported
163 * @param message message which shall be reported
164 */
165 private void error( final Log log, final Exception e, final String message )
166 {
167 if ( log == null )
168 {
169 System.err.println( "ERROR: " + message );
170 e.printStackTrace();
171 }
172 else
173 {
174 log.error( message, e );
175 }
176 }
177
178 }