Package org.apache.empire.db

Source Code of org.apache.empire.db.DBRecord

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*  http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.empire.db;

import java.lang.reflect.InvocationTargetException;
import java.sql.Connection;
import java.util.Collection;
import java.util.List;

import org.apache.commons.beanutils.BeanUtilsBean;
import org.apache.commons.beanutils.PropertyUtilsBean;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.empire.commons.Errors;
import org.apache.empire.commons.ObjectUtils;
import org.apache.empire.commons.Options;
import org.apache.empire.data.Column;
import org.apache.empire.data.ColumnExpr;
import org.apache.empire.data.Record;
import org.apache.empire.xml.XMLUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Element;


/**
*
* This class handles one record from a database table.
*
*/
public class DBRecord extends DBRecordData implements Record, Cloneable
{
    /*
     * TODO convert to an enum?
     */
    public static final int REC_INVALID  = -1;
    public static final int REC_EMTPY    = 0;
    public static final int REC_VALID    = 1;
    public static final int REC_MODIFIED = 2;
    public static final int REC_NEW      = 3;

    @SuppressWarnings("hiding")
    protected static final Log    log          = LogFactory.getLog(DBRecord.class);

    // This is the record data
    private int             state;
    private DBRowSet        rowset;
    private Object[]        fields;
    private boolean[]       modified;
    // Special Rowset Data (usually null)
    private Object          rowsetData;

    /**
     * Create a new DBRecord object.<BR>
     * The record is not attachted to a RowSet and the record's state is intitially set to REC_INVALID.
     *
     * Please derive your own Objects from this class.  
     */
    public DBRecord()
    {
        state = REC_INVALID;
        rowset = null;
        fields = null;
        modified = null;
        rowsetData = null;
    }
   
    /**
     * This method is used internally by the RowSet to initialize the record's properties
     * @param rowset the rowset to which to attach this record
     * @param state the state of the record
     * @param rowSetData any further RowSet specific data
     */
    protected void init(DBRowSet rowset, int state, Object rowSetData)
    {
        // Init
        if (this.rowset != rowset)
        {   // Set Rowset
            this.rowset = rowset;
            if (rowset!=null)
                fields = new Object[rowset.getColumns().size()];
            else
                fields = null;
            onRowSetChanged();
        }
        else if (fields!=null)
        {   // clear fields
            for (int i=0; i<fields.length; i++)
                fields[i]=null;
        }
        // Set State
        changeState(state, rowSetData);
    }
   
    /**
     * This function provides direct access to the record fields.<BR>
     * This method is used internally be the RowSet to fill the data.<BR>
     * @return an array of field values
     */
    protected Object[] getFields()
    {
        return fields;
    }
   
    /**
     * This method is used internally be the RowSet to change the record's state<BR>
     * @param state
     * @param rowSetData
     */
    protected void changeState(int state, Object rowSetData)
    {
        this.state = state;
        this.rowsetData = rowSetData;
        this.modified = null;
    }

    /**
     * Closes the record by releasing all resources and resetting the record's state to invalid.
     */
    @Override
    public void close()
    {
        init(null, REC_INVALID, null);
    }
   
    /** {@inheritDoc} */
    @Override
    public DBRecord clone()
    {
        try
        {
            DBRecord rec = (DBRecord)super.clone();
            rec.rowset = rowset;
            rec.state = state;
            if (rec.fields == fields && fields!=null)
                rec.fields = fields.clone();
            if (rec.modified == modified && modified!=null)
                rec.modified = modified.clone();
            rec.rowsetData = rowsetData;
            return rec;
           
        } catch (CloneNotSupportedException e)
        {
            log.error("Unable to clone record.", e);
            return null;
        }
    }

    /**
     * Returns the current DBDatabase object.
     *
     * @return the current DBDatabase object
     */
    @Override
    public DBDatabase getDatabase()
    {
        return (rowset != null) ? rowset.db : null;
    }

    /**
     * Returns the DBRowSet object.
     *
     * @return the DBRowSet object
     */
    public DBRowSet getRowSet()
    {
        return rowset;
    }

    /**
     * Returns the DBRowSet object.
     *
     * @return the DBRowSet object
     */
    public Object getRowSetData()
    {
        return rowsetData;
    }

