| 56 | | * at http://hsqldb.org/. |
| 57 | | * @param {String|Number} address Either the IP address or the port number or a combination |
| 58 | | * of both in the form "ip:port". By default the IP address is "127.0.0.1" (aka localhost) |
| 59 | | * and the port is 9001. |
| | 56 | * at http://www.h2database.com/. |
| | 57 | * @param {helma.File} baseDir The directory where the database files |
| | 58 | * are located or should be stored |
| | 59 | * @param {Number} port The port to listen on (defaults to 9001) |
| | 60 | * @param {Boolean} createOnDemand If true this server will create non-existing |
| | 61 | * databases on-the-fly, if false it only accepts connections to already |
| | 62 | * existing databases in the given base directory |
| | 63 | * @param {Boolean} makePublic If true this database is reachable from outside, |
| | 64 | * if false it's only reachable from localhost |
| | 65 | * @param {Boolean} useSsl If true SSL will be used to encrypt the connection |
| 98 | | * Returns the database with the given name. |
| 99 | | * @param {String} name The name of the database to return |
| 100 | | * @returns The database with the given name |
| 101 | | * @type jala.db.RamDatabase |
| | 103 | * Returns the directory used by this server instance |
| | 104 | * @returns The directory where the databases used by this |
| | 105 | * server are located in |
| | 106 | * @type helma.File |
| | 107 | */ |
| | 108 | this.getDirectory = function() { |
| | 109 | return baseDir; |
| | 110 | }; |
| | 111 | |
| | 112 | /** |
| | 113 | * Returns the port this server listens on |
| | 114 | * @returns The port this server listens on |
| | 115 | * @type Number |
| | 116 | */ |
| | 117 | this.getPort = function() { |
| | 118 | return config.tcpPort; |
| | 119 | }; |
| | 120 | |
| | 121 | /** |
| | 122 | * Returns the config of this server |
| | 123 | * @returns The config of this server |
| 104 | | this.getDatabase = function(name) { |
| 105 | | var dbIdx; |
| 106 | | if ((dbIdx = names[name]) != null) { |
| 107 | | return databases[dbIdx]; |
| 108 | | } |
| 109 | | return null; |
| 110 | | }; |
| 111 | | |
| 112 | | /** |
| 113 | | * Returns the map containing the database names registered |
| 114 | | * within this server instance. |
| 115 | | * @returns A map containing the database names as properties which |
| 116 | | * value is the index position of the database within this server |
| 117 | | * @type Object |
| 118 | | * @private |
| 119 | | */ |
| 120 | | this.getDatabaseMap = function() { |
| 121 | | return names; |
| 122 | | }; |
| 123 | | |
| 124 | | /** |
| 125 | | * Returns an array containing all databases within this server. |
| 126 | | * @returns All databases within this server |
| 127 | | * @type Array |
| 128 | | * @private |
| 129 | | */ |
| 130 | | this.getDatabases = function() { |
| 131 | | return databases; |
| 132 | | }; |
| 133 | | |
| 134 | | /** |
| 135 | | * Main constructor body |
| 136 | | */ |
| 137 | | var ip = "127.0.0.1"; |
| 138 | | var port = 9001; |
| 139 | | if (address != null) { |
| 140 | | if (address.indexOf(":") > -1) { |
| 141 | | ip = address.substring(0, address.indexOf(":")); |
| 142 | | port = parseInt(address.substring(address.indexOf(":") + 1), 10); |
| 143 | | } else if (!isNaN(address)) { |
| 144 | | port = parseInt(address, 10); |
| 145 | | } |
| 146 | | } |
| 147 | | // set the IP address and the port this server should listen on |
| 148 | | server.setAddress(ip); |
| 149 | | server.setPort(port); |
| 150 | | app.logger.info("Jala : created instance listening on " + ip + ":" + port); |
| | 126 | this.getConfig = function() { |
| | 127 | return config; |
| | 128 | }; |
| | 129 | |
| | 130 | /** |
| | 131 | * Starts the database server. |
| | 132 | * @returns True in case the server started successfully, false otherwise |
| | 133 | * @type Boolean |
| | 134 | */ |
| | 135 | this.start = function() { |
| | 136 | if (server != null && server.isRunning()) { |
| | 137 | throw "jala.db.Server: already listening on port " + this.getPort(); |
| | 138 | } |
| | 139 | // convert properties into an array |
| | 140 | var config = this.getConfig(); |
| | 141 | var args = []; |
| | 142 | for (var propName in config) { |
| | 143 | args.push("-" + propName); |
| | 144 | args.push(config[propName].toString()); |
| | 145 | } |
| | 146 | // create the server instance |
| | 147 | server = Packages.org.h2.tools.Server.createTcpServer(args); |
| | 148 | try { |
| | 149 | server.start(); |
| | 150 | } catch (e) { |
| | 151 | app.logger.error("jala.db.Server: unable to start server, reason: " + e); |
| | 152 | return false; |
| | 153 | } |
| | 154 | app.logger.info("jala.db.Server: listening on localhost:" + this.getPort()); |
| | 155 | return true; |
| | 156 | }; |
| | 157 | |
| | 158 | |
| 187 | | return this.getServer().getState() == Packages.org.hsqldb.ServerConstants.SERVER_STATE_ONLINE; |
| 188 | | }; |
| 189 | | |
| 190 | | /** |
| 191 | | * Adds a database to this server. |
| 192 | | * @param {jala.db.RamDatabase} db The database to add |
| 193 | | * @param {Object} props An optional parameter object containing database |
| 194 | | * properties |
| 195 | | */ |
| 196 | | jala.db.Server.prototype.addDatabase = function(db, props) { |
| 197 | | if (!(db instanceof jala.db.RamDatabase)) { |
| 198 | | throw "jala.db.Server: Invalid argument to addDatabase(): " + db; |
| 199 | | } |
| 200 | | var name = db.getName(); |
| 201 | | var map = this.getDatabaseMap(); |
| 202 | | if (map[name] != null) { |
| 203 | | throw "jala.db.Server: There is already a database registered with the name '" + |
| 204 | | name + "'"; |
| 205 | | } |
| 206 | | var server = this.getServer(); |
| 207 | | var databases = this.getDatabases(); |
| 208 | | var dbIdx = databases.length; |
| 209 | | var dbPath = db.getDatabasePath(); |
| 210 | | dbPath += ";sql.enforce_strict_size=true"; |
| 211 | | if (props != null) { |
| 212 | | dbPath += jala.db.getPropertyString(props); |
| 213 | | } |
| 214 | | this.getDatabaseMap()[name] = dbIdx; |
| 215 | | this.getDatabases()[dbIdx] = db; |
| 216 | | // add the database to the server |
| 217 | | server.setDatabaseName(dbIdx, name); |
| 218 | | server.setDatabasePath(dbIdx, dbPath); |
| | 190 | return this.getServer().isRunning(); |
| | 191 | }; |
| | 192 | |
| | 193 | /** |
| | 194 | * Toggles the use of Ssl encryption within this server. This should be set |
| | 195 | * before starting the server. |
| | 196 | * @param {Boolean} bool If true SSL encryption will be used, false |
| | 197 | * otherwise. If no argument is given, this method returns the |
| | 198 | * current setting. |
| | 199 | * @returns The current setting if no argument is given, or void |
| | 200 | * @type Boolean |
| | 201 | */ |
| | 202 | jala.db.Server.prototype.useSsl = function(bool) { |
| | 203 | var config = this.getConfig(); |
| | 204 | if (bool != null) { |
| | 205 | config.tcpSSL = (bool === true); |
| | 206 | } else { |
| | 207 | return config.tcpSSL; |
| | 208 | } |
| 223 | | * Returns the JDBC Url to use for connections to the |
| 224 | | * specified database. |
| | 213 | * If called with boolean true as argument, this server creates databases |
| | 214 | * on-the-fly, otherwise it only accepts connections to already existing |
| | 215 | * databases. This should be set before starting the server. |
| | 216 | * @param {Boolean} bool If true this server creates non-existing databases |
| | 217 | * on demand, if false it only allows connections to existing databases. |
| | 218 | * If no argument is given, this method returns the current setting. |
| | 219 | * @returns The current setting if no argument is given, or void |
| | 220 | * @type Boolean |
| | 221 | */ |
| | 222 | jala.db.Server.prototype.createOnDemand = function(bool) { |
| | 223 | var config = this.getConfig(); |
| | 224 | if (bool != null) { |
| | 225 | config.ifExists = (bool === false); |
| | 226 | } else { |
| | 227 | return !config.ifExists; |
| | 228 | } |
| | 229 | return; |
| | 230 | }; |
| | 231 | |
| | 232 | /** |
| | 233 | * If called with boolean true as argument, this server accepts connections |
| | 234 | * from outside localhost. This should be set before starting the server. |
| | 235 | * @param {Boolean} bool If true this server accepts connections from outside |
| | 236 | * localhost. If no argument is given, this method returns the current setting. |
| | 237 | * @returns The current setting if no argument is given, or void |
| | 238 | * @type Boolean |
| | 239 | */ |
| | 240 | jala.db.Server.prototype.isPublic = function(bool) { |
| | 241 | var config = this.getConfig(); |
| | 242 | if (bool != null) { |
| | 243 | config.tcpAllowOthers = (bool === true); |
| | 244 | } else { |
| | 245 | return config.tcpAllowOthers; |
| | 246 | } |
| | 247 | return; |
| | 248 | }; |
| | 249 | |
| | 250 | /** |
| | 251 | * Returns the JDBC Url to use for connections to a given database. |
| 261 | | rp.put(name + ".driver", "org.hsqldb.jdbcDriver"); |
| 262 | | rp.put(name + ".user", "sa"); |
| 263 | | rp.put(name + ".password", ""); |
| | 284 | rp.put(name + ".driver", "org.h2.Driver"); |
| | 285 | rp.put(name + ".user", username || "sa"); |
| | 286 | rp.put(name + ".password", password || ""); |
| 379 | | * at http://hsqldb.org/. |
| 380 | | * @param {String} name The name of the database |
| | 404 | * at http://www.h2database.com/. |
| | 405 | * @param {String} name The name of the database. If not given a private |
| | 406 | * un-named database is created, that can only be accessed through this instance |
| | 407 | * of jala.db.RamDatabase |
| | 408 | * @param {String} username Optional username (defaults to "sa"). This username |
| | 409 | * is used when creating the database, so the same should be used when |
| | 410 | * creating subsequent instances of jala.db.RamDatabase pointing to a named |
| | 411 | * database. |
| | 412 | * @param {String} password Optional password (defaults to ""). |
| 440 | | rp.put(name + ".driver", "org.hsqldb.jdbcDriver"); |
| 441 | | rp.put(name + ".user", "sa"); |
| 442 | | rp.put(name + ".password", ""); |
| | 500 | rp.put(name + ".driver", "org.h2.Driver"); |
| | 501 | rp.put(name + ".user", this.getUsername()); |
| | 502 | rp.put(name + ".password", this.getPassword()); |
| 712 | | * @param {helma.File} file The script file to run. |
| 713 | | */ |
| 714 | | jala.db.RamDatabase.prototype.runScript = function(file) { |
| | 772 | * @param {helma.File} file The script file to run |
| | 773 | * @param {Object} props Optional object containing connection properties |
| | 774 | * @param {String} charset Optional character set to use (defaults to "UTF-8") |
| | 775 | * @param {Boolean} continueOnError Optional flag indicating whether to continue |
| | 776 | * on error or not (defaults to false) |
| | 777 | * @returns True in case the script was executed successfully, false otherwise |
| | 778 | * @type Boolean |
| | 779 | */ |
| | 780 | jala.db.RamDatabase.prototype.runScript = function(file, props, charset, continueOnError) { |
| 716 | | var sqlFile = new Packages.org.hsqldb.util.SqlFile(new java.io.File(file), false, new java.util.HashMap()); |
| 717 | | var conn = this.getConnection().getConnection(); |
| 718 | | sqlFile.execute(conn, false); |
| 719 | | app.logger.info("Jala Database: successfully executed SQL script '" + file.getAbsolutePath() + "'"); |
| 720 | | return true; |
| | 782 | Packages.org.h2.tools.RunScript.execute( |
| | 783 | this.getUrl(props), |
| | 784 | "sa", |
| | 785 | "", |
| | 786 | file.getAbsolutePath(), |
| | 787 | charset || "UTF-8", |
| | 788 | continueOnError === true |
| | 789 | ); |
| | 790 | app.logger.info("jala.db: successfully executed SQL script '" + |
| | 791 | file.getAbsolutePath() + "'"); |
| 724 | | } finally { |
| 725 | | if (conn != null) { |
| 726 | | conn.close(); |
| 727 | | } |
| 728 | | } |
| 729 | | }; |
| 730 | | |
| | 795 | } |
| | 796 | return true; |
| | 797 | }; |
| | 798 | |
| | 799 | /** |
| | 800 | * Dumps the database schema and data into a file |
| | 801 | * @param {helma.File} file The file where the database dump will be |
| | 802 | * @param {Object} props Optional object containing connection properties |
| | 803 | * @returns True in case the database was successfully dumped, false otherwise |
| | 804 | * @type Boolean |
| | 805 | */ |
| | 806 | jala.db.RamDatabase.prototype.dump = function(file, props) { |
| | 807 | try { |
| | 808 | Packages.org.h2.tools.Script.execute(this.getUrl(props), |
| | 809 | "sa", "", file.getAbsolutePath()); |
| | 810 | } catch (e) { |
| | 811 | app.logger.error("jala.db: Unable to dump database to '" + file.getAbsolutePath() + |
| | 812 | ", reason: " + e.toString()); |
| | 813 | return false; |
| | 814 | } |
| | 815 | return true; |
| | 816 | }; |
| | 863 | /** |
| | 864 | * Returns the username of this database |
| | 865 | * @returns The username of this database |
| | 866 | * @type String |
| | 867 | */ |
| | 868 | this.getUsername = function() { |
| | 869 | return username; |
| | 870 | }; |
| | 871 | |
| | 872 | /** |
| | 873 | * Returns the password of this database |
| | 874 | * @returns The password of this database |
| | 875 | * @type String |
| | 876 | */ |
| | 877 | this.getPassword = function() { |
| | 878 | return password; |
| | 879 | }; |
| | 880 | |
| | 881 | if (!name || typeof(name) != "string" || |
| | 882 | !directory || !(directory instanceof helma.File)) { |
| | 883 | throw "jala.db.FileDatabase: Missing or invalid arguments" |
| | 884 | } else if (!directory.exists()) { |
| | 885 | throw "jala.db.FileDatabase: directory '" + directory + "' does not exist"; |
| | 886 | } |
| | 887 | |
| | 910 | |
| | 911 | /** |
| | 912 | * Deletes all files of this database on disk. Note that this also |
| | 913 | * closes the database before removing it. |
| | 914 | * @returns True in case the database was removed successfully, false otherwise |
| | 915 | * @type Boolean |
| | 916 | */ |
| | 917 | jala.db.FileDatabase.prototype.remove = function() { |
| | 918 | var directory = this.getDirectory(); |
| | 919 | try { |
| | 920 | // shut down the database |
| | 921 | this.shutdown(); |
| | 922 | Packages.org.h2.tools.DeleteDbFiles.execute( |
| | 923 | directory.getAbsolutePath(), |
| | 924 | this.getName(), |
| | 925 | false |
| | 926 | ); |
| | 927 | } catch(e) { |
| | 928 | app.logger.error("jala.db: Unable to delete database in " + |
| | 929 | directory.getAbsolutePath() + ", reason: " + e); |
| | 930 | return false; |
| | 931 | } |
| | 932 | return true; |
| | 933 | }; |
| | 934 | |
| | 935 | /** |
| | 936 | * Creates a backup of this database, using the file passed as argument. The |
| | 937 | * result will be a zipped file containing the database files |
| | 938 | * @param {helma.File} file The file to write the backup to |
| | 939 | * @returns True if the database backup was created successfully, false otherwise |
| | 940 | * @type Boolean |
| | 941 | */ |
| | 942 | jala.db.FileDatabase.prototype.backup = function(file) { |
| | 943 | try { |
| | 944 | Packages.org.h2.tools.Backup.execute( |
| | 945 | file.getAbsolutePath(), |
| | 946 | this.getDirectory().getAbsolutePath(), |
| | 947 | this.getName(), |
| | 948 | false |
| | 949 | ); |
| | 950 | } catch (e) { |
| | 951 | app.logger.error("jala.db: Unable to backup database to '" + |
| | 952 | file.getAbsolutePath() + ", reason: " + e); |
| | 953 | return false; |
| | 954 | } |
| | 955 | return true; |
| | 956 | }; |
| | 957 | |
| | 958 | /** |
| | 959 | * Restores this database using a backup on disk. |
| | 960 | * @param {helma.File} backupFile The backup file to use for restore |
| | 961 | * @returns True if the database was successfully restored, false otherwise |
| | 962 | * @type Boolean |
| | 963 | */ |
| | 964 | jala.db.FileDatabase.prototype.restore = function(backupFile) { |
| | 965 | try { |
| | 966 | Packages.org.h2.tools.Restore.execute( |
| | 967 | backupFile.getAbsolutePath(), |
| | 968 | this.getDirectory().getAbsolutePath(), |
| | 969 | this.getName(), |
| | 970 | false |
| | 971 | ); |
| | 972 | } catch (e) { |
| | 973 | app.logger.error("jala.db: Unable to restore database using '" + |
| | 974 | backupFile.getAbsolutePath() + ", reason: " + e); |
| | 975 | return false; |
| | 976 | } |
| | 977 | return true; |
| | 978 | }; |