%line | %branch | |||||||||
---|---|---|---|---|---|---|---|---|---|---|
org.apache.turbine.services.BaseInitableBroker |
|
|
1 | package org.apache.turbine.services; |
|
2 | ||
3 | /* |
|
4 | * Copyright 2001-2005 The Apache Software Foundation. |
|
5 | * |
|
6 | * Licensed under the Apache License, Version 2.0 (the "License") |
|
7 | * you may not use this file except in compliance with the License. |
|
8 | * You may obtain a copy of the License at |
|
9 | * |
|
10 | * http://www.apache.org/licenses/LICENSE-2.0 |
|
11 | * |
|
12 | * Unless required by applicable law or agreed to in writing, software |
|
13 | * distributed under the License is distributed on an "AS IS" BASIS, |
|
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
15 | * See the License for the specific language governing permissions and |
|
16 | * limitations under the License. |
|
17 | */ |
|
18 | ||
19 | import java.util.Hashtable; |
|
20 | import java.util.Stack; |
|
21 | ||
22 | import org.apache.commons.logging.Log; |
|
23 | import org.apache.commons.logging.LogFactory; |
|
24 | ||
25 | /** |
|
26 | * A generic implementation of <code>InitableBroker</code>. |
|
27 | * Functionality provided by the broker includes: |
|
28 | * |
|
29 | * <ul> |
|
30 | * |
|
31 | * <li>Maintaining single instance of each <code>Initable</code> in |
|
32 | * the system.</li> |
|
33 | * |
|
34 | * <li>Early initialization of <code>Initables</code> during system |
|
35 | * startup.</li> |
|
36 | * |
|
37 | * <li>Late initialization of <code>Initables</code> before they are |
|
38 | * used.</li> |
|
39 | * |
|
40 | * <li>Providing instances of <code>Initables</code> to requesting |
|
41 | * parties.</li> |
|
42 | * |
|
43 | * <li>Maintaining dependencies between <code>Initables</code> during |
|
44 | * early initalization phases, including circular dependencies |
|
45 | * detection.</li> |
|
46 | * |
|
47 | * </ul> |
|
48 | * |
|
49 | * @author <a href="mailto:burton@apache.org">Kevin Burton</a> |
|
50 | * @author <a href="mailto:krzewski@e-point.pl">Rafal Krzewski</a> |
|
51 | * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a> |
|
52 | * @version $Id: BaseInitableBroker.java 264148 2005-08-29 14:21:04Z henning $ |
|
53 | */ |
|
54 | public abstract class BaseInitableBroker |
|
55 | implements InitableBroker |
|
56 | { |
|
57 | /** A repository of Initable instances. */ |
|
58 | 0 | protected Hashtable initables = new Hashtable(); |
59 | ||
60 | /** |
|
61 | * Names of classes being early-initialized are pushed onto this |
|
62 | * stack. A name appearing twice indicates a circular dependency |
|
63 | * chain. |
|
64 | */ |
|
65 | 0 | protected Stack stack = new Stack(); |
66 | ||
67 | /** Logging */ |
|
68 | 0 | private Log log = LogFactory.getLog(this.getClass()); |
69 | ||
70 | /** |
|
71 | * Default constructor of InitableBroker. |
|
72 | * |
|
73 | * This constructor does nothing. Your brokers should be |
|
74 | * singletons, therefore their constructors should be |
|
75 | * private. They should also have public YourBroker getInstance() |
|
76 | * methods. |
|
77 | */ |
|
78 | protected BaseInitableBroker() |
|
79 | 0 | { |
80 | 0 | } |
81 | ||
82 | /** |
|
83 | * Performs early initialization of an Initable class. |
|
84 | * |
|
85 | * @param className The name of the class to be initialized. |
|
86 | * @param data An Object to be used for initialization activities. |
|
87 | * @exception InitializationException Initialization was not successful. |
|
88 | */ |
|
89 | public void initClass(String className, Object data) |
|
90 | throws InitializationException |
|
91 | { |
|
92 | // make sure that only one thread calls this method recursively |
|
93 | 0 | synchronized (stack) |
94 | { |
|
95 | 0 | int pos = stack.search(className); |
96 | 0 | if (pos != -1) |
97 | { |
|
98 | 0 | StringBuffer msg = new StringBuffer().append(className) |
99 | .append(" couldn't be initialized because of circular depency chain:\n"); |
|
100 | 0 | for (int i = pos; i > 0; i--) |
101 | { |
|
102 | 0 | msg.append((String) stack.elementAt(stack.size() - i - 1) + "->"); |
103 | } |
|
104 | 0 | msg.append(className).append('\n'); |
105 | ||
106 | 0 | throw new InitializationException(msg.toString()); |
107 | } |
|
108 | try |
|
109 | { |
|
110 | 0 | stack.push(className); |
111 | 0 | Initable instance = getInitableInstance(className); |
112 | 0 | if (!instance.getInit()) |
113 | { |
|
114 | // this call might result in an indirect recursion |
|
115 | 0 | instance.init(data); |
116 | } |
|
117 | } |
|
118 | finally |
|
119 | { |
|
120 | // Succeeded or not, make sure the name gets off the stack. |
|
121 | 0 | stack.pop(); |
122 | 0 | } |
123 | 0 | } |
124 | 0 | } |
125 | ||
126 | /** |
|
127 | * Shuts down an <code>Initable</code>. |
|
128 | * |
|
129 | * This method is used to release resources allocated by an |
|
130 | * <code>Initable</code>, and return it to its initial (uninitailized) |
|
131 | * state. |
|
132 | * |
|
133 | * @param className The name of the class to be uninitialized. |
|
134 | */ |
|
135 | public void shutdownClass(String className) |
|
136 | { |
|
137 | try |
|
138 | { |
|
139 | 0 | Initable initable = getInitableInstance(className); |
140 | 0 | if (initable.getInit()) |
141 | { |
|
142 | 0 | initable.shutdown(); |
143 | 0 | ((BaseInitable) initable).setInit(false); |
144 | } |
|
145 | } |
|
146 | 0 | catch (InstantiationException e) |
147 | { |
|
148 | // Shutdown of a nonexistent class was requested. |
|
149 | // This does not hurt anything, so we log the error and continue. |
|
150 | 0 | log.error("Shutdown of a nonexistent class " + |
151 | className + " was requested", e); |
|
152 | 0 | } |
153 | 0 | } |
154 | ||
155 | /** |
|
156 | * Provides an instance of Initable class ready to work. |
|
157 | * |
|
158 | * If the requested class couldn't be instatiated or initialized, |
|
159 | * an InstantiationException will be thrown. You needn't handle |
|
160 | * this exception in your code, since it indicates fatal |
|
161 | * misconfigurtion of the system. |
|
162 | * |
|
163 | * @param className The name of the Initable requested. |
|
164 | * @return An instance of the requested Initable. |
|
165 | * @exception InstantiationException if there was a problem |
|
166 | * during instantiation or initialization of the Initable. |
|
167 | */ |
|
168 | public Initable getInitable(String className) |
|
169 | throws InstantiationException |
|
170 | { |
|
171 | Initable initable; |
|
172 | try |
|
173 | { |
|
174 | 0 | initable = getInitableInstance(className); |
175 | 0 | if (!initable.getInit()) |
176 | { |
|
177 | 0 | synchronized (initable.getClass()) |
178 | { |
|
179 | 0 | if (!initable.getInit()) |
180 | { |
|
181 | 0 | initable.init(); |
182 | } |
|
183 | 0 | if (!initable.getInit()) |
184 | { |
|
185 | // this exception will be caught & rethrown by this |
|
186 | // very method. getInit() returning false indicates |
|
187 | // some initialization issue, which in turn prevents |
|
188 | // the InitableBroker from passing a working |
|
189 | // instance of the initable to the client. |
|
190 | 0 | throw new InitializationException( |
191 | "init() failed to initialize class " |
|
192 | + className); |
|
193 | } |
|
194 | 0 | } |
195 | } |
|
196 | 0 | return initable; |
197 | } |
|
198 | 0 | catch (InitializationException e) |
199 | { |
|
200 | 0 | throw new InstantiationException("Class " + className + |
201 | " failed to initialize", e); |
|
202 | } |
|
203 | } |
|
204 | ||
205 | /** |
|
206 | * Retrieves an instance of an Initable from the repository. |
|
207 | * |
|
208 | * If the requested class is not present in the repository, it is |
|
209 | * instantiated and passed a reference to the broker, saved and |
|
210 | * then returned. |
|
211 | * |
|
212 | * @param className The name of the class to be instantiated. |
|
213 | * @exception InstantiationException if the requested class can't |
|
214 | * be instantiated. |
|
215 | */ |
|
216 | protected Initable getInitableInstance(String className) |
|
217 | throws InstantiationException |
|
218 | { |
|
219 | 0 | Initable initable = (Initable) initables.get(className); |
220 | ||
221 | 0 | if (initable == null) |
222 | { |
|
223 | try |
|
224 | { |
|
225 | 0 | initable = (Initable) Class.forName(className).newInstance(); |
226 | } |
|
227 | ||
228 | // those two errors must be passed to the VM |
|
229 | 0 | catch (ThreadDeath t) |
230 | { |
|
231 | 0 | throw t; |
232 | } |
|
233 | 0 | catch (OutOfMemoryError t) |
234 | { |
|
235 | 0 | throw t; |
236 | } |
|
237 | ||
238 | 0 | catch (Throwable t) |
239 | { |
|
240 | // Used to indicate error condition. |
|
241 | 0 | String msg = null; |
242 | ||
243 | 0 | if (t instanceof NoClassDefFoundError) |
244 | { |
|
245 | 0 | msg = "A class referenced by " + className + |
246 | " is unavailable. Check your jars and classes."; |
|
247 | } |
|
248 | 0 | else if (t instanceof ClassNotFoundException) |
249 | { |
|
250 | 0 | msg = "Class " + className + |
251 | " is unavailable. Check your jars and classes."; |
|
252 | } |
|
253 | 0 | else if (t instanceof ClassCastException) |
254 | { |
|
255 | 0 | msg = "Class " + className + |
256 | " doesn't implement Initable."; |
|
257 | } |
|
258 | else |
|
259 | { |
|
260 | 0 | msg = "Failed to instantiate " + className; |
261 | } |
|
262 | ||
263 | 0 | throw new InstantiationException(msg, t); |
264 | 0 | } |
265 | ||
266 | 0 | initable.setInitableBroker(this); |
267 | 0 | initables.put(className, initable); |
268 | } |
|
269 | ||
270 | 0 | return initable; |
271 | } |
|
272 | ||
273 | } |
This report is generated by jcoverage, Maven and Maven JCoverage Plugin. |