    /**
     * Returns the record state.
     *
     * @return the record state
     */
    public int getState()
    {
        return state;
    }

    /**
     * Returns true if the record is valid.
     *
     * @return true if the record is valid
     */
    public boolean isValid()
    {
        return (state >= DBRecord.REC_VALID);
    }

    /**
     * Returns true if the record is modified.
     *
     * @return true if the record is modified
     */
    public boolean isModified()
    {
        return (state >= DBRecord.REC_MODIFIED);
    }

    /**
     * Returns true if this record is a new record.
     *
     * @return true if this record is a new record
     */
    public boolean isNew()
    {
        return (state == DBRecord.REC_NEW);
    }

    /**
     * Returns the number of the columns.
     *
     * @return the number of the columns
     */
    @Override
    public int getFieldCount()
    {
        return (fields != null) ? fields.length : 0;
    }

    /**
     * Returns the index value by a specified DBColumnExpr object.
     *
     * @return the index value
     */
    @Override
    public int getFieldIndex(ColumnExpr column)
    {
        DBColumnExpr expr = (DBColumnExpr)column;
        return (rowset != null) ? rowset.getColumnIndex(expr.getUpdateColumn()) : -1;
    }

    /**
     * Returns the index value by a specified column name.
     *
     * @return the index value
     */
    @Override
    public int getFieldIndex(String column)
    {
        if (rowset != null)
        {
            List<DBColumn> columns = rowset.getColumns();
            for (int i = 0; i < columns.size(); i++)
            {
                DBColumn col = columns.get(i);
                if (col.getName().equalsIgnoreCase(column))
                    return i;
            }
        }
        // not found
        return -1;
    }

    /**
     * Returns the DBColumn for the field at the given index.
     *
     * @param index the field index
     *
     * @return the index value
     */
    public DBColumn getDBColumn(int index)
    {
        return (rowset!=null ? rowset.getColumn(index) : null);
    }

    /**
     * Implements the Record Interface getColumn method.<BR>
     * Internally calls getDBColumn()
     * @return the Column at the specified index
     */
    public final Column getColumn(int index)
    {
        return getDBColumn(index);
    }
   
    /**
     * Returns a DBColumnExpr object by a specified index value.
     * @return the index value
     */
    @Override
    public final ColumnExpr getColumnExpr(int index)
    {
        return getDBColumn(index);
    }
   
    /**
     * Returns true if the field was modified.
     *
     * @param index the field index
     * 
     * @return true if the field was modified
     */
    public boolean wasModified(int index)
    {
        if (rowset == null)
            return error(Errors.ObjectNotValid, getClass().getName());
        if (index < 0 || index >= fields.length)
            return error(Errors.OutOfRange, index);
        // Check modified
        clearError();
        if (modified == null)
            return false;
        return modified[index];
    }

    /**
     * Returns true if the field was modified.
     *
     * @return true if the field was modified
     */
    public final boolean wasModified(Column column)
    {
        return wasModified(getFieldIndex(column));
    }

    /**
     * Sets the modified state of a column.<BR>
   * This will force the field to be updated in the database, if set to TRUE.
   *
     * @param column the column
     * @param isModified modified or not
     */
    public void setModified(DBColumn column, boolean isModified)
    {
        if (modified == null)
        { // Save all original values
            modified = new boolean[fields.length];
            for (int j = 0; j < fields.length; j++)
                modified[j] = false;
        }
        int index = getFieldIndex(column);
        if (index >= 0)
            modified[index] = isModified;
        // Set State to modified, if not already at least modified and isModified is set to true
        if (state < REC_MODIFIED && isModified)
            state = REC_MODIFIED;
        // Reset state to unmodified, if currently modified and not modified anymore after the change
        if (state == REC_MODIFIED && !isModified)
        {
          boolean recordNotModified = true;
            for (int j = 0; j < fields.length; j++)
            {
                if (modified[j] == true)
                {
                  recordNotModified = false;
                }
            }
            if (recordNotModified)
            {
              state = REC_VALID;
            }
        }
    }
   
    /**
     * returns an array of key columns which uniquely identify the record.
     * @return the array of key columns if any
     */
    public Column[] getKeyColumns()
    {
        return rowset.getKeyColumns();
    }

