1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.pluto.portalImpl.services;
21
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.util.HashMap;
25 import java.util.Iterator;
26 import java.util.LinkedList;
27 import java.util.List;
28 import java.util.Map;
29
30 import javax.servlet.ServletConfig;
31 import javax.servlet.ServletContext;
32
33 import org.apache.pluto.portalImpl.util.Properties;
34 import org.apache.pluto.util.StringUtils;
35
36 /***
37 * Manages the life-time of services registered during servlet startup.
38 * There are two types of services: Services required by the container,
39 * and Services used for the portal driver configuration and execution.
40 * All services required by the container have to derive from
41 * {@link org.apache.pluto.services.ContainerService} and implement the
42 * <CODE>init()</CODE> and <CODE>destroy()</CODE> methods as appropriate.
43 * All services must derive from the
44 * {@link org.apache.pluto.portalImpl.services.Service} interface if they
45 * are to be used with the portal driver.
46 * <P>
47 * By registering the service and its implementation in the file
48 * <CODE>/config/services.properties</CODE>, the service will become
49 * available to the portal engine. The format of the file is simple:
50 *
51 * <PRE>
52 * org.apache.pluto.portalImpl.services.log.Logger = org.apache.pluto.portalImpl.services.log.LogServicesImpl
53 * </PRE>
54 *
55 * Each entry represents one service. The left-hand side is the abstract
56 * service class, the right-hand side is the implementation of this service.
57 * The services are initialized in the order of appearance.
58 *
59 * <P>
60 * Each service can have its own configuration file, located in
61 * <CODE>/config/services</CODE>. It has to have the name of either
62 * implementation or abstract class of the service, without the
63 * leading package name. For example, the service manager looks
64 * for <CODE>LoggerImpl
65 .properties</CODE>. This allows a special
66 * implementation to provide different configuration than the
67 * general (abstract) service requires.
68 *
69 * <P>
70 * If present, one of the services configuration files is loaded
71 * and passed to the service as {@link org.apache.pluto.portalImpl.util.Properties}
72 * object. Not providing a service configuration file is okay too,
73 * in that case the properties are emptyemptySessionPath .
74 *
75 * @see org.apache.pluto.services.ContainerService
76 */
77 public class ServiceManager
78 {
79
80 private final static String SERVICES_CONFIG_FILE = "/WEB-INF/config/services.properties";
81 private final static String SERVICES_CONFIG_DIR = "/WEB-INF/config/services/";
82
83 /***
84 ** Initializes all services specified in <CODE>services.properties</CODE>.
85 ** By specifying a different implementation of the service the behaviour
86 ** of the portal can be modified.
87 **
88 ** @param aConfig
89 ** the servlet configuration
90 **
91 ** @exception Exception
92 ** if loading <CODE>services.properties</CODE>
93 ** or initializing any of its contained services fails
94 **/
95
96 public static void init (ServletConfig aConfig) throws Exception
97 {
98 init (aConfig, SERVICES_CONFIG_FILE, SERVICES_CONFIG_DIR);
99 }
100
101 /***
102 ** Initializes all services specified in <CODE>services.properties</CODE>.
103 ** By specifying a different implementation of the service the behaviour
104 ** of the portal can be modified.
105 **
106 ** @param aConfig
107 ** the servlet configuration
108 ** @param aServiceConfigFile
109 ** The location of <CODE>services.properties</CODE> (relative to classpath)
110 ** @param aServiceConfigDir
111 ** The direcory with the services' properties files (relative to classpath)
112 **
113 ** @exception Exception
114 ** if loading <CODE>services.properties</CODE>
115 ** or initializing any of its contained services fails
116 **/
117
118 public static void init (ServletConfig aConfig,
119 String aServiceConfigFile,
120 String aServiceConfigDir) throws Exception
121 {
122
123
124 if (! cInitialized)
125 {
126 synchronized (ServiceManager.class)
127 {
128 if (! cInitialized)
129 {
130 cInitialized = true;
131 }
132 else
133 {
134 return;
135 }
136 }
137 }
138 else
139 {
140 return;
141 }
142
143 ServletContext context = null;
144
145 if (aConfig != null)
146 context = aConfig.getServletContext ();
147
148 if (context != null)
149 context.log ("ServiceManager: Loading services...");
150
151 Properties props = new Properties ();
152
153 try
154 {
155 props.load (context.getResourceAsStream (aServiceConfigFile));
156 }
157 catch (IOException exc)
158 {
159 if (context != null)
160 context.log ("ServiceManager: File \"" + aServiceConfigFile + "\" cannot be found or read.");
161 throw new Exception("ServiceManager: File \"" + aServiceConfigFile + "\" cannot be found or read.");
162 }
163
164 int numAll = 0;
165 int numSuccessful = 0;
166
167 for (Iterator iter = props.names (); iter.hasNext (); )
168 {
169 String serviceBaseName = (String) iter.next ();
170
171 numAll++;
172
173
174
175 Class serviceBase;
176
177 try
178 {
179 serviceBase = Class.forName (serviceBaseName);
180 }
181 catch (ClassNotFoundException exc)
182 {
183 if (context != null)
184 context.log ("ServiceManager: A service with name " + serviceBaseName + " cannot be found.");
185
186 continue;
187 }
188
189 String serviceImplName = props.getString (serviceBaseName);
190
191 Class serviceImpl = null;
192
193 Service service = null;
194
195 try
196 {
197 serviceImpl = Class.forName (serviceImplName);
198
199 service = (Service) serviceImpl.newInstance ();
200
201 Properties serviceProps = new Properties ();
202
203 try
204 {
205 InputStream is = null;
206
207 is = context.getResourceAsStream (aServiceConfigDir + StringUtils.nameOf (serviceImpl) + ".properties");
208
209 if (is == null)
210 is = context.getResourceAsStream (aServiceConfigDir + StringUtils.nameOf (serviceBase) + ".properties");
211
212 if (is != null)
213 serviceProps.load (is);
214 }
215 catch (IOException exc)
216 {
217
218 }
219
220 if (context != null)
221 context.log (StringUtils.nameOf (serviceBase) + " initializing...");
222
223 service.init (aConfig, serviceProps);
224
225 if (context != null)
226 context.log (StringUtils.nameOf (serviceBase) + " done.");
227 }
228 catch (ClassNotFoundException exc)
229 {
230 if (context != null)
231 context.log ("ServiceManager: A service implementation with name " + serviceImplName + " cannot be found.", exc);
232
233 continue;
234 }
235 catch (ClassCastException exc)
236 {
237 if (context != null)
238 context.log ("ServiceManager: Service implementation " + serviceImplName + " is not a service of the required type.", exc);
239
240 continue;
241 }
242 catch (InstantiationException exc)
243 {
244 if (context != null)
245 context.log ("ServiceManager: Service implementation " + serviceImplName + " cannot be instantiated.", exc);
246
247 continue;
248 }
249 catch (Exception exc)
250 {
251 if (context != null)
252 context.log ("ServiceManager: An unidentified error occurred", exc);
253
254 service = null;
255 }
256
257 if (service != null)
258 {
259 cServicesMap.put (serviceBase, service);
260
261
262
263 cServicesList.add (0, service);
264
265 numSuccessful++;
266 }
267 }
268
269 if (context != null)
270 context.log ("ServiceManager: Services initialized (" + numSuccessful + "/" + numAll + " successful).");
271 if (numSuccessful!=numAll)
272 {
273 throw new Exception("ServiceManager: Services initialized (" + numSuccessful + "/" + numAll + " successful).");
274 }
275 }
276
277 /***
278 * Calls post init for all services
279 *
280 * @param aConfig
281 * the servlet configuration
282 **/
283 public static void postInit(ServletConfig aConfig) {
284
285
286 if (cInitialized)
287 {
288 synchronized (ServiceManager.class)
289 {
290 if (cInitialized)
291 {
292 cInitialized = false;
293 }
294 else
295 {
296 return;
297 }
298 }
299 }
300 else
301 {
302 return;
303 }
304
305 ServletContext context = null;
306
307 if (aConfig != null)
308 context = aConfig.getServletContext ();
309
310
311 for (Iterator iterator = cServicesList.iterator (); iterator.hasNext (); )
312 {
313 Service service = (Service) iterator.next ();
314
315 try
316 {
317 service.postInit(aConfig);
318 }
319 catch (Exception exc)
320 {
321 if (context != null)
322 context.log ("ServiceManager: Service couldn't be started (postInit) after init..", exc);
323 }
324 }
325
326 }
327
328 /***
329 ** Destroys all services.
330 **
331 ** @param aConfig
332 ** the servlet configuration
333 **/
334
335 public static void destroy (ServletConfig aConfig)
336 {
337
338
339 if (cInitialized)
340 {
341 synchronized (ServiceManager.class)
342 {
343 if (cInitialized)
344 {
345 cInitialized = false;
346 }
347 else
348 {
349 return;
350 }
351 }
352 }
353 else
354 {
355 return;
356 }
357
358 ServletContext context = null;
359
360 if (aConfig != null)
361 context = aConfig.getServletContext ();
362
363
364
365 for (Iterator iterator = cServicesList.iterator (); iterator.hasNext (); )
366 {
367 Service service = (Service) iterator.next ();
368
369 try
370 {
371 service.destroy (aConfig);
372 }
373 catch (Exception exc)
374 {
375 if (context != null)
376 context.log ("ServiceManager: Service couldn't be destroyed.", exc);
377 }
378 }
379
380 cServicesList.clear();
381 cServicesMap.clear();
382
383 }
384
385 /***
386 ** Returns the service implementation for the given service class, or
387 ** <CODE>null</CODE> if no such service is registered.
388 **
389 ** @param aClass
390 ** the service class
391 **
392 ** @return the service implementation
393 **/
394
395 public static Service getService (Class aClass)
396 {
397
398
399
400 return ((Service) cServicesMap.get (aClass));
401 }
402
403
404
405 private static volatile boolean cInitialized = false;
406
407 private static Map cServicesMap = new HashMap ();
408 private static List cServicesList = new LinkedList ();
409 }
410
411
412