View Javadoc

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