    /**
     * Returns the array of primary key columns.
     * @return the array of primary key columns
     */
    public Object[] getKeyValues()
    {
        return ((rowset != null) ? rowset.getRecordKey(this) : null);
    }

    /**
     * Returns the value for the given column or null if either the index is out of range or the value is not valid (see {@link DBRecord#isValueValid(int)})
     * @return the index value
     */
    @Override
    public Object getValue(int index)
    {   // Check state
        if (fields == null)
        {   // Record not valid
            error(Errors.ObjectNotValid, getClass().getName());
            return null;
        }
        // Check index
        if (index < 0 || index>= fields.length)
        {   // Index out of range
            error(Errors.OutOfRange, index);
            return null;
        }
        clearError();
        // Special check for NO_VALUE
        if (fields[index] == ObjectUtils.NO_VALUE)
            return null;
        // Return field value
        return fields[index];
    }
   
    /**
     * Returns whether a field value is provided i.e. the value is not DBRowSet.NO_VALUE<BR>
     * This function is only useful in cases where records are partically loaded.<BR>
     *
     * @param index the filed index
     * 
     * @return true if a valid value is supplied for the given field or false if value is {@link ObjectUtils#NO_VALUE} 
     */
    public boolean isValueValid(int index)
    {   // Check state
        if (fields == null)
            return error(Errors.ObjectNotValid, getClass().getName());
        // Check index
        if (index < 0 || index>= fields.length)
        {   // Index out of range
            return error(Errors.OutOfRange, index);
        }
        clearError();
        // Special check for NO_VALUE
        return (fields[index] != ObjectUtils.NO_VALUE);
    }

    /**
     * Gets the possbile Options for a field in the context of the current record.
     *
     * @param column the database field column
     * 
     * @return the field options
     */
    public Options getFieldOptions(DBColumn column)
    {
        // DBColumn col = ((colexpr instanceof DBColumn) ? ((DBColumn) colexpr) : colexpr.getUpdateColumn());
        return column.getOptions();
    }

    /**
     * Gets the possbile Options for a field in the context of the current record.<BR>
     * Same as getFieldOptions(DBColumn)
     * @return the Option
     */
    public final Options getFieldOptions(Column column)
    {
        return getFieldOptions((DBColumn)column);
    }

    /**
     * Modifies a column value bypassing all checks made by setValue.
     * Use this to explicitly set invalid values i.e. for temporary storage.
     *
     * @param i index of the column
     * @param value the column value
     */
    public void modifyValue(int i, Object value)
    { // Init original values
        if (modified == null)
        { // Save all original values
            modified = new boolean[fields.length];
            for (int j = 0; j < fields.length; j++)
                modified[j] = false;
        }
        // Set Modified
        if (fields[i]!=ObjectUtils.NO_VALUE || value!=null)
            modified[i] = true;
        // Set Value
        fields[i] = value;
        // Set State
        if (state < REC_MODIFIED)
            state = REC_MODIFIED;
        // field changed
        onFieldChanged(i);
    }

    /**
     * Sets the value of the column in the record.
     * The functions checks if the column and the value are valid and whether the
     * value has changed.
     *
     * @param i the index of the column
     * @param value the value
     * @return true if successful
     */
    public boolean setValue(int i, Object value)
    {
        if (rowset == null)
            return error(Errors.ObjectNotValid, getClass().getName());
        if (i < 0 || i >= fields.length)
            return error(Errors.OutOfRange, i);
        // Strings special
        if ((value instanceof String) && ((String)value).length()==0)
            value = null;
        // Has Value changed?
        if (ObjectUtils.compareEqual(fields[i], value))
            return success(); // no change
        // Field has changed
        DBColumn column = rowset.getColumn(i);
        if (column.isAutoGenerated())
        {   // Read Only column may be set
            return error(DBErrors.FieldIsReadOnly, column.getName());
        }
        // Is Value valid
        if (column.checkValue(value) == false)
        { // Invalid Value for column
            return error(column);
        }
        // Init original values
        modifyValue(i, value);
        return success();
    }

