1 package org.apache.turbine.services;
2
3 /* ====================================================================
4 * The Apache Software License, Version 1.1
5 *
6 * Copyright (c) 2001 The Apache Software Foundation. All rights
7 * reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 *
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in
18 * the documentation and/or other materials provided with the
19 * distribution.
20 *
21 * 3. The end-user documentation included with the redistribution,
22 * if any, must include the following acknowledgment:
23 * "This product includes software developed by the
24 * Apache Software Foundation (http://www.apache.org/)."
25 * Alternately, this acknowledgment may appear in the software itself,
26 * if and wherever such third-party acknowledgments normally appear.
27 *
28 * 4. The names "Apache" and "Apache Software Foundation" and
29 * "Apache Turbine" must not be used to endorse or promote products
30 * derived from this software without prior written permission. For
31 * written permission, please contact apache@apache.org.
32 *
33 * 5. Products derived from this software may not be called "Apache",
34 * "Apache Turbine", nor may "Apache" appear in their name, without
35 * prior written permission of the Apache Software Foundation.
36 *
37 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
38 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
39 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
40 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
41 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
43 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
44 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
45 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
46 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
47 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48 * SUCH DAMAGE.
49 * ====================================================================
50 *
51 * This software consists of voluntary contributions made by many
52 * individuals on behalf of the Apache Software Foundation. For more
53 * information on the Apache Software Foundation, please see
54 * <http://www.apache.org/>.
55 */
56
57 import java.util.Date;
58 import java.util.Hashtable;
59 import java.util.Stack;
60 import org.apache.turbine.util.TurbineException;
61
62 /***
63 * A generic implementation of <code>InitableBroker</code>.
64 * Functionality provided by the broker includes:
65 *
66 * <ul>
67 *
68 * <li>Maintaining single instance of each <code>Initable</code> in
69 * the system.</li>
70 *
71 * <li>Early initialization of <code>Initables</code> during system
72 * startup.</li>
73 *
74 * <li>Late initialization of <code>Initables</code> before they are
75 * used.</li>
76 *
77 * <li>Providing instances of <code>Initables</code> to requesting
78 * parties.</li>
79 *
80 * <li>Maintaining dependencies between <code>Initables</code> during
81 * early initalization phases, including circular dependencies
82 * detection.</li>
83 *
84 * </ul>
85 *
86 * @author <a href="mailto:burton@apache.org">Kevin Burton</a>
87 * @author <a href="mailto:krzewski@e-point.pl">Rafal Krzewski</a>
88 * @version $Id: BaseInitableBroker.java,v 1.2 2002/07/11 16:53:29 mpoeschl Exp $
89 */
90 public abstract class BaseInitableBroker
91 implements InitableBroker
92 {
93 /*** A repository of Initable instances. */
94 protected Hashtable initables = new Hashtable();
95
96 /***
97 * Names of classes being early-initialized are pushed onto this
98 * stack. A name appearing twice indicates a circular dependency
99 * chain.
100 */
101 protected Stack stack = new Stack();
102
103 /***
104 * Default constructor of InitableBorker.
105 *
106 * This constructor does nothing. Your brokers should be
107 * singletons, therefore their constructors should be
108 * private. They should also have public YourBroker getInstance()
109 * methods.
110 */
111 protected BaseInitableBroker()
112 {
113 }
114
115 /***
116 * Performs early initialization of an Initable class.
117 *
118 * @param className The name of the class to be initailized.
119 * @param data An Object to be used for initialization activities.
120 * @exception InitializationException Initialization was not successful.
121 */
122 public void initClass( String className,
123 Object data )
124 throws InitializationException
125 {
126 // make sure that only one thread calls this method recursively
127 synchronized(stack)
128 {
129 int pos = stack.search(className);
130 if(pos != -1)
131 {
132 StringBuffer msg = new StringBuffer().append(className)
133 .append(" couldn't be initialized because of circular depency chain:\n");
134 for(int i=pos; i>0; i--)
135 {
136 msg.append((String)stack.elementAt(stack.size()-i-1)+"->");
137 }
138 msg.append(className).append('\n');
139
140 throw new InitializationException(msg.toString());
141 }
142 try
143 {
144 stack.push(className);
145 Initable instance = getInitableInstance(className);
146 if(!instance.getInit())
147 {
148 // this call might result in an indirect recursion
149 instance.init(data);
150 }
151 }
152 finally
153 {
154 // Succeeded or not, make sure the name gets off the stack.
155 stack.pop();
156 }
157 }
158 }
159
160 /***
161 * Shuts down an <code>Initable</code>.
162 *
163 * This method is used to release resources allocated by an
164 * <code>Initable</code>, and return it to its initial (uninitailized)
165 * state.
166 *
167 * @param className The name of the class to be uninitialized.
168 */
169 public void shutdownClass( String className )
170 {
171 try
172 {
173 Initable initable = getInitableInstance(className);
174 if(initable.getInit())
175 {
176 initable.shutdown();
177 ((BaseInitable)initable).setInit(false);
178 }
179 }
180 catch( InstantiationException e )
181 {
182 // Shutdown of a nonexistent class was requested.
183 // This does not hurt anything, so we log the error and continue.
184 error(new TurbineException("Shutdown of a nonexistent class " +
185 className + " was requested", e));
186 }
187 }
188
189 /***
190 * Provides an instance of Initable class ready to work.
191 *
192 * If the requested class couldn't be instatiated or initialized,
193 * an InstantiationException will be thrown. You needn't handle
194 * this exception in your code, since it indicates fatal
195 * misconfigurtion of the system.
196 *
197 * @param className The name of the Initable requested.
198 * @return An instance of the requested Initable.
199 * @exception InstantiationException, if there was a problem
200 * during instantiation or initialization of the Initable.
201 */
202 public Initable getInitable( String className )
203 throws InstantiationException
204 {
205 Initable initable;
206 try
207 {
208 initable = getInitableInstance(className);
209 if(!initable.getInit())
210 {
211 synchronized(initable.getClass())
212 {
213 if(!initable.getInit())
214 {
215 initable.init();
216 }
217 if(!initable.getInit())
218 {
219 // this exception will be caught & rethrown by this very method.
220 // getInit() returning false indicates some initialization issue,
221 // which in turn prevents the InitableBroker from passing a working
222 // instance of the initable to the client.
223 throw new InitializationException(
224 "init() failed to initialize class " + className);
225 }
226 }
227 }
228 return initable;
229 }
230 catch( InitializationException e )
231 {
232 throw new InstantiationException("Class " + className +
233 " failed to initialize", e);
234 }
235 }
236
237 /***
238 * Retrieves an instance of an Initable from the repository.
239 *
240 * If the requested class is not present in the repository, it is
241 * instantiated and passed a reference to the broker, saved and
242 * then returned.
243 *
244 * @param className The name of the class to be instantiated.
245 * @exception InstantiationException, if the requested class can't
246 * be instantiated.
247 */
248 protected Initable getInitableInstance( String className )
249 throws InstantiationException
250 {
251 Initable initable = (Initable)initables.get(className);
252
253 if(initable == null)
254 {
255 try
256 {
257 initable = (Initable)Class.forName(className).newInstance();
258 }
259
260 // those two errors must be passed to the VM
261 catch( ThreadDeath t )
262 {
263 throw t;
264 }
265 catch( OutOfMemoryError t )
266 {
267 throw t;
268 }
269
270 catch( Throwable t )
271 {
272 // Used to indicate error condition.
273 String msg = null;
274
275 if(t instanceof NoClassDefFoundError)
276 {
277 msg = "A class referenced by " + className +
278 " is unavailable. Check your jars and classes.";
279 }
280 else if(t instanceof ClassNotFoundException)
281 {
282 msg = "Class " + className +
283 " is unavailable. Check your jars and classes.";
284 }
285 else if(t instanceof ClassCastException)
286 {
287 msg = "Class " + className +
288 " doesn't implement Initable.";
289 }
290 else
291 {
292 msg = "Failed to instantiate " + className;
293 }
294
295 throw new InstantiationException(msg, t);
296 }
297
298 initable.setInitableBroker(this);
299 initables.put(className, initable);
300 }
301
302 return initable;
303 }
304
305 /***
306 * Output a diagnostic notice.
307 *
308 * This method is used by the service framework classes for producing
309 * tracing mesages that might be useful for debugging (newline terminated).
310 *
311 * <p>The default implementation uses system error stream. When writing
312 * your own, remeber to direct that message to the proper logging
313 * mechanism.
314 *
315 * @param msg the message to print.
316 */
317 public void notice(String msg)
318 {
319 System.err.println('[' + new Date().toString() + "] " + msg);
320 }
321
322 /***
323 * Output an error message.
324 *
325 * This method is used by the service framework classes for displaying
326 * stacktraces of any exceptions that might be caught during processing.
327 *
328 * <p>The default implementation uses system error stream. When writing
329 * your own, remeber to direct that message to the proper logging
330 * mechanism.
331 *
332 * @param msg the message to print.
333 */
334 public void error(Throwable t)
335 {
336 t.printStackTrace(System.err);
337 }
338 }
This page was automatically generated by Maven