001: /*
002: * HsqlDbEngineDaemon: The hsql db engine daemon
003: * Copyright (C) 2006 Rift IT Contracting
004: *
005: * This library is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU Lesser General Public
007: * License as published by the Free Software Foundation; either
008: * version 2.1 of the License, or (at your option) any later version.
009: *
010: * This library is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: * Lesser General Public License for more details.
014: *
015: * You should have received a copy of the GNU Lesser General Public
016: * License along with this library; if not, write to the Free Software
017: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
018: *
019: * HsqlDBEngineImpl.java
020: *
021: * The implementation of the HsqlDBEngine daemon.
022: *
023: * $Revision: 1.1.2.1 $
024: */
025:
026: // package path
027: package com.rift.coad.daemon.hsqldb;
028:
029: // java imports
030: import java.rmi.Remote;
031: import java.rmi.RemoteException;
032: import java.net.InetAddress;
033:
034: // logging import
035: import org.apache.log4j.Logger;
036:
037: // hsqldb imports
038: import org.hsqldb.Server;
039: import org.hsqldb.ServerConstants;
040: import org.hsqldb.DatabaseManager;
041: import org.hsqldb.persist.HsqlProperties;
042:
043: // coadunation imports
044: import com.rift.coad.lib.bean.BeanRunnable;
045: import com.rift.coad.lib.configuration.Configuration;
046: import com.rift.coad.lib.configuration.ConfigurationFactory;
047: import com.rift.coad.lib.thread.ThreadStateMonitor;
048:
049: /**
050: * The implementation of the HsqlDBEngine daemon.
051: *
052: * @author Brett Chaldecott
053: */
054: public class HsqlDBEngine implements HsqlDBEngineMBean, BeanRunnable {
055:
056: // index value
057: private final static int LOCK_INDEX = 0;
058: private final static String DB_HOSTNAME = "db_hostname";
059: private final static String DB_PORT = "db_port";
060: private final static String DB_PATH = "db_path";
061: private final static String DB_NAME = "db_name";
062: private final static String DEFAULT_DB_NAME = "coadunation";
063: private final static String DB_SILENT = "db_silent";
064: private final static boolean DEFAULT_DB_SILENT = true;
065: private final static String DB_TRACE = "db_trace";
066: private final static boolean DEFAULT_DB_TRACE = false;
067: private final static String DB_TLS = "db_tls";
068: private final static boolean DEFAULT_DB_TLS = false;
069:
070: // private member variables
071: private Logger log = Logger.getLogger(HsqlDBEngine.class.getName());
072: private Server server = null;
073: private ThreadStateMonitor state = new ThreadStateMonitor();
074:
075: /**
076: * Creates a new instance of HsqlDBEngineImpl
077: *
078: * @exception HsqlDBEngineException
079: */
080: public HsqlDBEngine() throws HsqlDBEngineException {
081: try {
082: server = new Server();
083: HsqlProperties props = new HsqlProperties();
084:
085: Configuration config = ConfigurationFactory.getInstance()
086: .getConfig(HsqlDBEngine.class);
087:
088: // set the properties
089: props.setProperty(ServerConstants.SC_KEY_ADDRESS, config
090: .getString(DB_HOSTNAME, InetAddress.getLocalHost()
091: .getCanonicalHostName()));
092: props
093: .setProperty(
094: ServerConstants.SC_KEY_PORT,
095: new Long(
096: config
097: .getLong(
098: DB_PORT,
099: ServerConstants.SC_DEFAULT_HSQL_SERVER_PORT))
100: .toString());
101: props.setProperty(ServerConstants.SC_KEY_DATABASE + "."
102: + LOCK_INDEX, config.getString(DB_PATH));
103: props.setProperty(ServerConstants.SC_KEY_DBNAME + "."
104: + LOCK_INDEX, config.getString(DB_NAME,
105: DEFAULT_DB_NAME));
106:
107: server.setProperties(props);
108: server.setSilent(config.getBoolean(DB_SILENT,
109: DEFAULT_DB_SILENT));
110: server.setTrace(config.getBoolean(DB_TRACE,
111: DEFAULT_DB_TRACE));
112: server.setTls(config.getBoolean(DB_TLS, DEFAULT_DB_TLS));
113: server.setNoSystemExit(true);
114: server.setRestartOnShutdown(true);
115: } catch (Exception ex) {
116: throw new HsqlDBEngineException(
117: "Failed to init the HsqlDB Engine : "
118: + ex.getMessage(), ex);
119: }
120: }
121:
122: /**
123: * Retrieves, in string form, this server's host address.
124: *
125: * @return this server's host address
126: *
127: * @jmx.managed-attribute
128: * access="read-write"
129: * description="Host InetAddress"
130: * @exception RemoteException
131: * @exception HsqlDBEngineException
132: */
133: public String getAddress() throws RemoteException,
134: HsqlDBEngineException {
135: try {
136: return server.getAddress();
137: } catch (Exception ex) {
138: throw new HsqlDBEngineException(
139: "Failed to retrieve the address "
140: + "information : " + ex.getMessage(), ex);
141: }
142: }
143:
144: /**
145: * Retrieves the url alias (network name) of the i'th database
146: * that this Server hosts.
147: *
148: * @param index the index of the url alias upon which to report
149: * @param asconfigured if true, report the configured value, else
150: * the live value
151: * @return the url alias component of the i'th database
152: * that this Server hosts, or null if no such name exists.
153: *
154: * @jmx.managed-operation
155: * impact="INFO"
156: * description="url alias component of the i'th hosted Database"
157: *
158: * @jmx.managed-operation-parameter
159: * name="index"
160: * type="int"
161: * position="0"
162: * description="This Server's index for the hosted Database"
163: *
164: * @jmx.managed-operation-parameter
165: * name="asconfigured"
166: * type="boolean"
167: * position="1"
168: * description="if true, the configured value, else the live value"
169: *
170: * @exception RemoteException
171: * @exception HsqlDBEngineException
172: */
173: public String getDatabaseName(int index, boolean asconfigured)
174: throws RemoteException, HsqlDBEngineException {
175: try {
176: return server.getDatabaseName(LOCK_INDEX, asconfigured);
177: } catch (Exception ex) {
178: throw new HsqlDBEngineException(
179: "Failed to retrieve the address "
180: + "information : " + ex.getMessage(), ex);
181: }
182: }
183:
184: /**
185: * Retrieves the HSQLDB path descriptor (uri) of the i'th
186: * Database that this Server hosts.
187: *
188: * @param index the index of the uri upon which to report
189: * @param asconfigured if true, report the configured value, else
190: * the live value
191: * @return the HSQLDB database path descriptor of the i'th database
192: * that this Server hosts, or null if no such path descriptor
193: * exists
194: *
195: * @jmx.managed-operation
196: * impact="INFO"
197: * description="For i'th hosted database"
198: *
199: * @jmx.managed-operation-parameter
200: * name="index"
201: * type="int"
202: * position="0"
203: * description="This Server's index for the hosted Database"
204: *
205: * @jmx.managed-operation-parameter
206: * name="asconfigured"
207: * type="boolean"
208: * position="1"
209: * description="if true, the configured value, else the live value"
210: *
211: * @exception RemoteException
212: * @exception HsqlDBEngineException
213: */
214: public String getDatabasePath(int index, boolean asconfigured)
215: throws RemoteException, HsqlDBEngineException {
216: try {
217: return server.getDatabasePath(LOCK_INDEX, asconfigured);
218: } catch (Exception ex) {
219: throw new HsqlDBEngineException(
220: "Failed to retrieve the database " + "path : "
221: + ex.getMessage(), ex);
222: }
223: }
224:
225: /**
226: * This method returns the HsqlDB type
227: *
228: * @return A string containing the type of this db.
229: * @param index The index of this type.
230: * @exception RemoteException
231: * @exception HsqlDBEngineException
232: */
233: public String getDatabaseType(int index) throws RemoteException,
234: HsqlDBEngineException {
235: try {
236: return server.getDatabaseType(LOCK_INDEX);
237: } catch (Exception ex) {
238: throw new HsqlDBEngineException(
239: "Failed to retrieve the database " + "type : "
240: + ex.getMessage(), ex);
241: }
242: }
243:
244: /**
245: * Retrieves this server's host port.
246: *
247: * @return this server's host port
248: *
249: * @jmx.managed-attribute
250: * access="read-write"
251: * description="At which ServerSocket listens for connections"
252: *
253: * @exception RemoteException
254: * @exception HsqlDBEngineException
255: */
256: public int getPort() throws RemoteException, HsqlDBEngineException {
257: try {
258: return server.getPort();
259: } catch (Exception ex) {
260: throw new HsqlDBEngineException(
261: "Failed to retrieve the database " + "port : "
262: + ex.getMessage(), ex);
263: }
264: }
265:
266: /**
267: * Retrieves this server's product name. <p>
268: *
269: * Typically, this will be something like: "HSQLDB xxx server".
270: *
271: * @return the product name of this server
272: *
273: * @jmx.managed-attribute
274: * access="read-only"
275: * description="Of Server"
276: *
277: * @exception RemoteException
278: * @exception HsqlDBEngineException
279: */
280: public String getProductName() throws RemoteException,
281: HsqlDBEngineException {
282: try {
283: return server.getProductName();
284: } catch (Exception ex) {
285: throw new HsqlDBEngineException(
286: "Failed to retrieve the database "
287: + "product name : " + ex.getMessage(), ex);
288: }
289: }
290:
291: /**
292: * Retrieves the server's product version, as a String. <p>
293: *
294: * Typically, this will be something like: "1.x.x" or "2.x.x" and so on.
295: *
296: * @return the product version of the server
297: *
298: * @jmx.managed-attribute
299: * access="read-only"
300: * description="Of Server"
301: *
302: * @exception RemoteException
303: * @exception HsqlDBEngineException
304: */
305: public String getProductVersion() throws RemoteException,
306: HsqlDBEngineException {
307: try {
308: return server.getProductVersion();
309: } catch (Exception ex) {
310: throw new HsqlDBEngineException(
311: "Failed to retrieve the database "
312: + "product version : " + ex.getMessage(),
313: ex);
314: }
315: }
316:
317: /**
318: * Retrieves a string respresentaion of the network protocol
319: * this server offers, typically one of 'HTTP', HTTPS', 'HSQL' or 'HSQLS'.
320: *
321: * @return string respresentation of this server's protocol
322: *
323: * @jmx.managed-attribute
324: * access="read-only"
325: * description="Used to handle connections"
326: *
327: * @exception RemoteException
328: * @exception HsqlDBEngineException
329: */
330: public String getProtocol() throws RemoteException,
331: HsqlDBEngineException {
332: try {
333: return server.getProtocol();
334: } catch (Exception ex) {
335: throw new HsqlDBEngineException(
336: "Failed to retrieve the database " + "protocol : "
337: + ex.getMessage(), ex);
338: }
339: }
340:
341: /**
342: * Retrieves a String identifying this Server object.
343: *
344: * @return a String identifying this Server object
345: *
346: * @jmx.managed-attribute
347: * access="read-only"
348: * description="Identifying Server"
349: *
350: * @exception RemoteException
351: * @exception HsqlDBEngineException
352: */
353: public String getServerId() throws RemoteException,
354: HsqlDBEngineException {
355: try {
356: return server.getServerId();
357: } catch (Exception ex) {
358: throw new HsqlDBEngineException(
359: "Failed to retrieve the server " + "id : "
360: + ex.getMessage(), ex);
361: }
362: }
363:
364: /**
365: * Retrieves current state of this server in numerically coded form. <p>
366: *
367: * Typically, this will be one of: <p>
368: *
369: * <ol>
370: * <li>ServerProperties.SERVER_STATE_ONLINE (1)
371: * <li>ServerProperties.SERVER_STATE_OPENING (4)
372: * <li>ServerProperties.SERVER_STATE_CLOSING (8)
373: * <li>ServerProperties.SERVER_STATE_SHUTDOWN (16)
374: * </ol>
375: *
376: * @return this server's state code.
377: *
378: * @jmx.managed-attribute
379: * access="read-only"
380: * description="1:ONLINE 4:OPENING 8:CLOSING, 16:SHUTDOWN"
381: *
382: * @exception RemoteException
383: * @exception HsqlDBEngineException
384: */
385: public int getState() throws RemoteException, HsqlDBEngineException {
386: try {
387: return server.getState();
388: } catch (Exception ex) {
389: throw new HsqlDBEngineException(
390: "Failed to retrieve the state : " + ex.getMessage(),
391: ex);
392: }
393: }
394:
395: /**
396: * Retrieves a character sequence describing this server's current state,
397: * including the message of the last exception, if there is one and it
398: * is still in context.
399: *
400: * @return this server's state represented as a character sequence.
401: *
402: * @jmx.managed-attribute
403: * access="read-only"
404: * description="State as string"
405: *
406: * @exception RemoteException
407: * @exception HsqlDBEngineException
408: */
409: public String getStateDescriptor() throws RemoteException,
410: HsqlDBEngineException {
411: try {
412: return server.getStateDescriptor();
413: } catch (Exception ex) {
414: throw new HsqlDBEngineException(
415: "Failed to retrieve the state " + "description : "
416: + ex.getMessage(), ex);
417: }
418: }
419:
420: /**
421: * Retrieves whether the use of secure sockets was requested in the
422: * server properties.
423: *
424: * @return if true, secure sockets are requested, else not
425: *
426: * @jmx.managed-attribute
427: * access="read-write"
428: * description="Use TLS/SSL sockets?"
429: *
430: * @exception RemoteException
431: * @exception HsqlDBEngineException
432: */
433: public boolean isTls() throws RemoteException,
434: HsqlDBEngineException {
435: try {
436: return server.isTls();
437: } catch (Exception ex) {
438: throw new HsqlDBEngineException(
439: "Failed to retrieve the value of "
440: + "the TLs flag : " + ex.getMessage(), ex);
441: }
442: }
443:
444: /**
445: * Attempts to put properties from the file
446: * with the specified path. The file
447: * extension '.properties' is implicit and should not
448: * be included in the path specification.
449: *
450: * @param path the path of the desired properties file, without the
451: * '.properties' file extension
452: * @throws RuntimeException if this server is running
453: * @return true if the indicated file was read sucessfully, else false
454: *
455: * @jmx.managed-operation
456: * impact="ACTION"
457: * description="Reads in properties"
458: *
459: * @jmx.managed-operation-parameter
460: * name="path"
461: * type="java.lang.String"
462: * position="0"
463: * description="(optional) returns false if path is empty"
464: *
465: * @exception RemoteException
466: * @exception HsqlDBEngineException
467: */
468: public boolean putPropertiesFromFile(String path)
469: throws RemoteException, HsqlDBEngineException {
470: try {
471: return server.putPropertiesFromFile(path);
472: } catch (Exception ex) {
473: throw new HsqlDBEngineException(
474: "Failed to set the properties "
475: + "from the specified file : "
476: + ex.getMessage(), ex);
477: }
478: }
479:
480: /**
481: * Puts properties from the supplied string argument. The relevant
482: * key value pairs are the same as those for the (web)server.properties
483: * file format, except that the 'server.' prefix should not be specified.
484: *
485: * @param s semicolon-delimited key=value pair string,
486: * e.g. k1=v1;k2=v2;k3=v3...
487: * @throws RuntimeException if this server is running
488: *
489: * @jmx.managed-operation
490: * impact="ACTION"
491: * description="'server.' key prefix automatically supplied"
492: *
493: * @jmx.managed-operation-parameter
494: * name="s"
495: * type="java.lang.String"
496: * position="0"
497: * description="semicolon-delimited key=value pairs"
498: *
499: * @exception RemoteException
500: * @exception HsqlDBEngineException
501: */
502: public void putPropertiesFromString(String s)
503: throws RemoteException, HsqlDBEngineException {
504: try {
505: server.putPropertiesFromString(s);
506: } catch (Exception ex) {
507: throw new HsqlDBEngineException(
508: "Failed to set the properties "
509: + "from the string : " + ex.getMessage(),
510: ex);
511: }
512: }
513:
514: /**
515: * This method will be called to perform the processing. This method
516: * replaces the traditional run method.
517: */
518: public void process() {
519: try {
520: server.start();
521: while (!state.isTerminated()) {
522: state.monitor();
523: }
524: log.info("process method exiting");
525: } catch (Exception ex) {
526: log.error(
527: "Failed to start the server : " + ex.getMessage(),
528: ex);
529: }
530: }
531:
532: /**
533: * This method is called to soft terminate the processing thread.
534: */
535: public void terminate() {
536: try {
537: server.shutdown();
538: DatabaseManager.closeDatabases(0);
539: state.terminate(true);
540: log.info("Hsql has been shut down exiting");
541: } catch (Exception ex) {
542: log.error("Failed to stop the logger : " + ex.getMessage(),
543: ex);
544: }
545: }
546: }
|