KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > jdbc > HypersonicDatabase


1 /*
2  * JBoss, Home of Professional Open Source
3  * Copyright 2005, JBoss Inc., and individual contributors as indicated
4  * by the @authors tag. See the copyright.txt in the distribution for a
5  * full listing of individual contributors.
6  *
7  * This is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU Lesser General Public License as
9  * published by the Free Software Foundation; either version 2.1 of
10  * the License, or (at your option) any later version.
11  *
12  * This software is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this software; if not, write to the Free
19  * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20  * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21  */

22 package org.jboss.jdbc;
23
24 import java.awt.HeadlessException JavaDoc;
25 import java.io.File JavaDoc;
26 import java.io.IOException JavaDoc;
27 import java.lang.reflect.Method JavaDoc;
28 import java.sql.Connection JavaDoc;
29 import java.sql.DriverManager JavaDoc;
30 import java.sql.Statement JavaDoc;
31
32 import org.jboss.system.ServiceMBeanSupport;
33 import org.jboss.system.server.ServerConfigLocator;
34
35 /**
36  * Integration with <a HREF="http://sourceforge.net/projects/hsqldb">HSQLDB</a>
37  *
38  * @author <a HREF="mailto:rickard.oberg@telkel.com">Rickard Öberg</a>
39  * @author <a HREF="mailto:Scott_Stark@displayscape.com">Scott Stark</a>.
40  * @author <a HREF="mailto:pf@iprobot.com">Peter Fagerlund</a>
41  * @author <a HREF="mailto:jason@planet57.com">Jason Dillon</a>
42  * @author <a HREF="mailto:vesco.claudio@previnet.it">Claudio Vesco</a>
43  * @author <a HREF="mailto:dimitris@jboss.org">Dimitris Andreadis</a>
44  * @version $Revision: 42436 $
45  */

