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 entries = new HashMap(); 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()); } }