    /**
     * Sets the value of the column in the record.
     * The functions checks if the column and the value are valid and whether the
     * value has changed.
     *
     * @param column a DBColumn object
     * @param value the value
     * @return true if successful
     */
    public final boolean setValue(Column column, Object value)
    {
        if (rowset == null)
            return error(Errors.ObjectNotValid, getClass().getName());
        // Get Column Index
        return setValue(rowset.getColumnIndex(column), value);
    }
   
    /**
     * returns whether a field is read only or not
     *
     * @param column the database column
     *
     * @return true if the field is read only
     */
    public boolean isFieldReadOnly(DBColumn column)
    {
        if (rowset==null)
        {   error(Errors.ObjectNotValid, getClass().getName());
            return true;
        }
        // Ask RowSet
        return (rowset.isColumnReadOnly(column));
    }
   
    /**
     * returns whether a field is read only or not
     */
    public final boolean isFieldReadOnly(Column column)
    {
        return isFieldReadOnly((DBColumn)column);
    }
   
    /**
     * returns whether a field is visible to the client or not
     * <P>
     * May be overridden to implement context specific logic.
     * @param column the column which to check for visibility
     * @return true if the column is visible or false if not
     */
    public boolean isFieldVisible(DBColumn column)
    {
        if (rowset==null)
            return error(Errors.ObjectNotValid, getClass().getName());
        // Check if field is present and the value is valid
        int index = rowset.getColumnIndex(column);
        return (index>=0 && isValueValid(index));
    }
   
    /**
     * returns whether a field is read only or not
     */
    public final boolean isFieldVisible(Column column)
    {
        return isFieldVisible((DBColumn)column);
    }

    /**
     * Initializes this record object by attaching it to a rowset,
     * setting its primary key values and setting the record state.<BR>
     * This function is useful for updating a record without prior reading.
     * <P>
     * @param table the rowset
     * @param keyValues a Object array, the primary key(s)
     * @param insert if true change the state of this object to REC_NEW
     * @return true if successful or false otherwise
     */
    public boolean init(DBRowSet table, Object[] keyValues, boolean insert)
    { // Init with keys
        if (table.initRecord(this, keyValues) == false)
            return error(table);
        if (insert)
            state = DBRecord.REC_NEW;
        return success();
    }

    /**
     * @param table
     * @param conn
     * @return true on succes
     * @deprecated use {@link DBRecord#create(DBRowSet, Connection)}
     */
    @Deprecated
  public final boolean initNew(DBRowSet table, Connection conn)
    {
        return (table.createRecord(this, conn) == false) ? error(table) : success();
    }

    /**
     * @param table
     * @return true on succes
     * @deprecated use {@link DBRecord#create(DBRowSet)}
     */
    @Deprecated
  public final boolean initNew(DBRowSet table)
    {
        return initNew(table, null);
    }
   
    /**
     * Creates a new record for the given table.<BR>
     * All record fields will be filled with their default values.
     * The record's state is set to NEW
     * <P>
     * If a connection is supplied sequence generated values will be obtained<BR>
     * Otherwise the sequence will be generated later.
     * <P>
     * @param table the table for which to create a record
     * @param conn a valid JDBC connection
     * @return true if successful
     */
    public boolean create(DBRowSet table, Connection conn)
    {
        return (table.createRecord(this, conn) == false) ? error(table) : success();
    }
   
    /**
     * Creates a new record for the given table.<BR>
     * All record fields will be filled with their default values.<BR>
     * The record's state is set to NEW
     * <P>
     * @param table the table for which to create a record
     * @return true if successful
     */
    public boolean create(DBRowSet table)
    {
        return create(table, null);
    }

    /**
     * Loads a record from the database identified by it's primary key.
     * After sucessful reading the record will be valid and all values will be accessible.
     * @see org.apache.empire.db.DBTable#readRecord(DBRecord, Object[], Connection)
     *
     * @param table the rowset from which to read the record
     * @param keys an array of the primary key values
     * @param conn a valid connection to the database.
     * @return true if the record was sucessfully loaded or false if the record was not found or an error occurred.
     */
    public boolean read(DBRowSet table, Object[] keys, Connection conn)
    {
        return (table.readRecord(this, keys, conn) == false) ? error(table) : success();
    }

