Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/RuntimeCollective/webapps/servlet/InitialiserServlet.java


1   /* $Header: /home/CVS/rjp/src/com/RuntimeCollective/webapps/servlet/InitialiserServlet.java,v 1.26 2003/10/15 11:14:16 joe Exp $
2    * $Revision: 1.26 $
3    * $Date: 2003/10/15 11:14:16 $
4    *
5    * ====================================================================
6    *
7    * Josephine : http://www.runtime-collective.com/josephine/index.html
8    *
9    * Copyright (C) 2003 Runtime Collective
10   * 
11   * This product includes software developed by the
12   * Apache Software Foundation (http://www.apache.org/).
13   *
14   * This library is free software; you can redistribute it and/or
15   * modify it under the terms of the GNU Lesser General Public
16   * License as published by the Free Software Foundation; either
17   * version 2.1 of the License, or (at your option) any later version.
18   *
19   * This library is distributed in the hope that it will be useful,
20   * but WITHOUT ANY WARRANTY; without even the implied warranty of
21   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
22   * Lesser General Public License for more details.
23   *
24   * You should have received a copy of the GNU Lesser General Public
25   * License along with this library; if not, write to the Free Software
26   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
27   *
28   */
29  
30  package com.RuntimeCollective.webapps.servlet;
31  
32  import java.io.IOException;
33  import java.sql.SQLException;
34  import java.util.Enumeration;
35  import java.util.HashSet;
36  import java.util.Properties;
37  import java.util.StringTokenizer;
38  
39  import javax.mail.Session;
40  import javax.naming.Context;
41  import javax.naming.InitialContext;
42  import javax.naming.NamingException;
43  import javax.servlet.ServletConfig;
44  import javax.servlet.ServletException;
45  import javax.servlet.http.HttpServlet;
46  import javax.sql.DataSource;
47  
48  import org.apache.log4j.BasicConfigurator;
49  import org.apache.log4j.FileAppender;
50  import org.apache.log4j.HTMLLayout;
51  import org.apache.log4j.Level;
52  import org.apache.log4j.Logger;
53  import org.apache.log4j.SimpleLayout;
54  import org.apache.log4j.net.SocketAppender;
55  import org.apache.log4j.xml.XMLLayout;
56  
57  import com.RuntimeCollective.webapps.EntityBeanStore;
58  import com.RuntimeCollective.webapps.EntityBeanStoreHandler;
59  import com.RuntimeCollective.webapps.RuntimeDataSource;
60  import com.RuntimeCollective.webapps.RuntimeParameters;
61  import com.RuntimeCollective.webapps.UserGroups;
62  import com.RuntimeCollective.webapps.WrappedDataSource;
63  /**
64   * This servlet initializes the Runtime webapps environment using the initialisation parameters. These parameters are of the following kinds:
65   * <ul>
66   * <li><strong>Beans</strong> -- parameters used to register beans on an EntityBeanStore, where the name of the parameter is bean.<i>bean_class_name</i> (for example, 'bean.com.RuntimeCollective.webapps.bean.SimpleUser') and the value is the name of the class of EntityBeanStore where they should be stored (for example, 'com.RuntimeCollective.webapps.SimpleEntityBeanStore').</li>.
67   * <li><strong>Parameters</strong> -- general purpose parameters registered on RuntimeParameters, where the name of the parameter is param.</i>param_name</li> and the value is that given.
68   * <li><strong>Properties</strong> -- System properties that will be set with <code>System.setProperty</code>, where the name of the parameter is property.</i>property_name</li> and the value is that given.
69   * <li><strong>Database</strong> -- One or more RDBMS data sources can be defined. The parameters for the first are defined as db.*, the second as db.1.*, and so on. Once defined, these data sources can be accessed using <code>RuntimeDataSource</code>.
70   * <ul>
71   * <li><code>db.alias</code>: Alias of the database. This will then be used by <code>RuntimeDataSource</code> to identify the database. If only one database is defined, then no alias is required.
72   * <li><code>db.JDBCDriverClass</code>: Name of JDBC driver class (eg oracle.jdbc.driver.OracleDriver).
73   * <li><code>db.maxConnections</code>: Maximum number of connections to maintain in the DB pool.
74   * <li><code>db.minConnections</code>: Minimum number of connections to maintain in the DB pool.
75   * <li><code>db.user</code>: User name for DB access
76   * <li><code>db.password</code>: Password for DB access
77   * <li><code>db.url</code>: URL of the database (eg. jdbc:oracle:thin:@sirius:1521:infodb)
78   * </ul>
79   * <li><strong>Log</strong> -- Define the logger used by this application. If none is defined then logging messages are sent to System.out by default. Otherwise, different types of log can be configured using the following parameters:
80   * <ul>
81   * <li><code>log.level</code>: The (lowest) level of log output required. Any of FATAL, ERROR, WARN, INFO, or DEBUG.
82   * <li><code>log.host</code>: The name of the host on which a log4J reader is running, and the port that it is listening to (eg 'localhost:8801'). If the port is not defined, then output is send to port 4445 by default. To read the output of this log, try using Lumbermill or Chainsaw.
83   * <li><code>log.file</code>: The name of a file to send logging messages to in Log4j SimpleLayout (human readable).
84   * <li><code>log.xmlFile</code>: The name of a file to send logging messages to in Log4j xml format (readable using Chainsaw).
85   * <li><code>log.htmlFile</code>: The name of a file to send logging messages to in Log4j  html format (readable using a browser).
86   * </ul>
87   *
88   * @version $Id: InitialiserServlet.java,v 1.26 2003/10/15 11:14:16 joe Exp $
89   * @see com.RuntimeCollective.webapps.EntityBeanStore
90   * @see com.RuntimeCollective.webapps.RuntimeDataSource
91   * @see com.RuntimeCollective.webapps.RuntimeParameters 
92   */
93  public final class InitialiserServlet extends HttpServlet {
94  
95      /**
96       * Initialize the environment.
97       * @exception ServletException if we cannot configure ourselves correctly
98       */
99      public void init() throws ServletException {
100   ServletConfig sc = getServletConfig();
101   initLogging(sc);
102   initDataSource(sc);
103         initParameters(sc);
104   initBeanStore(sc);
105   initProperties(sc);
106   initProxy(sc);
107   initUserGroups(sc);
108   initMailSession(sc);
109     }
110     
111     
112     /** Initialise the logger. */
113     private void initLogging(ServletConfig sc) {
114 
115   RuntimeParameters.logInfo( this,"Configuring the logger");
116 
117   // Default to not logging via a log4j logger
118   RuntimeParameters.setLog4jLogging(false);
119 
120   // Set the log level in RuntimeParameters (only useful for non-log4j logging)
121   String loggingLevel = sc.getInitParameter("log.level");
122   if (loggingLevel == null) {
123       // default to debug
124       loggingLevel = RuntimeParameters.LOG_LEVEL_DEBUG;
125   } else if (!loggingLevel.equals(RuntimeParameters.LOG_LEVEL_DEBUG) && !loggingLevel.equals(RuntimeParameters.LOG_LEVEL_INFO) && !loggingLevel.equals(RuntimeParameters.LOG_LEVEL_WARN) && !loggingLevel.equals(RuntimeParameters.LOG_LEVEL_ERROR) && !loggingLevel.equals(RuntimeParameters.LOG_LEVEL_FATAL)) {
126       // unrecognised error level
127       loggingLevel = RuntimeParameters.LOG_LEVEL_DEBUG;
128   }
129   RuntimeParameters.setLogLevel(loggingLevel);
130 
131   // Log to a host
132   String loggingHostPort = sc.getInitParameter("log.host");
133   if (loggingHostPort != null) {
134       // Extract the host and port (defaults to 4445)
135       StringTokenizer st = new StringTokenizer( loggingHostPort, ":" );
136       String host = st.nextToken();
137       String port = "4445";
138       if ( st.hasMoreTokens() ) port = st.nextToken();
139       SocketAppender appender = new SocketAppender( host, Integer.parseInt(port) );
140       BasicConfigurator.configure(appender);
141       RuntimeParameters.setLog4jLogging(true);
142       // set the log level
143       setLogLevel(loggingLevel);
144   }
145   
146   // Log to a file
147   String loggingFile = sc.getInitParameter("log.file");
148   if (loggingFile != null ) {
149       try {
150     FileAppender appender = new FileAppender( new SimpleLayout(), loggingFile);
151     BasicConfigurator.configure(appender);
152     RuntimeParameters.setLog4jLogging(true);
153     // set the log level
154     setLogLevel(loggingLevel);
155       } catch (IOException e) { throw new RuntimeException( "Unable to create file logger to "+loggingFile ); }
156   }
157 
158   // Log to an XML file
159   loggingFile = sc.getInitParameter("log.xmlFile");
160   if (loggingFile != null ) {
161       try {
162     FileAppender appender = new FileAppender( new XMLLayout(), loggingFile);
163     BasicConfigurator.configure(appender);
164     RuntimeParameters.setLog4jLogging(true);
165     // set the log level
166     setLogLevel(loggingLevel);
167       } catch (IOException e) { throw new RuntimeException( "Unable to create xml file logger to "+loggingFile ); }
168   }
169 
170   // Log to an HTML file
171   loggingFile = sc.getInitParameter("log.htmlFile");
172   if (loggingFile != null ) {
173       try {
174     FileAppender appender = new FileAppender( new HTMLLayout(), loggingFile);
175     BasicConfigurator.configure(appender);
176     RuntimeParameters.setLog4jLogging(true);
177     // set the log level
178     setLogLevel(loggingLevel);
179       } catch (IOException e) { throw new RuntimeException( "Unable to create html file logger to "+loggingFile ); }
180   }
181     }
182     
183     /** Set the root log level, specified in web.xml as a String. */
184     private void setLogLevel(String logLevel) {
185   // the string has already been checked/defaulted in initLogging, don't do it again.
186 
187   if (logLevel != null) {
188       if (logLevel.equals(RuntimeParameters.LOG_LEVEL_DEBUG)) {
189     Logger.getRootLogger().setLevel((Level) Level.DEBUG);
190       } else if (logLevel.equals(RuntimeParameters.LOG_LEVEL_INFO)) {
191     Logger.getRootLogger().setLevel((Level) Level.INFO);
192       } else if (logLevel.equals(RuntimeParameters.LOG_LEVEL_WARN)) {
193     Logger.getRootLogger().setLevel((Level) Level.WARN);
194       } else if (logLevel.equals(RuntimeParameters.LOG_LEVEL_ERROR)) {
195     Logger.getRootLogger().setLevel((Level) Level.ERROR);
196       } else if (logLevel.equals(RuntimeParameters.LOG_LEVEL_FATAL)) {
197     Logger.getRootLogger().setLevel((Level) Level.FATAL);
198       }
199   }
200     }
201 
202 
203     /** Initialise the parameters object. */
204     private void initParameters(ServletConfig sc) {
205   RuntimeParameters.logInfo(this, "Starting to register the init parameters");
206   
207   // Add all parameters in web.xml that start with "param."
208   Enumeration params = sc.getInitParameterNames();
209   while (params.hasMoreElements()) {
210       String paramName = (String) params.nextElement();
211       
212       if (paramName.startsWith("param.")) {
213     String paramClassName = paramName.substring(6);
214     String paramValue = sc.getInitParameter( paramName );
215     
216     RuntimeParameters.logInfo(this, "Registering init parameter : " + paramClassName + " = " + paramValue);
217     
218     // Add the parameter
219     RuntimeParameters.set( paramClassName, paramValue );
220       }
221   }
222   RuntimeParameters.logInfo(this, "Finished registering the init parameters");
223     }
224 
225     /** Initialise the system properties. */
226     private void initProperties(ServletConfig sc) {
227   RuntimeParameters.logInfo(this, "Starting to set the system properties");
228   
229   // Add all parameters in web.xml that start with "property."
230   Enumeration params = sc.getInitParameterNames();
231   while (params.hasMoreElements()) {
232       String paramName = (String) params.nextElement();
233       
234       if (paramName.startsWith("property.")) {
235     String propertyName = paramName.substring(9);
236     String propertyValue = sc.getInitParameter( paramName );
237     
238     RuntimeParameters.logInfo(this, "Setting system property : " + propertyName + " = " + propertyValue);
239     
240     // Set the System.property
241     System.setProperty( propertyName, propertyValue );
242       }
243   }
244   RuntimeParameters.logInfo(this, "Finished registering the init parameters");
245     }
246 
247     /** Initialise the use of an http proxy for all <code>java.net.URLConnection</code>s,
248      * if we have the web.xml parameters <code>param.proxyHost</code> and <code>proxyPort</code> */
249     private void initProxy(ServletConfig sc) {
250   String proxyHost="";
251   String proxyPort="";
252   try {
253       proxyHost = RuntimeParameters.get("proxyHost");
254       proxyPort = RuntimeParameters.get("proxyPort");
255   } catch (RuntimeException e) {
256       RuntimeParameters.logInfo(this, "No proxy information specified.");
257       return;
258       }
259 
260   // Set up the http proxy
261   RuntimeParameters.logInfo(this, "Starting to set up the HTTP proxy");
262 
263   if (!proxyHost.equals("") && !proxyPort.equals("")) {
264       System.getProperties().setProperty("http.proxyHost", proxyHost);
265       System.getProperties().setProperty("http.proxyPort", proxyPort);
266       RuntimeParameters.logInfo(this, "Using proxy "+proxyHost+", port "+proxyPort);
267   } else {
268       RuntimeParameters.logInfo(this, "No proxy information specified.");
269   }
270 
271   RuntimeParameters.logInfo(this, "Finished setting up the HTTP proxy");
272     }
273 
274     
275     /** Initialise the datasource. */
276     private void initDataSource(ServletConfig sc) throws ServletException {
277   // Create a data source with the required parameters.
278   
279   // Find out how many data sources we're supposed to be creating
280   // Special case: the first one (0) is not referenced by a number
281   int dbNum = 1;
282   while ( sc.getInitParameter( "db."+dbNum+".alias" ) != null ) {
283       dbNum++;
284   }
285   dbNum--;
286   
287   // Inform the RuntimeDataSource of all the databases we're using
288   RuntimeParameters.logInfo( this,"Creating RuntimeDataSource instance");
289   try {
290 
291       // Database info in web.xml is stored like:
292       //   db.alias, db.JDBCDriverClass, etc.
293       //   db.1.alias, db.1.JDBCDriverClass, etc.
294       //   db.2.alias, db.2.JDBCDriverClass, etc.
295       for (int db=0; db <= dbNum; db++) {
296     
297     String sep="db.";
298     // First database is just "db.*"; subsequent databases are "db.1.*"
299     if (db>0)
300         sep=sep+db+".";
301 
302         if (null == sc.getInitParameter( sep+"jndi" )) {
303             RuntimeDataSource.addDb(db,
304                  sc.getInitParameter( sep+"alias" ),
305                  sc.getInitParameter( sep+"JDBCDriverClass" ),
306                  Integer.parseInt( sc.getInitParameter(sep+"maxConnections") ),
307                  Integer.parseInt( sc.getInitParameter(sep+"minConnections") ),
308                  sc.getInitParameter( sep+"user" ),
309                  sc.getInitParameter( sep+"password" ),
310                  sc.getInitParameter( sep+"url" ),
311                  sc.getInitParameter( sep+"type" ));
312         } else {
313             Context ctx = new InitialContext();
314             DataSource ds = (DataSource)
315                 ctx.lookup("jdbc" +
316                            sc.getInitParameter( sep+"jndi" ));
317 
318             WrappedDataSource wds = new WrappedDataSource(ds);
319             wds.setType(sc.getInitParameter( sep+"type" ));
320 
321             RuntimeDataSource.addDb(sc.getInitParameter( sep+"alias" ), wds);
322         }
323         }
324 
325       // keep a copy of the "db.alias", used by RuntimeDataSource to get the default DB
326       RuntimeParameters.set("db.alias", sc.getInitParameter("db.alias"));
327 
328   } catch (NamingException e) {
329         RuntimeParameters.logError(this,
330                                    "Unable to locate jndi data source",
331                                    e);
332         throw new ServletException("Unable to initialise RuntimeDataSource",e);
333     } catch (RuntimeException e) {
334       RuntimeParameters.logError( this,"Unable to initialise RuntimeDataSource",e);
335       throw new ServletException("Unable to initialise RuntimeDataSource",e);
336   }
337 
338   // Tell the datasource to stop accepting new databases
339   RuntimeDataSource.doneAdding();
340 
341     }
342     
343     /** Initialise the bean store. */
344     private void initBeanStore(ServletConfig sc) throws ServletException {
345   try {
346       // GarbageCollectedCache is the default default
347       String defaultCacheClass = "com.RuntimeCollective.webapps.GarbageCollectedCache";
348 
349       // Registers all beans in web.xml (all init-params starting with "bean.")
350       RuntimeParameters.logInfo( this,"Registering beans on RuntimeParameters.getStore().");
351 
352       Enumeration params = sc.getInitParameterNames();  
353       String paramName;
354 
355       // First get a set of all the types of EntityBeanStore required by this application,
356       // in order to find out the number of entity bean stores required.
357       HashSet ebsTypes = new HashSet();
358       while (params.hasMoreElements()) {
359     paramName = (String) params.nextElement();
360 
361     if (paramName.startsWith("bean.")) {
362         String paramValue = sc.getInitParameter(paramName);
363         // get the bit before the first comma
364         if (paramValue.indexOf(",") != -1)
365       paramValue = paramValue.substring(0, paramValue.indexOf(",")).trim();
366         ebsTypes.add(paramValue);
367     }
368 
369     // get the default cache class
370     // (it's a Parameter, but those are initialised after EntityBeans)
371     if (paramName.equals("param.defaultCacheClass"))
372         defaultCacheClass = sc.getInitParameter(paramName);
373       }
374 
375       RuntimeParameters.logInfo( this,"[InitialiserServlet.initBeanStore()] defaultCacheClass : "+defaultCacheClass);
376 
377       // If there were no EBS's required, then forget about it
378       if (ebsTypes.size()==0) return;
379 
380       // If there is more than one type of EBS required, then we have to use an
381       // EntityBeanStoreHandler to handle them
382       if ( ebsTypes.size()>1 ) {
383 
384     String beanClassName;
385     String storeClassName;
386     String cacheClassName;
387     EntityBeanStoreHandler ebs = new EntityBeanStoreHandler();
388     
389     // And register each of the beans 
390     params = sc.getInitParameterNames();  
391     while (params.hasMoreElements()) {
392         paramName = (String) params.nextElement();
393         if (paramName.startsWith("bean.")) {
394 
395       // the bean name
396       beanClassName = paramName.substring(5);
397       
398       // the store name (get the bit before the first comma)
399       storeClassName = sc.getInitParameter(paramName);
400       if (storeClassName.indexOf(",") != -1)
401           storeClassName = storeClassName.substring(0, storeClassName.indexOf(",")).trim();
402 
403       // the cache name (bit after the first comma, default to defaultCacheClass)
404       cacheClassName = sc.getInitParameter(paramName);
405       if (cacheClassName.indexOf(",") != -1)
406           cacheClassName = cacheClassName.substring(cacheClassName.indexOf(",")+1).trim();
407       else
408           cacheClassName = defaultCacheClass;
409 
410       RuntimeParameters.logInfo( this,"[InitialiserServlet.initBeanStore()] Registering bean\n - Class : "+beanClassName+"\n - Store : "+storeClassName+"\n - Cache : "+cacheClassName);
411       ebs.registerBean(beanClassName, cacheClassName, storeClassName);
412         } 
413     }
414     
415     // Initialise the store, and stick it in the toolbox
416     RuntimeParameters.logInfo( this,"Initialising bean store.");
417     ebs.init();
418     RuntimeParameters.setStore( ebs );
419       }
420 
421       // If there is only one type of EBS required create an EBS of the appropriate type.
422       if ( ebsTypes.size()==1 ) {
423 
424     String beanClassName;
425     String cacheClassName;
426     EntityBeanStore ebs;
427 
428     try {
429         ebs = (EntityBeanStore) Class.forName( (String) ebsTypes.iterator().next() ).getConstructor( new Class[] {} ).newInstance( new Object[] {} );
430     } catch (Exception e) {
431         RuntimeParameters.logError( this,"Unable to construct EntityBeanStore of type "+ebsTypes.iterator().next(),e);
432         throw new ServletException("Unable to construct EntityBeanStore of type "+ebsTypes.iterator().next(),e);
433     }
434     
435     // And register each of the beans 
436     params = sc.getInitParameterNames();  
437     while (params.hasMoreElements()) {
438         paramName = (String) params.nextElement();
439         if (paramName.startsWith("bean.")) {
440 
441       // the bean name
442       beanClassName = paramName.substring(5);
443 
444       // the cache name (bit after the first comma, default to defaultCacheClass)
445       cacheClassName = sc.getInitParameter(paramName);
446       if (cacheClassName.indexOf(",") != -1)
447           cacheClassName = cacheClassName.substring(cacheClassName.indexOf(",")+1).trim();
448       else
449           cacheClassName = defaultCacheClass;
450 
451       RuntimeParameters.logInfo( this,"[InitialiserServlet.initBeanStore()] Registering bean\n - Class : "+beanClassName+"\n - Cache : "+cacheClassName);
452       ebs.registerBean(beanClassName, cacheClassName);
453         } 
454     }
455     
456     // Initialise the store, and stick it in the toolbox
457     RuntimeParameters.logInfo( this,"Initialising bean store.");
458     ebs.init();
459     RuntimeParameters.setStore( ebs );
460     
461       }
462 
463 
464   } catch (RuntimeException e) {
465       RuntimeParameters.logError( this,"Unable to register beans on EntityBeanStore.", e );
466       e.printStackTrace(System.out);
467       throw new ServletException("Unable to register beans on EntityBeanStore: "+e);
468   }
469     }
470 
471 
472     /** Initialise the UserGroups object. */
473     private void initUserGroups(ServletConfig sc) throws ServletException {
474   RuntimeParameters.setUserGroups(new UserGroups());
475     }
476     
477     /** Initialise the JavaMail Session object. */
478     private void initMailSession(ServletConfig sc) throws ServletException {
479   try {
480       if (null == sc.getInitParameter( "mail.jndi" )) {
481     Properties mailProps = new Properties();
482     mailProps.put("mail.transport.protocol", "smtp");
483     mailProps.put("mail.host", RuntimeParameters.get("smtpHost"));
484     mailProps.put("mail.from", RuntimeParameters.get("systemEmailAddress"));
485     
486     // FIXME: MAYBE this should be getDefaultInstance(mailProps)... but there's no guarantee
487     // we're the first thing to try and set up a mail session.  I don't think...
488     RuntimeParameters.setMailSession(Session.getInstance(mailProps, null));
489       } else {
490     Context ctx = new InitialContext();
491     Session mailSession = (Session)
492         ctx.lookup( sc.getInitParameter( "mail.jndi" ));
493     
494     RuntimeParameters.setMailSession(mailSession);
495       }
496   } catch (Exception e) {
497       e.printStackTrace(System.out);
498       RuntimeParameters.logError(this, "initMailSession could not initialise a mail session; web.xml must specify \"smtpHost\" and \"systemEmailAddress\" properties: "+e);
499   }
500     }
501 
502     /**
503      * Gracefully shut down this servlet, releasing any resources
504      * that were allocated at initialization.
505      */
506     public void destroy(){
507   try {
508       RuntimeDataSource.closeInstance();
509   } catch (SQLException e) {
510       RuntimeParameters.logError( this,"Unable to close RuntimeDataSource.", e );
511   }
512     }
513     
514 }