Package appl.Portal.DB

Source Code of appl.Portal.DB.AttributedTableView

/*
*  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;
    }
}
TOP

Related Classes of appl.Portal.DB.AttributedTableView

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.