KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > continuent > sequoia > controller > core > Controller


1 /**
2  * Sequoia: Database clustering technology.
3  * Copyright (C) 2002-2004 French National Institute For Research In Computer
4  * Science And Control (INRIA).
5  * Copyright (C) 2005 AmicoSoft, Inc. dba Emic Networks
6  * Copyright (C) 2006 Continuent, Inc.
7  * Contact: sequoia@continuent.org
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  * http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  * Free Software Foundation; either version 2.1 of the License, or any later
22  * version.
23  *
24  * This library is distributed in the hope that it will be useful, but WITHOUT
25  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
26  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General public final License
27  * for more details.
28  *
29  * You should have received a copy of the GNU Lesser General public final License
30  * along with this library; if not, write to the Free Software Foundation,
31  * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
32  *
33  * Initial developer(s): Emmanuel Cecchet.
34  * Contributor(s): Mathieu Peltier, Nicolas Modrzyk.
35  */

36
37 package org.continuent.sequoia.controller.core;
38
39 import java.io.BufferedOutputStream JavaDoc;
40 import java.io.BufferedReader JavaDoc;
41 import java.io.BufferedWriter JavaDoc;
42 import java.io.DataOutputStream JavaDoc;
43 import java.io.File JavaDoc;
44 import java.io.FileNotFoundException JavaDoc;
45 import java.io.FileOutputStream JavaDoc;
46 import java.io.FileReader JavaDoc;
47 import java.io.FileWriter JavaDoc;
48 import java.io.IOException JavaDoc;
49 import java.io.InputStream JavaDoc;
50 import java.net.URL JavaDoc;
51 import java.net.URLDecoder JavaDoc;
52 import java.text.SimpleDateFormat JavaDoc;
53 import java.util.ArrayList JavaDoc;
54 import java.util.Date JavaDoc;
55 import java.util.Enumeration JavaDoc;
56 import java.util.Hashtable JavaDoc;
57 import java.util.Iterator JavaDoc;
58 import java.util.List JavaDoc;
59 import java.util.zip.ZipEntry JavaDoc;
60 import java.util.zip.ZipFile JavaDoc;
61
62 import javax.management.MalformedObjectNameException JavaDoc;
63 import javax.management.Notification JavaDoc;
64 import javax.management.NotificationBroadcasterSupport JavaDoc;
65
66 import org.continuent.sequoia.common.exceptions.ControllerException;
67 import org.continuent.sequoia.common.exceptions.VirtualDatabaseException;
68 import org.continuent.sequoia.common.i18n.Translate;
69 import org.continuent.sequoia.common.jmx.JmxConstants;
70 import org.continuent.sequoia.common.jmx.notifications.SequoiaNotificationList;
71 import org.continuent.sequoia.common.log.LogManager;
72 import org.continuent.sequoia.common.log.Trace;
73 import org.continuent.sequoia.common.net.SSLConfiguration;
74 import org.continuent.sequoia.common.util.Constants;
75 import org.continuent.sequoia.common.xml.ControllerXmlTags;
76 import org.continuent.sequoia.common.xml.XmlComponent;
77 import org.continuent.sequoia.common.xml.XmlTools;
78 import org.continuent.sequoia.controller.core.shutdown.ControllerShutdownThread;
79 import org.continuent.sequoia.controller.jmx.RmiConnector;
80 import org.continuent.sequoia.controller.virtualdatabase.VirtualDatabase;
81 import org.continuent.sequoia.controller.xml.DatabasesParser;
82
83 /**
84  * The Sequoia controller main class. It loads its configuration file and wait
85  * for virtual database to be loaded.
86  *
87  * @author <a HREF="mailto:Emmanuel.Cecchet@inria.fr">Emmanuel Cecchet </a>
88  * @author <a HREF="mailto:Mathieu.Peltier@inrialpes.fr">Mathieu Peltier </a>
89  * @author <a HREF="mailto:Nicolas.Modrzyk@inrialpes.fr">Nicolas Modrzyk </a>
90  * @author <a HREF="mailto:duncan@mightybot.com">Duncan Smith </a>
91  * @version 1.0
92  */

