/*
* This software and supporting documentation were developed by
*
* Siemens Corporate Technology
* Competence Center Knowledge Management and Business Transformation
* D-81730 Munich, Germany
*
* Authors (representing a really great team ;-) )
* Stefan B. Augustin, Thorbj�rn Hansen, Manfred Langen
*
* This software is Open Source under GNU General Public License (GPL).
* Read the text of this license in LICENSE.TXT
* or look at www.opensource.org/licenses/
*
* Once more we emphasize, that:
* THIS SOFTWARE IS MADE AVAILABLE, AS IS, WITHOUT ANY WARRANTY
* REGARDING THE SOFTWARE, ITS PERFORMANCE OR
* FITNESS FOR ANY PARTICULAR USE, FREEDOM FROM ANY COMPUTER DISEASES OR
* ITS CONFORMITY TO ANY SPECIFICATION. THE ENTIRE RISK AS TO QUALITY AND
* PERFORMANCE OF THE SOFTWARE IS WITH THE USER.
*
*/
// KfmTransientDBTable2
package KFM.DB;
// KFM packages
import KFM.Exceptions.KFM_SQLException;
import KFM.Exceptions.ProgrammerException;
import KFM.log.*;
// java packages
import java.lang.Integer;
import java.sql.*;
import java.util.*;
/** A better `TransientDBTable� with support for iterators
* and with access by column name rather than by column position.
*
* <P>`KfmTransientDBTable� improves `TransientDBTable� in two ways. Firstly, it supports
* iterators, which are objects of the class `DbTagValueIterator2� (yes, the naming is unfortunate).
* Secondly, it has access by column name rather than by column position.</P>
*
* Change by KS, 13.3.2000 <BR>
* Added a method to set values.
*
* @author ThH, 04.03.99
*/
public class KfmTransientDBTable2 /*extends TransientDBTable*/
{
//
// Variables
//
/** For internal fetching of data from db. */
private TransientDBTable2 mTable = new TransientDBTable2();
/** Set of DbTagIterators which currently scan this table. */
private Hashtable mCurrentIterators = new Hashtable();
/** This id is needed for creating the next unique iterator id. */
long mNextIteratorId = 0;
/** Connection to communicate with the database - also needed for creating new iterators. */
private KFM_Database mDB;
/** Needed for creating new iterators. */
private String[] colNames;
/** Map column names to column numbers. */
protected Hashtable colNameToNumber; // String -> Integer // You cannot put an `int� into a `Hashtable�.
//
// Methoden
//
public KfmTransientDBTable2 (String[] ccolNames, KFM_Database aDB)
{
colNames = ccolNames;
mDB = aDB;
colNameToNumber = new Hashtable();
for(int i = 0; i < colNames.length; ++i) {
// Note: Array indices are 0-based, column numbers are 1-based.
colNameToNumber.put(colNames[i], new Integer(i+1));
}
}
public void finalize()
throws Throwable
{
invalidateAllIterators();
}
/** L�dt eine Datenbank-Tabelle in den Speicher dieses Objektes.
*
* @param sql Eine g�ltige sql-Anweisung
*/
public void loadTable (String sql)
throws KFM_SQLException
{
//X long tTime = System.currentTimeMillis();
mTable = new TransientDBTable2();
try {
mTable.loadTable(sql, mDB/*.getConnection()*/);
}
catch(ProgrammerException e){
throw new ProgrammerException(
"KfmTransientDBTable2::loadTable: getConnection() produced exception " + e.getMessage());
}
invalidateAllIterators();
//X tTime = System.currentTimeMillis() - tTime;
//X KFMSystem.log.info("loaded " + sql + " in " + tTime + " msec. (size: " + mTable.size() + ")");
}
/** Appends a database table to the memory of this object.
*
* @param sql Eine g�ltige sql-Anweisung
*/
public void appendTable (String sql)
throws KFM_SQLException
{
//X long tTime = System.currentTimeMillis();
if (mTable == null)
mTable = new TransientDBTable2();
try {
mTable.appendTable(sql, mDB /*.getConnection()*/);
}
catch(ProgrammerException e){
throw new ProgrammerException(
"KfmTransientDBTable2::appendTable: getConnection() produced exception " + e.getMessage());
}
invalidateAllIterators();
//X tTime = System.currentTimeMillis() - tTime;
//X KFMSystem.log.info("loaded " + sql + " in " + tTime + " msec. (size: " + mTable.size() + ")");
}
/*
public boolean loadTable (String sql, String[] colNames, Connection con)
{
colNameToNumber = new Hashtable();
for(int i = 0; i < colNames.length; ++i) {
// Note: Array indices are 0-based, column numbers are 1-based.
colNameToNumber.put(colNames[i], new Integer(i+1));
}
long tTime = System.currentTimeMillis();
boolean ret = mTable.loadTable(sql, con);
tTime = System.currentTimeMillis() - tTime;
KFMSystem.log.info("loaded " + sql + " in " + tTime + " msec.");
return ret;
}
*/
/** Check whether a colname exists.
*
* @return True iff `aColName� is a valid colname.
*/
public boolean isColName (String aColName)
{
final Object obj = colNameToNumber.get(aColName);
return (obj != null);
}
/**
* Get from table by row number and column name, returning a String or null.
* If the column name is invalid, a ProgrammerException is thrown.
*
* @return String oder null
*
* @see getString
*
* @exception ProgrammerException
* When the colname does not exist. Do not try to catch this exception,
* use `isColName� instead.
*/
public String get (int rowNr, String colName)
{
final Object obj = colNameToNumber.get(colName);
if(obj == null) {
throw new ProgrammerException("KfmTransientDBTable2: colName '" + colName + "' does not exist.");
}
final int colNr = ((Integer) obj).intValue();
return mTable.get(rowNr, colNr);
}
/**
* Get from table by row number and column name, always returning a string ("" if DB value is NULL).
* If the column name is invalid, a ProgrammerException is thrown.
*
* @return Always return a String.
* @see get
*/
public String getString(int rowNr, String colName)
{
String ret = get(rowNr, colName);
if ((null == ret)||(ret.trim().equalsIgnoreCase("NULL")))
ret = "";
else ret = ret.trim();
return ret;
}
/**
* Set a value in the table by row number and column name.
*
* If the column name is invalid, a ProgrammerException is thrown.
* If the row number is greater than the actual size, new (empty) rows are added.
*
* @param rowNr the row number for the new value, first row has index 0
* @param colName the name of the column for the new value
* @param value the value (as a String) to be set
*/
public void set (int rowNr, String colName, String value)
{
final Object obj = colNameToNumber.get(colName);
if(obj == null) {
throw new ProgrammerException("KfmTransientDBTable2: colName '" + colName + "' does not exist.");
}
final int colNr = ((Integer) obj).intValue();
mTable.set (rowNr, colNr, value);
}
/**
* @return number of rows which are currently loaded
*/
public int size()
{
return mTable.size();
}
/**
* This is needed for identifying it again while disconnecting
* @return id for this iterator
*/
synchronized String connectIterator(DbTagValueIterator2 aIterator)
{
// increase the id
mNextIteratorId++;
// TODO: later the ids may not be enough. In this case use the date and
// time as prefix
// insert here
String tIteratorIdString = Long.toString(mNextIteratorId);
mCurrentIterators.put(tIteratorIdString, aIterator);
// tell iterator its id
return tIteratorIdString;
}
/**
* This is needed for identifying it again while disconnecting
* @return id for this iterator
*/
synchronized void disconnectIterator(String id)
{
if ( ! mCurrentIterators.containsKey(id))
throw new ProgrammerException("KfmTransientDBTaBLE2.disconnect() - wrong iterator id");
mCurrentIterators.remove(id);
}
public synchronized void invalidateAllIterators()
{
//X String tStr = "";
for (Enumeration tEnum = mCurrentIterators.elements(); tEnum.hasMoreElements();)
{
((DbTagValueIterator2) tEnum.nextElement()).invalidate();
//X tStr += ".";
}
//X KFMSystem.log.info("Invalidating all Iterators" + tStr);
}
/** Sorts the table after a column.
*
* Note by ThH: This method was added by HS on 1999-06-24.
* He did not know that KfmTransientDBTable2 should use *names* (Strings) instead of position (ints)
* to access the columns, so he just copied the signature of `TransientDBTable2.sort�.
*
* See also `TransientDBTable2.sort�.
*
* @param aColumnToSort
* Column to be sorted, starting with 1.
* E.g. if you want to access the first column, use aColumnToSort=1.
* New: Now a name!
* @param aTypeToSort
* Type of the column which should be sorted. Use <br>
* aTypeToSort=1 for int <br>
* aTypeToSort=2 for String
* @param aSortDirection
* Chooses sort direction: ascending or descending. Use<br>
* direction=1 for ascending<br>
* direction=2 for descending
* @return false if any problem did occur, true else
*
* @see TransientDBTable2#sort(int, int, int)
*/
public synchronized boolean sort (
String aColumnToSort,
int aTypeToSort,
int aSortDirection)
{
final Object obj = colNameToNumber.get(aColumnToSort);
if(obj == null) {
throw new ProgrammerException("KfmTransientDBTable2: colName '" + aColumnToSort+ "' does not exist.");
}
final int colNr = ((Integer) obj).intValue();
// Call sort methode from TransientDBTable2.
return mTable.sort(colNr, aTypeToSort, aSortDirection );
}
/** Sorts the table after a column and eliminates duplicates.
* Two rows are considered as duplicates if aColumnToSort has the same value fo them.
*
* @param aColumnToSort
* Name of the column to be sorted
* @param aTypeToSort
* Type of the column which should be sorted. Use <br>
* aTypeToSort=1 for int <br>
* aTypeToSort=2 for String
* @param aSortDirection
* Chooses sort direction: ascending or descending. Use<br>
* direction=1 for ascending<br>
* direction=2 for descending
* @return false if any problem did occur, true else
*
* @see TransientDBTable2#sortAndUnique(int, int, int)
*/
public synchronized boolean sortAndUnique (
String aColumnToSort,
int aTypeToSort,
int aSortDirection)
{
final Object obj = colNameToNumber.get(aColumnToSort);
if(obj == null) {
throw new ProgrammerException("KfmTransientDBTable2: colName '" + aColumnToSort+ "' does not exist.");
}
final int colNr = ((Integer) obj).intValue();
// Call sortAndUnique method from TransientDBTable2.
return mTable.sortAndUnique(colNr, aTypeToSort, aSortDirection );
}
/** Eliminates duplicates from the presorted table.
* Two adjacent rows are considered as duplicates if aColumnToSort has the same value fo them.
*
* @param aColumnToSort
* Name of the column for which duplicates are to be eliminated
* @return false if any problem did occur, true else
*
* @see TransientDBTable2#uniqueAfterSort(int)
*/
public synchronized boolean uniqueAfterSort (
String aColumnToSort)
{
final Object obj = colNameToNumber.get(aColumnToSort);
if(obj == null) {
throw new ProgrammerException("KfmTransientDBTable2: colName '" + aColumnToSort+ "' does not exist.");
}
final int colNr = ((Integer) obj).intValue();
// Call uniqueAfterSort method from TransientDBTable2.
return mTable.uniqueAfterSort(colNr);
}
/** Eliminates duplicates from the presorted table.
* Two adjacent rows are considered as duplicates if both aColumnToSort1 and aColumnToSort1 have the same value fo them.
*
* Note: This is an intermediate method for the time until this class (and TransientDBTable2) are refactored
* concerning their sort and unique behavior.
*
* @param aColumnToSort1
* Name of the first column for which duplicates are to be eliminated
* @param aColumnToSort2
* Name of the second column for which duplicates are to be eliminated
* @return false if any problem did occur, true else
*
* @see TransientDBTable2#uniqueAfterSort(int, int)
*/
public synchronized boolean uniqueAfterSort (
String aColumnToSort1,
String aColumnToSort2)
{
final Object obj1 = colNameToNumber.get(aColumnToSort1);
if(obj1 == null) {
throw new ProgrammerException("KfmTransientDBTable2: colName '" + aColumnToSort1+ "' does not exist.");
}
final Object obj2 = colNameToNumber.get(aColumnToSort2);
if(obj2 == null) {
throw new ProgrammerException("KfmTransientDBTable2: colName '" + aColumnToSort2+ "' does not exist.");
}
final int colNr1 = ((Integer) obj1).intValue();
final int colNr2 = ((Integer) obj2).intValue();
// Call uniqueAfterSort method from TransientDBTable2.
return mTable.uniqueAfterSort(colNr1, colNr2);
}
/* Gets the table used for getting data from the database */
public TransientDBTable2 getInternalTable(){
return mTable;
}
}