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.
602 lines
18 KiB
602 lines
18 KiB
package de.memtext.db; |
|
|
|
import java.lang.reflect.Constructor; |
|
import java.lang.reflect.InvocationTargetException; |
|
import java.math.BigDecimal; |
|
import java.sql.Connection; |
|
import java.sql.DatabaseMetaData; |
|
import java.sql.PreparedStatement; |
|
import java.sql.ResultSet; |
|
import java.sql.SQLException; |
|
import java.sql.Statement; |
|
import java.util.ArrayList; |
|
import java.util.Arrays; |
|
import java.util.HashMap; |
|
import java.util.Iterator; |
|
import java.util.LinkedList; |
|
import java.util.List; |
|
import java.util.Map; |
|
import de.memtext.baseobjects.NamedIdObject; |
|
import de.memtext.baseobjects.NamedIdObjectWithParent; |
|
import de.memtext.baseobjects.coll.NamedIdObjectList; |
|
import de.memtext.baseobjects.coll.NamedIdObjectWithParentList; |
|
import de.memtext.tree.KeyParentEqualException; |
|
import de.memtext.util.StringUtils; |
|
|
|
|
|
/** |
|
* This class faciliates access to databases. It offers easy standardized |
|
* access. To start with one has to call the create method with an existing |
|
* Connection to the database and a name for this connection. In other parts of |
|
* your programme database access is possible using |
|
* DBAccess.get("connectionname").function |
|
* |
|
* WICHTIG: Einige Methoden werden nicht für SuperX aber für Joolap benötigt, |
|
* daher nicht einfach entfernen. |
|
* |
|
* @author: MB |
|
*/ |
|
public class DBAccess { |
|
private String name; |
|
private Connection con = null; |
|
private Statement stmt = null; |
|
private boolean isInJar = false; |
|
private int updateCount; |
|
private static IllegalStateException illegalStateEx = new IllegalStateException( |
|
"DBAccess not inited - connection is null"); |
|
private static Map<String, DBAccess> entries = new HashMap<String, DBAccess>(); |
|
|
|
public static DBAccess get(String name) { |
|
DBAccess one = entries.get(name); |
|
if (one != null) { |
|
Connection con = one.getConnection(); |
|
try { |
|
if (con.isClosed()) { |
|
throw new RuntimeException("DBAccess: Connection already closed!"); |
|
} |
|
} catch (SQLException e) { |
|
throw new RuntimeException("DBAccess: Cannot check for closed connection.", e); |
|
} |
|
} |
|
return one; |
|
} |
|
|
|
public Connection getConn() { |
|
return con; |
|
} |
|
|
|
public static boolean hasConnection(String name) { |
|
return entries.containsKey(name); |
|
} |
|
|
|
/** |
|
* |
|
* when adding an hsqldb connection also notices from the url if the db is |
|
* inside a jar, can be questioned by isInJar() |
|
* |
|
* @param name |
|
* @param con |
|
* @throws SQLException |
|
* |
|
*/ |
|
public static void addConnection(String name, Connection con) throws SQLException { |
|
DBAccess dba = DBAccess.get(name); |
|
if (dba != null && !dba.getConnection().isClosed()) { |
|
// System.out.println("There is already an entry with the name " + name); |
|
} else { |
|
entries.put(name, new DBAccess(name, con)); |
|
} |
|
} |
|
|
|
public static void removeConnection(String name) throws SQLException { |
|
DBAccess dba = DBAccess.get(name); |
|
if (dba != null && !dba.getConnection().isClosed()) { |
|
dba.closeConnection(); |
|
entries.remove(name); |
|
} |
|
} |
|
|
|
public void closeConnection() throws SQLException { |
|
if (stmt != null) |
|
stmt.close(); |
|
con.close(); |
|
con = null; |
|
entries.remove(this); |
|
} |
|
|
|
static public void closeConnection(String name) throws SQLException { |
|
DBAccess.get(name).closeConnection(); |
|
} |
|
|
|
private DBAccess(String name, Connection con) throws SQLException { |
|
this.name = name; |
|
this.con = con; |
|
if (con.getMetaData().getDriverName().equals("HSQL Database Engine Driver") |
|
&& con.getMetaData().getURL().indexOf("res:") > 0) |
|
isInJar = true; |
|
stmt = con.createStatement(); |
|
} |
|
|
|
/** |
|
* Returns the java.sql.Connection with the given name. Normally get(name) |
|
* returns a DBAccess object this method is only used when the very Connection |
|
* is needed. |
|
* |
|
* @param name |
|
* @return |
|
*/ |
|
|
|
public Connection getConnection() { |
|
return con; |
|
} |
|
|
|
/** |
|
* WICHTIG: Einige Methoden werden nicht für SuperX aber für Joolap benötigt, daher nicht einfach entfernen. |
|
* @return |
|
*/ |
|
public boolean isInJar() { |
|
return isInJar; |
|
} |
|
|
|
public String getName() { |
|
return name; |
|
} |
|
|
|
/** |
|
* WICHTIG: Einige Methoden werden nicht für SuperX aber für Joolap benötigt, daher nicht einfach entfernen. |
|
* @return |
|
* @throws SQLException |
|
*/ |
|
public String getTableNames() throws SQLException { |
|
StringBuffer result = new StringBuffer("Tabellen in der Datenbank:"); |
|
DatabaseMetaData meta = con.getMetaData(); |
|
ResultSet rs = null; |
|
rs = meta.getTables(null, null, null, null); |
|
while (rs.next()) { |
|
result.append(rs.getObject(3) + " "); |
|
} |
|
rs.close(); |
|
return result.toString(); |
|
} |
|
|
|
public boolean hasTable(String tablename) throws SQLException { |
|
boolean result = false; |
|
ResultSet rs = con.getMetaData().getTables(null, null, null, null); |
|
while (rs.next()) { |
|
if (tablename.equalsIgnoreCase(rs.getObject(3).toString())) { |
|
result = true; |
|
break; |
|
} |
|
} |
|
rs.close(); |
|
return result; |
|
} |
|
|
|
public static boolean hasTable(Connection c, String tablename) throws SQLException { |
|
boolean result = false; |
|
ResultSet rs = c.getMetaData().getTables(null, null, null, null); |
|
while (rs.next()) { |
|
if (tablename.equalsIgnoreCase(rs.getObject(3).toString())) { |
|
result = true; |
|
break; |
|
} |
|
} |
|
rs.close(); |
|
return result; |
|
} |
|
|
|
/** |
|
* select key from blueprint; _> "1,2,3,4,5,6,7" |
|
* |
|
* WICHTIG: Einige Methoden werden nicht für SuperX aber für Joolap benötigt, |
|
* daher nicht einfach entfernen. |
|
* |
|
* @param sql separator is comma null is ignored |
|
* @throws SQLException |
|
*/ |
|
public StringBuffer getSeperatedString(String sql) throws SQLException { |
|
return getSeperatedString(sql, ","); |
|
} |
|
|
|
/** |
|
* select key from blueprint; _> "'1','2','3','4','5','6','7'" WICHTIG: Einige |
|
* Methoden werden nicht für SuperX aber für Joolap benötigt, daher nicht |
|
* einfach entfernen. |
|
* |
|
* @param sql |
|
* @param separator null is ignored |
|
* @throws SQLException |
|
*/ |
|
public StringBuffer getSeperatedString(String sql, String separator) throws SQLException { |
|
StringBuffer erg = new StringBuffer(); |
|
ResultSet result = stmt.executeQuery(sql); |
|
Object value; |
|
while (result.next()) { |
|
value = result.getObject(1); |
|
if (value == null) |
|
erg.append("null" + separator); |
|
else |
|
erg.append("'" + value + "'" + separator); |
|
} |
|
result.close(); |
|
|
|
if (erg.length() > 0) |
|
StringUtils.deleteLastChar(erg); |
|
return erg; |
|
} |
|
|
|
/** |
|
* WICHTIG: Einige Methoden werden nicht für SuperX aber für Joolap benötigt, |
|
* daher nicht einfach entfernen. |
|
* |
|
* @param pstSql |
|
* @param args |
|
* @return |
|
* @throws SQLException |
|
*/ |
|
public String getString(String pstSql, Object... args) throws SQLException { |
|
String erg = null; |
|
PreparedStatement pst = null; |
|
ResultSet rs = null; |
|
pst = this.con.prepareStatement(pstSql); |
|
int paramPos = 1; |
|
for (Object arg : args) { |
|
pst.setObject(paramPos, arg); |
|
paramPos++; |
|
} |
|
rs = pst.executeQuery(); |
|
while (rs.next()) { |
|
erg = rs.getString(1); |
|
break; |
|
} |
|
rs.close(); |
|
return erg; |
|
} |
|
|
|
public int execute(String sql) throws SQLException { |
|
if (con == null) |
|
throw illegalStateEx; |
|
updateCount = stmt.executeUpdate(sql); |
|
return updateCount; |
|
|
|
} |
|
|
|
public ResultSet executeQuery(String sql) throws SQLException { |
|
if (con == null) |
|
throw illegalStateEx; |
|
if (stmt != null) |
|
stmt.close(); |
|
stmt = con.createStatement(); |
|
ResultSet rs = stmt.executeQuery(sql); |
|
return rs; |
|
|
|
} |
|
|
|
/** |
|
* WICHTIG: Einige Methoden werden nicht für SuperX aber für Joolap benötigt, daher nicht einfach entfernen. |
|
* @param prefix |
|
* @return |
|
* @throws SQLException |
|
*/ |
|
public Object[] getTablesStartingWith(String prefix) throws SQLException { |
|
if (con == null) |
|
throw illegalStateEx; |
|
ArrayList list = new ArrayList(); |
|
ResultSet rs = con.getMetaData().getTables(null, null, prefix + "%", null); |
|
while (rs.next()) { |
|
list.add(rs.getString(3)); |
|
} |
|
rs.close(); |
|
Object[] result = list.toArray(); |
|
Arrays.sort(result); |
|
return result; |
|
} |
|
|
|
/** |
|
* Es wird einfach das erste Objekt der ersten Spalte genommen |
|
* WICHTIG: Einige Methoden werden nicht für SuperX aber für Joolap benötigt, daher nicht einfach entfernen. |
|
* @param sql |
|
* @return |
|
* @throws SQLException |
|
*/ |
|
public Double getDoubleValue(String sql) throws SQLException { |
|
Double val = null; |
|
ResultSet rs = executeQuery(sql); |
|
rs.next(); |
|
Object o = rs.getObject(1); |
|
rs.close(); |
|
if (o instanceof Double) |
|
val = (Double) o; |
|
else if (o instanceof java.math.BigDecimal) { |
|
BigDecimal merk = (BigDecimal) o; |
|
val = Double.valueOf(merk.doubleValue()); |
|
} else if (o != null) |
|
val = Double.valueOf(o.toString()); |
|
return val; |
|
} |
|
|
|
/** |
|
* Method hasColumn. can be problem for other databases. |
|
* WICHTIG: Einige Methoden werden nicht für SuperX aber für Joolap benötigt, daher nicht einfach entfernen. |
|
* @param aTablename |
|
* @param string |
|
* @return boolean |
|
* @throws SQLException |
|
*/ |
|
public boolean hasColumn(String aTablename, String colname) throws SQLException { |
|
if (con == null) |
|
throw illegalStateEx; |
|
boolean result = false; |
|
|
|
if (!hasTable(aTablename)) |
|
throw new IllegalArgumentException("Database doesn't contain table " + aTablename); |
|
// Hsql had problems with metadata stuff |
|
ResultSet rs = con.getMetaData().getColumns(null, null, aTablename.toUpperCase(), colname.toUpperCase()); |
|
// ResultSetMetaData rsmd = rs.getMetaData(); |
|
// int numberOfColumns = rsmd.getColumnCount(); |
|
while (rs.next()) { |
|
// wenn etwas gefunden wurde, gibt's die Spalte |
|
result = true; |
|
} |
|
rs.close(); |
|
return result; |
|
|
|
} |
|
|
|
public int getInt(String query, Object... args) throws SQLException { |
|
Integer result = getInteger(query, args); |
|
if (result == null) |
|
throw new RuntimeException("nothing or null found"); |
|
return result.intValue(); |
|
} |
|
|
|
/* |
|
* If more than one value is found, only considers the first |
|
*/ |
|
public Integer getInteger(String pstSQL, Object... args) throws SQLException { |
|
Integer erg = null; |
|
PreparedStatement pst = null; |
|
ResultSet rs = null; |
|
pst = this.con.prepareStatement(pstSQL); |
|
int paramPos = 1; |
|
for (Object arg : args) { |
|
pst.setObject(paramPos, arg); |
|
paramPos++; |
|
} |
|
rs = pst.executeQuery(); |
|
Object o = null; |
|
boolean isFirst = true; |
|
while (rs.next()) { |
|
if (isFirst) { |
|
o = rs.getObject(1); |
|
isFirst = false; |
|
} |
|
} |
|
if (o != null) { |
|
if (o instanceof Integer) |
|
erg = (Integer) o; |
|
else if (o instanceof Long) |
|
erg = Integer.valueOf(((Long) o).intValue()); |
|
else if (o instanceof Short) |
|
erg = Integer.valueOf(((Short) o).intValue()); |
|
else { |
|
throw new IllegalArgumentException( |
|
"Unbekannter Datentyp in DBAccess getInteger:" + o.getClass() + " - " + pstSQL); |
|
|
|
} |
|
} |
|
rs.close(); |
|
return erg; |
|
} |
|
|
|
/** |
|
* WICHTIG: Einige Methoden werden nicht für SuperX aber für Joolap benötigt, daher nicht einfach entfernen. |
|
* @return |
|
* @throws SQLException |
|
*/ |
|
public List getTableList() throws SQLException { |
|
if (con == null) |
|
throw illegalStateEx; |
|
List result = new LinkedList(); |
|
ResultSet rs = con.getMetaData().getTables(null, null, null, null); |
|
while (rs.next()) { |
|
result.add(rs.getObject(3).toString()); |
|
} |
|
rs.close(); |
|
return result; |
|
} |
|
|
|
/** |
|
* WICHTIG: Einige Methoden werden nicht für SuperX aber für Joolap benötigt, |
|
* daher nicht einfach entfernen. |
|
* |
|
* @param sql |
|
* @return List in LIst!! |
|
* @throws SQLException |
|
*/ |
|
public List getResultList(String sql) throws SQLException { |
|
List result = new LinkedList(); |
|
ResultSet rs = executeQuery(sql); |
|
result = DbUtils.toResultList(rs); |
|
rs.close(); |
|
return result; |
|
} |
|
|
|
/** |
|
* Hsql needs uppercase! |
|
* WICHTIG: Einige Methoden werden nicht für SuperX aber für Joolap benötigt, daher nicht einfach entfernen. |
|
* @throws SQLException |
|
*/ |
|
public int getColumnType(String tablename, String colname) throws SQLException { |
|
int result = -9999; |
|
if (!hasTable(tablename)) |
|
throw new RuntimeException("Database doesn't contain table " + tablename); |
|
if (!hasColumn(tablename, colname)) |
|
throw new RuntimeException("Table " + tablename + " doesn't have column:" + colname); |
|
ResultSet rs = con.getMetaData().getColumns(null, null, tablename.toUpperCase(), colname.toUpperCase()); |
|
while (rs.next()) { |
|
result = rs.getInt(5); |
|
} |
|
rs.close(); |
|
return result; |
|
} |
|
|
|
/* |
|
* WICHTIG: Einige Methoden werden nicht für SuperX aber für Joolap benötigt, daher nicht einfach entfernen. |
|
*/ |
|
public int getColumnCount(String tablename) throws SQLException { |
|
int result = 0; |
|
if (!hasTable(tablename)) |
|
throw new RuntimeException("Database doesn't contain table " + tablename); |
|
ResultSet rs = con.getMetaData().getColumns(null, null, tablename.toUpperCase(), null); |
|
while (rs.next()) { |
|
result++; |
|
} |
|
rs.close(); |
|
return result; |
|
} |
|
|
|
/** |
|
* Hsql needs uppercase! |
|
* WICHTIG: Einige Methoden werden nicht für SuperX aber für Joolap benötigt, daher nicht einfach entfernen. |
|
* @throws SQLException |
|
*/ |
|
public List getColumnNames(String tablename) throws SQLException { |
|
List result = new LinkedList(); |
|
if (!hasTable(tablename)) |
|
throw new RuntimeException("Database doesn't contain table " + tablename); |
|
ResultSet rs = con.getMetaData().getColumns(null, null, tablename.toUpperCase(), null); |
|
while (rs.next()) { |
|
result.add(rs.getObject(4).toString()); |
|
} |
|
rs.close(); |
|
return result; |
|
} |
|
|
|
/** |
|
* Method executeAndCheckUpdate1Row. |
|
* WICHTIG: Einige Methoden werden nicht für SuperX aber für Joolap benötigt, daher nicht einfach entfernen. |
|
* @param string |
|
* @throws SQLException |
|
*/ |
|
public void executeAndCheckUpdate1Row(String sql) throws SQLException { |
|
int updateRowCount = execute(sql); |
|
if (updateRowCount != 1) |
|
throw new IllegalStateException("Es wurde nicht 1 Zeile geupdated, sondern " + updateRowCount); |
|
} |
|
|
|
/** |
|
* Sets a property in the properties table of a db WICHTIG: Einige Methoden |
|
* werden nicht für SuperX aber für Joolap benötigt, daher nicht einfach |
|
* entfernen. |
|
* |
|
* @param key |
|
* @param value |
|
* @throws SQLException |
|
*/ |
|
public void setProperty(String key, String value) throws SQLException { |
|
if (key == null || value == null) |
|
throw new IllegalArgumentException("no nulls allowed in properties table"); |
|
execute("delete from properties where name='key';insert into properties (name,value) values('" + key + "','" |
|
+ value + "');"); |
|
} |
|
|
|
/** |
|
* Gets a property from the properties table WICHTIG: Einige Methoden werden |
|
* nicht für SuperX aber für Joolap benötigt, daher nicht einfach entfernen. |
|
* |
|
* @param key |
|
* @return String - null if nothing found |
|
* @throws SQLException |
|
*/ |
|
public String getProperty(String key) throws SQLException { |
|
return getString("select value from properties where name='" + key + "'"); |
|
} |
|
|
|
/** |
|
* creates a java.util.List with NamedIDObjects from a table in the database |
|
* WICHTIG: Einige Methoden werden nicht für SuperX aber für Joolap benötigt, |
|
* daher nicht einfach entfernen. |
|
* |
|
* @param tablename - name of the source table |
|
* @param idColName - name of the ID column in the table (e.g. tid) |
|
* @param nameColName - name of the name column in the table (e.g. name or text) |
|
* @param restriction - optionally a restriction like "where id>2" may be null |
|
* @return NamedIdObjectList |
|
|
|
*/ |
|
public NamedIdObjectList getNamedIdObjectList(String tablename, String idColName, String nameColName, |
|
String restriction, String orderby, Class targetClass) |
|
throws SecurityException, NoSuchMethodException, IllegalArgumentException, InstantiationException, |
|
IllegalAccessException, InvocationTargetException, SQLException { |
|
NamedIdObjectList result = new NamedIdObjectList(); |
|
if (restriction == null) |
|
restriction = ""; |
|
Object id; |
|
String name; |
|
List rawList = getResultList( |
|
"select " + idColName + "," + nameColName + " from " + tablename + " " + restriction + " " + orderby); |
|
Class[] constparams = { Object.class, String.class }; |
|
Object[] data = new Object[2]; |
|
Constructor constr = targetClass.getConstructor(constparams); |
|
for (Iterator it = rawList.iterator(); it.hasNext();) { |
|
List row = (List) it.next(); |
|
id = row.get(0); |
|
name = ""; |
|
if (row.get(1) != null) |
|
name = row.get(1).toString(); |
|
data[0] = id; |
|
data[1] = name; |
|
Object o = constr.newInstance(data); |
|
result.add(o); |
|
} |
|
return result; |
|
} |
|
|
|
/** |
|
* WICHTIG: Einige Methoden werden nicht für SuperX aber für Joolap benötigt, |
|
* daher nicht einfach entfernen. |
|
* |
|
* @param tablename |
|
* @param idColName |
|
* @param nameColName |
|
* @param restriction |
|
* @param orderby |
|
|
|
*/ |
|
public NamedIdObjectList getNamedIdObjectList(String tablename, String idColName, String nameColName, |
|
String restriction, String orderby) throws IllegalArgumentException, SQLException, SecurityException, |
|
NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException { |
|
NamedIdObjectList result = null; |
|
result = getNamedIdObjectList(tablename, idColName, nameColName, restriction, orderby, NamedIdObject.class); |
|
return result; |
|
} |
|
|
|
public NamedIdObjectWithParentList getNamedIdObjectWithParentList(String tablename, String idColName, |
|
String nameColName, String restriction) throws KeyParentEqualException, SQLException { |
|
NamedIdObjectWithParentList result = new NamedIdObjectWithParentList(); |
|
if (restriction == null) |
|
restriction = ""; |
|
Object id; |
|
String name; |
|
Object parentKey; |
|
NamedIdObjectWithParent one; |
|
List rawList = getResultList( |
|
"select " + idColName + "," + nameColName + ",parent from " + tablename + " " + restriction); |
|
for (Iterator it = rawList.iterator(); it.hasNext();) { |
|
List row = (List) it.next(); |
|
id = row.get(0); |
|
name = ""; |
|
if (row.get(1) != null) |
|
name = row.get(1).toString(); |
|
parentKey = row.get(2); |
|
one = new NamedIdObjectWithParent(id, name, parentKey); |
|
result.add(one); |
|
} |
|
return result; |
|
} |
|
|
|
public void execute(StringBuffer sql) throws SQLException { |
|
execute(sql.toString()); |
|
} |
|
} |