SuperX-Kernmodul
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

381 lines
14 KiB

/*
* Copyright (c) 2001-2004, The HSQL Development Group All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the HSQL Development Group nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG, OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package de.memtext.db;
import java.awt.Component;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
import java.util.ResourceBundle;
import javax.swing.JOptionPane;
/**
* A class which helps managing multiple connections to a stand-alone database
* (e.g. on a network path). After one user has opened the database other users
* can get the option to open a temporary copy of the database. The temporary
* copy may be read-only, but doesn't has to be. If it's not read-only all, all
* changes will be discarded when the connection is closed. (May be useful if
* the application only does some dispensible logging or so). see
* SampleApplication
*/
public class HsqlStandaloneMgr {
private static AbstractHsqlStandaloneMgrResources resources;
private HsqlStandaloneMgr() {
}
private static void initResources() {
String mypackage = "";
//if you place the Resources classes in some package, define it like this
mypackage = "de.memtext.db.";
resources = (AbstractHsqlStandaloneMgrResources) ResourceBundle.getBundle(mypackage + "HsqlStandaloneMgrResources");
}
/**
* Checks if a database is already opened (by checking if a .lck file
* exists) Use from HSQLDB 1.7.2 or higher
*
* @param String
* path - null,"" or "." for current directory
* @param String
* databasename
* @return true if database is already opened
*/
public static boolean isDatabaseOpen(String path, String databasename) {
File lckFile = new File(getAdaptedPath(path) + databasename + ".lck");
return lckFile.exists();
}
/**
* Deletes any temporary files which the HsqlStandaloneMgr may have created
* for the given url
*
* @param String
* url
* @param String
* path - null,"" or "." for current dir
* @param String
* databasename - of the original database, no _TMP_COPY appendix
*/
public static void deleteTmpFiles(String url, String path, String databasename) {
if (databasename.indexOf("_TMP_COPY") > -1) throw new IllegalArgumentException("Please specifiy the name of the original database without _TMP_COPY");
path = getAdaptedPath(path);
int tmpPos = url.indexOf("_TMP_COPY");
if (tmpPos == -1) {
//if the main connection is closed delete info about the user
File f = new File(path + databasename + "_user.properties");
if (f.exists()) f.delete();
} else {
//delete files for temp. connection
String tmp = url.substring(tmpPos);
if (path == null || path.equals("")) path = ".";
File fpath = new File(path);
File tmpFiles[] = fpath.listFiles(new TmpFileFilter(databasename + tmp));
for (int i = 0; i < tmpFiles.length; i++) {
tmpFiles[i].delete();
}
}
}
/**
* Asks the user if he/she wants to open a temporary copy of the database or
* not. A boolean indicates if the questions concerns read-only mode or not.
*
* @param Component
* parentComponent - usually the application Frame, but may be
* null
* @param String
* databasename - name of original database
* @param boolean
* isReadOnlyCopyWanted - should the temp. copy be read-only
* @return int from JOptionPane.showConfirmDialog
*/
public static int askUser(Component parentComponent, String path,
String databasename, boolean isReadOnlyCopyWanted) {
if (resources == null) initResources();
String username = null;
File f = new File(getAdaptedPath(path) + databasename + "_user.properties");
if (f.exists()) {
Properties p = new Properties();
FileInputStream fis;
try {
fis = new FileInputStream(f);
p.load(fis);
username = p.getProperty("user");
fis.close();
} catch (Exception e) {
System.err.println(resources.getString("Couldn't read user name"));
e.printStackTrace();
}
}
StringBuffer msg = new StringBuffer(resources.getDbInUseBy(databasename, username));
if (isReadOnlyCopyWanted)
msg.append(resources.getString("Would you like to open a temporary copy in read-only mode?"));
else
msg.append(resources.getString("Would you like to open a temporary copy?\nAttention - any changes to the database will be lost after closing the program!"));
return JOptionPane.showConfirmDialog(parentComponent, msg, "HSQLDB", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
}
/**
* Returns a connection to a temporary copy of a database either in
* read-only mode or not.
*
* @param Component
* parentComponent - usually the application Frame, but may be
* null
* @param String
* path - null,"" or "." for current dir
* @param String
* databasename
* @param String
* username
* @param String
* password
* @param boolean
* isReadOnlyCopyWanted - should the temporary copy of the
* database be in read-only mode
* @return Connection to the temporary copy of the database
* @throws ClassNotFoundException
* @throws SQLException
* @throws IOException
*/
public static Connection getTmpConnection(Component parentComponent, String path, String databasename, String username, String password, boolean isReadOnlyCopyWanted)
throws ClassNotFoundException, SQLException, IOException {
if (resources == null) initResources();
Class.forName("org.hsqldb.jdbcDriver");
path = getAdaptedPath(path);
int tmpInstanceNumber = checkNumber(path, databasename);
try {
copyDatabaseFiles(path, databasename, tmpInstanceNumber);
} catch (IOException e) {
JOptionPane.showMessageDialog(parentComponent, resources.getString("Could not create temporary copy of database.)") + "\n" + e, "HSQLDB", JOptionPane.WARNING_MESSAGE);
throw e;
}
if (isReadOnlyCopyWanted) {
try {
setReadonly(path + databasename + "_TMP_COPY" + tmpInstanceNumber + ".properties");
} catch (IOException e) {
JOptionPane.showMessageDialog(parentComponent, resources.getString("Could not set temporary copy of database to readonly mode.") + "\n" + e, "HSQLDB",
JOptionPane.WARNING_MESSAGE);
throw e;
}
}
String url = "jdbc:hsqldb:file:" + path + databasename + "_TMP_COPY" + tmpInstanceNumber;
Connection con = java.sql.DriverManager.getConnection(url, username, password);
if (!isReadOnlyCopyWanted) {
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("select count(*) from system_tables where hsqldb_type='TEXT'");
rs.next();
if (rs.getInt(1) > 0) {
stmt.execute("shutdown");
stmt.close();
con.close();
deleteTmpFiles(url, path, databasename);
throw new SQLException(resources.getString("Handling non read-only temporary database with text tables is not supported"));
}
rs.close();
stmt.close();
}
return con;
}
private static int checkNumber(String path, String databasename) {
int result = 1;
while (new File(path + databasename + "_TMP_COPY" + result + ".script").exists())
result++;
return result;
}
/**
* Returns a regular connection to a database and creates a file
* database_user.properties with the name of the user that opens the
* database
*
* @param String
* path - null,"" or "." for current dir
* @param String
* databasename
* @param String
* username
* @param String
* password
* @return Connection to the database
* @throws ClassNotFoundException
* @throws SQLException
* @throws IOException
*/
public static Connection getConnection(String path, String databasename, String username, String password) throws ClassNotFoundException, SQLException, IOException {
Class.forName("org.hsqldb.jdbcDriver");
String url = null;
if (path == null)
url = "jdbc:hsqldb:" + databasename;
else
url = "jdbc:hsqldb:file:" + getAdaptedPath(path) + databasename;
Connection con = java.sql.DriverManager.getConnection(url, username, password);
Properties p = new Properties();
p.put("user", System.getProperty("user.name"));
String filename = (path != null ? path + "/" + databasename + "_user.properties" : databasename + "_user.properties");
FileOutputStream fos = new FileOutputStream(filename);
p.store(fos, "User which uses the HSQL database");
fos.close();
return con;
}
/**
* String and makes sure separator char is at the end
*
* @param String
* path
* @return adapted path String
*/
private static String getAdaptedPath(String path) {
if (path == null) path = "";
if ((path.equals(".") || path.length() > 1) && !(path.endsWith("/") || path.endsWith("\\"))) path += File.separator;
return path;
}
/**
* Changes the property readonly to true in a database properties file
*
* @param String
* propertiesFile including path if necessary
* @throws IOException
*/
private static void setReadonly(String propertiesFile) throws IOException {
Properties p = new Properties();
p.load(new FileInputStream(propertiesFile));
p.put("readonly", "true");
p.store(new FileOutputStream(propertiesFile), "HSQL database");
}
/**
* Makes a temporary copy of all existing database files with the appendix
* _TMP_COPY
*
* @param String
* path - may be null for current dir, no / or \ at the end
* @param String
* databasename
* @throws IOException
*/
private static void copyDatabaseFiles(String path, String databasename, int number) throws IOException {
String s = path + databasename;
copyFile(s + ".script", s + "_TMP_COPY" + number + ".script");
copyFile(s + ".properties", s + "_TMP_COPY" + number + ".properties");
if (new File(s + ".log").exists()) copyFile(s + ".log", s + "_TMP_COPY" + number + ".log");
if (new File(s + ".data").exists()) copyFile(s + ".data", s + "_TMP_COPY" + number + ".data");
if (new File(s + ".backup").exists()) copyFile(s + ".backup", s + "_TMP_COPY" + number + ".backup");
if (new File(s + ".nio").exists()) copyFile(s + ".nio", s + "_TMP_COPY" + number + ".nio");
}
/**
* Creates a copy of a file
*
* @param String
* source - source file name (incl. path if necessary)
* @param String
* target - target file name (incl. path if necessary)
* @throws IOException
*/
static public void copyFile(String source, String target) throws IOException {
try {
FileInputStream is = new FileInputStream(source);
FileOutputStream os = new FileOutputStream(target);
BufferedInputStream in = new BufferedInputStream(is);
BufferedOutputStream out = new BufferedOutputStream(os);
int buffer_size = 32768;
byte[] buffer = new byte[buffer_size];
int len = in.read(buffer, 0, buffer_size);
while (len != -1) {
out.write(buffer, 0, len);
len = in.read(buffer, 0, buffer_size);
}
in.close();
is.close();
out.close();
os.close();
} catch (IOException e) {
throw new IOException("Couldn't copy file " + source + ": " + e.toString());
}
}
private static class TmpFileFilter implements FilenameFilter {
private String tmpName;
TmpFileFilter(String tmpName) {
this.tmpName = tmpName;
}
@Override
public boolean accept(File dir, String name) {
return name.indexOf(tmpName) > -1;
}
}
}
//Created on 21.10.2004 at 20:35:55