93 public final class Controller implements XmlComponent
94 {
95   /**
96    * The IP address to bind the controller to. Useful for machines that contain
97    * multiple network interface cards and wish to bind to a specific card.
98    * Default evaluates to localhost IP address (127.0.0.1).
99    */

100   private String JavaDoc jdbcIpAddress;
101   /** Sequoia controller port number listening for driver connections */
102   private int jdbcPortNumber;
103   private int backlogSize;
104   private String JavaDoc name;
105   private boolean allowAdditionalDriver;
106
107   private RmiConnector rmiConnector;
108   private SSLConfiguration sslConfiguration = null;
109
110   /** Thread that listens for driver connections */
111   private ControllerServerThread connectionThread;
112
113   /** Logger instances. */
114   static Trace logger = Trace
115                                                                     .getLogger("org.continuent.sequoia.controller.core.Controller");
116   static Trace endUserLogger = Trace
117                                                                     .getLogger("org.continuent.sequoia.enduser");
118
119   /** Hashtable of <code>VirtualDatabase</code> objects. */
120   private Hashtable JavaDoc virtualDatabases;
121
122   /** Hashtable of options */
123   private Hashtable JavaDoc configuration;
124
125   /** Report Manager */
126   private ReportManager report;
127
128   private boolean isShuttingDown;
129
130   protected NotificationBroadcasterSupport JavaDoc notificationBroadcasterSupport;
131
132   protected int notificationSequence = 0;
133
134   /* Constructor(s) */
135
136   /**
137    * Creates a new <code>Controller</code> instance.
138    *
139    * @param name optional controller name (null if none)
140    * @param ipAddress bind the controller to this ip address
141    * @param port bind the controller to listen to this port
142    * @param backlog backlog connection size
143    * @param allowAdditionalDriver true if drivers can be uploaded on this
144    * controller
145    */

146   public Controller(String JavaDoc name, String JavaDoc ipAddress, int port, int backlog,
147       boolean allowAdditionalDriver)
148   {
149     virtualDatabases = new Hashtable JavaDoc();
150     setControllerName(name);
151     this.jdbcIpAddress = ipAddress;
152     this.jdbcPortNumber = port;
153     this.backlogSize = backlog;
154     this.allowAdditionalDriver = allowAdditionalDriver;
155   }
156
157   /**
158    * Sets the NotificationBroadcasterSupport associated with the MBean managing
159    * this controller.
160    *
161    * @param notificationBroadcasterSupport the notificationBroadcasterSupport
162    * associated with the mbean managing this controller
163    */

164   public void setNotificationBroadcasterSupport(
165       NotificationBroadcasterSupport JavaDoc notificationBroadcasterSupport)
166   {
167     this.notificationBroadcasterSupport = notificationBroadcasterSupport;
168   }
169
170   /**
171    * Sends a JMX Notification on behalf of the MBean associated with this
172    * controller
173    *
174    * @param type type of the JMX notification
175    * @param message message associated with the notification
176    * @see SequoiaNotificationList
177    */

178   protected void sendJmxNotification(String JavaDoc type, String JavaDoc message)
179   {
180     try
181     {
182       notificationBroadcasterSupport.sendNotification(new Notification JavaDoc(type,
183           JmxConstants.getControllerObjectName(), notificationSequence++,
184           message));
185     }
186     catch (MalformedObjectNameException JavaDoc e)
187     {
188       // unable to get a correct controller object name: do nothing
189
logger.warn("Unable to send JMX notification", e);
190     }
191   }
192
193   //
194
// Virtual databases management
195
//
196

197   /**
198    * Adds virtual databases contained in the XML document given as a String. If
199    * a virtual database name is provided, only this database is loaded with the
200    * provided autoLoad and checkpoint information.
201    *
202    * @param xml XML configuration file content
203    * @param vdbName optional virtual database name to autoload
204    * @param autoEnable autoenable backend mode for virtual database
205    * @throws ControllerException if an error occurs
206    */

207   public void addVirtualDatabases(String JavaDoc xml, String JavaDoc vdbName, int autoEnable)
208       throws ControllerException
209   {
210     if (logger.isDebugEnabled())
211       logger.debug(Translate.get("controller.add.virtualdatabase", vdbName));
212     if (vdbName != null && this.hasVirtualDatabase(vdbName))
213     {
214       throw new ControllerException(Translate.get(
215           "controller.add.virtualdatabase.already.used", vdbName));
216     }
217     try
218     {
219       DatabasesParser parser = new DatabasesParser(this, vdbName, autoEnable);
220       parser.readXML(xml, true);
221     }
222     catch (Exception JavaDoc e)
223     {
224       String JavaDoc msg = Translate.get("controller.add.virtualdatabases.failed", e
225           .getMessage());
226       logger.warn(msg, e);
227       throw new ControllerException(msg);
228     }
229   }
230
231   /**
232    * Register a VirtualDatabase with default options
233    *
234    * @see org.continuent.sequoia.common.jmx.mbeans.ControllerMBean#addVirtualDatabases(String)
235    */

236   public void addVirtualDatabases(String JavaDoc xml) throws ControllerException
237   {
238     if (logger.isDebugEnabled())
239     {
240       logger.debug(Translate.get("controller.loading.virtualdatabase"));
241     }
242     this.addVirtualDatabases(xml, null, ControllerConstants.AUTO_ENABLE_FALSE);
243   }
244
245   /**
246    * Registers a new <code>VirtualDatabase</code> in this controller.
247    *
248    * @param vdb the <code>VirtualDatabase</code> to register
249    * @throws ControllerException if an error occurs
250    */

251   public void addVirtualDatabase(VirtualDatabase vdb)
252       throws ControllerException
253   {
254     this.addVirtualDatabase(vdb, ControllerConstants.AUTO_ENABLE_FALSE);
255   }
256
257   /**
258    * Add the virtual database with the specified options
259    *
260    * @param vdb the <code>VirtualDatabase</code> object to add
261    * @param autoLoad specified if backends should be enabled
262    * @throws ControllerException if database already exists on the specified
263    * <code>Controller</code> object
264    */

265   public synchronized void addVirtualDatabase(VirtualDatabase vdb, int autoLoad)
266       throws ControllerException
267   {
268     // Add the database or retrieve it if it already exists
269
if (hasVirtualDatabase(vdb.getDatabaseName()))
270     {
271       String JavaDoc msg = Translate.get("controller.add.virtualdatabase.already.used",
272           vdb.getDatabaseName());
273       logger.warn(msg);
274       throw new ControllerException(msg);
275     }
276     else
277     {
278       virtualDatabases.put(vdb.getDatabaseName(), vdb);
279     }
280
281     // Enable backends with the proper states
282
try
283     {
284       if (logger.isDebugEnabled())
285         logger.debug(Translate.get("controller.database.autoenable", autoLoad));
286
287       switch (autoLoad)
288       {
289         case ControllerConstants.AUTO_ENABLE_TRUE :
290           vdb.enableAllBackendsFromCheckpoint();
291           break;
292         case ControllerConstants.AUTO_ENABLE_FALSE :
293           break;
294         default :
295           logger
296               .error("Unsupported autoEnabledBackends mode in controller configuration");
297           break;
298       }
299     }
300     catch (VirtualDatabaseException e)
301     {
302       logger
303           .warn("Failed to automatically enable backends, manual resynchronization is probably needed");
304     }
305
306     logger.info(Translate.get("controller.add.virtualdatabase", vdb
307         .getDatabaseName()));
308     endUserLogger.info(Translate.get("controller.add.virtualdatabase.success",
309         vdb.getDatabaseName()));
310     sendJmxNotification(
311         SequoiaNotificationList.CONTROLLER_VIRTUALDATABASE_ADDED, Translate
312             .get("notification.virtualdatabase.added", vdb.getDatabaseName()));
313   }
314
315   /**
316    * Gets the <code>VirtualDatabase</code> object corresponding to a virtual
317    * database name.
318    *
319    * @param virtualDatabaseName the virtual database name
320    * @return a <code>VirtualDatabase</code> object or null if not found
321    */

322   public VirtualDatabase getVirtualDatabase(String JavaDoc virtualDatabaseName)
323   {
324     return (VirtualDatabase) virtualDatabases.get(virtualDatabaseName);
325   }
326
327   /**
328    * @see org.continuent.sequoia.common.jmx.mbeans.ControllerMBean#getVirtualDatabaseNames()
329    */

330   public ArrayList JavaDoc getVirtualDatabaseNames()
331   {
332     ArrayList JavaDoc result = new ArrayList JavaDoc();
333     for (Iterator JavaDoc iter = virtualDatabases.values().iterator(); iter.hasNext();)
334       result.add(((VirtualDatabase) iter.next()).getVirtualDatabaseName());
335     return result;
336   }
337
338   /**
339    * Returns information about the available virtual databases.
340    *
341    * @return ArrayList of information about virtual databases.
342    */

343   public ArrayList JavaDoc getVirtualDatabases()
344   {
345     return new ArrayList JavaDoc(virtualDatabases.values());
346   }
347
348   /**
349    * Tests if a <code>VirtualDatabase</code> of a given name exists in this
350    * controller.
351    *
352    * @param name the virtual database name
353    * @return <code>true</code> if the virtual database exists
354    */

355   public boolean hasVirtualDatabase(String JavaDoc name)
356   {
357     return virtualDatabases.containsKey(name);
358   }
359
360   /**
361    * Removes the virtual database with the given name (if any)
362    *
363    * @param virtualname name of the virtual database
364    * @return a translated string for success message
365    */

366   public String JavaDoc removeVirtualDatabase(String JavaDoc virtualname)
367   {
368     if (hasVirtualDatabase(virtualname))
369     {
370       if (this.virtualDatabases.remove(virtualname) == null)
371       {
372         logger.warn("Unexpected missing virtual database named " + virtualname
373             + " while removing from virtual database list");
374       }
375
376       // Send notification
377
sendJmxNotification(
378           SequoiaNotificationList.CONTROLLER_VIRTUALDATABASE_REMOVED, Translate
379               .get("notification.virtualdatabase.shutdown", virtualname));
380     }
381     return Translate.get("controller.removeVirtualDatabase.success",
382         virtualname);
383   }
384
385   //
386
// Controller operations
387
//
388

389   /**
390    * @see org.continuent.sequoia.common.jmx.mbeans.ControllerMBean#addDriver(byte[])
391    */

392   public void addDriver(byte[] bytes) throws Exception JavaDoc
393   {
394     // Try to find drivers directory in the classpath
395
File JavaDoc driversDirectory = null;
396     URL JavaDoc url = Controller.class
397         .getResource(ControllerConstants.SEQUOIA_DRIVER_JAR_FILE);
398     boolean error = false;
399     if (url != null)
400     {
401       driversDirectory = (new File JavaDoc(URLDecoder.decode(url.getFile())))
402           .getParentFile();
403       error = (driversDirectory == null) || !driversDirectory.exists();
404     }
405
406     if (error)
407     {
408       String JavaDoc msg = Translate.get("controller.driver.dir.not.found",
409           driversDirectory.toString());
410       logger.error(msg);
411       endUserLogger.error(Translate.get("controller.add.driver.failed", msg));
412       throw new ControllerException(msg);
413     }
414
415     // Read the array of bytes to a file
416
File JavaDoc temp = null;
417     try
418     {
419       temp = File.createTempFile("driver", "zip", driversDirectory);
420       FileOutputStream JavaDoc output = new FileOutputStream JavaDoc(temp);
421       output.write(bytes);
422       output.close();
423     }
424     catch (IOException JavaDoc e)
425     {
426       String JavaDoc msg = Translate.get("controller.add.jar.write.failed", e);
427       logger.error(msg);
428       endUserLogger.error(Translate.get("controller.add.driver.failed", msg));
429       throw new ControllerException(msg);
430     }
431
432     // Unzip the file content
433
try
434     {
435       Enumeration JavaDoc entries;
436       ZipFile JavaDoc zipFile = new ZipFile JavaDoc(temp);
437
438       // Read the file
439
int lenght;
440       InputStream JavaDoc in;
441       BufferedOutputStream JavaDoc out;
442       byte[] buffer = new byte[1024];
443
444       entries = zipFile.entries();
445       while (entries.hasMoreElements())
446       {
447         ZipEntry JavaDoc entry = (ZipEntry JavaDoc) entries.nextElement();
448
449         if (entry.isDirectory())
450         {
451           // Create the directory
452
if (logger.isDebugEnabled())
453             logger.debug(Translate.get("controller.add.jar.extract.dir", entry
454                 .getName()));
455
456           (new File JavaDoc(driversDirectory, entry.getName())).mkdir();
457           continue;
458         }
459
460         // Extract the file
461
if (logger.isDebugEnabled())
462           logger.debug(Translate.get("controller.add.jar.extract.file", entry
463               .getName()));
464
465         in = zipFile.getInputStream(entry);
466         out = new BufferedOutputStream JavaDoc(new FileOutputStream JavaDoc(driversDirectory
467             + System.getProperty("file.separator") + entry.getName()));
468         while ((lenght = in.read(buffer)) >= 0)
469           out.write(buffer, 0, lenght);
470
471         in.close();
472         out.close();
473       }
474
475       zipFile.close();
476       temp.delete();
477       String JavaDoc msg = Translate.get("controller.add.driver.success",
478           driversDirectory.toString());
479       logger.info(msg);
480       endUserLogger.info(msg);
481     }
482     catch (IOException JavaDoc e)
483     {
484       String JavaDoc msg = Translate.get("controller.driver.extract.failed",
485           new String JavaDoc[]{temp.getCanonicalPath(), e.getMessage()});
486       logger.error(msg);
487       endUserLogger.error(Translate.get("controller.add.driver.failed", msg));
488       throw new ControllerException(msg);
489     }
490   }
491
492   /**
493    * Create report about fatal error
494    *
495    * @param fatal the cause of the fatal error
496    */

497   public void endOfController(Exception JavaDoc fatal)
498   {
499     logger.fatal(Translate.get("fatal.error"));
500     if (report.isGenerateOnFatal())
501     {
502       new ReportManager(this).generateAndWriteException(true, fatal);
503       logger.info(Translate.get("fatal.report.generated", report
504           .getReportLocation()
505           + File.separator + ControllerConstants.REPORT_FILE));
506     }
507     Runtime.getRuntime().exit(1);
508   }
509
510   /**
511    * Read a XML configuration file and load only the
512    * <code>VirtualDatabase</code> specified in the arguments list
513    *
514    * @param filename XML configuration file name to take info on
515    * <code>VirtualDatabase</code>
516    * @param virtualName the only database to load, null if should load all
517    * @param autoLoad specifies if the backends should be enabled automatically
518    * after loading
519    * @return a diagnostic message (success or error)
520    * @throws Exception if an error occurs
521    */

522   public String JavaDoc loadXmlConfiguration(String JavaDoc filename, String JavaDoc virtualName,
523       int autoLoad) throws Exception JavaDoc
524   {
525     FileReader JavaDoc fileReader = null;
526     try
527     {
528       filename = filename.trim();
529       try
530       {
531         fileReader = new FileReader JavaDoc(filename);
532       }
533       catch (FileNotFoundException JavaDoc fnf)
534       {
535         return Translate.get("controller.file.not.found", filename);
536       }
537
538       if (logger.isDebugEnabled())
539         logger.debug("Loading virtual database configuration " + filename);
540       // Read the file
541
BufferedReader JavaDoc in = new BufferedReader JavaDoc(fileReader);
542       StringBuffer JavaDoc xml = new StringBuffer JavaDoc();
543       String JavaDoc line;
544       do
545       {
546         line = in.readLine();
547         if (line != null)
548           xml.append(line);
549       }
550       while (line != null);
551
552       // Send it to the controller
553
addVirtualDatabases(xml.toString(), virtualName, autoLoad);
554       return Translate.get("controller.file.send", filename);
555     }
556     catch (Exception JavaDoc e)
557     {
558       logger.error(Translate.get("controller.loadXml.failed",
559           ControllerConstants.PRODUCT_NAME, e), e);
560       throw new ControllerException(Translate.get("controller.loadXml.failed",
561           ControllerConstants.PRODUCT_NAME, e));
562     }
563     finally
564     {
565       if (fileReader != null)
566         fileReader.close();
567     }
568   }
569
570   //
571
// Logging system
572
//
573

574   /**
575    * @see org.continuent.sequoia.common.jmx.mbeans.ControllerMBean#refreshLogConfiguration()
576    */

577   public void refreshLogConfiguration() throws ControllerException
578   {
579     try
580     {
581       LogManager.configure(URLDecoder.decode(this.getClass().getResource(
582           ControllerConstants.LOG4J_RESOURCE).getFile()));
583       if (logger.isDebugEnabled())
584         logger.info(Translate.get("controller.refresh.log.success"));
585     }
586     catch (Exception JavaDoc e)
587     {
588       throw new ControllerException(Translate
589           .get("controller.logconfigfile.not.found"));
590     }
591   }
592
593   /**
594    * Save current configuration of the controller to a default file
595    *
596    * @return Status message
597    * @see org.continuent.sequoia.controller.core.ControllerConstants#getSaveFile
598    */

599   public String JavaDoc saveConfiguration()
600   {
601     String JavaDoc msg = Translate.get("controller.save.configuration.failed");
602     try
603     {
604       String JavaDoc configurationFile = ControllerConstants
605           .getSaveFile(new SimpleDateFormat JavaDoc("yyyy-MM-dd-HH-mm")
606               .format(new Date JavaDoc()));
607       DataOutputStream JavaDoc dos = new DataOutputStream JavaDoc(new BufferedOutputStream JavaDoc(
608           new FileOutputStream JavaDoc(configurationFile)));
609       StringBuffer JavaDoc xml = new StringBuffer JavaDoc();
610       xml.append(XmlTools.prettyXml(getXmlVirtualDatabases()));
611       String JavaDoc prettyXml = xml.toString();
612       // ugly hack to insert the doctype which has been stripped
613
// when prettyfying the xml
614
prettyXml = XmlTools.insertDoctype(prettyXml,
615           ControllerConstants.VIRTUAL_DATABASE_DOCTYPE);
616       dos.write(prettyXml.getBytes());
617       dos.close();
618       msg = Translate.get("controller.save.configuration", configurationFile);
619     }
620     catch (Exception JavaDoc e)
621     {
622       msg = Translate.get("controller.save.configuration.failed", e);
623       logger.error(msg);
624     }
625     return msg;
626   }
627
628   /**
629    * @see org.continuent.sequoia.common.jmx.mbeans.ControllerMBean#updateLogConfigurationFile(java.lang.String)
630    */

631   public void updateLogConfigurationFile(String JavaDoc newConfiguration)
632       throws IOException JavaDoc, ControllerException
633   {
634     File JavaDoc logFile = new File JavaDoc(URLDecoder.decode(getClass().getResource(
635         ControllerConstants.LOG4J_RESOURCE).getFile()));
636     BufferedWriter JavaDoc writer = new BufferedWriter JavaDoc(new FileWriter JavaDoc(logFile));
637     writer.write(newConfiguration);
638     writer.flush();
639     writer.close();
640     refreshLogConfiguration();
641   }
642
643   //
644
// Logging system
645
//
646

647   /**
648    * @see org.continuent.sequoia.common.jmx.mbeans.ControllerMBean#viewLogConfigurationFile()
649    */

650   public String JavaDoc viewLogConfigurationFile() throws IOException JavaDoc
651   {
652     File JavaDoc logFile = new File JavaDoc(URLDecoder.decode(getClass().getResource(
653         ControllerConstants.LOG4J_RESOURCE).getFile()));
654     BufferedReader JavaDoc reader = new BufferedReader JavaDoc(new FileReader JavaDoc(logFile));
655     StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
656     String JavaDoc line;
657     while ((line = reader.readLine()) != null)
658       buffer.append(line + System.getProperty("line.separator"));
659     reader.close();
660     return buffer.toString();
661   }
662
663   //
664
// Controller shutdown
665
//
666

667   /**
668    * @see org.continuent.sequoia.common.jmx.mbeans.ControllerMBean#isShuttingDown()
669    */

670   public boolean isShuttingDown()
671   {
672     return isShuttingDown;
673   }
674
675   /**
676    * @see org.continuent.sequoia.common.jmx.mbeans.ControllerMBean#shutdown()
677    */

678   public void shutdown() throws ControllerException
679   {
680     if (virtualDatabases.size() != 0)
681     {
682       throw new ControllerException(Translate.get(
683           "controller.shutdown.error.existing.virtualdatabases",
684           getControllerName()));
685     }
686
687     ControllerShutdownThread shutdownThread = null;
688     synchronized (this)
689     {
690       if (isShuttingDown())
691       {
692         logger.info(Translate.get("controller.already.shutting.down", this
693             .getControllerName()));
694         return;
695       }
696
697       isShuttingDown = true;
698       shutdownThread = new ControllerShutdownThread(this);
699       logger.info(Translate
700           .get("controller.shutdown", this.getControllerName()));
701     }
702
703     Thread JavaDoc thread = new Thread JavaDoc(shutdownThread.getShutdownGroup(),
704         shutdownThread, "Controller Shutdown Thread");
705     thread.start();
706
707     try
708     {
709       logger.info("Waiting for controller shutdown");
710       thread.join();
711       logger.info(Translate.get("controller.shutdown.completed", this
712           .getControllerName()));
713     }
714     catch (InterruptedException JavaDoc e)
715     {
716       e.printStackTrace();
717     }
718   }
719
720   /**
721    * Launches the Sequoia controller. Command line options are defined in
722    * {@link ControllerConfiguration}.
723    * <p>
724    * The controller starts listening for socket connections on the default port.
725    * Jmx is configured, and a virtual database can be added.
726    * <p>
727    * {@link org.continuent.sequoia.controller.core.ControllerConstants#DEFAULT_PORT}
728    * Default Listening port
729    *
730    * @param args command line arguments (see above)
731    * @throws Exception when everything goes wrong
732    */

733   public static void main(String JavaDoc[] args) throws Exception JavaDoc
734   {
735     System.setProperty("javax.management.builder.initial",
736         org.continuent.sequoia.controller.jmx.MBeanServerBuilder.class
737             .getName());
738
739     if (ControllerConstants.CONTROLLER_FACTORY == null)
740     {
741       System.err
742           .println("Impossible to start Controller with an invalid controller.properties file.");
743       System.exit(1);
744     }
745
746     // This parses command line arguments and exits for
747
// --help and --version
748
ControllerConfiguration conf = new ControllerConfiguration(args);
749
750     logger.info(getVersion());
751
752     Controller controller = conf.getController();
753     if (controller != null)
754       controller.launch();
755     else
756     {
757       endUserLogger.error(Translate.get("controller.configure.failed"));
758       throw new Exception JavaDoc(Translate.get("controller.configure.failed"));
759     }
760   }
761
762   /**
763    * Actively launch the <code>controller</code>. Add startup actions here to
764    * avoid them in <method>main </method>
765    */

766   public void launch()
767   {
768     connectionThread = new ControllerServerThread(this);
769     connectionThread.start();
770
771     SimpleDateFormat JavaDoc formatter = new SimpleDateFormat JavaDoc(
772         "yyyy.MM.dd ww 'at' hh:mm:ss a zzz");
773     Date JavaDoc day = new Date JavaDoc();
774     String JavaDoc date = formatter.format(day);
775     logger.info(Translate.get("controller.date", date));
776     logger.info(Translate.get("controller.ready", getControllerName()));
777     endUserLogger.info(Translate.get("controller.ready", getControllerName()));
778   }
779
780   //
781
// Controller information
782
//
783

784   /**
785    * Returns true if the controller allow driver to be uploaded.
786    *
787    * @return true if driver can be uploaded on this controller
788    */

789   public boolean allowAdditionalDriver()
790   {
791     return allowAdditionalDriver;
792   }
793
794   /**
795    * @see org.continuent.sequoia.common.jmx.mbeans.ControllerMBean#getBacklogSize()
796    */

797   public int getBacklogSize()
798   {
799     return backlogSize;
800   }
801
802   /**
803    * @see org.continuent.sequoia.common.jmx.mbeans.ControllerMBean#setBacklogSize(int)
804    */

805   public void setBacklogSize(int size)
806   {
807     backlogSize = size;
808   }
809
810   /**
811    * Get current configuration options
812    *
813    * @return configure a <code>Hashtable</code> with controller options
814    */

815   public Hashtable JavaDoc getConfiguration()
816   {
817     return configuration;
818   }
819
820   /**
821    * Sets the configuration value.configureController
822    *
823    * @param configuration The configuration to set.
824    */

825   public void setConfiguration(Hashtable JavaDoc configuration)
826   {
827     this.configuration = configuration;
828   }
829
830   /**
831    * Access the connection thread. Need this for shutting down
832    *
833    * @return <code>connectionThread</code>
834    */

835   public ControllerServerThread getConnectionThread()
836   {
837     return connectionThread;
838   }
839
840   /**
841    * Returns the controller name
842    *
843    * @return String the controller name
844    */

845   public String JavaDoc getControllerName()
846   {
847     return name;
848   }
849
850   /**
851    * Sets the controller name (IP:port if name is null).
852    *
853    * @return String the controller name
854    */

855   public void setControllerName(String JavaDoc name)
856   {
857     if (name == null)
858       name = jdbcIpAddress + ":" + jdbcPortNumber;
859     this.name = name;
860   }
861
862   /**
863    * Get the IP address to bind the controller to
864    *
865    * @return the IP address
866    */

867   public String JavaDoc getIPAddress()
868   {
869     return jdbcIpAddress;
870   }
871
872   /**
873    * Set the IP address to bind the controller to
874    *
875    * @param ipAddress the IP address to use
876    */

877   public void setIPAddress(String JavaDoc ipAddress)
878   {
879     this.jdbcIpAddress = ipAddress;
880   }
881
882   /**
883    * Get the controller JDBC port number
884    *
885    * @return the JDBC port number
886    */

887   public int getJdbcPortNumber()
888   {
889     return jdbcPortNumber;
890   }
891
892   /**
893    * Set the controller backlog size.
894    *
895    * @param port the port number to set
896    */

897   public void setJdbcPortNumber(int port)
898   {
899     jdbcPortNumber = port;
900   }
901
902   /**
903    * Return the jmx name of this controller (hostname:rmiport)
904    *
905    * @return jmx name
906    */

907   public String JavaDoc getJmxName()
908   {
909     if (rmiConnector != null)
910       return rmiConnector.getHostName() + ":" + rmiConnector.getPort();
911     else
912       return getControllerName();
913   }
914
915   /**
916    * Returns the report value.
917    *
918    * @return Returns the report.
919    */

920   public ReportManager getReport()
921   {
922     return report;
923   }
924
925   /**
926    * Sets the report value.
927    *
928    * @param report The report to set.
929    */

930   public void setReport(ReportManager report)
931   {
932     this.report = report;
933   }
934
935   /**
936    * Returns the rmiConnector value.
937    *
938    * @return Returns the rmiConnector.
939    */

940   public RmiConnector getRmiConnector()
941   {
942     return rmiConnector;
943   }
944
945   /**
946    * Sets the rmiConnector value.
947    *
948    * @param rmiConnector The rmiConnector to set.
949    */

950   public void setRmiConnector(RmiConnector rmiConnector)
951   {
952     this.rmiConnector = rmiConnector;
953   }
954
955   /**
956    * Returns the sslConfiguration value.
957    *
958    * @return Returns the sslConfiguration.
959    */

960   public SSLConfiguration getSslConfiguration()
961   {
962     return sslConfiguration;
963   }
964
965   /**
966    * Sets the sslConfiguration value.
967    *
968    * @param sslConfiguration The sslConfiguration to set.
969    */

970   public void setSslConfiguration(SSLConfiguration sslConfiguration)
971   {
972     this.sslConfiguration = sslConfiguration;
973   }
974
975   /**
976    * Returns Version as a long String
977    *
978    * @return version
979    */

980   public static String JavaDoc getVersion()
981   {
982     return Translate.get("controller.info", ControllerConstants.PRODUCT_NAME,
983         Constants.VERSION);
984   }
985
986   /**
987    * @see org.continuent.sequoia.common.jmx.mbeans.ControllerMBean#getVersionNumber()
988    */

989   public String JavaDoc getVersionNumber()
990   {
991     return Constants.VERSION;
992   }
993
994   /**
995    * @see org.continuent.sequoia.common.xml.XmlComponent#getXml()
996    */

997   public String JavaDoc getXml()
998   {
999     try
1000    {
1001      String JavaDoc prettyXml = XmlTools.prettyXml(getXmlController());
1002      return XmlTools.insertDoctype(prettyXml,
1003          ControllerConstants.CONTROLLER_DOCTYPE);
1004    }
1005    catch (Exception JavaDoc e)
1006    {
1007      logger.error(Translate.get("controller.xml.transformation.failed", e));
1008      return e.getMessage();
1009    }
1010  }
1011
1012  /**
1013   * Return the xml version of the controller.xml file without doc type
1014   * declaration, just data.
1015   *
1016   * @return controller xml data
1017   */

1018  public String JavaDoc getXmlController()
1019  {
1020    StringBuffer JavaDoc info = new StringBuffer JavaDoc();
1021    info.append("<" + ControllerConstants.CONTROLLER_XML_ROOT_ELEMENT + ">");
1022    info.append("<" + ControllerXmlTags.ELT_CONTROLLER + " "
1023        + ControllerXmlTags.ATT_CONTROLLER_NAME + "=\"" + getControllerName()
1024        + "\" " + ControllerXmlTags.ATT_CONTROLLER_IP + "=\"" + getIPAddress()
1025        + "\" " + ControllerXmlTags.ATT_CONTROLLER_PORT + "=\""
1026        + getJdbcPortNumber() + "\" "
1027        + ControllerXmlTags.ATT_ALLOW_ADDITIONAL_DRIVER + "=\""
1028        + allowAdditionalDriver() + "\">");
1029
1030    // JMX config
1031
info.append("<" + ControllerXmlTags.ELT_JMX + " "
1032        + ControllerXmlTags.ATT_JMX_ADAPTOR_IP + "=\""
1033        + rmiConnector.getHostName() + "\" "
1034        + ControllerXmlTags.ATT_JMX_ADAPTOR_PORT + "=\""
1035        + rmiConnector.getPort() + "\" ");
1036    if (configuration.containsKey(ControllerXmlTags.ATT_JMX_CONNECTOR_USERNAME))
1037    {
1038      info.append(ControllerXmlTags.ATT_JMX_CONNECTOR_USERNAME + "=\""
1039          + configuration.get(ControllerXmlTags.ATT_JMX_CONNECTOR_USERNAME)
1040          + "\" " + ControllerXmlTags.ATT_JMX_CONNECTOR_PASSWORD + "=\""
1041          + configuration.get(ControllerXmlTags.ATT_JMX_CONNECTOR_PASSWORD)
1042          + "\" ");
1043    }
1044    info.append(">");
1045    if (rmiConnector.getSslConfig() != null) // RMI-SSL config if any
1046
info.append(rmiConnector.getSslConfig().getXml());
1047    info.append("</" + ControllerXmlTags.ELT_JMX + ">");
1048
1049    // Controller SSL config
1050
if (sslConfiguration != null)
1051    {
1052      info.append(sslConfiguration.getXml());
1053    }
1054
1055    // Report
1056
if (report.isReportEnabled())
1057    {
1058      info.append("<" + ControllerXmlTags.ELT_REPORT + " "
1059          + ControllerXmlTags.ATT_REPORT_ENABLE_FILE_LOGGING + "=\""
1060          + report.isEnableFileLogging() + "\" "
1061          + ControllerXmlTags.ATT_REPORT_HIDE_SENSITIVE_DATA + "=\""
1062          + report.isHideSensitiveData() + "\" "
1063          + ControllerXmlTags.ATT_REPORT_GENERATE_ON_FATAL + "=\""
1064          + report.isGenerateOnFatal() + "\" "
1065          + ControllerXmlTags.ATT_REPORT_GENERATE_ON_SHUTDOWN + "=\""
1066          + report.isGenerateOnShutdown() + "\" "
1067          + ControllerXmlTags.ATT_REPORT_REPORT_LOCATION + "=\""
1068          + report.getReportLocation() + "\" />");
1069    }
1070
1071    info.append("</" + ControllerXmlTags.ELT_CONTROLLER + ">");
1072    info.append("</" + ControllerConstants.CONTROLLER_XML_ROOT_ELEMENT + ">");
1073    return info.toString();
1074  }
1075
1076  /**
1077   * Same as above but for the virtual databases.
1078   *
1079   * @return xml virtual databases data.
1080   */

1081  public String JavaDoc getXmlVirtualDatabases()
1082  {
1083    try
1084    {
1085      StringBuffer JavaDoc info = new StringBuffer JavaDoc();
1086      info.append(XmlComponent.XML_VERSION);
1087      info.append("\n");
1088      info.append("<" + ControllerConstants.VIRTUAL_DATABASE_XML_ROOT_ELEMENT
1089          + ">");
1090      List JavaDoc vdbs = this.getVirtualDatabases();
1091      for (int i = 0; i < vdbs.size(); i++)
1092      {
1093        info.append(((XmlComponent) vdbs.get(i)).getXml());
1094      }
1095      info.append("</" + ControllerConstants.VIRTUAL_DATABASE_XML_ROOT_ELEMENT
1096          + ">");
1097      return info.toString();
1098    }
1099    catch (Exception JavaDoc e)
1100    {
1101      logger.error(e.getMessage(), e);
1102      return e.getMessage();
1103    }
1104  }
1105
1106}
Popular Tags