/* XXL: The eXtensible and fleXible Library for data processing
Copyright (C) 2000-2011 Prof. Dr. Bernhard Seeger
Head of the Database Research Group
Department of Mathematics and Computer Science
University of Marburg
Germany
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; If not, see <http://www.gnu.org/licenses/>.
http://code.google.com/p/xxl/
*/
package xxl.core.util;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import xxl.core.functions.AbstractFunction;
import xxl.core.functions.Function;
/**
* This class contains all neccessary information to connect to
* a database. This information (name of the driver, username, password
* and URL of the database) can be stored and retained from a
* property file. This class does not implement any security issues.
* The password is stored inside a String.
* <p>
* Example for a property file:
* <br><code><pre>
* driver=sun.jdbc.odbc.JdbcOdbcDriver
* url=jdbc:odbc:testdb
* askForPassword=false
* </pre></code>
*/
public class DatabaseAccess {
/**
* Function which asks the user for a password via the command line.
* The function returns the password as a String.
*/
public static Function<String,String> ASK_FOR_PW_CONSOLE = new AbstractFunction<String,String>() {
public String invoke(List<? extends String> list) {
System.out.print("No password availlable for datasource. Please enter password for user "+list.get(1)+": ");
BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
try {
return bf.readLine();
}
catch (Exception e) {
throw new WrappingRuntimeException(e);
}
}
};
/**
* The name of the class of the used JDBC-driver.
*/
private String classname;
/**
* The name of the user.
*/
private String username;
/**
* The password for the logon to the database.
*/
private String password;
/**
* The URL of the database.
*/
private String dburl;
/**
* A boolean flag that determines whether the user is asked for a password
* on the command line if no password is specified in the constructor call.
*/
private boolean askForPassword;
/**
* A function which asks the user to enter a password for the database. The
* function gets the url and the username as two parameters of type String.
*/
private Function<String,String> askForPasswordFunction;
/**
* Initialize the connection data explizitly.
*
* @param classname name of the class of the JDBC-driver
* @param username name of the user
* @param password password for the logon to the database
* @param dburl URL of the database
* @param askForPassword If no password is specified: should be asked for a
* password on the command line?
* @param askForPasswordFunction Function which asks the user to enter a password for
* the database. The function gets the url and the username as two parameters of type
* String.
*/
public DatabaseAccess(String classname, String username, String password, String dburl, boolean askForPassword, Function<String,String> askForPasswordFunction) {
this.classname = classname;
this.username = username;
this.password = password;
this.dburl = dburl;
this.askForPassword = askForPassword;
this.askForPasswordFunction = askForPasswordFunction;
}
/**
* Initialize the connection data explizitly.
*
* @param classname name of the class of the JDBC-driver
* @param username name of the user
* @param password password for the logon to the database
* @param dburl URL of the database
* @param askForPassword If no password is specified: should be asked for a
* password on the command line?
*/
public DatabaseAccess(String classname, String username, String password, String dburl, boolean askForPassword) {
this (classname, username, password, dburl, askForPassword, ASK_FOR_PW_CONSOLE);
}
/**
* Creates a DatabaseAccess object and initializes it with the data
* from a property file. The names of the properties have to be
* "driver", "user", "password", "url" and "askForPassword".
*
* @param fileName name of the file with the property information.
* @param askForPasswordFunction Function which asks the user to enter a password for
* the database. The function gets the url and the username as two parameters of type
* String.
* @return DatabaseAccess object created
*/
public static DatabaseAccess loadFromPropertyFile(String fileName, Function<String,String> askForPasswordFunction) {
Properties dbprop = new Properties();
// The password may not be in the set of properties ==> returns null
try {
dbprop.load(new FileInputStream(fileName));
String afp = dbprop.getProperty("askForPassword");
return new DatabaseAccess(
dbprop.getProperty("driver"),
dbprop.getProperty("user"),
dbprop.getProperty("password"),
dbprop.getProperty("url"),
afp==null? true: (Boolean.valueOf(dbprop.getProperty("askForPassword")).booleanValue()),
askForPasswordFunction
);
}
catch (IOException e) {
throw new WrappingRuntimeException(e);
}
}
/**
* Creates a DatabaseAccess object and initializes it with the data
* from a property file. The names of the properties have to be
* "driver", "user", "password", "url" and "askForPassword".
*
* @param fileName name of the file with the property information.
* @return DatabaseAccess object created
*/
public static DatabaseAccess loadFromPropertyFile(String fileName) {
return loadFromPropertyFile(fileName, ASK_FOR_PW_CONSOLE);
}
/**
* Stores the information about the connection in a property file.
*
* @param fileName Name of the property file
* @param header if this argument is not null, then an ASCII # character, the header string,
* and a line separator are first written to the output stream. Thus, this header can serve as
* an identifying comment.
*/
public void storePropertyFile(String fileName, String header) {
Properties dbprop = new Properties();
dbprop.setProperty("driver",classname);
dbprop.setProperty("user",username);
// The password may not be in the set of properties ==> returns null
if (password!=null && !askForPassword)
dbprop.setProperty("password",password);
dbprop.setProperty("url",dburl);
dbprop.setProperty("askForPassword",new Boolean(askForPassword).toString());
try {
dbprop.store(new FileOutputStream(fileName),header);
}
catch (IOException e) {
throw new WrappingRuntimeException(e);
}
}
/**
* Returns the Driver.
* @return a String with the driver.
*/
public String getDriver() { return classname; }
/**
* Returns the User.
* @return a String with the username.
*/
public String getUser() { return username; }
/**
* Returns the Password. If the password is null so far, the user is asked
* to enter a password on the command line.
* @return a String with the password.
*/
public String getPassword() {
if ((password==null) && askForPassword && askForPasswordFunction!=null) {
List<String> list = new ArrayList<String>();
list.add(dburl);
list.add(username);
return askForPasswordFunction.invoke(list);
}
else
return password;
}
/**
* Returns the URL.
* @return returns the URL
*/
public String getURLString() { return dburl; }
/**
* Returns a connection to the specified database. This Method might throw a {@link xxl.core.util.WrappingRuntimeException}.
* @return the connection to the database.
*/
public Connection getConnection() {
// Initialize and load the specified driver
try {
Class.forName (getDriver());
return DriverManager.getConnection(getURLString(),getUser(),getPassword());
}
catch (ClassNotFoundException e) {
throw new WrappingRuntimeException(e);
}
catch (SQLException e) {
throw new WrappingRuntimeException(e);
}
}
/**
* Returns the path where the database property-files are stored.
*
* @return String - the database property path
*/
public static String getPropsDataPath() {
return XXLSystem.getRootPath() + System.getProperty("file.separator") +
"data" + System.getProperty("file.separator") +
"databases" + System.getProperty("file.separator");
}
/**
* Converts the database access data into a String
* @return String containing the connection data.
*/
public String toString() {
return "DatabaseAccess:\nClassname: "+classname+"\nUser: "+username+"\nPassword: "+password+"\nURL: "+dburl;
}
}