46 public class HypersonicDatabase extends ServiceMBeanSupport
47    implements HypersonicDatabaseMBean
48 {
49    /** Default password: <code>empty string</code>. */
50    private static final String JavaDoc DEFAULT_PASSWORD = "";
51    
52    /** Default user: <code>sa</code>. */
53    private static final String JavaDoc DEFAULT_USER = "sa";
54    
55    /** JDBC Driver class: <code>org.hsqldb.jdbcDriver</code>. */
56    private static final String JavaDoc JDBC_DRIVER_CLASS = "org.hsqldb.jdbcDriver";
57    
58    /** JDBC URL common prefix: <code>jdbc:hsqldb:</code>. */
59    private static final String JavaDoc JDBC_URL_PREFIX = "jdbc:hsqldb:";
60    
61    /** Default shutdown command for remote hypersonic: <code>SHUTDOWN COMPACT</code>. */
62    private static final String JavaDoc DEFAULT_REMOTE_SHUTDOWN_COMMAND = "SHUTDOWN COMPACT";
63    
64    /** Default shutdown command for in process persist hypersonic: <code>SHUTDOWN COMPACT</code>. */
65    private static final String JavaDoc DEFAULT_IN_PROCESS_SHUTDOWN_COMMAND = "SHUTDOWN COMPACT";
66    
67    /** Default shutdown command for in process only memory hypersonic: <code>SHUTDOWN IMMEDIATELY</code>. */
68    private static final String JavaDoc DEFAULT_IN_MEMORY_SHUTDOWN_COMMAND = "SHUTDOWN IMMEDIATELY";
69    
70    /** Default data subdir: <code>hypersonic</code>. */
71    private static final String JavaDoc HYPERSONIC_DATA_DIR = "hypersonic";
72    
73    /** Default port for remote hypersonic: <code>1701</code>. */
74    private static final int DEFAULT_PORT = 1701;
75    
76    /** Default address for remote hypersonic: <code>0.0.0.0</code>. */
77    private static final String JavaDoc DEFAULT_ADDRESS = "0.0.0.0";
78    
79    /** Default database name: <code>default</code>. */
80    private static final String JavaDoc DEFAULT_DATABASE_NAME = "default";
81    
82    /** Database name for memory-only hypersonic: <code>.</code>. */
83    private static final String JavaDoc IN_MEMORY_DATABASE = ".";
84    
85    /** Default database manager (UI) class: <code>org.hsqldb.util.DatabaseManagerSwing</code>. */
86    private static final String JavaDoc DEFAULT_DATABASE_MANAGER_CLASS = "org.hsqldb.util.DatabaseManagerSwing";
87    
88    /** Default server class for remote hypersonic: <code>org.hsqldb.Server</code>. */
89    private static final String JavaDoc DEFAULT_SERVER_CLASS = "org.hsqldb.Server";
90
91    // Private Data --------------------------------------------------
92

93    /** Full path to db/hypersonic. */
94    private File JavaDoc dbPath;
95
96    /** Database name. */
97    private String JavaDoc name = DEFAULT_DATABASE_NAME;
98
99    /** Default port. */
100    private int port = DEFAULT_PORT;
101
102    /** Default address. */
103    private String JavaDoc address = DEFAULT_ADDRESS;
104    
105    /** Default silent. */
106    private boolean silent = true;
107
108    /** Default trace. */
109    private boolean trace = false;
110
111    /** Default no_system_exit, new embedded support in 1.7 */
112    private boolean no_system_exit = true;
113    
114    /** Default persisted DB */
115    private boolean persist = true;
116
117    /** Shutdown command. */
118    private String JavaDoc shutdownCommand;
119    
120    /** In process/remote mode. */
121    private boolean inProcessMode = false;
122    
123    /** Database user. */
124    private String JavaDoc user = DEFAULT_USER;
125    
126    /** Database password. */
127    private String JavaDoc password = DEFAULT_PASSWORD;
128    
129    /** Database manager (UI) class. */
130    private String JavaDoc databaseManagerClass = DEFAULT_DATABASE_MANAGER_CLASS;
131    
132    /** Server class for remote hypersonic. */
133    private String JavaDoc serverClass = DEFAULT_SERVER_CLASS;
134    
135    /** Server thread for remote hypersonic. */
136    private Thread JavaDoc serverThread;
137    
138    /** Hold a connection for in process hypersonic. */
139    private Connection JavaDoc connection;
140
141    private String JavaDoc dbDataDir;
142
143    // Constructors --------------------------------------------------
144

145    /**
146     * Costructor, empty.
147     */

148    public HypersonicDatabase()
149    {
150       // empty
151
}
152
153    // Attributes ----------------------------------------------------
154

155    public String JavaDoc getDbDataDir()
156    {
157       return dbDataDir;
158    }
159
160    public void setDbDataDir(String JavaDoc dbDataDir)
161    {
162       this.dbDataDir = dbDataDir;
163    }
164
165    /**
166     * Set the database name.
167     *
168     * @jmx.managed-attribute
169     */

170    public void setDatabase(String JavaDoc name)
171    {
172       if (name == null)
173       {
174          name = DEFAULT_DATABASE_NAME;
175       }
176       this.name = name;
177    }
178
179    /**
180     * Get the database name.
181     *
182     * @jmx.managed-attribute
183     */

184    public String JavaDoc getDatabase()
185    {
186       return name;
187    }
188
189    /**
190     * Set the port for remote hypersonic.
191     *
192     * @jmx.managed-attribute
193     */

194    public void setPort(final int port)
195    {
196       this.port = port;
197    }
198
199    /**
200     * Get the port for remote hypersonic.
201     *
202     * @jmx.managed-attribute
203     */

204    public int getPort()
205    {
206       return port;
207    }
208
209    /**
210     * Set the bind address for remote hypersonic.
211     *
212     * @jmx.managed-attribute
213     */

214    public void setBindAddress(final String JavaDoc address)
215    {
216       this.address = address;
217    }
218    
219    /**
220     * Get the bind address for remote hypersonic.
221     *
222     * @jmx.managed-attribute
223     */

224    public String JavaDoc getBindAddress()
225    {
226       return address;
227    }
228    
229    /**
230     * Set silent flag.
231     *
232     * @jmx.managed-attribute
233     */

234    public void setSilent(final boolean silent)
235    {
236       this.silent = silent;
237    }
238
239    /**
240     * Get silent flag.
241     *
242     * @jmx.managed-attribute
243     */

244    public boolean getSilent()
245    {
246       return silent;
247    }
248
249    /**
250     * Set trace flag.
251     *
252     * @jmx.managed-attribute
253     */

254    public void setTrace(final boolean trace)
255    {
256       this.trace = trace;
257    }
258
259    /**
260     * Get trace flag.
261     *
262     * @jmx.managed-attribute
263     */

264    public boolean getTrace()
265    {
266       return trace;
267    }
268
269    /**
270     * If <b>true</b> the server thread for remote hypersonic does no call <code>System.exit()</code>.
271     *
272     * @jmx.managed-attribute
273     */

274    public void setNo_system_exit(final boolean no_system_exit)
275    {
276       this.no_system_exit = no_system_exit;
277    }
278
279    /**
280     * Get the <code>no_system_exit</code> flag.
281     *
282     * @jmx.managed-attribute
283     */

284    public boolean getNo_system_exit()
285    {
286       return no_system_exit;
287    }
288
289    /**
290     * Set persist flag.
291     *
292     * @deprecated use {@link #setInProcessMode(boolean)(boolean) inProcessMode}.
293     *
294     * @jmx.managed-attribute
295     */

296    public void setPersist(final boolean persist)
297    {
298       this.persist = persist;
299    }
300
301    /**
302     * Get persist flag.
303     *
304     * @deprecated use {@link #setInProcessMode(boolean)(boolean) inProcessMode}.
305     *
306     * @jmx.managed-attribute
307     */

308    public boolean getPersist()
309    {
310       return persist;
311    }
312
313    /**
314     * Get the full database path.
315     *
316     * @jmx.managed-attribute
317     */

318    public String JavaDoc getDatabasePath()
319    {
320       if (dbPath != null)
321       {
322          return dbPath.toString();
323       }
324       else
325       {
326          return null;
327       }
328    }
329
330    /**
331     * @return the <code>inProcessMode</code> flag.
332     *
333     * @jmx.managed-attribute
334     */

335    public boolean isInProcessMode()
336    {
337       return inProcessMode;
338    }
339
340    /**
341     * @return the shutdown command.
342     *
343     * @jmx.managed-attribute
344     */

345    public String JavaDoc getShutdownCommand()
346    {
347       return shutdownCommand;
348    }
349
350    /**
351     * If <b>true</b> the hypersonic is in process mode otherwise hypersonic is in server or remote mode.
352     *
353     * @param b in process mode or remote mode.
354     *
355     * @jmx.managed-attribute
356     */

357    public void setInProcessMode(boolean b)
358    {
359       inProcessMode = b;
360    }
361
362    /**
363     * @param string the shutdown command
364     *
365     * @jmx.managed-attribute
366     */

367    public void setShutdownCommand(String JavaDoc string)
368    {
369       shutdownCommand = string;
370    }
371
372    /**
373     * @return the password
374     *
375     * @jmx.managed-attribute
376     */

377    public String JavaDoc getPassword()
378    {
379       return password;
380    }
381
382    /**
383     * @return the user
384     *
385     * @jmx.managed-attribute
386     */

387    public String JavaDoc getUser()
388    {
389       return user;
390    }
391
392    /**
393     * @param password
394     *
395     * @jmx.managed-attribute
396     */

397    public void setPassword(String JavaDoc password)
398    {
399       if (password == null)
400       {
401          password = DEFAULT_PASSWORD;
402       }
403       this.password = password;
404    }
405
406    /**
407     * @param user
408     *
409     * @jmx.managed-attribute
410     */

411    public void setUser(String JavaDoc user)
412    {
413       if (user == null)
414       {
415          user = DEFAULT_USER;
416       }
417       this.user = user;
418    }
419
420    /**
421     * @return
422     *
423     * @jmx.managed-attribute
424     */

425    public String JavaDoc getDatabaseManagerClass()
426    {
427       return databaseManagerClass;
428    }
429
430    /**
431     * Set the database manager (UI) class.
432     *
433     * @param databaseManagerClass
434     *
435     * @jmx.managed-attribute
436     */

437    public void setDatabaseManagerClass(String JavaDoc databaseManagerClass)
438    {
439       if (databaseManagerClass == null)
440       {
441          databaseManagerClass = DEFAULT_DATABASE_MANAGER_CLASS;
442       }
443       this.databaseManagerClass = databaseManagerClass;
444    }
445
446    /**
447     * @return server class for remote hypersonic.
448     */

449    public String JavaDoc getServerClass()
450    {
451       return serverClass;
452    }
453
454    /**
455     * Set the server class for remote hypersonic.
456     *
457     * @param serverClass
458     */

459    public void setServerClass(String JavaDoc serverClass)
460    {
461       if (serverClass == null)
462       {
463          serverClass = DEFAULT_SERVER_CLASS;
464       }
465       this.serverClass = serverClass;
466    }
467
468    // Operations ----------------------------------------------------
469

470    /**
471     * Start of DatabaseManager accesible from the management console.
472     *
473     * @jmx.managed-operation
474     */

475    public void startDatabaseManager()
476    {
477       // Start DBManager in new thread
478
new Thread JavaDoc()
479       {
480          public void run()
481          {
482             try
483             {
484                // If bind address is the default 0.0.0.0, use localhost
485
String JavaDoc connectHost = DEFAULT_ADDRESS.equals(address) ? "localhost" : address;
486                String JavaDoc driver = JDBC_DRIVER_CLASS;
487                String JavaDoc[] args;
488                if (!inProcessMode)
489                {
490                   args =
491                      new String JavaDoc[] {
492                         "-noexit",
493                         "-driver", driver,
494                         "-url", JDBC_URL_PREFIX + "hsql://" + connectHost + ":" + port,
495                         "-user", user,
496                         "-password", password,
497                         "-dir", getDatabasePath()
498                         };
499                }
500                else if (IN_MEMORY_DATABASE.equals(name))
501                {
502                   args =
503                      new String JavaDoc[] {
504                         "-noexit",
505                         "-driver", driver,
506                         "-url", JDBC_URL_PREFIX + IN_MEMORY_DATABASE,
507                         "-user", user,
508                         "-password", password
509                         };
510                }
511                else
512                {
513                   args =
514                      new String JavaDoc[] {
515                         "-noexit",
516                         "-driver", driver,
517                         "-url", JDBC_URL_PREFIX + getDatabasePath(),
518                         "-user", user,
519                         "-password", password,
520                         "-dir", getDatabasePath()
521                         };
522                }
523
524                // load (and link) the class only if needed
525
ClassLoader JavaDoc cl = Thread.currentThread().getContextClassLoader();
526                Class JavaDoc clazz = Class.forName(databaseManagerClass, true, cl);
527                Method JavaDoc main = clazz.getMethod("main", new Class JavaDoc[] { args.getClass() });
528                main.invoke(null, new Object JavaDoc [] { args });
529             }
530             catch (HeadlessException JavaDoc e)
531             {
532                log.error("Failed to start database manager because this is an headless configuration (no display, mouse or keyword)");
533             }
534             catch (Exception JavaDoc e)
535             {
536                log.error("Failed to start database manager", e);
537             }
538          }
539       }
540       .start();
541    }
542
543    // Lifecycle -----------------------------------------------------
544

545    /**
546     * Start the database
547     */

548    protected void startService() throws Exception JavaDoc
549    {
550       // check persist for old compatibility
551
if (!persist)
552       {
553          inProcessMode = true;
554          name = IN_MEMORY_DATABASE;
555       }
556       
557       // which database?
558
if (!inProcessMode)
559       {
560          startRemoteDatabase();
561       }
562       else if (IN_MEMORY_DATABASE.equals(name))
563       {
564          startInMemoryDatabase();
565       }
566       else
567       {
568          startStandaloneDatabase();
569       }
570    }
571
572    /**
573     * We now close the connection clean by calling the
574     * serverSocket throught jdbc. The MBeanServer calls this
575     * method at closing time.
576     */

577    protected void stopService() throws Exception JavaDoc
578    {
579       // which database?
580
if (!inProcessMode)
581       {
582          stopRemoteDatabase();
583       }
584       else if (IN_MEMORY_DATABASE.equals(name))
585       {
586          stopInMemoryDatabase();
587       }
588       else
589       {
590          stopStandaloneDatabase();
591       }
592    }
593    
594    // Private -------------------------------------------------------
595

596    /**
597     * Start the standalone (in process) database.
598     */

599    private void startStandaloneDatabase() throws Exception JavaDoc
600    {
601       // Get the server data directory
602
File JavaDoc dataDir = null;
603
604       if (dbDataDir == null) dataDir = ServerConfigLocator.locate().getServerDataDir();
605       else dataDir = new File JavaDoc(dbDataDir);
606
607       // Get DB directory
608
File JavaDoc hypersoniDir = new File JavaDoc(dataDir, HYPERSONIC_DATA_DIR);
609
610       if (!hypersoniDir.exists())
611       {
612          hypersoniDir.mkdirs();
613       }
614
615       if (!hypersoniDir.isDirectory())
616       {
617          throw new IOException JavaDoc("Failed to create directory: " + hypersoniDir);
618       }
619       
620       dbPath = new File JavaDoc(hypersoniDir, name);
621
622       String JavaDoc dbURL = JDBC_URL_PREFIX + getDatabasePath();
623
624       // hold a connection so hypersonic does not close the database
625
connection = getConnection(dbURL);
626    }
627
628    /**
629     * Start the only in memory database.
630     */

631    private void startInMemoryDatabase() throws Exception JavaDoc
632    {
633       String JavaDoc dbURL = JDBC_URL_PREFIX + IN_MEMORY_DATABASE;
634
635       // hold a connection so hypersonic does not close the database
636
connection = getConnection(dbURL);
637    }
638
639    /**
640     * Start the remote database.
641     */

642    private void startRemoteDatabase() throws Exception JavaDoc
643    {
644       // Get the server data directory
645
File JavaDoc dataDir = null;
646       if (dbDataDir == null) dataDir = ServerConfigLocator.locate().getServerDataDir();
647       else dataDir = new File JavaDoc(dbDataDir);
648
649       // Get DB directory
650
File JavaDoc hypersoniDir = new File JavaDoc(dataDir, HYPERSONIC_DATA_DIR);
651
652       if (!hypersoniDir.exists())
653       {
654          hypersoniDir.mkdirs();
655       }
656
657       if (!hypersoniDir.isDirectory())
658       {
659          throw new IOException JavaDoc("Failed to create directory: " + hypersoniDir);
660       }
661       
662       dbPath = new File JavaDoc(hypersoniDir, name);
663
664       // Start DB in new thread, or else it will block us
665
serverThread = new Thread JavaDoc("hypersonic-" + name)
666       {
667          public void run()
668          {
669             try
670             {
671                // Create startup arguments
672
String JavaDoc[] args =
673                   new String JavaDoc[] {
674                      "-database", dbPath.toString(),
675                      "-port", String.valueOf(port),
676                      "-address", address,
677                      "-silent", String.valueOf(silent),
678                      "-trace", String.valueOf(trace),
679                      "-no_system_exit", String.valueOf(no_system_exit),
680                      };
681
682                // Start server
683
ClassLoader JavaDoc cl = Thread.currentThread().getContextClassLoader();
684                Class JavaDoc clazz = Class.forName(serverClass, true, cl);
685                Method JavaDoc main = clazz.getMethod("main", new Class JavaDoc[] { args.getClass() });
686                main.invoke(null, new Object JavaDoc[] { args } );
687             }
688             catch (Exception JavaDoc e)
689             {
690                log.error("Failed to start database", e);
691             }
692          }
693       };
694       serverThread.start();
695    }
696
697    /**
698     * Stop the standalone (in process) database.
699     */

700    private void stopStandaloneDatabase() throws Exception JavaDoc
701    {
702       String JavaDoc dbURL = JDBC_URL_PREFIX + getDatabasePath();
703
704       Connection JavaDoc connection = getConnection(dbURL);
705       Statement JavaDoc statement = connection.createStatement();
706       
707       String JavaDoc shutdownCommand = this.shutdownCommand;
708       if (shutdownCommand == null)
709       {
710          shutdownCommand = DEFAULT_IN_PROCESS_SHUTDOWN_COMMAND;
711       }
712       
713       statement.executeQuery(shutdownCommand);
714       this.connection = null;
715       log.info("Database standalone closed clean");
716    }
717
718    /**
719     * Stop the in memory database.
720     */

721    private void stopInMemoryDatabase() throws Exception JavaDoc
722    {
723       String JavaDoc dbURL = JDBC_URL_PREFIX + IN_MEMORY_DATABASE;
724
725       Connection JavaDoc connection = getConnection(dbURL);
726       Statement JavaDoc statement = connection.createStatement();
727       
728       String JavaDoc shutdownCommand = this.shutdownCommand;
729       if (shutdownCommand == null)
730       {
731          shutdownCommand = DEFAULT_IN_MEMORY_SHUTDOWN_COMMAND;
732       }
733       
734       statement.executeQuery(shutdownCommand);
735       this.connection = null;
736       log.info("Database in memory closed clean");
737    }
738
739    /**
740     * Stop the remote database.
741     */

742    private void stopRemoteDatabase() throws Exception JavaDoc
743    {
744       // If bind address is the default 0.0.0.0, use localhost
745
String JavaDoc connectHost = DEFAULT_ADDRESS.equals(address) ? "localhost" : address;
746       String JavaDoc dbURL = JDBC_URL_PREFIX + "hsql://" + connectHost + ":" + port;
747
748       Connection JavaDoc connection = getConnection(dbURL);
749       Statement JavaDoc statement = connection.createStatement();
750       
751       String JavaDoc shutdownCommand = this.shutdownCommand;
752       if (shutdownCommand == null)
753       {
754          shutdownCommand = DEFAULT_REMOTE_SHUTDOWN_COMMAND;
755       }
756       
757       statement.executeQuery(shutdownCommand);
758       // TODO: join thread?
759
serverThread = null;
760       this.connection = null;
761       log.info("Database remote closed clean");
762    }
763    
764    /**
765     * Get the connection.
766     *
767     * @param dbURL jdbc url.
768     * @return the connection, allocate one if needed.
769     * @throws Exception
770     */

771    private synchronized Connection JavaDoc getConnection(String JavaDoc dbURL) throws Exception JavaDoc
772    {
773       if (connection == null)
774       {
775          ClassLoader JavaDoc cl = Thread.currentThread().getContextClassLoader();
776          Class.forName(JDBC_DRIVER_CLASS, true, cl).newInstance();
777          connection = DriverManager.getConnection(dbURL, user, password);
778       }
779       return connection;
780    }
781
782 }
783
Popular Tags