    /**
     * Loads a record from the database identified by it's primary key.
     * After sucessful reading the record will be valid and all values will be accessible.
     * @see org.apache.empire.db.DBTable#readRecord(DBRecord, Object[], Connection)
     *
     * @param table the rowset from which to read the record
     * @param id the primary key of the record to load.
     * @param conn a valid connection to the database.
     * @return true if the record was sucessfully loaded or false if the record was not found or an error occurred.
     */
    public final boolean read(DBRowSet table, Object id, Connection conn)
    {
        if (id instanceof Collection<?>)
        {   // If it's a collection then convert it to an array
            return read(table, ((Collection<?>)id).toArray(), conn);
        }
        // Simple One-Column key
        return read(table, new Object[] { id }, conn);
    }

    /**
     * Updates the record and saves all changes in the database.
     *
     * @see org.apache.empire.db.DBTable#updateRecord(DBRecord, Connection)
     * @param conn a valid connection to the database.
     * @return true if successful
     */
    public boolean update(Connection conn)
    {
        if (rowset == null)
            return error(Errors.ObjectNotValid, getClass().getName());
        if (!rowset.updateRecord(this, conn))
            return error(rowset);
        return success();
    }

    /**
     * This helper function calls the DBRowset.deleteRecord method
     * to delete the record.
     *
     * WARING: There is no guarantee that it ist called
     * Implement delete logic in the table's deleteRecord method if possible
     *
     * @see org.apache.empire.db.DBTable#deleteRecord(Object[], Connection)
     * @param conn a valid connection to the database.
     * @return true if successful
     */
    public boolean delete(Connection conn)
    {
        if (isValid()==false)
            return error(Errors.ObjectNotValid, getClass().getName());
        // Delete only if record is not new
        if (!isNew())
        {
            Object[] keys = rowset.getRecordKey(this);
            if (rowset.deleteRecord(keys, conn)==false)
                return error(rowset);
        }
        close();
        return success();
    }

    /**
     * This function set the field descriptions to the the XML tag.
     *
     * @return true if successful
     */
    @Override
    public boolean addColumnDesc(Element parent)
    {
        if (rowset == null)
            return error(Errors.ObjectNotValid, getClass().getName());
        // Add Field Description
        List<DBColumn> columns = rowset.getColumns();
        for (int i = 0; i < columns.size(); i++)
        { // Add Field
            DBColumn column = columns.get(i);
            if (isFieldVisible(column)==false)
                continue;
            column.addXml(parent, 0);
        }
        return success();
    }

    /**
     * Add the values of this record to the specified XML Element object.
     *
     * @param parent the XML Element object
     * @return true if successful
     */
    @Override
    public boolean addRowValues(Element parent)
    {
        if (rowset == null)
            return error(Errors.ObjectNotValid, getClass().getName());
        // set row key
        DBColumn[] keyColumns = rowset.getKeyColumns();
        if (keyColumns != null && keyColumns.length > 0)
        { // key exits
            if (keyColumns.length > 1)
            { // multi-Column-id
                StringBuilder buf = new StringBuilder();
                for (int i = 0; i < keyColumns.length; i++)
                { // add
                    if (i > 0)
                        buf.append("/");
                    buf.append(getString(keyColumns[i]));
                }
                parent.setAttribute("id", buf.toString());
            }
            else
                parent.setAttribute("id", getString(keyColumns[0]));
        }
        // row attributes
        if (isNew())
            parent.setAttribute("new", "1");
        // Add all children
        List<DBColumn> columns = rowset.getColumns();
        for (int i = 0; i < fields.length; i++)
        { // Read all
            DBColumn column = columns.get(i);
            if (isFieldVisible(column)==false)
                continue;
            // Add Field Value
            String name = column.getName();
            if (fields[i] != null)
                XMLUtil.addElement(parent, name, getString(i));
            else
                XMLUtil.addElement(parent, name).setAttribute("null", "yes"); // Null-Value
        }
        return success();
    }
   
    /**
     * returns the DBXmlDictionary that should used to generate XMLDocuments<BR>
     * @return the DBXmlDictionary
     */
    protected DBXmlDictionary getXmlDictionary()
    {
        return DBXmlDictionary.getInstance();
    }

