Main Page | Packages | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | Related Pages

ControllerFactory.java

00001 /**
00002  * C-JDBC: Clustered JDBC.
00003  * Copyright (C) 2002-2004 French National Institute For Research In Computer
00004  * Science And Control (INRIA).
00005  * Contact: c-jdbc@objectweb.org
00006  * 
00007  * This library is free software; you can redistribute it and/or modify it
00008  * under the terms of the GNU Lesser General Public License as published by the
00009  * Free Software Foundation; either version 2.1 of the License, or any later
00010  * version.
00011  * 
00012  * This library is distributed in the hope that it will be useful, but WITHOUT
00013  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00014  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
00015  * for more details.
00016  * 
00017  * You should have received a copy of the GNU Lesser General Public License
00018  * along with this library; if not, write to the Free Software Foundation,
00019  * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
00020  *
00021  * Initial developer(s): Emmanuel Cecchet. 
00022  * Contributor(s): Mathieu Peltier, Nicolas Modrzyk, Duncan Smith.
00023  */
00024 
00025 package org.objectweb.cjdbc.controller.core;
00026 
00027 import java.io.File;
00028 import java.io.FileReader;
00029 import java.net.InetAddress;
00030 import java.net.URL;
00031 import java.net.URLDecoder;
00032 import java.net.UnknownHostException;
00033 import java.util.Hashtable;
00034 
00035 import org.apache.commons.cli.CommandLine;
00036 import org.apache.commons.cli.CommandLineParser;
00037 import org.apache.commons.cli.GnuParser;
00038 import org.apache.commons.cli.HelpFormatter;
00039 import org.apache.commons.cli.Option;
00040 import org.apache.commons.cli.OptionGroup;
00041 import org.apache.commons.cli.Options;
00042 import org.apache.commons.cli.ParseException;
00043 import org.objectweb.cjdbc.common.i18n.Translate;
00044 import org.objectweb.cjdbc.common.jmx.JmxConstants;
00045 import org.objectweb.cjdbc.common.jmx.JmxException;
00046 import org.objectweb.cjdbc.common.log.Trace;
00047 import org.objectweb.cjdbc.common.net.SSLConfiguration;
00048 import org.objectweb.cjdbc.controller.authentication.PasswordAuthenticator;
00049 import org.objectweb.cjdbc.controller.core.security.ControllerSecurityManager;
00050 import org.objectweb.cjdbc.controller.jmx.HttpAdaptor;
00051 import org.objectweb.cjdbc.controller.jmx.MBeanServerManager;
00052 import org.objectweb.cjdbc.controller.jmx.RmiConnector;
00053 import org.objectweb.cjdbc.controller.monitoring.datacollector.DataCollector;
00054 import org.objectweb.cjdbc.controller.xml.ControllerParser;
00055 
00056 /**
00057  * The <code>ControllerFactory</code> class prepares a <code>Controller</code>
00058  * object by configurating ports, security, loaded databases.
00059  * 
00060  * @author <a href="mailto:Emmanuel.Cecchet@inria.fr">Emmanuel Cecchet </a>
00061  * @author <a href="mailto:Nicolas.Modrzyk@inrialpes.fr">Nicolas Modrzyk </a>
00062  * @author <a href="mailto:duncan@mightybot.com">Duncan Smith </a>
00063  * @version 1.0
00064  */
00065 public class ControllerFactory extends Hashtable
00066 {
00067   /**
00068    * The different fields that can be set on the command line.
00069    */
00070   /** The Rmi port value */
00071   public static final String RMI_PORT           = "rmiPort";
00072 
00073   /** The jmx port value */
00074   public static final String JMX_PORT           = "jmxPort";
00075 
00076   /** The jmx enable value */
00077   public static final String JMX_ENABLE         = "jmxEnable";
00078 
00079   /** The xml file possibly used to configure controller */
00080   public static final String XML_FILE           = "xmlFile";
00081 
00082   /** The NIC IP address to bind the controller to */
00083   public static final String CONTROLLER_IP      = "controllerIP";
00084 
00085   /** The controller port number */
00086   public static final String CONTROLLER_PORT    = "controllerPort";
00087 
00088   /** The controller backlog size */
00089   public static final String CONTROLLER_BACKLOG = "controllerBackLogSize";
00090 
00091   /** Add driver enable */
00092   public static final String ADD_DRIVER_ENABLE  = "addDriverEnable";
00093 
00094   /** Logger instance. */
00095   static Trace               logger             = Trace
00096                                                     .getLogger(Controller.class
00097                                                         .getName());
00098 
00099   private Controller         controller         = null;
00100 
00101   /**
00102    * Configure the controller with parameters
00103    * 
00104    * @param args parameters from the command line
00105    */
00106   public ControllerFactory(String args[])
00107   {
00108     System.setProperty("org.xml.sax.driver",
00109         "org.apache.crimson.parser.XMLReaderImpl");
00110 
00111     URL defaultControllerXmlFile = ControllerFactory.class.getResource("/"
00112         + ControllerConstants.DEFAULT_CONFIG_FILE);
00113     if (defaultControllerXmlFile == null)
00114       logger
00115           .warn("Unable to find default controller.xml configuration file in CLASSPATH.");
00116     else
00117     {
00118       String file = URLDecoder.decode(defaultControllerXmlFile.getFile());
00119       this.put(XML_FILE, file);
00120     }
00121     this.put(CONTROLLER_IP, ControllerConstants.DEFAULT_IP);
00122     this.put(CONTROLLER_PORT, "" + ControllerConstants.DEFAULT_PORT);
00123     this.put(CONTROLLER_BACKLOG, "" + ControllerConstants.DEFAULT_BACKLOG_SIZE);
00124 
00125     // Create options object
00126     Options options = createOptions();
00127 
00128     // Parse command line
00129     CommandLineParser parser = new GnuParser();
00130     CommandLine commandLine = null;
00131     try
00132     {
00133       commandLine = parser.parse(options, args);
00134     }
00135     catch (ParseException e)
00136     {
00137       logger.fatal(Translate.get("controller.configure.commandline.error", e),
00138           e);
00139       printUsage(options);
00140       Runtime.getRuntime().exit(1);
00141     }
00142 
00143     // Non-recognized options
00144     int n = commandLine.getArgs().length;
00145     for (int i = 0; i < n; i++)
00146     {
00147       logger.fatal(Translate.get("controller.configure.unknown.option",
00148           commandLine.getArgs()[i]));
00149       printUsage(options);
00150       Runtime.getRuntime().exit(1);
00151     }
00152     // Handle --help option
00153     if (commandLine.hasOption('h'))
00154     {
00155       if (commandLine.getOptions().length > 1)
00156         logger.fatal(Translate.get("controller.configure.commandline.error"));
00157 
00158       printUsage(options);
00159       Runtime.getRuntime().exit(1);
00160     }
00161 
00162     // Handle --version option
00163     if (commandLine.hasOption('v'))
00164     {
00165       if (commandLine.getOptions().length > 1)
00166       {
00167         logger.fatal(Translate.get("controller.configure.commandline.error"));
00168         printUsage(options);
00169       }
00170       else
00171         logger.info(Controller.getVersion());
00172       Runtime.getRuntime().exit(1);
00173     }
00174 
00175     // Handle -rmi option
00176     if (commandLine.hasOption('r'))
00177     {
00178       String s = commandLine.getOptionValue('r');
00179       if (s != null)
00180       {
00181         this.put(JMX_ENABLE, "true");
00182         this.put(RMI_PORT, s);
00183         this.put(JmxConstants.ADAPTOR_TYPE_RMI, s);
00184       }
00185     }
00186 
00187     // Handle -jmx option
00188     if (commandLine.hasOption('j'))
00189     {
00190       String s = commandLine.getOptionValue('j');
00191       if (s != null)
00192       {
00193         this.put(JMX_ENABLE, "true");
00194         this.put(JMX_PORT, s);
00195         this.put(JmxConstants.ADAPTOR_TYPE_HTTP, s);
00196       }
00197     }
00198 
00199     // Handle --ip option
00200     if (commandLine.hasOption('i'))
00201     {
00202       String ipAddress = commandLine.getOptionValue('i');
00203       if (ipAddress != null)
00204         this.put(CONTROLLER_IP, ipAddress);
00205     }
00206 
00207     //  Handle --port option
00208     if (commandLine.hasOption('p'))
00209     {
00210       String port = commandLine.getOptionValue('p');
00211       if (port != null)
00212         this.put(CONTROLLER_PORT, port);
00213     }
00214 
00215     // Handle -f option
00216     if (commandLine.hasOption('f'))
00217     {
00218       // If a config file is specified we ignore the default file.
00219       this.remove(XML_FILE);
00220       String filePath = commandLine.getOptionValue('f');
00221       File f = new File(filePath);
00222       logger.debug(f.getAbsolutePath());
00223       if (f.exists() == false || f.isFile() == false)
00224         logger
00225             .warn(Translate.get("controller.configure.optional.file.invalid"));
00226       else
00227         this.put(XML_FILE, filePath);
00228     }
00229   }
00230 
00231   /**
00232    * This method is going to call a <code>ControllerParser</code> object to
00233    * configure controller while parsing file. This method will call <method>
00234    * setUpRmi() </method> and <method>setUpJmx() </method> as well as <method>
00235    * setUpVirtualDatabases </method> while parsing.
00236    * 
00237    * @param filename path to the xml file to parse from
00238    * @throws Exception if configuration fails
00239    */
00240   public void setUpByXml(String filename) throws Exception
00241   {
00242     logger.info(Translate.get("controller.configure.loading.file", filename));
00243     FileReader fileReader = null;
00244     try
00245     {
00246       fileReader = new FileReader(filename);
00247       ControllerParser cparser = new ControllerParser(this);
00248       cparser.readXML(fileReader, true);
00249       fileReader.close();
00250     }
00251     catch (Exception e)
00252     {
00253 
00254       logger.warn(Translate.get("controller.configure.xml.file.error", e), e);
00255       throw e;
00256     }
00257     finally
00258     {
00259       if (fileReader != null)
00260         fileReader.close();
00261     }
00262   }
00263 
00264   /**
00265    * Test if there is a file to take configuration from, if so call <method>
00266    * setUpByXml() </method>
00267    * 
00268    * @return an instanciated and configured object of class
00269    *              <code>Controller</code>
00270    * @throws Exception if configuration fails
00271    */
00272   private Controller setup() throws Exception
00273   {
00274     String xml = (String) this.get(XML_FILE);
00275 
00276     int portNumber = Integer.parseInt((String) this.get(CONTROLLER_PORT));
00277     int backlog = Integer.parseInt((String) this.get(CONTROLLER_BACKLOG));
00278     String ipAddress = (String) this.get(CONTROLLER_IP);
00279 
00280     controller = new Controller(ipAddress, portNumber, backlog);
00281     controller.setConfiguration(this);
00282 
00283     if (xml != null)
00284     {
00285       try
00286       {
00287         setUpByXml(xml);
00288       }
00289       catch (Exception e)
00290       {
00291         logger.error(Translate.get(
00292             "controller.configure.load.file.failed.minimum.configuration",
00293             new String[]{xml, e.getMessage()}), e);
00294       }
00295     }
00296     else
00297       setUpJmx();
00298 
00299     return this.controller;
00300   }
00301 
00302   /**
00303    * Retrieve the controller associated with this <code>ControllerFactory</code>
00304    * instance.
00305    * 
00306    * @return <code>Controller</code> object. Can be null if this method is
00307    *              called before setup
00308    * @throws Exception if an error occurs
00309    */
00310   public Controller getController() throws Exception
00311   {
00312     if (controller == null)
00313       setup();
00314     return this.controller;
00315   }
00316 
00317   /**
00318    * Start up the jmx services if enabled.
00319    * 
00320    * @throws JmxException an exception
00321    */
00322   public void setUpJmx() throws JmxException
00323   {
00324     boolean jmxEnable = new Boolean((String) get(JMX_ENABLE)).booleanValue();
00325     if (jmxEnable == false)
00326     {
00327       MBeanServerManager.setJmxEnabled(false);
00328       logger.info(Translate.get("jmx.configure.disabled"));
00329     }
00330     else
00331     {
00332       MBeanServerManager.setJmxEnabled(true);
00333       logger.info(Translate.get("jmx.configure.enabled"));
00334       // Create and start the JMX agent
00335       try
00336       {
00337         new DataCollector(controller);
00338         String hostIP = controller.getIPAddress();
00339 
00340         logger.info(Translate.get("controller.configure.start.jmx", hostIP));
00341 
00342         if (this.containsKey(JmxConstants.ADAPTOR_TYPE_HTTP))
00343         {
00344           int port = Integer.parseInt((String) this
00345               .get(JmxConstants.ADAPTOR_TYPE_HTTP));
00346           HttpAdaptor http = new HttpAdaptor(hostIP, port, null, null);
00347           http.start();
00348         }
00349         if (this.containsKey(JmxConstants.ADAPTOR_TYPE_RMI))
00350         {
00351           SSLConfiguration ssl = null;
00352           PasswordAuthenticator authenticator = null;
00353           int port = Integer.parseInt((String) this
00354               .get(JmxConstants.ADAPTOR_TYPE_RMI));
00355           if (this.containsKey(JmxConstants.CONNECTOR_AUTH_USERNAME))
00356           {
00357             String username = (String) this
00358                 .get(JmxConstants.CONNECTOR_AUTH_USERNAME);
00359             String password = (String) this
00360                 .get(JmxConstants.CONNECTOR_AUTH_PASSWORD);
00361             authenticator = new PasswordAuthenticator(username, password);
00362           }
00363           if (this.containsKey(JmxConstants.CONNECTOR_RMI_SSL))
00364           {
00365             ssl = (SSLConfiguration) this.get(JmxConstants.CONNECTOR_RMI_SSL);
00366           }
00367           RmiConnector rmi = new RmiConnector(controller.getControllerName(), hostIP,
00368               port, authenticator, ssl);
00369           rmi.start();
00370         }
00371         logger.debug(Translate.get("controller.configure.jmx.started"));
00372       }
00373       catch (Exception e)
00374       {
00375         logger
00376             .error(Translate.get("controller.configure.jmx.fail.start", e), e);
00377       }
00378     }
00379     controller.setJmxEnable(jmxEnable);
00380   }
00381 
00382   /**
00383    * Set up security settings if needed here.
00384    * 
00385    * @param security to enforce
00386    */
00387   public void setUpSecurity(ControllerSecurityManager security)
00388   {
00389     controller.setSecurity(security);
00390   }
00391 
00392   /**
00393    * Will load the <code>VirtualDatabase</code> configuration into the
00394    * controller.
00395    * 
00396    * @param filePath the path to xml definition of the virtual database
00397    * @param virtualName the name of the virtualDatabase to load
00398    * @param autoLoad specified if backend should be enabled.
00399    * @param checkPoint the check point to load the database from.
00400    */
00401   public void setUpVirtualDatabase(String filePath, String virtualName,
00402       int autoLoad, String checkPoint)
00403   {
00404     try
00405     {
00406       controller.loadXmlConfiguration(filePath, virtualName, autoLoad,
00407           checkPoint);
00408       if (logger.isDebugEnabled())
00409         logger.debug(Translate.get("controller.configure.file.autoload",
00410             new String[]{filePath, "" + autoLoad}));
00411 
00412     }
00413     catch (Exception e)
00414     {
00415       logger.error(Translate.get("controller.configure.load.file.failed",
00416           new String[]{filePath, e.getMessage()}), e);
00417     }
00418   }
00419 
00420   /**
00421    * Displays usage message.
00422    * 
00423    * @param options available command line options
00424    */
00425   private static void printUsage(Options options)
00426   {
00427     String header = Translate.get("controller.commandline.header");
00428     header += System.getProperty("line.separator");
00429     header += Translate.get("controller.commandline.options");
00430     String footer = Translate.get("controller.commandline.footer");
00431 
00432     (new HelpFormatter()).printHelp(80, "controller(.sh|.bat) [options]",
00433         header, options, footer);
00434   }
00435 
00436   /**
00437    * Creates <code>Options</code> object that contains all available options
00438    * that can be used launching C-JDBC controller.
00439    * 
00440    * @return an <code>Options</code> instance
00441    */
00442   private static Options createOptions()
00443   {
00444     Options options = new Options();
00445     OptionGroup group = new OptionGroup();
00446 
00447     // help and verbose options
00448     group.addOption(new Option("h", "help", false, Translate
00449         .get("controller.commandline.option.help")));
00450     group.addOption(new Option("v", "version", false, Translate
00451         .get("controller.commandline.option.version")));
00452     options.addOptionGroup(group);
00453 
00454     // RMI port option
00455     options.addOption(new Option("r", "rmi", true, Translate.get(
00456         "controller.commandline.option.rmi", ""
00457             + JmxConstants.DEFAULT_JMX_RMI_PORT)));
00458     // JMX port option
00459     options.addOption(new Option("j", "jmx", true, Translate.get(
00460         "controller.commandline.option.jmx", ""
00461             + JmxConstants.DEFAULT_JMX_HTTP_PORT)));
00462 
00463     // IP option
00464     String defaultIp = "127.0.0.1";
00465     try
00466     {
00467       defaultIp = InetAddress.getLocalHost().getHostAddress();
00468     }
00469     catch (UnknownHostException e)
00470     {
00471 
00472     }
00473     options.addOption(new Option("i", "ip", true, Translate.get(
00474         "controller.commandline.option.ip", "" + defaultIp)));
00475 
00476     // Port options
00477     options.addOption(new Option("p", "port", true, Translate.get(
00478         "controller.commandline.option.port", ""
00479             + ControllerConstants.DEFAULT_PORT)));
00480 
00481     // configuration file option
00482     options.addOption(new Option("f", "file", true, Translate
00483         .get("controller.commandline.option.file")));
00484 
00485     return options;
00486   }
00487 
00488 }

Generated on Mon Apr 11 22:01:30 2005 for C-JDBC by  doxygen 1.3.9.1