/*
* 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.
*
*/
// AttributedTableView
// ************ package ******************************************************
package appl.Portal.DB;
// ************ imports ******************************************************
import KFM.Exceptions.KFM_SQLException;
import KFM.DB.*;
import KFM.Converter;
import java.util.*;
import java.sql.*;
/** AttributedTableView allows to access all attributes of a DB table entry
* that can have inlined, dedicated and hashed attributes.
*
* <P>See the DB scheme of tables 'Link' and 'Category' for an example.
* For further explanation of inlined, dedicated and hashed attributes see ???.</P>
*
*
* <H2>Usage</H2>
*
* <H3>Scenario 1: Nested loop</H3>
*
* <P>The typical usage might be that of a nested loop (or iteration).
* The <B>outer loop</B> iterates through all entries of a given DB table
* (the one with the inlined attributes).
* For one given entry of the outer loop, the <B>inner loop</B> then iterates
* through all of its attributes (inlined, dedicated, hashed).</P>
*
* <P>Here's an example:</P>
*
* <PRE>
* AttributesContainer tAttrCont = LinkView.getAttributesContainer();
* LinkView tView = new LinkView(mDbA);
* AttributedTableView tAttrView = new AttributedTableView("Link", tAttrCont, mDbA);
* tView.loadAllLinkIDs ();
* tView.reset();
* while(tView.next()) {
* String tLinkId = tView.get("ID");
* tAttrView.loadById(tLinkId);
* tAttrView.reset();
* while(tAttrView.next()) {
* Attribute tAttr = tAttrView.getAttribute();
* String tValue = tAttrView.getAttributeValue();
* ...
* }
* }
* </PRE>
*
*
* <H3>Scenario 2: No outer iterator</H3>
*
* <P>There is, however, also the need to get all possible attributes for a given entry ID
* without having an outer iterator. This forbids coupling this class (or its
* subclasses) to tightly to the outer iterators.</P>
*
* <P>Here's an example:</P>
*
* <PRE>
* AttributesContainer tAttrCont = LinkView.getAttributesContainer();
* AttributedTableView tAttrView = new AttributedTableView("Link", tAttrCont, mDbA);
* // Get attribute info about the Link with ID 1020
* tAttrView.loadById("1020");
* tAttrView.reset();
* while(tAttrView.next()) {
* Attribute tAttr = tAttrView.getAttribute();
* String tValue = tAttrView.getAttributeValue();
* ...
* }
* </PRE>
*
* <H3>Scenario 3: access attributes by name</H3>
*
* <P>Instead of iterating through all the attributes with reset() and next(),
* we might need to access individual attributes by name (i.e. in a random access manner).
* Any class that implements interface LinkSearch.ResultSetItem (for database access) might need that.
* Therefore, we introduced methods getAllAttributeNames(), getAttributeValueOf(Name),
* getAllAttributeValuesOf(Name).</P>
*
* <P>Here's an example:</P>
*
* <PRE>
* AttributesContainer tAttrCont = LinkView.getAttributesContainer();
* LinkView tView = new LinkView(mDbA);
* AttributedTableView tAttrView = new AttributedTableView("Link", tAttrCont, mDbA);
* tView.loadAllLinkIDs ();
* tView.reset();
* while(tView.next()) {
* String tLinkId = tView.get("ID");
* tAttrView.loadById(tLinkId);
* String tTitle = tAttrView.getAttributeValueOf("Title"); // this one is inlined
* String tAuthor = tAttrView.getAttributeValueOf("SourceAuthor"); // this one is hashed
* String tContent = tAttrView.getAttributeValue("Content"); // this one is dedicated
* String tFirstKeyword = tAttrView.getAttributeValue("Keyword"); // this one is dedicated
* String[] tAllKeywords = tAttrView.getAllAttributeValuesOf("Keyword"); // this one is dedicated
* ...
* }
* }
* </PRE>
*
* <H2>Issues for future improvement</H2>
*
* <UL>
* <LI> Find a better name for the class. It's meaning is still not
* evident. Worse, because of the View part in the name it implies
* a close resemblence to a 'normal' View. But this class is not good
* for iterating through all entries of a table, but for iterating
* through all attributes of a table entry. (what about EntryAttributesView ?)</LI>
* <LI> Extend the class to allow for writing attributes into a View entry.
* Right now, this class is for read-only access. </LI>
* <LI> Introduce methods seek(aName) and seek(aAttr) that allow to position the cursor
* to the place where the attribute given (either by its Attribute or by its name)
* is found. </LI>
* <LI> Subclass AttributedTableView to provide an implementation using a
* more efficient 'lazy loading' mechanism, i.e. inlined, hashed or dedicated
* attributes are only loaded when they are accessed for the first time.
* A possible name for that subclass: AttributedTableView_Lazy.</LI>
* </UL>
*
* This issue was dropped:
* <UL>
* <LI> Establish a closer relationship with the View class that delivers
* the IDs for method loadByID(). This could happen by constructing
* AttributedTableView with an instance of that 'outer' View class.
* Later on, these two objects can exchange information about their common
* understanding of DatabaseAdapter, TableName, AttributesContainer, etc. <BR>
* (see scenario 2 above for explanation why this was dropped)
* </LI>
* </UL>
*
* @see Attribute
* @see AttributesContainer
*
* @author KS (Design by ThH), 08.03.2000
* @version 1.0 (2000-04-28), ready, more efficient version of loadIdInlined()<br>
* version 0.5 (2000-03-13), ready, but rather inefficient<br>
* version 0.1 (2000-03-08), first shot
*/
public class AttributedTableView extends View
{
// ************************************************************
// Variables
// ************************************************************
/** The column names we use to store all attributes within inherited kfmTable. */
static final private String[] mSelects2 = {
"Name",
"Value"
};
/** The database adapter for access to the DB. */
protected KFM_JdbcAdapter mDbA;
/** The AttributesContainer describing all possible attributes. */
protected AttributesContainer mAttrCont;
/** The name of the DB table with the inlined attributes.
*
* It will be provided when constructing objects of this class.
*/
protected String mTableNameInlined;
/** The prefix of the DB table names that contain the hashed / dedicated attributes.
*
* This is normally the same as mTableNameInlined, but can also be set to something else.
*/
protected String mTableNameHashedDedicated_Prefix;
/** The name of the ID field within the DB tables that contain the hashed / dedicated attributes.
*
* This is normally the table name of the inlined attributes suffixed with "_ID",
* but can also be set to something else.
*/
protected String mIDfieldHashedDedicated;
/** Separator to construct DB table names. */
static protected final String mTableNameSeparator = "_";
/** Suffix of the DB Table with the hashed attributes. */
static final protected String mTableNameHashed_Suffix = "Attribute";
/** A container to store (for the loaded entry within kfmTable) a mapping
* of attribute names to row positions.
*
* We use this mapping for reasons of efficiency.
* For each attribute present, the Hashtable's key is the attribute and the
* Hashtable's value is an Integer indicating the row number within kfmTable,
* where the ocurrence of that attribute is contained
* (with multi-value attributes it is the first ocurrence).
*/
protected Hashtable mAttrMapping = new Hashtable();
/** The ID of the database entry currently loaded.
*
* It is provided as argument to loadById() and used by the sub-methods of loadById().
*/
protected String mID;
/** The outer iterator that should be used if provided within the appropriate constructor. */
protected View mOuterView = null;
/** The array of IDs to identify all the PreparedStatement used within loadByIdDedicated().
*
* ThH: In earlier versions, the PreparedStatements were kept open.
* But as it is unclear whether they got closed early enough, they now are closed
* immediately. That's how it is everywhere else.
*/
protected int[] mDedicatedSQLCmds = null;
/** The ID to identify the PreparedStatement used within loadByIdHashed().
*
* ThH: See `mDedicatedSQLCmds�.
*/
protected int mHashedSQLCmd = -1;
// ************************************************************
// Methods
// ************************************************************
/** Construct an instance of AttributedTableView without an outer view (scenario 2).
*
* <P>It will operate on a DB table with a given name (and its related tables for dedicated
* and hashed attributes).
* The possible attributes of all these tables are described by an AttributesContainer.
* Database access will be gained by the KFM_JdbcAdapter object provided.</P>
*
* @param aTableName the name of the table (with the inlined attributes)
* @param aAttrCont the AttributesContainer describing all attributes
* @param aDbA the database adapter for access to the DB
*/
public AttributedTableView (
String aTableName,
AttributesContainer aAttrCont,
KFM_JdbcAdapter aDbA)
throws KFM_SQLException
{
super(mSelects2, aDbA.getDatabase());
mTableNameInlined = aTableName;
mTableNameHashedDedicated_Prefix = aTableName;
mIDfieldHashedDedicated = mTableNameInlined + "_ID";
mDbA = aDbA;
mAttrCont = aAttrCont;
}
/** Construct an instance of AttributedTableView with an outer view (scenario 1).
*
* <P>It will operate on a DB table with a given name (and its related tables for dedicated
* and hashed attributes).
* The possible attributes of all these tables are described by an AttributesContainer.
* Database access will be gained by the KFM_JdbcAdapter object provided.</P>
*
* <P>It additionally gets a reference to the View class (a View) that
* serves as the outer iterator (see usage scenario 1 above).
* By knowing this outer iterator, we can implement the loading of the inlined attributes
* much more efficient.
* Reason: We don't perform a separate SQL statement for them within loadByIdInlined(), but rely
* on the attributes being present in the outer iterator (so we perform a get() on it).</P>
*
* @param aTableName the name of the table (with the inlined attributes)
* @param aAttrCont the AttributesContainer describing all attributes
* @param aDbA the database adapter for access to the DB
* @param anOuterView the View that serves as the outer iterator
*/
public AttributedTableView (
String aTableName,
AttributesContainer aAttrCont,
KFM_JdbcAdapter aDbA,
View aOuterView)
throws KFM_SQLException
{
this(aTableName, aAttrCont, aDbA);
mOuterView = aOuterView;
}
/** Load all attributes (inlined, dedicated, hashed) for an entry with a given ID.
*
* <P>This is the place where the central logic of this class is placed.</P>
*
* <P>Technical note 1:
* You should not make any assumptions about the order of the attributes
* (e.g. that inlined attributes come first, then hashed etc.). Subclasses
* may prefer to change the order preferred by this class. <BR>
* In this class, there is a reliable order, however, which is as follows:
* The attributes (when iterated through with next) are ordered as follows:
* First, all inlined attributes
* Second, all hashed attributes
* Third, all dedicated attributes
* Inside one of these groups, the order is determined by the AttributesContainer.
* If a dedicated attribute is present more than once, all occurences of that are adjacent.</P>
*
* <P>Technical note 2:
* This method was rather long in the first place, therefore we divided it into 5 smaller methods.
* This conforms to the Composed Method Pattern of Kent Beck.</P>
*
* <P>Open issue: What about tables with a primary key consisting of more than one attribute?
* Is this method better placed into table-specific subclasses?
* ThH: Not currentyl needed.</P>
*
* @param aID The primary key value of the table with the inline attributes.
* @exception KFM_SQLException can be thrown on database read problems.
*/
public void loadById (String aID)
throws KFM_SQLException
{
// * Preparation
// Construct all the PreparedStatements used within loadByIdDedicated() and loadByIdHashed()
this.prepareAllStatements();
// Store ID in member variable to avoid passing it as an argument to each of
// the sub-methods below.
mID = aID;
// * Main stuff
//
// How this method (implemented within sub-methods) works:
// ---------------------------------------------------------
//
// There are 3 major steps: retrieving the inlined, hashed and detailed attributes.
// To do so, we issue several SQL statements, that place their result into an intermediate
// TransientDBTable. We then fold all these results into a single Container
// (the inherited kfmTable) which has two columns called 'Name' and 'Value'.
// That is: Each attribute retrieved becomes a single row within kfmTable.
//
// On the way, we also maintain a hashtable (mAttrMapping) to allow for a faster mapping
// of attributes to kfmTable's row indices later on.
// Call the sub-methods
this._loadByIdPrologue();
this._loadByIdInlined();
this._loadByIdHashed();
this._loadByIdDedicated();
this._loadByIdEpilogue();
// We made it. Attribute names and values are now stored in kfmTable.
// mAttrMapping additionally contains the row indices for all attributes.
//
// Subsequent calls of getAllAttributeValuesOf(), getAttributeValueOf() or getAllAttributeNames()
// allow accessing them in a random access manner.
//
// Subsequent calls of reset(), next(), getAttribute() and getAttributeValue()
// allow accessing them in a serialized (iterator-like) manner.
// * Finalization
close();
}
// ************************************************************
// Here come the methods of the 'iterator-like' interface of this class.
// ************************************************************
/** Return the attribute actually iterated through, or null if the attribute is not present.
*
* <P>This method is part of the 'iterator-like' interface of this class.
* See scenarios 1, 2 within class comment.</P>
*
* @return the actual attribute
* @see getAttributeValue
*/
public Attribute getAttribute ()
{
return mAttrCont.getAttribute(get("Name"));
}
/** Return the value of the attribute (as a String) actually iterated through,
* or an empty String ("") if the attribute is not present.
*
* <P>This method is part of the 'iterator-like' interface of this class.
* See scenarios 1, 2 within class comment.</P>
*
* @return the value of the actual attribute
* @see getAttribute
*/
public String getAttributeValue ()
{
return getString("Value"); // we use getString() so that null becomes ""
}
/** This method is derived from class DbTagValueIterator2 and should not
* be used for this class, use getAttribute() and getAttributeValue() instead.
*
* <P>It gets used internally, however, to obtain the actual attribute name and value.</P>
*
* @see getAttribute
* @see getAttributeValue
* @deprecated
*/
public String get (String name)
{
// do the same as in superclass
return super.get(name);
}
// ************************************************************
// Here come the methods of the 'random access' interface of this class.
// ************************************************************
/** Return an array with the values of all attributes with a given name,
* or null if the attribute is not possible or not present.
*
* <P>This method is part of the 'random access' interface of this class.
* See scenario 3 within class comment.<P>
*
* @param aName the name of the attribute to be looked for
* @return an array with the values
* @see #getAllAttributeValuesOf(Attribute)
*/
public String[] getAllAttributeValuesOf (String aName)
{
Attribute tAttr = mAttrCont.getAttribute(aName);
if(tAttr == null)
return null; // attribute not possible
if(! mAttrMapping.containsKey(tAttr))
return null; // attribute not present
int tRowNr = ((Integer) mAttrMapping.get(tAttr)).intValue();
int tSize = kfmTable.size();
Vector tVect = new Vector();
// As long as the attributes (starting with index tRowNr) have the right name,
// collect them into a Vector
while((tRowNr < tSize) && (kfmTable.get(tRowNr, "Name").equals(aName))) {
tVect.addElement(kfmTable.getString(tRowNr, "Value")); // Careful: using kfmTable.get()
// may return null
tRowNr++;
}
// transform Vector to array
String[] tResultArray = new String[tVect.size()];
tVect.copyInto(tResultArray);
return tResultArray;
}
/** Return an array with all the values of a given attribute,
* or null if the attribute is not present.
*
* <P>This method is part of the 'random access' interface of this class.
* See scenario 3 within class comment.</P>
*
* @param anAttribute the attribute to be looked for
* @return an array with the values
* @see #getAllAttributeValuesOf(String)
*/
public String[] getAllAttributeValuesOf (Attribute anAttribute)
{
return getAllAttributeValuesOf(anAttribute.getId());
}
/** Return the first value of an attribute with a given name,
* or null if the attribute is not possible or present.
*
* <P>If the attribute is present several times, only the first ocurrence is returned
* (use getAllAttributeValuesOf() for all ocurrences).</P>
*
* <P>This method is part of the 'random access' interface of this class.
* See scenario 3 within class comment.</P>
*
* @param aName the name of the attribute to be looked for
* @return the value
* @see #getAttributeValueOf(Attribute)
* @see #getAllAttributeValuesOf(String)
*/
public String getAttributeValueOf (String aName)
{
Attribute tAttr = mAttrCont.getAttribute(aName);
if(tAttr == null)
return null; // attribute not possible
if(! mAttrMapping.containsKey(tAttr))
return null; // attribute not present
int tRowNr = ((Integer) mAttrMapping.get(tAttr)).intValue();
return kfmTable.get(tRowNr, "Value");
}
/** Return the first value of a given attribute
* or null if the attribute is not possible or present.
*
* <P>If the attribute is present several times, only the first ocurrence is returned
* (use getAllAttributeValuesOf() for all ocurrences).</P>
*
* <P>This method is part of the 'random access' interface of this class.
* See scenario 3 within class comment.</P>
*
* @param anAttribute the attribute to be looked for
* @return the value
* @see #getAttributeValueOf(Attribute)
* @see #getAllAttributeValuesOf(String)
*/
public String getAttributeValueOf (Attribute anAttribute)
{
return getAttributeValueOf(anAttribute.getId());
}
/** Return an array with the names of all attributes present within the loaded entry.
*
* <P>This can be different from the set of all 'possible' attributes (as described by mAttrCont).
* If no attributes at all are present (a rather improbable case) return null.</P>
*
* <P>This method is part of the 'random access' interface of this class.
* See scenario 3 within class comment.</P>
*
* @return the array with the attribute names
*/
public String[] getAllAttributeNames ()
{
String[] tResultArray = new String[mAttrMapping.size()];
Enumeration tEnum = mAttrMapping.keys();
int tIndex=0;
while(tEnum.hasMoreElements()) {
tResultArray[tIndex] = (String)tEnum.nextElement();
tIndex++;
}
return tResultArray;
}
// ************************************************************
// Here come other methods of this class (e.g. helpers & protected stuff)
// ************************************************************
/** Helper method to construct all the PreparedStatements used within loadByIdDedicated()
* and loadByIdHashed().
*
* KS wrote: To be of real (re-)use, they can only be closed within finalize().
* Thh: They are now closed in `close�. We do not wish to reuse the PreparedStatements.
* We only want to use the "?"s.
*/
protected void prepareAllStatements ()
throws KFM_SQLException
{
Attribute[] tAttrAsArray;
String tSqlString;
int tSize;
// First, prepare for Statements for loadIdByDedicated(). Store them in array mDedicatedSQLCmds.
tAttrAsArray = mAttrCont.getDedicatedAttributes();
if(tAttrAsArray != null && (tSize = tAttrAsArray.length) != 0) {
mDedicatedSQLCmds = new int[tSize];
// prepare the query string for each table with dedicated attributes.
// Each table name is deduced from mTableNameInlined by appending the dedicated attribute name
String tTableNameDedicated;
for(int i=0; i < tSize; i++) {
tTableNameDedicated = // e.g.
mTableNameHashedDedicated_Prefix + // "Link" +
mTableNameSeparator + // "_" +
tAttrAsArray[i].getId(); // "Keyword"
tSqlString = "SELECT Value FROM " + tTableNameDedicated + " WHERE " + mIDfieldHashedDedicated + " = ?";
mDedicatedSQLCmds[i] = mDbA.prepareStmt(tSqlString);
}
}
// Then, prepare for the Statement for loadIdByHashed(). Store it in mHashedSQLCmd.
String tTableNameHashed = mTableNameHashedDedicated_Prefix
+ mTableNameSeparator
+ mTableNameHashed_Suffix;
tAttrAsArray = mAttrCont.getHashedAttributes();
if(tAttrAsArray != null && tAttrAsArray.length != 0) {
// prepare the query string for the table with hashed attributes.
tSqlString = "SELECT Name, Value FROM " + tTableNameHashed +
" WHERE " + mIDfieldHashedDedicated + " = ?";
mHashedSQLCmd = mDbA.prepareStmt(tSqlString);
}
}
/** Closes all the PreparedStatements.
*/
protected void close ()
throws KFM_SQLException
{
// First, close all the PreparedStatements within array mDedicatedSQLCmds
if(mDedicatedSQLCmds != null) {
for(int i=0; i < mDedicatedSQLCmds.length; i++) {
mDbA.closeStmt(mDedicatedSQLCmds[i]);
}
}
// Then, close the PreparedStatement within mHashedSQLCmd
if (mHashedSQLCmd != -1)
mDbA.closeStmt(mHashedSQLCmd);
}
// ************************************************************
// Here come the sub-methods of method loadById().
// ************************************************************
/** Sub-method of loadById that takes care of initialization issues.
*
* @see loadById
*/
protected void _loadByIdPrologue ()
{
// At first, reset kfmTable to get rid of any old underlying container.
// This would normally be done during loadTable, but we don't call this, here.
kfmTable = new KfmTransientDBTable2(mSelects, mDbA.getDatabase());
// reset mAttrMapping
mAttrMapping = new Hashtable();
}
/** Sub-method of loadById that It takes care of loading inlined attributes.
*
* <P>This method now distinguishes between the absence or presence of an outer iterator (this depends
* on the way this object was constructed) to allow for a more efficient retrieving of the inliend
* attributes (if the outer iterator is present).</P>
*
* <P>Note: If we make use of the outer iterator, we assume that it still points to the row with the ID
* that was provided with this method.</P>
*
* @see loadById
*/
protected void _loadByIdInlined ()
throws KFM_SQLException
{
try {
String tAttrAsList;
String[] tAttrNamesAsArray;
Attribute[] tAttrAsArray;
Attribute tAttr;
String tAttrName, tAttrValue;
String tSqlString;
int tCmd;
ResultSet tRs;
int tRowCnt = mAttrMapping.size(); // the index of the next row to be filled
// Load all inlined attributes , e.g.
// 'SELECT ID, Url, ... FROM Link WHERE ID = aID'.
// Fold them and append them to kfmTable.
tAttrNamesAsArray = mAttrCont.getInlinedAttributeNames();
tAttrAsArray = mAttrCont.getInlinedAttributes();
tAttrAsList = Converter.arrayToCommaString(tAttrNamesAsArray);
// make sure we have inlined attributes at all
if(tAttrAsList == null) {
// if not so, we can stop here.
return;
}
// Depending on the way we constructed this object, we
// - either use mOuterView to get access to inlined attributes (the efficient version)
// - or perform a SELECT on the inlined DB table (the inefficient version)
if(mOuterView == null) {
// prepare the query string
// Note: The SQL below assumes that there is an attribute called 'ID'
tSqlString = "SELECT " + tAttrAsList + " FROM " + mTableNameInlined + " WHERE ID = ?";
tCmd = mDbA.prepareStmt(tSqlString);
mDbA.setValue(tCmd, 1, mID);
tRs = mDbA.executeQuery(tCmd);
// We either found zero or one record. If no record was found, we can stop here.
if(! tRs.next()) {
mDbA.closeStmt(tCmd);
return;
}
// Fold the inlined attributes (names are in tAttrAsArray, values are in tRs) into kfmTable
for(int i=0; i < tAttrAsArray.length; i++) {
tAttr = tAttrAsArray[i];
tAttrValue = tRs.getString(i+1);
kfmTable.set(tRowCnt, "Name", tAttr.getId()); // set the name of the attribute
kfmTable.set(tRowCnt, "Value", tAttrValue); // set the value of the attribute
mAttrMapping.put(tAttr, new Integer(tRowCnt));
tRowCnt++;
}
mDbA.closeStmt(tCmd);
} else {
// Fold the inlined attributes (names are in tAttrAsArray, values are in tRs) into kfmTable
for(int i=0; i < tAttrAsArray.length; i++) {
tAttr = tAttrAsArray[i];
tAttrValue = mOuterView.getString(tAttr.getId());
kfmTable.set(tRowCnt, "Name", tAttr.getId()); // set the name of the attribute
kfmTable.set(tRowCnt, "Value", tAttrValue); // set the value of the attribute
mAttrMapping.put(tAttr, new Integer(tRowCnt));
tRowCnt++;
}
}
} catch(SQLException ex) {
throw new KFM_SQLException(ex);
}
}
/** Sub-method of loadById that takes care of loading hashed attributes.
*
* @see loadById
*/
protected void _loadByIdHashed ()
throws KFM_SQLException
{
try {
String tAttrName, tAttrValue;
ResultSet tRs;
int tRowCnt = mAttrMapping.size(); // the index of the next row to be filled
// Load all hashed attributes, e.g.
// 'SELECT Link_ID, Name, Value FROM Link_Attribute WHERE Link_ID = aID'.
// Fold them and append them to kfmTable.
// make sure we have hashed attributes at all. If not so, simply return.
if(mHashedSQLCmd != -1) {
mDbA.setValue(mHashedSQLCmd, 1, mID);
tRs = mDbA.executeQuery(mHashedSQLCmd);
while(tRs.next()) {
tAttrName = tRs.getString(1);
tAttrValue = tRs.getString(2);
kfmTable.set(tRowCnt, "Name", tAttrName); // set the name of the attribute
kfmTable.set(tRowCnt, "Value", tAttrValue); // set the value of the attribute
mAttrMapping.put(mAttrCont.getAttribute(tAttrName), new Integer(tRowCnt));
tRowCnt++;
}
}
} catch(SQLException e) {
throw new KFM_SQLException(e);
}
}
/** Sub-method of loadById that takes care of loading dedicated attributes.
*
* @see loadById
*/
protected void _loadByIdDedicated ()
throws KFM_SQLException
{
try {
Attribute tAttr;
String tAttrValue;
ResultSet tRs;
int tRowCnt = mAttrMapping.size(); // the index of the next row to be filled
// Load all dedicated attributes, e.g.
// 'SELECT Link_ID, Value FROM Link_Keyword WHERE Link_ID = aID'.
// Fold them and append them to kfmTable.
// Note: There may be more than one table with dedicated attributes.
// Make sure we have dedicated attributes at all. If not so, simply return.
if(mDedicatedSQLCmds != null && mDedicatedSQLCmds.length > 0) {
Attribute[] tAttrAsArray = mAttrCont.getDedicatedAttributes();
// prepare the query string for each table with dedicated attributes.
for(int i=0; i < mDedicatedSQLCmds.length; i++) {
mDbA.setValue(mDedicatedSQLCmds[i], 1, mID);
tRs = mDbA.executeQuery(mDedicatedSQLCmds[i]);
while(tRs.next()) {
tAttr = tAttrAsArray[i];
tAttrValue = tRs.getString(1);
kfmTable.set(tRowCnt, "Name", tAttr.getId()); // set the name of the attribute
kfmTable.set(tRowCnt, "Value", tAttrValue); // set the value of the attribute
if(! mAttrMapping.containsKey(tAttr))
mAttrMapping.put(tAttr, new Integer(tRowCnt)); // only on 1st ocurrence
tRowCnt++;
}
}
}
} catch(SQLException e) {
throw new KFM_SQLException(e);
}
}
/** Sub-method of loadById that takes care of finalizing issues.
*
* @see loadById
*/
protected void _loadByIdEpilogue ()
{
// Currently empty, subclasses may add some 'finalizing' behavior, though.
}
/** Set the prefix of the DB table names for hashed and dedicated attributes,
* that is the part in front of ..._Attribute or ..._Keyword.
*
* <P>You only need to call this when this prefix is not(!!!) the same as the
* DB table name for the inlined attributes.</P>
*
* <P>The prefix is needed when constructing table names within loadByIdHashed()
* or loadByIdDedicated().</P>
*
* @param aPrefix the prefix to be set
*/
public void setTableNameHashedDedicated_Prefix (String aPrefix)
{
mTableNameHashedDedicated_Prefix = aPrefix;
}
/** Set the name of the foreign key field within the DB tables for hashed and dedicated attributes.
*
* <P>You only need to call this when this field is not (!!!) the table name of
* the inlined attributes suffixed by "_ID" (e.g. Link_ID).</P>
*
* <P>The foreign key field is needed when constructing the SQL query within loadByIdHashed()
* or loadByIdDedicated().</P>
*
* @param anIDfield the foreign key field to be set
*/
public void setIDfieldHashedDedicated (String anIDfield)
{
mIDfieldHashedDedicated = anIDfield;
}
}