    /**
     * Returns a XML document with the field descriptiona an values of this record.
     *
     * @return the new XML Document object
     */
    @Override
    public Document getXmlDocument()
    {
        if (rowset == null)
        {   error(Errors.ObjectNotValid, getClass().getName());
            return null;
        }
        // Create Document
        DBXmlDictionary xmlDic = getXmlDictionary();
        Element root = XMLUtil.createDocument(xmlDic.getRowSetElementName());
        if (rowset.getName() != null)
            root.setAttribute("name", rowset.getName());
        // Add Field Description
        if (!addColumnDesc(root))
            return null;
        // Add row Values
        if (!addRowValues(XMLUtil.addElement(root, xmlDic.getRowElementName())))
            return null;
        // return Document
        clearError();
        return root.getOwnerDocument();
    }

    /**
     * Set the record default value for the fields with
     * the value {@link ObjectUtils.NoValue}
     *
     * @param conn the sql connection
     * 
     * @return the number of fields set to default
     */
    public int fillMissingDefaults(Connection conn)
    {
        int count = 0;
        for (int i = 0; i < fields.length; i++)
        {
            if (fields[i] == ObjectUtils.NO_VALUE)
            {
                DBTableColumn col = (DBTableColumn) rowset.getColumn(i);
                Object value = col.getRecordDefaultValue(conn);
                if (value==null)
                    continue;
                // Modify value
                modifyValue(i, value);
                count++;
            }
        }
        return count;
    }
   

    /**
     * set a record value from a particular bean property.
     * <P>
     * For a property called FOO this is equivalent of calling<BR>
     *     setValue(column, bean.getFOO())
     * <P>
     * @param bean the Java Bean from which to read the value from
     * @param property the name of the property
     * @param column the column for which to set the record value
     * @return true if the value has been sucessfully set or false if not   
     */
    protected boolean setBeanValue(Object bean, String property, Column column)
    {
        try
        {   /*
            if (log.isTraceEnabled())
                log.trace(bean.getClass().getName() + ": getting property '" + property + "' for column " + column.getName());
            */
           
            // Get Property Value
            PropertyUtilsBean pub = BeanUtilsBean.getInstance().getPropertyUtils();
            Object value = pub.getSimpleProperty(bean, property);

            // Now, set the record value
            return setValue( column, value );

        } catch (IllegalAccessException e)
        {   log.error(bean.getClass().getName() + ": unable to get property '" + property + "'");
            return error(e);
        } catch (InvocationTargetException e)
        {   log.error(bean.getClass().getName() + ": unable to get property '" + property + "'");
            return error(e);
        } catch (NoSuchMethodException e)
        {
            log.warn(bean.getClass().getName() + ": no getter available for property '" + property + "'");
            return error(e);
        }
    }
   
    /**
     * Sets record values from the suppied java bean.
     *
     * @return true if at least one value has been set sucessfully
     */
    public boolean setBeanValues(Object bean, Collection<Column> ignoreList)
    {
        // Add all Columns
        int count = 0;
        for (int i = 0; i < getFieldCount(); i++)
        { // Check Property
            DBColumn column = getDBColumn(i);
            if (column.isReadOnly())
                continue;
            if (ignoreList != null && ignoreList.contains(column))
                continue; // ignore this property
            // Get Property Name
            String property = column.getBeanPropertyName();
            if (setBeanValue(bean, property, column))
                count++;
        }
        return (count > 0);
    }

    /**
     * Sets record values from the suppied java bean.
     * @return true if at least one value has been set sucessfully
     */
    public final boolean setBeanValues(Object bean)
    {
        return setBeanValues(bean, null);
    }
   
    /**
     * Override this to do extra handling when the rowset for this record changes
     */
    protected void onRowSetChanged()
    {
        if (log.isTraceEnabled() && rowset!=null)
            log.trace("Record has been attached to rowset " + rowset.getName());
    }
   
    /**
     * Override this to do extra handling when the record changes
     */
    protected void onRecordChanged()
    {
        if (log.isTraceEnabled() && isValid())
            log.trace("Record has been changed");
    }
   
    /**
     * Override this to get notified when a field value changes
     */
    protected void onFieldChanged(int i)
    {
        if (log.isDebugEnabled())
            log.debug("Record field " + rowset.getColumn(i).getName() + " changed to " + String.valueOf(fields[i]));
    }
   
}
TOP

Related Classes of org.apache.empire.db.DBRecord

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.