/* * Copyright (c) 2000-2006 ASP Converters Pty Ltd. * * www.aspconverters.com.au * * All Rights Reserved. * * This software is the proprietary information of * ASP Converters Pty Ltd. * Use is subject to license terms. */ package com.aspc.DBObj; import org.apache.commons.logging.Log; import com.aspc.message.DBMessage; import com.aspc.DBObj.Contact.Login; import com.aspc.DBObj.Archive.*; import com.aspc.DBObj.Errors.*; import com.aspc.DBObj.Formula.DBFieldQuery; import com.aspc.DBObj.Formula.DBFormula; import com.aspc.DBObj.Internal.*; import com.aspc.DBObj.Internal.DataLoader.LazyLoadValue; import com.aspc.DBObj.Internal.DataLoader.LinkedValue; import com.aspc.DBObj.Internal.DataLoader.StoredArrayValue; import com.aspc.DBObj.Internal.Helper.DBObjectHelper; import com.aspc.DBObj.Internal.Holders.PossibleRowsHolder; import com.aspc.DBObj.Language.*; import com.aspc.DBObj.Language.Internal.MutableMultiLingualValue; import com.aspc.DBObj.Language.Internal.ReadOnlyMultiLingualValue; import com.aspc.DBObj.Listeners.ReloadEventListener; import com.aspc.DBObj.Query.DBCriteria; import com.aspc.remote.database.InvalidDataException; import com.aspc.remote.database.NotFoundException; import com.aspc.remote.database.DeletedRecordException; import com.aspc.remote.database.NullValueException; import com.aspc.remote.database.TooManyRowsException; import com.aspc.remote.util.misc.CLogger; import com.aspc.remote.util.misc.StringUtilities; import com.aspc.remote.util.misc.TimeUtil; import com.aspc.DBObj.Misc.AutoEnterPredefined; import com.aspc.Util.Memory.HashLongMap; import com.aspc.remote.util.misc.ConcurrentDecimalFormat; import java.lang.ref.WeakReference; import java.util.*; /** * DBObject is an instance of a DBClass. * Extend this class to add functionality to Super-Tracker
* The class represents a single row in the database. Each datasource will generate a * new instance of a DBObject which holds the specific state of this record for a datasource.
*
* MIXED MODE THREADING: When a DBObject is comes from a mutable data source or * archive data source the DBObject is in SINGLE THREADED mode and is NOT * shared. When the DBObject is retrieved via a VirtualDB (Read only data source) the DBObject is in * MULTI-THREADED mode and is shared.
*
* TODO: Create a "SingleThreadDBObject" interface to mark a DBObject as only being able to be accessed in single thread mode. *
*
* * * * * * *

Extending a DBObject

* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

What

When

Why ?

 
Events
 eventDataLoaded()When the underlying database record is changed ( Always Multi-threaded) *
    *
  1. Clear secondary cache items. *
*
 eventFieldUpdated() * When a field value is changed via a setXXXX method this method will be called. * *
    *
  1. Create composite keys based on the new field values. *
  2. Update other fields when a field changes. Eg. If a person's title is set to 'Mr' we could set the person's gender to be 'Male' *
  3. Touch() other objects that you wish to include in the universe validation. *
*
 extAutoEnterCreate() * When a new DBObject is created by calling create( className) method of a MutableDataSource, * *
    *
  1. Extend this method to add auto entered values. * If the values to be entered are "simple" values ('Mr', 'Entered' etc) or one of the predefined calculated ( Created By Person, Created time etc) then * these maybe selected in the DBField web administration screen *
*
 extDelete() * When a record is marked for deletion by calling the delete() method of DBObect. * *
    *
  1. We could also delete other associated records and thus avoid foreign key restrictions *
  2. We could set a status on a parent record. *
*
Listeners
 eventDependantAdded()When the DBObject implements a DependanceListener and a dependant record is added *
    *
  1. Clear secondary cache items. *
*
 eventDependantRemoved()When the DBObject implements a DependanceListener and a dependant record is removed *
    *
  1. Clear secondary cache items. *
*
Gets and Sets methods
 extGetDerivedGlobalKey()When a getXXXX method is called for a derived linked field *
    *
  1. To return a dynamically calculated linked field. *
*
 extGetDerivedValue()When a getXXXX method is called for a derived non linked field *
    *
  1. To return a dynamically calculated field value. *
*
 extGetValue()When a getXXXX method is called for any field *
    *
  1. Blank out a password or sensitive field. *
  2. Make sure that the value returned is the "SAME" value as would normally be returned as the database searches used the final method getPureValue() and will return unexpected results if the value is altered. *
*
 extSetValue()When a setXXXX method is called for any field *
    *
  1. Allow you to ignore a value set by any publicly available set methods *
  2. Any internal setting of values should be done via the final method iSetValue *
*
Validation
 extValidationDelete()During the validation process for a record that is marked for deletion
  1. To add validations for records marked for deletion only
 extValidationField()For each field during the validation process for a new or modified record
  1. To add validations for a field
 extValidationRecord()During the validation process for a new or modified record
  1. To add validations for a record as a whole
Saving
 extDeleteRecord()During the universe save process for a record marked for deletion, and within the database transaction
  1. Make changes to database tables that should be rolled back if the whole transaction doesn't succeed
 extPostDeleteRecord()When a record is deleted and after the database transaction has been completed
  1. Send a message to another system notifying that a record has been deleted
 extPostSaveRecord()When a record modified and after the database transaction has been completed
  1. Send a message to another system notifying that a record has been modified
 extPreDeleteRecord()When a record is marked for deletion and before the MutableDataSource's final call to validation universe and before a database transaction is started and batch save begins
  1. Set a status in a related record.
 extPreSaveRecord()When a record is new or modified and before the MutableDataSource's final call to validation universe and before a database transaction is started and batch save begins
  1. Set a status in a related record.
 extSaveRecord()During the universe save process for a new or modified record, and within the database transaction
  1. Make changes to database tables that should be rolled back if the whole transaction doesn't succeed
Field name constants
  
  1. Always use the field name constants when possible
Access Control and Result filters
 extCanDeleteDependantObject()During the validation process, each record marked for deletion will check that it can either delete any dependant objects or that it doesn't have any dependant objects.
  1. A dependant record maybe automatically deleted if the record is dependant via a link that has been marked as 'Parent Can Delete Child' and it has no children that can't be deleted via the same rules. Extend this method to alter this behaviour.
 extCheckCreateAccess()Called during the validation process of a new DBObject. The Standard ACL restrictions will be invoked before calling extCheckCreateAccess().
    *
  1. Add additional restrictions to the creation of DBObjects. *
  2. Additional access restrictions here are simular to a normal validation error for NEW records only. *
  3. This method can only add additional restrictions, it can not ignore ones generated via the ACL mechanism. *
*
 extCheckDeleteAccess()Called during the validation process of deleted ( and not new) records. The Standard ACL restrictions will be invoked before calling extCheckDeleteAccess().
    *
  1. Add additional restrictions to the deletion of records. *
  2. Additional access restrictions here are simular to a normal validation error for DELETED only records. *
  3. This method can only add additional restrictions, it can not ignore ones generated via the ACL mechanism. *
*
 extCheckModifyAccess()Called during the validation process of a modified records and for each field modified. The Standard ACL restrictions will be invoked before calling extCheckModifyAccess().
    *
  1. Add additional restrictions to the modification of records. *
  2. Additional access restrictions here are simular to a normal validation error for MODIFIED records only. *
  3. This method can only add additional restrictions, it can not ignore ones generated via the ACL mechanism. *
*
 extCheckReadAccess()Called during the selection process. If you can't read a record you can't modify or delete it. The Standard ACL restrictions will be invoked before calling extCheckModifyAccess().
    *
  1. Add additional restrictions to filter the selection of records. *
  2. This method can only add additional restrictions, it can not ignore ones generated via the ACL mechanism. *
*
*
*
* * THREAD MODE: MIXED, SINGLE-THREADED when called from MutableDataSource else READONLY * * @author Nigel Leck * @version $Revision: 1.807 $ * @since July 1, 2000, 2:52 PM */ public class DBObject { /** * the class of this object */ public final DBClass dbClass; /** * the datasource for this object */ public final DataSource ds; /** hack to prevent a stack overflow */ private static boolean callingDisplayNameFromGlobalKey=false;//MT CHECKED private static final ThreadLocal< Boolean > CALLING_RESTORE_BY_JOURNAL = new ThreadLocal< Boolean >() { @Override protected Boolean initialValue() { return Boolean.FALSE; } }; private static final ConcurrentDecimalFormat JOURNAL_CHECK_FORMAT=new ConcurrentDecimalFormat("0.####################"); /** * Creates new DBObject. * * @param theClass The class of this object * @param dataSource Your current data source * * @throws Exception Failed to initiate the database object. */ public DBObject(final DBClass theClass, final DataSource dataSource) throws Exception { this.ds = dataSource; if( theClass != null) { dbClass = theClass; } else { if( this instanceof DBRawClass) { dbClass = (DBClass)this; } else { throw new InvalidParameterException("no class"); } } } /*====================================================================================================*/ /*===== SET METHODS =====*/ /*====================================================================================================*/ /** * Update a boolean field by field name. * * @param flag The boolean value to set * @param name The name of the field to be updated * * @throws Exception A serious problem, most validation is done later ( It's OK to be invalid here). * * @see #extSetValue(DBField, Object, FldParams) extSetValue() To filter public setting of values */ public final void setBoolean( final String name, final boolean flag) throws Exception { setValue( name, flag ? Boolean.TRUE : Boolean.FALSE, null); } /** * Update a boolean field by field name * * @param params the parameters * @param flag The boolean value to set * @param name The name of the field to be updated * * @throws Exception A serious problem, most validation is done later ( It's OK to be invalid here). * * @see #extSetValue(DBField, Object, FldParams) extSetValue() To filter public setting of values */ public final void setBoolean( final String name, final boolean flag, final FldParams params) throws Exception { setValue( name, flag ? Boolean.TRUE : Boolean.FALSE, params); } /** * Update a boolean field by field * * @param flag The boolean value to set. * @param field The name of the field to be updated * * @throws Exception A serious problem, most validation is done later ( It's OK to be invalid here). * * @see #extSetValue(DBField, Object, FldParams) extSetValue() To filter public setting of values */ public final void setBoolean( final DBField field, final boolean flag) throws Exception { setValue( field, flag ? Boolean.TRUE : Boolean.FALSE, null); } /** * Update a boolean field by field * * @see #extSetValue(DBField, Object, FldParams) extSetValue() To filter public setting of values * @param params The parameters * @param flag The boolean value to set. * @param field The name of the field to be updated * @throws Exception A serious problem, most validation is done later ( It's OK to be invalid here). */ public final void setBoolean( final DBField field, final boolean flag, final FldParams params) throws Exception { setValue( field, flag ? Boolean.TRUE : Boolean.FALSE, params); } /** * Update a integer field by field name * * @param name The name of the field to be updated * @param value The new value of the field * * @throws Exception A serious problem, most validation is done later ( It's OK to be invalid here). * * @see #extSetValue(DBField, Object, FldParams) extSetValue() To filter public setting of values */ public final void setInt( final String name, final int value) throws Exception { setValue( name, Integer.valueOf( value), null); } /** * Update a integer field * * @param field The name of the field to be updated * @param value The new value of the field * * @throws Exception A serious problem, most validation is done later ( It's OK to be invalid here). * * @see #extSetValue(DBField, Object, FldParams) extSetValue() To filter public setting of values */ public final void setInt( final DBField field, final int value) throws Exception { setValue( field, Integer.valueOf( value), null); } /** * Update a integer field by field name * * @param name The name of the field to be updated * @param value The new value of the field * * @throws Exception A serious problem, most validation is done later ( It's OK to be invalid here). * * @see #extSetValue(DBField, Object, FldParams) extSetValue() To filter public setting of values */ public final void setValue( final String name, final int value) throws Exception { setInt( name, value); } /** * Update a integer field * * @param field The name of the field to be updated * @param value The new value of the field * * @throws Exception A serious problem, most validation is done later ( It's OK to be invalid here). * * @see #extSetValue(DBField, Object, FldParams) extSetValue() To filter public setting of values */ public final void setValue( final DBField field, final int value) throws Exception { setInt( field, value); } /** * Update a long field by field name * * @param name The name of the field to be updated * @param value The new value of the field * * @throws Exception A serious problem, most validation is done later ( It's OK to be invalid here). * * @see #extSetValue(DBField, Object, FldParams) extSetValue() To filter public setting of values */ public final void setLong( final String name, final long value) throws Exception { setValue( name, new Long(value), null); } /** * Update a long field * * @param field The field to be updated * @param value The new value of the field * * @throws Exception A serious problem, most validation is done later ( It's OK to be invalid here). * * @see #extSetValue(DBField, Object, FldParams) extSetValue() To filter public setting of values */ public final void setLong( final DBField field, final long value) throws Exception { setValue( field, new Long(value), null); } /** * Update a long field by field name * * @param name The name of the field to be updated * @param value The new value of the field * * @throws Exception A serious problem, most validation is done later ( It's OK to be invalid here). * * @see #extSetValue(DBField, Object, FldParams) extSetValue() To filter public setting of values */ public final void setValue( final String name, final long value) throws Exception { setLong( name, value); } /** * Update a long field * * @param field The field to be updated * @param value The new value of the field * * @throws Exception A serious problem, most validation is done later ( It's OK to be invalid here). * * @see #extSetValue(DBField, Object, FldParams) extSetValue() To filter public setting of values */ public final void setValue( final DBField field, long value) throws Exception { setLong( field, value); } /** * Update a double field by field name * * @param name The name of the field to be updated * @param value The new value of the field * * @throws Exception A serious problem, most validation is done later ( It's OK to be invalid here). * * @see #extSetValue(DBField, Object, FldParams) extSetValue() To filter public setting of values */ public final void setDouble( final String name, final double value) throws Exception { setValue( name, new Double(value), null); } /** * Update a double field by field * * @param field The field to be updated * @param value The new value of the field * * @throws Exception A serious problem, most validation is done later ( It's OK to be invalid here). * * @see #extSetValue(DBField, Object, FldParams) extSetValue() To filter public setting of values */ public final void setDouble( final DBField field, final double value) throws Exception { setValue( field, new Double(value), null); } /** * Update a double field by field name * * @param name The name of the field to be updated * @param value The new value of the field * * @throws Exception A serious problem, most validation is done later ( It's OK to be invalid here). * * @see #extSetValue(DBField, Object, FldParams) extSetValue() To filter public setting of values */ public final void setValue( final String name, final double value) throws Exception { setDouble( name, value); } /** * Update a double field by field * * @param field The field to be updated * @param value The new value of the field * * @throws Exception A serious problem, most validation is done later ( It's OK to be invalid here). * * @see #extSetValue(DBField, Object, FldParams) extSetValue() To filter public setting of values */ public final void setValue( final DBField field, final double value ) throws Exception { setDouble( field, value); } /** * Update a field by field name * * @param name The name of the field to be updated * @param value The new value of the field * * @throws Exception A serious problem, most validation is done later ( It's OK to be invalid here). * * @see #extSetValue(DBField, Object, FldParams) extSetValue() To filter public setting of values */ public final void setValue( final String name, final Object value) throws Exception { setValue( name, value, null); } /** * Update a field by field name * * @param params The fld params * @param name The name of the field * @param value The new value of the Field * * @throws Exception A serious problem, most validation is done later ( It's OK to be invalid here). * * @see #extSetValue(DBField, Object, FldParams) extSetValue() To filter public setting of values */ public final void setValue( final String name, final Object value, final FldParams params) throws Exception { DBField field = dbClass.getDBField(name); if( field == null) { String fldList = ""; DBField flds[] = dbClass.getDBFieldList(); for(int i=0;i * * Please this is different to just not being allowed to see the record that it is pointed to. As this is a fairly normal condition * @param name The field to check for the broken link * @return true if the link is broken */ public final boolean isBrokenLink( final String name) { DBField field = dbClass.getDBField( name); if( field == null) return false; return isBrokenLink( field); } /** * Is this field a "broken" link ? Does the field in this object have a value but we can't find the object that it points to.
* * Please this is different to just not being allowed to see the record that it is pointed to. As this is a fairly normal condition * @param field The field to check for the broken link * @return true if the link is broken */ public final boolean isBrokenLink( final DBField field) { /** * if not linked then it aren't a broken link */ if( field.isLinked() == false) { return false; } /** * runtime fields are never broken links. */ if( field.isRuntimeEval()) { return false; } GlobalKey gk = getGlobalKey( field); /** * no global key then it isn't linked to anything. */ if( gk == null) { return false; } DBObject obj; obj = getLinkedObject( field, null); /** * If we can find the object then we don't have a problem */ if( obj != null) { return false; } /** * OK lets see if it exists but we aren't allowed to see it. */ VirtualDB layer = ds.getDataBase(); try { layer.findKey( gk); // We found it. return false; } catch( NotFoundException nf) { return true; } } /** * When was this object last touched ? * @return The time in milli-seconds */ public final long lastTouched() { if( helper != null) return helper.lastTouched(); return 0; } /** * calls the fix up routines for this object * @throws Exception a serious problem */ public final void fixUp() throws Exception { touch(); //#DEV_ONLY_START extFixUpCalled = false; //#DEV_ONLY_END extFixUp(); //#DEV_ONLY_START if( extFixUpCalled == false) { throw new Exception( getClass().getName() + ".extFixUp() overridden but super not called"); } //#DEV_ONLY_END } /** * Mark this object for deletion ( when save is called for the mutable data source) * * @throws Exception A serious problem */ public final void delete() throws Exception { touch(); if( LOGGER.isDebugEnabled()) { LOGGER.debug( "DEBUG { " + getRowKey() + " } : delete"); } helper.deleted = true; DBField all[]; all = dbClass.getDBFieldListAll(); for( int i = 0; i < all.length; i++) { DBField field = all[i]; if( field.isLinked() && field.isRuntimeEval() == false) { if( field.isArray()) { Object obj = getValue(field); if( obj instanceof ArrayValue) { ArrayValue av = (ArrayValue)obj; int size = av.size(); FldParams params = new FldParams(); for( int pos = 0; pos < size; pos++) { params.setPosition(pos); GlobalKey key; key = getGlobalKey( field, params); DBObjectHelper.raiseDependantRemovedEvent(ds, getGlobalKey(), key, field.getGlobalKey()); } } } else { GlobalKey key; key = getGlobalKey( field); DBObjectHelper.raiseDependantRemovedEvent(ds, getGlobalKey(), key, field.getGlobalKey()); } } } DBField inwardLinks[] = dbClass.getInwardLinks(); for( int i = 0; i < inwardLinks.length; i++) { DBField sourceField = inwardLinks[i]; /** * If the linked field is derived then don't checked the foreign key * constraints as a Derived field is not stored and temporary by it's * nature. BTW: can cause huge performance problems too. */ if( sourceField.isRuntimeEval()) continue; DBResult r = getInwardLinkage( sourceField, null); while( true) { DBObject o; o = r.next(); if( o == null) break; if( o.isDeleted() == false) { if( sourceField.canParentRemoveChild() || o.isNew() || extCanDeleteDependantObject( o)) { o.delete(); o.helper.setDeletedBy( this); helper.addCascadeDelete( o); } else if( sourceField.canParentClearChild()) { o.setValue( sourceField, null); helper.setClearedBy( o, sourceField); } } } } //#DEV_ONLY_START extDeleteCalled = false; //#DEV_ONLY_END extDelete( ); //#DEV_ONLY_START if( extDeleteCalled == false) { DBAccessException ae = new DBAccessException( getGlobalKey(), "Can't delete: " + getClass().getName() + ".extDelete() overridden but super not called" ); LOGGER.error( "Programmer error", ae); throw ae; } //#DEV_ONLY_END } /** * undelete this object * * @throws Exception a serious problem */ public final void undelete() throws Exception { touch(); if( helper.deleted == false) { DBDataInterface rawData = getRawData(); if( rawData == null || rawData.isDeleted(ds.getDataBase(), null) == false) { return; } } helper.doUndelete(); //#DEV_ONLY_START extUndeleteCalled = false; //#DEV_ONLY_END extUndelete( ); //#DEV_ONLY_START if( extUndeleteCalled == false) { DBAccessException ae = new DBAccessException( getGlobalKey(), "Can't delete: " + getClass().getName() + ".extDelete() overridden but super not called" ); LOGGER.error( "Programmer error", ae); throw ae; } //#DEV_ONLY_END } /** * we are currently calling restore by journal * @return true if currently calling */ public boolean callingRestoreByJournal() { return CALLING_RESTORE_BY_JOURNAL.get(); } /** * restore by journal * @param tr the transaction record * @param replayMode the replay mode * @throws java.lang.Exception a serious problem. */ public void restoreByJournal( final TransRecord tr, final boolean replayMode) throws Exception { try { CALLING_RESTORE_BY_JOURNAL.set(Boolean.TRUE); touch(); ArchiveDataSource ads = new ArchiveDataSource( ds, new Date(), true, true); ads.exclude( tr.getTransHeader()); DBObject previousVersion; try { previousVersion = ads.findRow(tr.getRowUID(), tr.getDBClass(), null); } catch( NotFoundException nf) { return; } DBField fieldList[] = previousVersion.dbClass.getDBFieldListAll(); for( DBField fld: fieldList) { if( fld.isRuntimeEval()) continue; String logValue=""; if( replayMode == false) { ModData md = (ModData)helper.updatedData.get( fld.getGlobalKey().toString()); if( md == null) { md = new ModData( fld, null, null ); helper.updatedData.put( md.getKey(), md); } if( fld.isArray()) { Object value = previousVersion.getValue(fld); if( value instanceof StoredArrayValue) { MutableArrayValue mav = MutableArrayValue.create( this, fld, (StoredArrayValue)value, helper); md.setCurrentValue( mav); logValue = mav.toString(); md.setCurrentKey( null); } else { md.setCurrentValue( value); if( value != null) { logValue = value.toString(); } md.setCurrentKey( null); } } else if( fld.isLinked()) { GlobalKey previousKey = previousVersion.getGlobalKey(fld); if( previousKey != null) { logValue = previousKey.toString(); md.setCurrentValue( previousKey.getString()); md.setCurrentKey( previousKey); } else { md.setCurrentValue( null); md.setCurrentKey( null); } } // simple field else { Object value = previousVersion.getValue(fld); if( value != null) { logValue = value.toString(); } md.setCurrentValue( value); } } else { if( fld.isArray()) { Object value = previousVersion.getValue(fld); if( value != null) { logValue = value.toString(); } setValue( fld, value); } else if( fld.isLinked()) { GlobalKey previousKey = previousVersion.getGlobalKey(fld); if( previousKey != null) { logValue = previousKey.toString(); } setValue( fld, previousKey); } // simple field else { Object value; value = previousVersion.iGetRawValue(fld); if( value != null) { logValue = value.toString(); } setValue( fld, value); } } TransHeader.writeThreadEraseLog( "UPDATE " + dbClass.getName() +"\n" + "SET " + fld.getName() + "='" + StringUtilities.replace(logValue, "'", "\\'") + "'\n" + "WHERE GLOBAL_KEY IS " + getGlobalKey() + ";\n" ); } } finally { CALLING_RESTORE_BY_JOURNAL.set( Boolean.FALSE); } } /** * copy the object * * @param mds the data source to create the object from * * @throws Exception A serious problem * * @return The new object */ public final DBObject copy( final MutableDataSource mds) throws Exception { if( LOGGER.isDebugEnabled()) { LOGGER.debug( "DEBUG { " + getRowKey() + " } : copy"); } DBObject obj; obj = mds.create( dbClass); obj.copyFields( this); //#DEV_ONLY_START extCopyCalled = false; //#DEV_ONLY_END extCopy( obj); //#DEV_ONLY_START if( extCopyCalled == false) { DBAccessException ae = new DBAccessException( getGlobalKey(), "Can't copy: " + getClass().getName() + ".extCopy() overridden but super not called" ); LOGGER.error( "Programmer error", ae); throw ae; } //#DEV_ONLY_END return obj; } /** * This allows the indexes for a records to be fixed up * * TODO: Should check for dirty cache. * * @throws Exception Failed to reindex */ public final void reindex( ) throws Exception { if( data == null) { throw new Exception( "can not reindex a new record."); } touch(); helper.reindexOnly = true; helper.forceReindex = true; long logicalLockTransId = data.getTransId( ds.getDataBase(), null); helper.setlockedTransaction( logicalLockTransId); } /** * Is the DBObject marked for reindexing only ? * * @return TRUE if marked for reindex. */ public final boolean isReindex() { if( helper == null) return false; return helper.reindexOnly; } /** * Standard method for Populating the fields when the object is created. * @see #extAutoEnterCreate() extAutoEnterCreate for a overridable method. * * @throws Exception Failed to auto enter value. */ public final void autoEnterCreate() throws Exception { if( isNew() == false) { throw new Exception( "autoEnterCreate() for an old record"); } DBClassConcrete def = dbClass; do { /* Auto enter specified fields */ DBField[] list = def.getDBFieldList(); for(int f=0; f < list.length; f++) { DBField field = list[f]; autoEnterCreate( field); } def = def.getParentDBClassConcrete(); } while( def != null); //#DEV_ONLY_START extAutoEnterCreateCalled = false; //#DEV_ONLY_END extAutoEnterCreate( ); //#DEV_ONLY_START if( extAutoEnterCreateCalled == false) { LOGGER.error( "Programmer error: " + getClass().getName() + ".extAutoEnterCreate() overridden but 'super' not called" ); } //#DEV_ONLY_END } /** * Gets the description for this object * * @throws Exception a Serious problem * @return The description */ public String getDesc() throws Exception { DBClass def = dbClass; String oDesc = def.getName() + ":" + getGlobalKey(); return oDesc; } /** * Returns the key value. Once a record has been created this never changes. * * @return The key Value */ public final Object getKeyValue() { if( cacheKeyValue == null) { DBField keyField = dbClass.getKeyField(); if( keyField == null) return null; Object value = getValue( keyField); if( isNew()) { return value; } cacheKeyValue = value; } return cacheKeyValue; } /** * The string version of the key * * @return The string key */ public final String getKeyString() { Object value = getKeyValue(); if( value == null) return ""; return value.toString(); } /** * Returns the unique global row id * * MutableDataSource uses a single thread model. No need to synchronized * * @return The row id */ public final long getRowId() { if( data instanceof DBData) { return ((DBData)data).rowId; } if( data != null) { return data.getRowId(); } if( this instanceof DBRawClass) { return ((DBRawClass)this).getRawRowId(); } if( this instanceof DBRawField) { return ((DBRawField)this).getRawRowId(); } Long rowKey = getRowKey(); return rowKey.longValue(); } /** * Return the row key ( Long) * * @return The row key */ public final Long getRowKey() { if( data != null) { return new Long( data.getRowId()); } if( helper != null && helper.newRowKey != null) return helper.newRowKey; if( helper == null) helper = new DBObjectHelper( this); if( this instanceof DBRawClass) { helper.newRowKey = new Long( ((DBRawClass)this).getRawRowId()); return helper.newRowKey; } int layerId = ds.getDataBase().id; long id = ds.nextNumber( MutableDataSource.NEXT_NUMBER_ROWID, 100); helper.newRowKey = new Long( GlobalRowId.makeLongId( layerId, id)); return helper.newRowKey; } /** * Returns the source layer of this object * * @return The source layer ( virtual DB) */ public int getSrcLayerID() { if( isNew()) { return ds.getDataBase().id; } int dbId; dbId = GlobalRowId.parseLayerId( getRowId()); return dbId; } /** * Returns the default value for the field. * * @param field The field to check * @return The default Value. */ public final Object getDefaultValue( final DBField field) { if( helper != null) { ModData tmpData; tmpData = (ModData)helper.updatedData.get( field.getGlobalKey().toString()); if( tmpData == null ) return null; return tmpData.getDefaultValue(); } return null; } /** * Get the cached DBResult set for the linkage passed. *
* Job:personId -> Contact::Person
*
* Passing the field "job:personId" to a person object will return all jobs for
* that person. * @return The list of DBObjects that point to this DBObject. * @param hint hint of other objects * @param sourceField The field that is linked to this class. * @throws Exception a serious problem */ public final DBResult getInwardLinkage( final DBField sourceField, final HintField hint) throws Exception { DBClassAbstract baseClass = sourceField.getBaseDBClassAbstract(); if( baseClass instanceof DBClass) { return ds.getInwardLinkage( (DBClass)baseClass, sourceField, this, hint); } else { DBClass list[] = baseClass.listClass(); HashLongMap map = new HashLongMap(); for( int i = 0; i < list.length; i++) { DBResult r = ds.getInwardLinkage( list[i], sourceField, this, hint); long rows[] = r.makeRowList(); map.putMultiRows( rows, ""); } PossibleRowsHolder pr= PossibleRowsHolder.create( map.getSortedKeyArray(), true); DBResult r = new DBResult( baseClass, ds, pr, null); return r; } } /** * Returns the linked object for the passed field * * @param fieldName The linked field name. * @return The linked object */ public final DBObject getLinkedObject( final String fieldName) { return getLinkedObject( fieldName, null); } /** * Returns the linked object for the passed field * @return The linked object * @param params The field parameters to use * @param fieldName The linked field name. */ public final DBObject getLinkedObject( final String fieldName, final FldParams params) { DBField field = dbClass.getDBField(fieldName); if( field == null ) return null; return getLinkedObject(field, params); } /** * Returns the linked object for the passed field * @return The linked Object * @param params The field parameters to use * @param field The linked field */ @SuppressWarnings("empty-statement") public final DBObject getLinkedObject( final DBField field, final FldParams params) { if( params != null && field.isArray()) { int pos = params.getPosition(); if( pos == -1 ) return null; Object obj = getValue(field); if( obj instanceof ArrayValue) { ArrayValue array = (ArrayValue)obj; Object value = array.rawGet( pos); if ( value instanceof LinkedValue) { LinkedValue lv = ((LinkedValue)value); long linkedRowId = lv.rowUID; if( linkedRowId != 0) { try { DBObject linkedObj = ds.findRow( linkedRowId, field.getLinkedDBClassConcrete(), null); return linkedObj; } catch( NotFoundException nf) { ; } } GlobalKey gk = lv.gkey; if( gk != null) { try { DBObject linkedObj = ds.findKey(gk); return linkedObj; } catch( NotFoundException nf) { ; } } } } return null; } else { long linkedRowId = getLinkedRowIdByData(field, params); if( linkedRowId != 0) { try { DBObject obj = ds.findRow( linkedRowId, field.getLinkedDBClassConcrete(), null); return obj; } catch( NotFoundException nf) { ; } } return getLinkedObjectByKey( field, params); } } /** * get the linked object by key * @return The linked object * @param params the field parameters to use * @param field The linked field */ public final DBObject getLinkedObjectByKey( final DBField field, final FldParams params) { if( field == null) return null; GlobalKey gk; gk = getGlobalKey( field, params); if( gk == null) { return null; } try { return ds.findKey( gk); } catch( DBAccessException access) { return null; } catch( DeletedRecordException access) { return null; } catch( NotFoundException nf) { if( isDeleted()) { return null; } if( LOGGER.isDebugEnabled()) { LOGGER.debug( "Try to relink global key... " + gk); } DBClass linkedClass = field.getLinkedDBClass(); DBField keyField = linkedClass.getKeyField(); if( keyField == null) { LOGGER.error( getGlobalKey() + ".getLinkedObject(" + field.getName() + ") linked to a class that has no key", nf ); return null; } try { DBObject obj; DBQuery q = new DBQuery( linkedClass, ds); q.addClause( keyField, "=", gk.getValue()); DBResult r; r = q.search(); obj = r.next(); if( obj != null && ds instanceof MutableDataSource) { /* Only setValue if you are not in validateUniverse */ if (!((MutableDataSource)ds).isInValidateUniverse()) { try { /** * Only try to relink this broken link once. * to prevent a stack overflow. */ if( RELINKING_OBJECTS.get( getGlobalKey().toString()) == null) { RELINKING_OBJECTS.put( getGlobalKey().toString(), ""); iSetValue( field, obj, null); } } finally { RELINKING_OBJECTS.remove( getGlobalKey().toString()); } } } return obj; } catch( Exception e) { LOGGER.error( getGlobalKey() + ".getLinkedObject(" + field + ") relink up " + gk, e ); } return null; } catch( Throwable t) { LOGGER.error( getGlobalKey() + ".getLinkedObject(" + field + ")", t ); return null; } } /** * Returns the row id of the linked object for the passed field * * @return The row id of the linked object * @param params the field parameters to use * @param fieldName The linked field name. */ public final long getLinkedRowId( final String fieldName, final FldParams params) { return getLinkedRowId(dbClass.getDBField(fieldName), params); } /** * Returns the row id of the linked object for the passed field * * @return The row id of the linked Object * @param params the field parameters to use * @param field The linked field */ public final long getLinkedRowId( final DBField field, final FldParams params) { long linkedRowId = getLinkedRowIdByData(field, params); if( linkedRowId != 0) return linkedRowId; DBObject obj = getLinkedObjectByKey(field, params); if (obj != null) { return obj.getRowId(); } return 0; } /** * find the linked row id using the underlying raw data * * @return the linked row id * @param params the field parameters to use * @param field The linked field */ public final long getLinkedRowIdByData( final DBField field, final FldParams params) { if (field == null) { return 0; } /** If the object is new we can't use the data */ if (data == null) return 0; if( helper != null) { /** If the field has been modified */ ModData md = (ModData)helper.updatedData.get( field.getGlobalKey().toString()); if( md != null) { return 0; } } VirtualDB layer = ds.getDataBase(); long linkedRowId = data.getLinkedRowId(layer, field, null); return linkedRowId; } /** * A short hand method of getting a result set for a path from this object. * * @param thePath The search path * @throws Exception A problem with the search * @return The result set. */ public final DBResult doSearch( final String thePath) throws Exception { Path path = new Path( ds, thePath); return path.getResult(this, null); } /** * Returns a list of non mutable changed fields and corresponding values/keys. * * @return The list of fields that have been changed. */ public final ChangedFields getChangedFields() { ChangedFieldData list[]; if( helper != null) { ArrayList array = new ArrayList(); Object keys[] = helper.updatedData.keySet().toArray(); for(int i = 0; i < keys.length; i++) { ModData md = (ModData)helper.updatedData.get( keys[i]); ChangedFieldData fd; fd = new ChangedFieldData( md.getField(), md.getOriginalValue(), md.getOriginalKey(), md.getDefaultValue(), md.getDefaultKey(), md.getCurrentValue(), md.getCurrentKey() ); array.add( fd); } if( GlobalRowId.parseLayerId( getRowId()) != ds.getDataBase().id) { DBField fields[] = dbClass.getDBFieldListAll(); VirtualDB parentDB = ds.getDataBase().parentDb; VirtualDB vDB = ds.getDataBase(); /* Only record the fields that have changed. */ for( int i = 0; i < fields.length; i++) { DBField field = fields[i]; if( field.isRuntimeEval()) continue; if( helper.updatedData.get( field.getGlobalKey().toString()) != null) continue; if( data.hasRawFieldInLayer( vDB, field, null) == false) continue; Object v1 = getRawValue( field), v2 = data.getRawValue( parentDB, field, null); boolean theSameAsBelow = false; if( v1 != null && v2 != null) { if(v1.equals( v2)) { theSameAsBelow = true; } } if( theSameAsBelow) { ChangedFieldData fd; fd = new ChangedFieldData( field, v2, data.getGlobalKey( parentDB, field, null), null, null, v1, getGlobalKey( field) ); array.add( fd); } } } list = new ChangedFieldData[ array.size()]; array.toArray( list); } else { list = new ChangedFieldData[0]; } return new ChangedFields( list); } /** * Returns a non mutable changed field and corresponding values/keys. * @return A ChangedFieldData object for the specified field * @param field The field */ public final ChangedFieldData getChangedFieldInfo( final DBField field) { ChangedFieldData fd = null; ModData md = (ModData)helper.updatedData.get( field.getGlobalKey().toString()); if( md != null) { fd = new ChangedFieldData( md.getField(), md.getOriginalValue(), md.getOriginalKey(), md.getDefaultValue(), md.getDefaultKey(), md.getCurrentValue(), md.getCurrentKey() ); } return fd; } /** * Adds a object to be notified when this object is reloaded. * * @param listener The object to be notified. */ public final synchronized void addReloadEventListener( final ReloadEventListener listener) { reloadEventListeners = DBObjectHelper.iAddEventListener( this, reloadEventListeners, listener); } /** * Adds a object to be notified when this object is reloaded. * * @param listener The object to be notified. */ public final synchronized void removeReloadEventListener( final ReloadEventListener listener) { DBObjectHelper.removeEventListener( reloadEventListeners, listener); } /** * Allows the on Change Event to be disabled. An example of when to do this is when * we copy an object. If the onChangeEvent wasn't disabled the copied object could be * different due to auto entered values. * * @param flag on or off */ public final void setDisableOnChangeEvent( final boolean flag) { if( helper == null) helper = new DBObjectHelper( this); helper.disableOnChange = flag; } /** * Is on changed disabled * @return is disabled */ public boolean getDisableOnChangeEvent() { if( helper == null) return false; return helper.disableOnChange; } /** * The description. * * @return The description */ @Override public String toString() { return displayName(); } /*====================================================================================================*/ /*===== GET GLOBAL KEY =====*/ /*====================================================================================================*/ /** * Returns the GlobalKey for this DBObject.
*
* THREAD SAFE Caching of global keys is easier than other things. A property of * a key is it may not be changed once created, so only updating of the key field needs * to be checked. Which may only be done in a MutableDataSource which is single threaded. * * @return The Global Key */ public final GlobalKey getGlobalKey() { GlobalKey gk=null; if( helper != null) { gk = helper.cacheGlobalKey; if( gk != null) { return gk; } } if( data != null) { gk = data.getGlobalKey(null); } else { if( this instanceof DBRawField) { gk = ((DBRawField)this).getRawGlobalKey(); } else if( this instanceof DBRawClass) { gk = ((DBRawClass)this).getRawGlobalKey(); } else { gk = new GlobalKey( this); } } if( helper != null) { helper.cacheGlobalKey=gk; } return gk; } /** * Returns the GlobalKey for the linked object via the passed field name. * * @param fieldName The name of the linked field. * @return The global key of the linked object. */ public final GlobalKey getGlobalKey( final String fieldName) { return getGlobalKey(fieldName, null); } /** Returns the GlobalKey for the linked object via the passed field name. * @return The global key of the linked object. * @param params The parameters for this request. * @param fieldName The name of the linked field. */ public final GlobalKey getGlobalKey( final String fieldName, final FldParams params) { DBField field = dbClass.getDBField(fieldName); if( field == null) { String tempName = "unknown"; if( callingDisplayNameFromGlobalKey == false) { try { callingDisplayNameFromGlobalKey = true; tempName = displayName(); } finally { callingDisplayNameFromGlobalKey=false; } } LOGGER.info( tempName + ".getGlobalKey( '" + fieldName + "') no such field"); return null; } return getGlobalKey(field, params); } /** * Returns the GlobalKey for the linked object via the passed field name. * * @param field The linked field * @return The GlobalKey of the linked object */ public final GlobalKey getGlobalKey( final DBField field) { return getGlobalKey( field, null); } /** * Returns the GlobalKey for the linked object via the passed field name. * * @return The GlobalKey of the linked object * @param params The parameters for this request. * @param field The linked field */ @SuppressWarnings("empty-statement") public final GlobalKey getGlobalKey( final DBField field, final FldParams params) { if( field == null) return null; if( field.isKey()) { return getGlobalKey(); } if( field.isLinked() == false) return null; if( this instanceof DBRawField) { return ((DBRawField)this).getRawGlobalKey( field); } if( params != null && field.isArray()) { int pos = params.getPosition(); if( pos == -1 ) return null; Object obj = getValue(field); if( obj instanceof ArrayValue) { ArrayValue array = (ArrayValue)obj; Object value = array.rawGet( pos); if ( value instanceof LinkedValue) { LinkedValue lv = ((LinkedValue)value); long linkedRowId = lv.rowUID; if( linkedRowId != 0) { try { DBObject linkedObj = ds.findRow( linkedRowId, field.getLinkedDBClassConcrete(), null); return linkedObj.getGlobalKey(); } catch( NotFoundException nf) { ; } } GlobalKey gk = lv.gkey; if( gk != null) { return gk; } } } return null; } if( helper != null) { GlobalKey fk = field.getGlobalKey(); ModData tmpData = (ModData)helper.updatedData.get( fk.toString()); if( tmpData != null) { return tmpData.getCurrentKey(); } } if( field.isRuntimeEval()) { if( StringUtilities.isBlank( field.getString( DBField.DBFIELD_FORMULA)) == false) { Object value = null; try { value = DBObjectHelper.calculateValue( this, field, params); } catch( Exception e) { LOGGER.warn( "getGlobalKey(" + field + ", " + params + ")", e ); return null; } if( value instanceof GlobalKey) { return (GlobalKey)value; } else { try { DBQuery q = new DBQuery( field.getLinkedDBClass(), ds); q.addClause( field.getLinkedDBClass().getKeyField(), "=", value); DBResult r; r = q.search(); DBObject obj = r.next(); if( obj != null) { return obj.getGlobalKey(); } } catch( Exception e) { LOGGER.warn( "getGlobalKey()", e); } } return null; } else { try { /* No Programmer check here as this is called in a multi-thread environment so we would have to synchronize */ GlobalKey gk = extGetDerivedGlobalKey( field, params); if( gk != null) { return gk; } } catch( Exception e) { LOGGER.warn( "getGlobalKey()", e); return null; } Object o = null; try { o = extGetDerivedValue( field, params); } catch( Exception e) { LOGGER.warn( "getGlobalKey()", e); return null; } if( o == null) return null; if( o instanceof GlobalKey) { return (GlobalKey)o; } DBQuery q = new DBQuery( field.getLinkedDBClass(), ds ); try { q.addClause( field.getLinkedDBClass().getKeyField(), "=", o); return q.findOne().getGlobalKey(); } catch( Exception e) { return null; } } } if( data != null) { return data.getGlobalKey(ds.getDataBase(), field, null); } return null; } /*====================================================================================================*/ /*===== VALIDATION =====*/ /*====================================================================================================*/ /** * Performs additional validations on this record. iValidateRecord performs the * full list of validations. * * The returned vector is a list of validationItems which may be warnings or errors. * * OVERRIDE this method to add additional validations to a record.
* The MutableDataSource is in READONLY mode at this stage. * * @throws Exception A serious problem * @return the list of errors and warnings. */ public final ValidationList validateRecord() throws Exception { ValidationList vl = new ValidationList( ds); iValidateRecord( vl, null); return vl; } /** * check the archive version to the current version. * * @throws Exception A serious problem * @return the list of errors and warnings. */ public final ValidationList archiveCheck() throws Exception { ValidationList vl = new ValidationList( ds); if( isNew() == false) { if( dbClass.getBoolean( DBClass.DBFIELD_RECORD_NO_JOURNAL_DATA) == false && dbClass.getBoolean( DBClass.DBFIELD_RECORD_NO_INTIAL_DATA) == false ) { HintData hint = null; if( ds instanceof MutableDataSource) { MutableDataSource mds = (MutableDataSource)ds; hint = mds.getJournalHint(dbClass); } Date date = (Date)ds.getCacheObject("ARCHIVE_CHECK_DATE"); if( date== null) { date = new Date(); } ArchiveDataSource ads = new ArchiveDataSource( ds, date, true, true); DBObject archiveVersion = null; try { archiveVersion= ads.findRow(getRowId(), dbClass, hint); } catch( NotFoundException nf) { vl.createError(this, null,this + " can't find archive version"); return vl; } if( dbClass.getClassId().equals( archiveVersion.dbClass.getClassId()) == false) { vl.createError(this, null,this + " not of type " + dbClass + " was " + archiveVersion.dbClass); return vl; } DBField fields[] = dbClass.getDBFieldListAll(); for( DBField fld : fields) { if( fld.isRuntimeEval()) continue; if( hasFieldChanged(fld)) continue; Object currentValue = getRawValue(fld); if( currentValue instanceof MultiLingualValue) { MultiLingualValue mlv = (MultiLingualValue)currentValue; if( mlv.isEmpty()) { currentValue=""; } } if( currentValue instanceof ArrayValue) { ArrayValue av = (ArrayValue)currentValue; if( av.size() == 0) { currentValue=null; } else { currentValue=av.toString(); } } // truncate to the seconds. if( currentValue instanceof Date) { Date d = (Date)currentValue; currentValue = new Date( d.getTime()/1000 * 1000); } if( fld.getType() == DBField.TYPE_BOOLEAN) { if( currentValue == null) { currentValue=Boolean.FALSE; } } if( fld.getType() == DBField.TYPE_CUSTOM) { if( currentValue != null) { currentValue=currentValue.toString(); } } if( currentValue instanceof Number ) { if( ((Number)currentValue).doubleValue() > Float.MAX_VALUE) { currentValue = Float.MAX_VALUE; } if( ((Number)currentValue).doubleValue() < Float.MIN_VALUE) { currentValue = Float.MIN_VALUE; } currentValue = JOURNAL_CHECK_FORMAT.format(currentValue); } Object archiveValue = ""; if( archiveVersion != null) { archiveValue = archiveVersion.getRawValue(fld); } // truncate to the seconds. if( archiveValue instanceof Date) { Date d = (Date)archiveValue; archiveValue = new Date( d.getTime()/1000 * 1000); } if( archiveValue instanceof MultiLingualValue) { MultiLingualValue mlv = (MultiLingualValue)archiveValue; if( mlv.isEmpty()) { archiveValue=""; } } if( archiveValue instanceof ArrayValue) { ArrayValue av = (ArrayValue)archiveValue; if( av.size() == 0) { archiveValue=null; } else { archiveValue=av.toString(); } } if( fld.getType() == DBField.TYPE_BOOLEAN) { if( archiveValue == null) { archiveValue=Boolean.FALSE; } } if( fld.getType() == DBField.TYPE_CUSTOM) { if( archiveValue != null) { archiveValue=archiveValue.toString(); } } if( archiveValue instanceof Number ) { if( ((Number)archiveValue).doubleValue() > Float.MAX_VALUE) { archiveValue = Float.MAX_VALUE; } if( ((Number)archiveValue).doubleValue() < Float.MIN_VALUE) { archiveValue = Float.MIN_VALUE; } archiveValue = JOURNAL_CHECK_FORMAT.format(archiveValue); } boolean problem=false; if( StringUtilities.isBlank( currentValue)) { if( StringUtilities.isBlank(archiveValue)) continue; vl.createError(this, fld, "removed '" + archiveValue +"'"); problem = true; } else if( StringUtilities.isBlank(archiveValue)) { if( StringUtilities.isBlank(currentValue)) continue; vl.createError(this, fld, "added '" + currentValue +"'"); problem = true; } else if( currentValue.equals(archiveValue) == false) { vl.createError(this, fld, "changed '" + archiveValue +"'->'" + currentValue +"'"); problem = true; } if( problem) { touch(); HashLongMap rm = (HashLongMap)ds.getAttribute(DBObjectHelper.ATTRIBUTE_CORRUPT_JOURNAL_FIELD); if( rm == null) { rm = new HashLongMap(); ((MutableDataSource)ds).setAttribute(DBObjectHelper.ATTRIBUTE_CORRUPT_JOURNAL_FIELD, rm); } HashMap fm = (HashMap)rm.get(getRowId()); if( fm == null) { fm = new HashMap(); rm.put( getRowId(), fm); } fm.put(fld.getFieldId().toString(), ""); } } } } return vl; } /** * Validate this field. * * @param field The field to be validated * @throws Exception a serious error * @return the error or warning. */ public final ValidationItem validateField( final DBField field) throws Exception { ValidationList list = new ValidationList( ds); iValidateField( field, list, null); return list.getWorstItem(); } /** * Checks if this object may be deleted. Foreign key restrictions. * * @throws DBAccessException You may not delete */ public final void checkDelete( ) throws DBAccessException { Hashtable table = new Hashtable(); checkDelete( table); } /** * Checks the users select access. * * @throws DBAccessException If the user has no select access */ public final void checkReadAccess() throws DBAccessException { // Stop recursion if( dbClass.getGlobalKey().equals( DBRawClass.CLASS_GKEY)) { return; } if( isNew() == false && ds instanceof VirtualDB == false ) { DBObject o; GlobalKey gk = getGlobalKey(); try { o = ds.getDataBase().findKey(gk); } catch(NotFoundException nfe) { throw new DBAccessException ( gk, "Record is deleted.", nfe); } o.iCheckReadAccess( ds); } } /** * * Checks the users select access. * This method provides greater performance then checkReadAccess() * in the case where we already have the object from virtual db * and the login from mutable data source as is the case for * MutableDataSource.recycleObject * @param realDS the real data source * @throws DBAccessException If the user has no select access */ public final void iCheckReadAccess(final DataSource realDS) throws DBAccessException { // Stop recursion if( dbClass.getGlobalKey().equals( DBRawClass.CLASS_GKEY)) { return; } DataSource oDS = VirtualDB.setCurrentDataSource( realDS); try { DBCriteria criteria = realDS.getLogin().getReadCriteria( dbClass); if( criteria != null) { DBObject obj; if( ds instanceof VirtualDB) { obj = this; } else { try { //Try to use the current version else the archive version obj = ds.getDataBase().findRow( getRowId(), dbClass, null); } catch( NotFoundException nf) { if( ds instanceof ArchiveDataSource) { // this is ok we'll use the archive version obj = this; } else { throw nf; } } } if( criteria.matches( obj, null) == false) { throw new DBAccessException( getGlobalKey(), "Cannot read: Access Denied\n" + criteria.toString() ); } } //#DEV_ONLY_START boolean extCheckReadAccessCalled[] = (boolean[])localExtCheckReadAccessCalled.get(); if( extCheckReadAccessCalled == null) { extCheckReadAccessCalled = new boolean[1]; localExtCheckReadAccessCalled.set(extCheckReadAccessCalled); } extCheckReadAccessCalled[ 0 ]= false; //#DEV_ONLY_END extCheckReadAccess(); //#DEV_ONLY_START if( extCheckReadAccessCalled[ 0 ] == false) { DBAccessException ae = new DBAccessException( getGlobalKey(), "Can't read: " + getClass().getName() + ".extCheckReadAccess() overridden but super not called" ); LOGGER.error( "Programmer error", ae); throw ae; } //#DEV_ONLY_END } catch( DBAccessException access) { throw access; } catch( Exception e) { LOGGER.error( "checkReadAccess()", e); throw new DBAccessException( getGlobalKey(), "Can't read: " + e.toString(), e); } finally { VirtualDB.setCurrentDataSource( oDS); } } /** * Checks the user has MODIFY access to this field of this object * * @see #extCheckModifyAccess() extCheckModifyAccess to add additional conditions. * * @param field The field to check * @throws DBAccessException No access */ public final void checkModifyAccess(final DBField field) throws DBAccessException { // check if it is derived field or calculated if( field.isRuntimeEval()) { throw new DBAccessException( getGlobalKey(), "Can't modify a runtime evaluated field (" + field + ")" ); } //#DEV_ONLY_START extCheckModifyAccessCalled = false; //#DEV_ONLY_END extCheckModifyAccess( field); //#DEV_ONLY_START if( extCheckModifyAccessCalled == false) { DBAccessException ae = new DBAccessException( getGlobalKey(), "Can't modify: " + getClass().getName() + ".extCheckWriteAccess(" + field + ") overridden but super not called" ); LOGGER.error( "Programmer error", ae); throw ae; } //#DEV_ONLY_END } /** * Check the user has MODIFY access to this obeject. * * @see #extCheckModifyAccess extCheckModifyAccess to add additional conditions. * * @throws DBAccessException No access */ public final void checkModifyAccess() throws DBAccessException { if( data != null && data.isFinal(ds.getDataBase(), null)) { throw new DBAccessException( getGlobalKey(), "Can't modify: Record marked as final (" + this + ")" ); } if( ds instanceof VirtualDB == true) { throw new RuntimeException( "Cannot modify in virtual db datasource."); } if( isNew() == false) { Login login = getLogin(); if( login.isSystem()) return; DBObject o; try { o = ds.getDataBase().findRow(getRowId(), dbClass, null); } catch( Exception e) { LOGGER.error( "checkReadAccess()", e); throw new RuntimeException ( "Could not get login checkModifyAccess().", e); } o.iCheckModifyAccess( ds); } } /** * Internal ONLY * @param realDS the real data source * @throws DBAccessException no access */ public final void iCheckModifyAccess(final DataSource realDS) throws DBAccessException { // Modify access checking should be done on the raw object without any // changes applied if( ds instanceof VirtualDB == false && ds instanceof ArchiveDataSource == false) { DBAccessException ae = new DBAccessException( getGlobalKey(), "Can't modify: " + getClass().getName() + ".iCheckModifyAccess() should be called on an object from virtualdb" ); LOGGER.error( "Programmer error", ae); throw ae; } DataSource oDS = null; try { oDS = VirtualDB.setCurrentDataSource( realDS); DBCriteria criteria = realDS.getLogin().getModifyCriteria( dbClass); // Check firstly that the modify rules do not apply to // original values if( criteria != null && criteria.matches( this, null) == false) { DBAccessException ae = makeModifyAccessException( criteria); if( ae == null) { throw new RuntimeException( "Programmer error: makeModifyAccessException returned null"); } throw ae; } iExtCheckModifyAccess(); } catch( DBAccessException access) { throw access; } catch( Exception e) { LOGGER.error( "checkModifyAccess()", e); throw new DBAccessException( getGlobalKey(), "Can't modify: " + e.toString(), e ); } finally { VirtualDB.setCurrentDataSource( oDS); } } /** * Checks the user has delete access to this object * * @see #extCheckDeleteAccess() extCheckDeleteAccess to add additional conditions. * * @throws DBAccessException No Access */ public final void checkDeleteAccess() throws DBAccessException { if( data != null && data.isFinal(ds.getDataBase(), null)) { throw new DBAccessException( getGlobalKey(), "Can't Delete: Record marked as final (" + this + ")" ); } if( ds instanceof VirtualDB == true) { throw new RuntimeException( "Cannot delete from virtual db datasource."); } Login login = getLogin(); if( login.isSystem()) return; DBObject o; try { o = ds.getDataBase().findRow(getRowId(), dbClass, null); } catch(NotFoundException nfe) { try { DBData tmpData = DBData.find( getRowId(), dbClass, true); tmpData.reloadLayer(ds.getDataBase()); } catch( Exception e) { LOGGER.warn( "Could not reload " + getRowId(), e); } LOGGER.warn( "checkDeleteAccess() - Could not find rowID. Login: " + login + " RowId: " + getRowId(), nfe); throw new DBAccessException( getGlobalKey(), "Can't Delete: as it's already deleted (" + this + ")", nfe ); } catch( Exception e) { LOGGER.error( "checkDeleteAccess() - Login: " + login, e); throw new RuntimeException ( "Could not find object for checkDeleteAccess()."); } o.iCheckDeleteAccess( ds); } /** * Internal ONLY * @param realDS the real data source * @throws DBAccessException no user access */ public final void iCheckDeleteAccess(final DataSource realDS) throws DBAccessException { // Delete access checking should be done on the raw object without any // changes applied if( ds instanceof VirtualDB == false && ds instanceof ArchiveDataSource == false) { DBAccessException ae = new DBAccessException( getGlobalKey(), "Can't delete: " + getClass().getName() + ".iCheckDeleteAccess() should be called on an object from virtualdb" ); LOGGER.error( "Programmer error", ae); throw ae; } DataSource oDS = null; try { oDS = VirtualDB.setCurrentDataSource( realDS); DBCriteria criteria = realDS.getLogin().getDeleteCriteria( dbClass); if( criteria != null && criteria.matches( this, null) == false) { throw new DBAccessException( getGlobalKey(), "Cannot Delete: Access Denied\n" + criteria.toString() ); } iExtCheckDeleteAccess(); } catch( DBAccessException access) { throw access; } catch( Exception e) { LOGGER.error( "checkDeleteAccess()", e); throw new DBAccessException( getGlobalKey(), "Can't Delete: " + e.toString() ); } finally { VirtualDB.setCurrentDataSource( oDS); } } /** * Checks the user has access to create an object. * TODO: this seems odd place for it. * * @throws DBAccessException No Access */ public final void checkCreateAccess() throws DBAccessException { if( ds instanceof MutableDataSource == false) { throw new RuntimeException( "Cannot create in a virtual db datasource."); } MutableDataSource mds = (MutableDataSource)ds; /** * If save has been disabled don't check access as part of the validation * as we don't intend to save it anyway. */ if( mds.isSaveDisabled()) { return; } //if( data != null) //{ // throw new DBAccessException( // getGlobalKey(), // "Can't Create: Record has already been saved" // ); //} if( dbClass.getBoolean( DBClass.DBFIELD_ABSTRACT_FG) == true) { throw new DBAccessException( getGlobalKey(), "Can't Create: Class '" + dbClass + "' has been declared as abstract" ); } // Cannot create instance of class if it is excluded from this layer if( dbClass.isLayerExcluded( ds.getDataBase().id)) { throw new DBAccessException( getGlobalKey(), "Can't Create: Class '" + dbClass + "' has been excluded from this layer" ); } if( ds instanceof VirtualDB == true) { throw new RuntimeException( "Cannot create in a virtual db datasource."); } Login login; try { login = getLogin(); } catch( Exception e) { LOGGER.error( "checkReadAccess()", e); throw new RuntimeException ( "Could not get login checkCreateAccess()."); } if( login != null && login.isSystem() == false) { DataSource oDS=null; try { oDS=VirtualDB.setCurrentDataSource( ds); DBCriteria criteria = login.getCreateCriteria( dbClass); if( criteria != null) { if( criteria.matches( this, null) == false) { throw new DBAccessException( getGlobalKey(), "Cannot Create: Access Denied\n" + criteria.toString() ); } } //#DEV_ONLY_START extCheckCreateAccessCalled = false; //#DEV_ONLY_END extCheckCreateAccess( ); //#DEV_ONLY_START if( extCheckCreateAccessCalled == false) { DBAccessException ae = new DBAccessException( getGlobalKey(), "Can't create: " + getClass().getName() + ".extCheckCreateAccess() overridden but super not called" ); LOGGER.error( "Programmer error", ae); throw ae; } //#DEV_ONLY_END } catch( DBAccessException access) { throw access; } catch( Exception e) { LOGGER.error( "checkCreateAccess()", e); throw new DBAccessException( getGlobalKey(), "Can't Create: " + e.toString() ); } finally { VirtualDB.setCurrentDataSource( oDS); } } } /** * Retrieves a reason why the object cannot be modified * * @param criteria the criteria to check * @return the access exception */ protected DBAccessException makeModifyAccessException( final DBCriteria criteria) { return new DBAccessException( getGlobalKey(), "Cannot Write: Access Denied\n" + criteria.toString()); } /*====================================================================================================*/ /*===== INFORMATIONAL METHODS =====*/ /*====================================================================================================*/ /** * is the data cache dirty * @return true if the data is know as dirty */ public final boolean isDataCacheKnownToBeDirty() { if( data instanceof DBData) { DBData dbData = (DBData)data; LayerData layerData = dbData.fetchLayerData(ds.getDataBase()); if( layerData instanceof DirtyLayerData) { return true; } } return false; } /** * Is this object marked as deleted ? * * @return True if deleted. */ public final boolean isDeleted() { if( helper != null) { if( helper.deleted == true) { return true; } if( helper.undeleted) { return false; } } if( data != null) { if( data.isDeleted(ds.getDataBase(), null)) { return true; } } return false; } /** * Is this field mandatory for this object ? * * @return True if deleted. * @param field The field */ public final boolean isMandatory( final DBField field) { if( field.isMandatory()) { return true; } return extIsMandatory( field); } /** * Does this field affect other fields when updated * * @return True if it affects other fields. * @param field The field */ public final boolean isOnChange( final DBField field) { /* Update fields that have this field set as onChangeField */ DBField[] list = dbClass.getDBFieldOnChangeList( field); if( list.length > 0) { return true; } return extIsOnChange( field); } /** * Has this object changed within this universe ? * * @return True if changed. */ public final boolean isChanged() { if( helper == null) return false; if( helper.deleted || helper.updatedData.size() > 0 ) { return true; } return false; } /** * Test if this field is null .
*
*   Special cases: No UI way of setting some field types back to null.
*    Blank string and text fields are treated as null.
*    Boolean fields that is false is also treated as null.
* * @param name The name of the field * @return true if the field is null */ public final boolean isNull( final String name) { DBField field = dbClass.getDBField( name); if( field == null) return true; return isNull( field); } /** * Test if this field is null .
*
*   Special cases: No UI way of setting some field types back to null.
*    Blank string and text fields are treated as null.
*    Boolean fields that is false is also treated as null.
* * @param field The field to check * @return true if null */ public final boolean isNull( final DBField field) { int type = field.getType(); if( type == DBField.TYPE_BOOLEAN) { return getBoolean( field) == false; } else if( type == DBField.TYPE_STRING || type == DBField.TYPE_MULTILINGUAL || type == DBField.TYPE_TEXT ) { String s = getString( field); return StringUtilities.isBlank(s); } return getValue(field) == null; } /** * Is this object empty.
*
* Are all fields are blank or the auto entered values ?
* * @return True if empty */ public final boolean isEmpty() { if( isNew() == false) { return false; } return (hasChangedByUser()==false); } /** * Has this object changed since last save
*
* Are all fields are blank or the auto entered values ?
* * @return True if changed */ public final boolean hasChanged() { return DBObjectHelper.hasChanged( this); } /** * Has the user changed this object since last save
*
* Are all fields are blank or the auto entered values ?
* * @return True if changed */ public final boolean hasChangedByUser() { return DBObjectHelper.hasChangedByUser( this); } /** * Tests weather the field has been changed. * * @param name The name of the field * @return True if the field has changed. */ public final boolean hasFieldChanged( final String name) { DBField field = dbClass.getDBField(name); if( field == null) return false; return hasFieldChanged(field); } /** * Tests weather the field has been changed. * * @param field The field to check * @return True if the field has changed. */ public final boolean hasFieldChanged( final DBField field) { if( field.isRuntimeEval()) return false; if( helper != null) { Object value = null; ModData md = (ModData)helper.updatedData.get( field.getGlobalKey().toString()); if( md != null) { value = md.getCurrentKey(); } else { return false; } if( value == null) { value = getValue( field); if( StringUtilities.isBlank(value)) { value = null; } } Object prevValue = null; if( field.isArray() == false) { prevValue = getOriginalKey( field); } if( prevValue == null) { prevValue = getOriginalValue(field); } if( StringUtilities.isBlank(prevValue)) { prevValue = null; } if( value != null) { if( field.getType() == DBField.TYPE_BOOLEAN) { try { Object o; o = field.parse(ds, value); if( prevValue != null) { prevValue = field.parse(ds, prevValue); } if( o == null) { o = Boolean.FALSE; } return o.equals( prevValue) == false; } catch( Exception e) { LOGGER.error( "Opps", e); return true; } } else { if( prevValue == null) return true; /* * If one of these are a string then convert them both to string so that we can compare. */ if( value instanceof String || prevValue instanceof String) { value = value.toString(); prevValue = prevValue.toString(); } if( prevValue.equals( value) == false) { return true; } } } else { if( field.getType() == DBField.TYPE_BOOLEAN) { if( prevValue instanceof Boolean) { Boolean b = (Boolean)prevValue; if( b.booleanValue() == false) { return false; } } } else { if( prevValue != null) { return true; } } } } return false; } /** * Tests whether the user has changed the field for this object. * * @param name The name of the field * @return True if the field has changed. */ public final boolean hasChangedByUserField( final String name) { DBField field = dbClass.getDBField(name); if( field == null) return false; return hasChangedByUserField(field); } /** * Tests whether the user has changed the field for this object. * * @param field The field to check * @return True if the field has changed. */ public final boolean hasChangedByUserField( final DBField field) { if( helper != null) { ModData md = (ModData)helper.updatedData.get( field.getGlobalKey().toString()); if( md != null) { if( md.isChangedByUser()) { if( isNew()) { Object v = md.getCurrentKey(); if( v == null) { v = md.getCurrentValue(); } Object d = md.getDefaultKey(); if( d == null) { d = md.getDefaultValue(); } if( v != null && v.equals( d)) { return false; } if( StringUtilities.isBlank( v) && StringUtilities.isBlank( d)) { return false; } } return true; } } } return false; } /** * Tests whether the change to the field was an auto enter * * @param name The name of the field * @return True if the field has changed. */ public final boolean hasAutoChanged( final String name) { DBField field = dbClass.getDBField(name); if( field == null) return false; return hasAutoChanged(field); } /** * Tests that the ONLY change that has been made is to set to the auto entered value. * * @param field The field to check * @return True if the field has changed TO the auto entered value. */ public final boolean hasAutoChanged( final DBField field) { if( helper != null) { ModData md = (ModData)helper.updatedData.get( field.getGlobalKey().toString()); if( md != null) { Object v = md.getCurrentKey(); if( v == null) { v = md.getCurrentValue(); } Object d = md.getDefaultKey(); if( d == null) { d = md.getDefaultValue(); } if( d != null && v != null && d.equals(v) ) { return true; } } } return false; } /** * Is this object new * * @return true if new */ public final boolean isNew() { if( this instanceof DBRawField || this instanceof DBRawClass) { return false; } if( data == null) return true; if( helper == null) return false; if( helper.undeleted ) return true; return helper.savingNewRecord; } /** * Has reindex been called ? * @return true if we should reindex */ public boolean isForceReindex() { if( helper == null) return false; return helper.forceReindex; } /*====================================================================================================*/ /*===== GET XXXX METHODS =====*/ /*====================================================================================================*/ /** * Returns the pure value for this field. This method is marked as final so if not * marked as derived it'll be the actual value in the database. * * @return The value of this field in this record. * @param params The parameters for this field eg. language= or default= * @param field The field to get */ public final Object getPureValue( final DBField field, final FldParams params) { try { return calculateValue( field, params); } catch( NullValueException nv) { if( params != null) { return params.getDefault( ds, field); } else { return null; } } catch( Exception e) { LOGGER.warn( "getValue(" + field + ", " + params + ")", e ); // Sr, 12/05/2005 Bug #5224 if( params != null) { return params.formatError( ds, field, e); } else { return null; } } } /** * Calculate the field value. * @param field The field * @param params The field parameters * @throws Exception calculate may throw an exception * @return the value */ public final Object calculateValue( final DBField field, final FldParams params) throws Exception { if( field == null) { return params != null ? params.getDefault( ds, field) : null; } if( field.isRuntimeEval()) { Object value; //#DEV_ONLY_START boolean fpLocked = false; try { if( params != null) { fpLocked = params.isLocked(); params.setLocked( true); } //#DEV_ONLY_END if( field.getFormula() != null) { return DBObjectHelper.calculateValue( this, field, params != null ? params.getDefault( ds, field) : null); } if( field.isLinked()) { GlobalKey gk = null; gk = extGetDerivedGlobalKey( field, params); if( gk != null) { return field.parse(ds, gk.getValue()); } } value = extGetDerivedValue( field, params); if( value instanceof GlobalKey) { value = ((GlobalKey)value).getValue(); } /** * Correction of field value returned by this method */ try { return field.parse( ds, value); } catch( Exception e) { LOGGER.error( "getValue(" + field + ", " + params + ")", e ); } //#DEV_ONLY_START } finally { if( params != null) { params.setLocked( fpLocked); } } //#DEV_ONLY_END return value; } Object value = iGetRawValue( field); if( value == null) { return params != null ? params.getDefault( ds, field) : null; } else if( params != null) { if( value instanceof ArrayValue) { int pos = params.getPosition(); if( pos != -1) { ArrayValue av = (ArrayValue)value; return av.get( pos); } } } return value; } /** * Calls the primary getField * @param name The name of the field. * @return The value of the field * @throws Exception calculate may throw an exception */ public final Object calculateValue(final String name) throws Exception { return calculateValue(name, null); } /** * * Calls the primary getField * @param params The parameters for this field eg. language= or default= * @param name The name of the field. * @return The value of the field * @throws Exception calculate may throw an exception */ public final Object calculateValue(final String name, final FldParams params) throws Exception { DBField field = dbClass.getDBField(name); if( field == null) { return params != null ? params.getDefault( ds, field) : null; } return calculateValue(field, params); } /*=================== GET VALUE ==========================*/ /** * Calls the extGetValue * * @return The value of the field * @param params The parameters for this request * @param field The field to get * * @see #extGetValue(DBField, FldParams) extGetValue() To filter public accessible values eg. **** for a password */ public final Object getValue(final DBField field, final FldParams params) { return extGetValue( field, params); } /** * calls the primary getValue * * @param field The field to get * @return The value of the field * * @see #extGetValue(DBField, FldParams) extGetValue() To filter public accessible values eg. **** for a password */ public final Object getValue( final DBField field) { return getValue(field, null); } /** * Calls the primary getField * * @param name The name of the field. * @return The value of the field * * @see #extGetValue(DBField, FldParams) extGetValue() To filter public accessible values eg. **** for a password */ public final Object getValue(final String name) { return getValue(name, null); } /** * Calls the primary getField * * @param params The parameters for this field eg. language= or default= * @param name The name of the field. * * @return The value of the field * * @see #extGetValue(DBField, FldParams) extGetValue() To filter public accessible values eg. **** for a password */ public final Object getValue(final String name, final FldParams params) { DBField field = dbClass.getDBField(name); if( field == null) { return params != null ? params.getDefault( ds, field) : null; } return getValue(field, params); } /*=================== GET FORMATTED STRING ==========================*/ /** * Returns the formatted value of the field.
*

* Boolean fields * -------------- * "True|False" or "Sexy|Ugly" or "on|off" or anything separated by a '|' * * Date & Timestamp fields * ----------------------- * We use the standard Java SimpleDateFormat patterns * * Integer and Long fields * ----------------------- * We use the standard Java DecimalFormat patterns *

* * @return The formatted string * @param params The parameters for this field eg. language= or default= * @param field The field to get. * @param specificFormat The format */ public final String getFormattedString( final DBField field, final String specificFormat, final FldParams params) { Object obj; obj = getValue(field, params); if( obj instanceof MultiLingualValue) { MultiLingualValue mlv = (MultiLingualValue)obj; obj = mlv.getText( params); } if( obj == null) return ""; return field.makeFormattedString( ds, obj, specificFormat, params); } /** * Returns the formatted value of the field.
*

* Boolean fields * -------------- * "True|False" or "Sexy|Ugly" or "on|off" or anything separated by a '|' * * Date & Timestamp fields * ----------------------- * We use the standard Java SimpleDateFormat patterns * * Integer and Long fields * ----------------------- * We use the standard Java DecimalFormat patterns *

* * @return The formatted string * @param params The parameters for this field eg. language= or default= * @param name The field name to be formatted * @param specificFormat The format */ public final String getFormattedString(final String name, final String specificFormat, final FldParams params) { DBField field; if( dbClass == null) { return ""; } field = dbClass.getDBField(name); if( field == null) return ""; return getFormattedString(field, specificFormat, params); } /* ============================= Get String =============================== */ /** * Get String * * @param field The field to get. * @return The string value * * @see #extGetValue(DBField, FldParams) extGetValue() To filter public accessible values eg. **** for a password */ public final String getString( final DBField field) { return getString(field, (FldParams)null); } /** * Get String * * @param params The parameters for this field eg. language= or default= * @param field The field to get. * @return The string value * * @see #extGetValue(DBField, FldParams) extGetValue() To filter public accessible values eg. **** for a password */ public final String getString( final DBField field, final String params) { FldParams theParams = null; if( params != null) { if( params.indexOf( "=") != -1) { theParams = new FldParams( params); return getString( field, theParams); } } String temp = getString( field, (FldParams)null); if( StringUtilities.isBlank( temp)) { return params; } return temp; } /** * Get String * * @return The string value * @param name The name of the field * @param params The parameters for this field eg. language= or default= * * @see #extGetValue(DBField, FldParams) extGetValue() To filter public accessible values eg. **** for a password */ public final String getString( final String name, final String params) { return getString( dbClass.getDBField(name), params); } /** * Get String * * @return The string value * @param params The parameters for this field eg. language= or default= * @param field The field to get. * * @see #extGetValue(DBField, FldParams) extGetValue() To filter public accessible values eg. **** for a password */ public final String getString( final DBField field, final FldParams params) { Object obj; obj = getValue(field, params); /* Ok so we have a multi lingual field result. */ if( obj instanceof MultiLingualValue) { MultiLingualValue mlv = (MultiLingualValue)obj; obj = mlv.getText( params); } if( obj instanceof String) { if( "".equals( obj)) { obj = null; } else { return (String)obj; } } if( obj == null) { if( params != null) { return params.getDefaultString(ds); } return ""; } return field.makeString( ds, obj); } /** * Get String * * @param name The name of the field * @return The string value * * @see #extGetValue(DBField, FldParams) extGetValue() To filter public accessible values eg. **** for a password */ public final String getString(final String name) { return getString( dbClass.getDBField( name), (FldParams)null); } /** * Get String * * @return The string value * @param params The parameters for this field eg. language= or default= * @param name The name of the field * * @see #extGetValue(DBField, FldParams) extGetValue() To filter public accessible values eg. **** for a password */ public final String getString(final String name, final FldParams params) { return getString( dbClass.getDBField(name), params); } /* ============================ Get Int ================================== */ /** * Get Int * * @param field The field to get. * @return The int value * * @see #extGetValue(DBField, FldParams) extGetValue() To filter public accessible values eg. **** for a password */ public final int getInt( final DBField field) { return getInt(field, null); } /** * Get Int * * @return The int value * @param defaultValue The default value * @param field The field to get. * * @see #extGetValue(DBField, FldParams) extGetValue() To filter public accessible values eg. **** for a password */ public final int getInt( final DBField field, final int defaultValue) { FldParams params = null; if( defaultValue != 0) { params = new FldParams( defaultValue); } return getInt(field, params); } /** * Get Int * * @param name The field name * @param defaultValue the default value * @return The int value * * @see #extGetValue(DBField, FldParams) extGetValue() To filter public accessible values eg. **** for a password */ public final int getInt( final String name, final int defaultValue) { return getInt( dbClass.getDBField( name), defaultValue); } /** * * Get Int * @return The int value * @see #extGetValue(DBField, FldParams) extGetValue() To filter public accessible values eg. **** for a password * @param name The field name * @param params The parameters for this field eg. language= or default= */ public final int getInt(final String name, final FldParams params) { return getInt(dbClass.getDBField( name), params); } /** * Get Int * * @param name The field Name * @return The int value * * @see #extGetValue(DBField, FldParams) extGetValue() To filter public accessible values eg. **** for a password */ public final int getInt(final String name) { return getInt( dbClass.getDBField( name), null); } /** * * Get Int * @return The int value * @see #extGetValue(DBField, FldParams) extGetValue() To filter public accessible values eg. **** for a password * @param field The field * @param params The parameters for this field eg. language= or default= */ public final int getInt( final DBField field, final FldParams params) { Object obj; obj = getValue(field, params); long value; if( obj instanceof Number) { value = ((Number)obj).longValue(); } else { if( StringUtilities.isBlank(obj)) { if( params == null) return 0; return params.getDefaultInt(); } try { value = Integer.parseInt(obj.toString()); } catch( NumberFormatException nf) { LOGGER.warn( "getInt( " + field + ")", nf); if( params == null) return 0; return params.getDefaultInt(); } } if( value > Integer.MAX_VALUE || value < Integer.MIN_VALUE) { LOGGER.warn( "Warning: Long {" + value + "}->Int {" + ((int)value) + "}"); Thread.dumpStack(); } return (int)value; } /* ============================ Get Double ================================== */ /** * Get Double * * @param field The field to get. * @return The double value * * @see #extGetValue(DBField, FldParams) extGetValue() To filter public accessible values eg. **** for a password */ public final double getDouble( final DBField field) { return getDouble(field, 0.0); } /** * Get Double * @return The double value * @see #extGetValue(DBField, FldParams) extGetValue() To filter public accessible values eg. **** for a password * @param name The field name * @param defaultValue The default value. */ public final double getDouble(final String name, final double defaultValue) { return getDouble( dbClass.getDBField( name), defaultValue); } /** * Get Double * * @param name The name of the field * @return The double value * * @see #extGetValue(DBField, FldParams) extGetValue() To filter public accessible values eg. **** for a password */ public final double getDouble(final String name) { return getDouble( dbClass.getDBField( name), 0); } /** * Get Double * @return The double value * @see #extGetValue(DBField, FldParams) extGetValue() To filter public accessible values eg. **** for a password * @param field The field * @param defaultValue The default value for the field. */ public final double getDouble( final DBField field, final double defaultValue) { Object obj; obj = getValue(field, null); if( obj instanceof Number) { return ((Number)obj).doubleValue(); } return defaultValue; } /* ============================ Get Long ================================== */ /** * Get Long * * @param field The field to get. * @return The long value * * @see #extGetValue(DBField, FldParams) extGetValue() To filter public accessible values eg. **** for a password */ public final long getLong( final DBField field) { return getLong(field, 0); } /** * Get Long * @return The long value * @see #extGetValue(DBField, FldParams) extGetValue() To filter public accessible values eg. **** for a password * @param name The field name * @param defaultValue The default value for the field */ public final long getLong(final String name, final long defaultValue) { return getLong(dbClass.getDBField( name), defaultValue); } /** * Get Long * * @param name The field name * @return The long value * * @see #extGetValue(DBField, FldParams) extGetValue() To filter public accessible values eg. **** for a password */ public final long getLong(final String name) { return getLong( dbClass.getDBField( name), 0); } /** * Get Long * @return The long value * @see #extGetValue(DBField, FldParams) extGetValue() To filter public accessible values eg. **** for a password * @param field The field * @param defaultValue The default value. */ public final long getLong( final DBField field, final long defaultValue) { Object obj; obj = getValue(field); if( obj instanceof Number) { return ((Number)obj).longValue(); } return defaultValue; } /* ============================ Get Boolean ================================== */ /** * Get Boolean * * @param field The field to get. * @return The boolean value * * @see #extGetValue(DBField, FldParams) extGetValue() To filter public accessible values eg. **** for a password */ public final boolean getBoolean( final DBField field) { return getBoolean(field, false); } /** * Get Boolean * * @param field The field to get. * @param flag The default value * @return The boolean value * * @see #extGetValue(DBField, FldParams) extGetValue() To filter public accessible values eg. **** for a password */ public final boolean getBoolean( final DBField field, final boolean flag) { Object obj; obj = getValue(field, null); if( obj == null) return flag; return ((Boolean)obj).booleanValue(); } /** * The boolean value * @param field The field * @param params The parameters * @return The value */ public final boolean getBoolean( final DBField field, final FldParams params) { Object obj; obj = getValue(field, params); if( obj == null) return false; return ((Boolean)obj).booleanValue(); } /** * The boolean value for a field * @param name The field name * @param params The parameters * @return The boolean value */ public final boolean getBoolean( final String name, final FldParams params) { Object obj; obj = getValue( dbClass.getDBField(name), params); if( obj == null) return false; return ((Boolean)obj).booleanValue(); } /** * Get Boolean * * @param name The field name * @return The boolean value * * @see #extGetValue(DBField, FldParams) extGetValue() To filter public accessible values eg. **** for a password */ public final boolean getBoolean(final String name) { return getBoolean( dbClass.getDBField(name), false); } /** * Get Boolean * * @param name The Field Name * @param flag The default value * @return The boolean value * * @see #extGetValue(DBField, FldParams) extGetValue() To filter public accessible values eg. **** for a password */ public final boolean getBoolean(final String name, final boolean flag) { return getBoolean(dbClass.getDBField(name), flag); } /* ============================ Get Date ================================== */ /** * Get Date * * @param field The field to get. * @return The Date value * * @see #extGetValue(DBField, FldParams) extGetValue() To filter public accessible values eg. **** for a password */ public final Date getDate( final DBField field) { return getDate(field, null); } /** * Get Date * * @param field The field to get. * @param theDate The default value * @return The date value * * @see #extGetValue(DBField, FldParams) extGetValue() To filter public accessible values eg. **** for a password */ public final Date getDate( final DBField field, final Date theDate) { Object obj; obj = getValue(field, null); if( obj instanceof Date) { return (Date)obj; } return theDate; } /** * Get Date * * @param name The field name * @return The date value * * @see #extGetValue(DBField, FldParams) extGetValue() To filter public accessible values eg. **** for a password */ public final Date getDate(final String name) { return getDate( dbClass.getDBField(name), null); } /** * Get Date * * @param name The Field Name * @param theDate The default value * @return The date value * * @see #extGetValue(DBField, FldParams) extGetValue() To filter public accessible values eg. **** for a password */ public final Date getDate(final String name, final Date theDate) { return getDate(dbClass.getDBField(name), theDate); } /* ============================ Get Raw Value ================================== */ /** * Returns the raw value for this field from the underlying DBData or the updated fields. * * @param fieldId The field's global key * @return The raw value */ public final Object getRawValue(final GlobalKey fieldId) { try { return getRawValue( dbClass.getDBField(fieldId)); } catch(Exception e) { LOGGER.error( "getRawValue(" + fieldId + ")",e); return null; } } /** * Returns the raw value for this field from the underlying DBData or the updated fields. * * @param field The field to get the raw value. * @return The Raw value. */ public final Object getRawValue( final DBField field) { if( field.isRuntimeEval()) return null; return iGetRawValue( field); } /* ============================ Get Original Value ================================== */ /** * Returns the original value for this field from the underlying DBData. * * @param fieldKey The field key * @return The original value. */ public final Object getOriginalValue(final GlobalKey fieldKey) { try { DBField field = dbClass.getDBField(fieldKey); return getOriginalValue( field); } catch(Exception e) { LOGGER.error( "getOriginalField(" + fieldKey + ")",e); return null; } } /** * Returns the original value for this field from the underlying DBData. * * @param field The field to get the raw value. * @return The original value. */ public final Object getOriginalValue( final DBField field) { if( data != null && field != null) { return data.getRawValue(ds.getDataBase(), field, null); } return null; } /** * Returns the original key for this field from the underlying DBData. * * @param field The field to get the raw value. * @return The original value. */ public final GlobalKey getOriginalKey( final DBField field) { if( data != null) { return data.getGlobalKey(ds.getDataBase(), field, null); } return null; } /*====================================================================================================*/ /*===== UTILITIES METHODS =====*/ /*====================================================================================================*/ /** * Copies the fields from another DBObject into this one. * fields such as derived and keys are ignored * * @param orig The original object to be copied. * @throws Exception A serious error. */ public final void copyFields( final DBObject orig) throws Exception { boolean originalFlag = getDisableOnChangeEvent(); setDisableOnChangeEvent( true); // Find common dbClass DBClassConcrete commonClass = null; // Search through class heirachy for both this class and original // to find which class is the same DBClassConcrete c1, c2; c1 = dbClass; while( c1 != null && commonClass == null) { c2 = orig.dbClass; while( c2 != null && commonClass == null) { if( c1.getGlobalKey().equals( c2.getGlobalKey())) { commonClass = c1; } c2 = c2.getParentDBClassConcrete(); } c1 = c1.getParentDBClassConcrete(); } if( commonClass == null) { throw new RuntimeException(); } /* Copy Fields */ DBField[] list = commonClass.getDBFieldListAll(); for(int f=0; f < list.length; f++) { DBField field = list[f]; if(copyIncludeField(orig, field)) { if( field.isIncremental() == false && field.isDeleted() == false && field.isRuntimeEval() == false && field.isKey() == false && field.isUnique() == false && StringUtilities.isBlank(field.getAutoFillPredefinedValue()) ) { Object o; o = orig.getGlobalKey( field); if( o == null) { o = orig.getValue( field); } setValue( field, o); } } } setDisableOnChangeEvent( originalFlag); } /** * To filter the field's not to copy. It can be overriden to add additional funcionality. * @param orig The original object to be copied. * @param field The field to be copied * @return false if the field is not allowed to copy. * @throws Exception A serious error. */ public boolean copyIncludeField( final DBObject orig, final DBField field) throws Exception { return true; } /** * Copies the objects pointing to this object. * @param orig The reference object * @param linkedField The Linked Field ? * @throws Exception A serious problem * @return The objects */ public final DBObject[] copyInwardLinks( final DBObject orig, final DBField linkedField) throws Exception { DBResult res = orig.getInwardLinkage( linkedField, null); ArrayList array = new ArrayList(); MutableDataSource mds = (MutableDataSource)ds; while( true) { DBObject origLink = res.next(); if( origLink == null) break; DBObject o = origLink.copy( mds); o.setValue( linkedField, getGlobalKey()); array.add( o); } DBObject[] list = new DBObject[ array.size()]; array.toArray( list); return list; } /** * Mark the save point which we can rollback to later. * @param id the save point id * @throws com.aspc.DBObj.Errors.NotInUniverseException DBObject had not been touched */ public final void markSavePoint( final String id) throws NotInUniverseException { if( helper == null) { throw new NotInUniverseException( "Not part of the universe"); } DBObjectHelper oldHelper = helper; helper = oldHelper.makeSavePoint( id); MutableArrayValue list[] = MutableArrayValue.list(this); if( list != null && list.length > 0) { for( int i = 0; i < list.length; i++) { MutableArrayValue mav = list[i]; if( mav.isSaved() == false) { mav.setSavePointHelper( this, mav.getField(), helper, oldHelper); } } } extMarkSavePoint( id); } /** * Rollback to save point. * * @param id the save point id * @throws NoSavePointException no save point found */ public final void rollbackTo( final String id) throws NoSavePointException { if( helper != null) { helper = helper.rollbackTo( id); } MutableArrayValue list[] = MutableArrayValue.list(this); if( list != null && list.length > 0) { if( helper == null) { helper = new DBObjectHelper(this); } for( int i = 0; i < list.length; i++) { MutableArrayValue mav = list[i]; if( mav.isSaved() == false) { mav.setSavePointHelper( this, mav.getField(), helper, null); } } } extRollbackTo( id); } /** * DEBUG dump of the current object's fields values to std. out */ public final void dump() { DBField list[] = dbClass.getDBFieldListAll(); String temp = ""; if( isNew()) { temp = " (NEW)"; } if( isDeleted()) { temp = " (DELETED)"; } LOGGER.info( dbClass.getName() + ":" + getGlobalKey() + temp); LOGGER.info( " |"); for( int i = 0; i < list.length; i++) { LOGGER.info( " +-> " + list[i].getName()); if( i + 1 != list.length) { LOGGER.info( " |"); } else { LOGGER.info( " "); } LOGGER.info( " =" + getString(list[i])); if( list[i].isLinked()) { if( i + 1 != list.length) { LOGGER.info( " |"); } else { LOGGER.info( " "); } LOGGER.info( " IS " + getGlobalKey(list[i])); } } } /*====================================================================================================*/ /*===== INTERNAL PUBLIC FUNCTIONS =====*/ /*====================================================================================================*/ /** * INTERNAL USE ONLY

* * Collects the raw SQL statements to be batch together and * executed as a single database transaction.
*
* These raw SQL statements store the objects state * into the database. * * @param sb The holder of all the SQL statements for this universe. * @throws Exception A serious problem has occurred. */ public final void iCollectStatements( final StatementBatch sb) throws Exception { if( isReindex()) { DBObjectHelper.reindex( this, sb); } else { DBObjectHelper.iCollectStatements( this, sb); } } /** * Allows for specific attributes to be set for the queries * * @return The search plan * @param query The calling query */ public static SearchPlan makeSearchPlan( final DBQuery query) { return new SearchPlan( query); } /** * The locked transaction number * * @return The transaction number */ public long getLockedTransaction() { if( helper != null) { return helper.getLockedTransaction(); } return 0; } /** * Use the current transaction number when applying the changes to the database. * @throws Exception A serious problem. */ public void forceLockedTransaction() throws Exception { touch(); if( data != null) { long logicalLockTransId = data.getTransId( ds.getDataBase(), null); helper.forcelockedTransaction( logicalLockTransId); } } /** * Internal Only * @throws Exception a serious problem */ public final void iPreValidate() throws Exception { if( isReindex() && (helper == null || helper.updatedData.size() == 0)) { return; } if( data != null) { long logicalLockTransId = data.getTransId( ds.getDataBase(), null); helper.setlockedTransaction( logicalLockTransId); } //#DEV_ONLY_START extPreValidateCalled = false; //#DEV_ONLY_END if( isDeleted()) { extPreValidateDelete(); } else { DBClass def = dbClass; /* Auto enter specified fields */ DBField[] list = def.getDBFieldListAll(); for(int f=0; f < list.length; f++) { DBField field = list[f]; Object predValName, value = null; predValName = field.getAutoFillPredefinedValue(); if( StringUtilities.isBlank( predValName) == false) { if( hasChangedByUser()) { if(predValName.toString().equalsIgnoreCase("ModifiedTime")) { value = new Date(); } else if(predValName.toString().equalsIgnoreCase("ModifiedByUser")) { value = ((MutableDataSource)ds).getRealLogin().getGlobalKey(Login.DBFIELD_PERSON_ID); } } } if(value != null) { setValue(field, value); } if( field.isLinked() && field.isRuntimeEval() == false ) { /** * This will cause the fields to relink up * In the case were we have to objects in the linked class * with the same key where one exists in the layer below, * this will link to the one in our layer when the one in the * layer below was deleted. */ getLinkedObject( field, null); } } extPreValidate(); } //#DEV_ONLY_START if( extPreValidateCalled == false) { throw new Exception( "PROGRAMMER ERROR: method " + getClass().getName() + ".extPreValidate() overridden without call to super"); } //#DEV_ONLY_END } /** * INTERNAL USE ONLY

* * Add Events to the EventQueue which have conditions that match the * current status of the Object. * The EventQueue entries will be validated on the next pass to ensure that * all the Event's validations pass. * If this is the case then any actions will then go on to be processed as * part of the preSave * @throws Exception A serious problem */ public final void iRaiseEvents() throws Exception { //#DEV_ONLY_START extRaiseEventsCalled = false; //#DEV_ONLY_END DBObjectHelper.raiseEvents((MutableDataSource)ds, this); extRaiseEvents(); //#DEV_ONLY_START if( extRaiseEventsCalled == false) { throw new Exception( "PROGRAMMER ERROR: method " + getClass().getName() + ".extRaiseEvents() overridden without call to super"); } //#DEV_ONLY_END } /** * INTERNAL USE ONLY

* * Do Auto enter values when a record is about to be saved. This method is * called before save and validation if some fields have changed. * * To add functionality to a DBObject before records are saved to the database override extPreSaveRecord() and extPreDeleteRecord() * * @see #extPreSaveRecord() * @see #extPreDeleteRecord() * * @throws Exception A Serious problem */ public final void iPreSaveOrDeleteRecord() throws Exception { if( isDeleted()) { //#DEV_ONLY_START extPreDeleteRecordCalled = false; //#DEV_ONLY_END extPreDeleteRecord(); //#DEV_ONLY_START if( extPreDeleteRecordCalled == false) { throw new Exception( "PROGRAMMER ERROR: method " + getClass().getName() + ".extPreDelete() overridden without call to super"); } //#DEV_ONLY_END } else { //#DEV_ONLY_START extPreSaveRecordCalled = false; //#DEV_ONLY_END helper.savingNewRecord = isNew(); extPreSaveRecord(); //#DEV_ONLY_START if( extPreSaveRecordCalled == false) { throw new Exception( "PROGRAMMER ERROR: method " + getClass().getName() + ".extPreSave() overridden without call to super"); } //#DEV_ONLY_END } } /** * INTERNAL USE ONLY

* * Called by the Mutable Data Source after all objects have been saved and commited. * * @see #extPostSave() * * @param transNr This transaction number that was just saved. */ public final void iPostSaveOrDeleteRecord( final long transNr) { try { if( helper.deleted == false) { //#DEV_ONLY_START extPostSaveRecordCalled = false; //#DEV_ONLY_END extPostSaveRecord( transNr); //#DEV_ONLY_START if( extPostSaveRecordCalled == false) { LOGGER.error( "Programmer error: " + getClass().getName() + ".extPostSaveRecord( " + transNr + ") overridden but 'super' not called"); } //#DEV_ONLY_END } else { //#DEV_ONLY_START extPostDeleteRecordCalled = false; //#DEV_ONLY_END extPostDeleteRecord( transNr); //#DEV_ONLY_START if( extPostDeleteRecordCalled == false) { LOGGER.error( "Programmer error: " + getClass().getName() + ".extPostDeleteRecord( " + transNr + ") overridden but 'super' not called"); } //#DEV_ONLY_END } MutableArrayValue.markAllAsSaved(this); } catch( Throwable e) { LOGGER.error( "iPostSaveOrDeleteRecord", e); } finally { helper = null; } } /** * INTERNAL USE ONLY

* * Called by the mutable data source to during the save process. * * @param transNr The current transaction number. * @throws Exception A serious problem */ public final void iSaveOrDeleteRecord(final long transNr) throws Exception { if( isDeleted()) { //#DEV_ONLY_START extDeleteRecordCalled = false; //#DEV_ONLY_END extDeleteRecord(transNr); //#DEV_ONLY_START if( extDeleteRecordCalled == false) { throw new Exception( "PROGRAMMER ERROR: method " + getClass().getName() + ".extDeleteRecord(" + transNr + ") overridden without call to super"); } //#DEV_ONLY_END } else { //#DEV_ONLY_START extSaveRecordCalled = false; //#DEV_ONLY_END extSaveRecord(transNr); //#DEV_ONLY_START if( extSaveRecordCalled == false) { throw new Exception( "PROGRAMMER ERROR: method " + getClass().getName() + ".extSaveRecord(" + transNr + ") overridden without call to super"); } //#DEV_ONLY_END MutableArrayValue list[] = MutableArrayValue.list(this); if( list != null) { for( int i = 0; i < list.length; i++) { MutableArrayValue mav = list[i]; Object value=null; if( data != null) { value = data.getRawValue(ds.getDataBase(), mav.getField(), null); } if( value instanceof StoredArrayValue) { mav.setStore( (StoredArrayValue) value); } } } } } /** * INTERNAL USE ONLY

* * Performs validations on this record. Override extValidateRecord to supply additional * validations. * * The returned vector is a list of validationItems which may be warnings or errors. * @param list The validation list * @param possibleConflicts The list of rows matching key and unique field values. This is done by a batch select to improve performance. * @throws Exception A serious problem */ @SuppressWarnings("empty-statement") public final void iValidateRecord( final ValidationList list, final HashMap possibleConflicts ) throws Exception { if( helper != null) { if( dbClass.isLayerExcluded( ds.getDataBase().id)) { ValidationError ve; ve = list.createError( this, null, getClass().getName() + " is excluded from " + ds.getDataBase().getSignature() ); list.add( ve); return; } } /* Don't validate if we are only reindexing */ if( isReindex() && (helper == null || helper.updatedData.size() == 0)) { return; } if( isDeleted()) { try { checkDelete(); //#DEV_ONLY_START extValidateDeleteCalled = false; //#DEV_ONLY_END extValidateDelete(list); //#DEV_ONLY_START if( extValidateDeleteCalled == false) { ValidationError ve; ve = list.createError( this, null, "Programming error: overridden method " + getClass().getName() + ".extValidateDelete(ValidationList list) never called super" ); list.add( ve); } //#DEV_ONLY_END } catch( DBAccessException access) { list.add( access); } return; } if( isNew()) { try { checkCreateAccess(); } catch( DBAccessException access) { list.add( access); } } else { // If there are no changes then don't check the modify access. if( helper != null && helper.updatedData != null && helper.updatedData.size() != 0 ) { try { checkModifyAccess(); } catch( DBAccessException access) { list.add( access); } } } DBField fieldList[] = dbClass.getDBFieldListAll(); /* Validate each field */ for( int i = 0; i < fieldList.length; i++) { DBField field; field = fieldList[i]; ValidationError err; err = iValidateField( field, list, possibleConflicts); if( err != null) { list.add( err); } } /* Check for duplication within field group */ Vector fieldGroup = new Vector();//NOPMD boolean doDupCheck = false; String fieldGroupTxt = dbClass.getString( DBClass.DBFIELD_DUPLICATE_WARNING_FIELDS); StringTokenizer st= new StringTokenizer( fieldGroupTxt, ",", false); while( st.hasMoreTokens()) { String tk = st.nextToken(); DBField field = dbClass.getDBField( tk); fieldGroup.addElement( field); if( hasFieldChanged( field) == true) { doDupCheck = true; } } if( doDupCheck) { try { VirtualDB layer; layer = ds.getDataBase(); /* * we need to create a new datasource based on the system login * so that we check the entire layer for duplicates rather then * just what the user can see. */ //MutableDataSource dupDs = new MutableDataSource( vDB.getSystemLogin()); DBQuery q = new DBQuery( dbClass, layer); ListIterator it = fieldGroup.listIterator(); while( it.hasNext()) { DBField field = (DBField)it.next(); q.addClause( field, "=", getValue( field)); } DBResult res = q.search(); boolean fndDup = false; while( fndDup == false) { DBObject dupObj = res.next(); if( dupObj == null) break; if( dupObj.getGlobalKey().equals( getGlobalKey()) == false) { fndDup = true; } } /* duplicate found so generate a warning */ if( fndDup == true) { String fields = ""; it = fieldGroup.listIterator(); while( it.hasNext()) { DBField field = (DBField)it.next(); String label; label = field.displayName(); fields += label;//NOPMD if( it.hasNext()) { fields += ";";//NOPMD } } ValidationWarning warning = new ValidationWarning(DBMessage.LIST_DB_DUP_FIELDS, this, fields); list.add( warning); } } catch( NotFoundException nf) { /* This is good - no warning necessary */ ; } } //#DEV_ONLY_START extValidateRecordCalled = false; //#DEV_ONLY_END extValidateRecord(list); //#DEV_ONLY_START if( extValidateRecordCalled == false) { ValidationError ve; ve = list.createError( this, null, "Programming error: overridden method " + getClass().getName() + ".extValidateRecord(ValidationList list) never called super" ); list.add( ve); } //#DEV_ONLY_END } /** * INTERNAL USE ONLY

* * This method is called when the underlying DBData is changed / loaded. This may be call via other * threads saving the object. Once a internal functions are performed the method eventDataLoaded is * called which may be overridden by classes extending DBObject.
*/ public final void fireEventDataLoaded() { //#DEV_ONLY_START int count = eventDataLoadedCount; //#DEV_ONLY_END eventDataLoaded(); //#DEV_ONLY_START if( eventDataLoadedCount == count) { throw new RuntimeException( "PROGRAMMER: Error " + getClass().getName() + ".eventDataLoaded() overridden but super not called"); } count = clearCacheCount; //#DEV_ONLY_END clearCache( getGlobalKey()); //#DEV_ONLY_START if( clearCacheCount == count) { throw new RuntimeException( "PROGRAMMER: Error " + getClass().getName() + ".clearCache( GlobalKey) overridden but super not called"); } //#DEV_ONLY_END for( int i = 0; reloadEventListeners != null; i++) { WeakReference wr; synchronized( reloadEventListeners) { if( i >= reloadEventListeners.size()) break; wr = (WeakReference)reloadEventListeners.get( i); } ReloadEventListener r; r = (ReloadEventListener)wr.get(); if( r != null) { r.eventReload( this); } } MutableArrayValue list[] = MutableArrayValue.list(this); if( list != null) { for( int i = 0; i < list.length; i++) { MutableArrayValue mav = list[i]; Object value=null; if( data != null) { value = data.getRawValue(ds.getDataBase(), mav.getField(), null); } if( value instanceof StoredArrayValue) { mav.setStore( (StoredArrayValue) value); } } } } /** * Automatically called for eventDataLoaded() with this GlobalKey and getCleanVersion() with null for the global key. * The design should clear ALL cache if the changedKey is null. * @param changedKey The key that was changed. */ protected void clearCache( final GlobalKey changedKey) { //#DEV_ONLY_START clearCacheCount++; //#DEV_ONLY_END } /** * INTERNAL USE ONLY

* * When a DataSource initiates a DBObject the Raw Data is set for existing DBObjects * * @param data The raw data */ public final void setRawData(final DBDataInterface data) { this.data = data; if( data != null) { data.register(this); } } /** * INTERNAL USE ONLY

* * @return The raw data object for this DBObject */ public final DBDataInterface getRawData() { return data; } /** * INTERNAL USE ONLY

* * When a object is being watched by another object we store a * hard link to the watched object from the watcher to prevent watch objects from being GCed.
*
* An example is DBClass stores information about the associated fields. It places a watch on these * fields so that an event is raised in DBClass when a DBField is loaded/changed. * * @param obj The database object to be watched. */ public final synchronized void registerWatchedObject( final DBObject obj) { if( watchedObjects == null) { watchedObjects = new Hashtable(); } watchedObjects.put( obj, ""); } /** * * Please don't overload this method as it'll cause odd errors where internal messages will be lost. * * This is final method. * * @return The normal value */ @Override public final int hashCode() { return super.hashCode(); } /** * * Please don't overload this method as it'll cause odd errors where internal messages will be lost * * @param o The normal value * @return The normal value */ @Override public final boolean equals(final Object o) { if( o instanceof DBObject) { if( this == o) return true; } return false; } /*=========================================================================================================================*/ /*==== PROTECTED METHODS =====*/ /*=========================================================================================================================*/ /** * If the currentValue is a DBObject it'll be converted to a GlobalKey * * @param userValue The new value * @param params The parameters for this field eg. language= or default= * @param field The field to update * * @throws Exception A serious problem */ protected final void iSetValue( final DBField field, final Object userValue, final FldParams params ) throws Exception { if( field.isRuntimeEval()) { //#DEV_ONLY_START LOGGER.warn( this + ".iSetValue( " + field +"," + userValue + "," + params + ")"); //#DEV_ONLY_END return; } //#DEV_ONLY_START boolean fpLocked = false; //#DEV_ONLY_END try { Object prevValue, currentValue; //#DEV_ONLY_START if( params != null) { fpLocked = params.isLocked(); params.setLocked( true); } //#DEV_ONLY_END prevValue = getValue(field); boolean isLookup = false; // Check if linked field value is to be retrieved via a lookup if( userValue == null && params != null && params.getLookupFld() != null && StringUtilities.isBlank(params.getLookupValue()) == false && field.isLinked() == true ) { isLookup = true; } /* * fast check. If the previous value and this value equals then don't search for keys etc. Just return. */ if( ( userValue == null && prevValue == null ) || ( userValue != null && prevValue != null && userValue.equals( prevValue) ) ) { if( userValue == null) { if( isLookup == false) { return; } } else { return; } } if( prevValue == null) { /** * Bug found 21 Dec 2002: When trying to change the Global class in the self_test layer. It was complaining about changing the keyFg "" -> "FALSE" */ int type = field.getType(); if( type == DBField.TYPE_BOOLEAN) { prevValue = Boolean.FALSE; } else if( type == DBField.TYPE_MULTILINGUAL) { prevValue = new ReadOnlyMultiLingualValue( new MutableMultiLingualValue()); } else { prevValue = ""; } } boolean isLinked = field.isLinked(); GlobalKey linkedGlobalKey=null; if( isLinked && ( field.isArray() == false || ( params != null && params.getPosition() != -1))) { linkedGlobalKey = DBObjectHelper.makeLinkedKey(ds, field, isLinked, userValue, params); } if( linkedGlobalKey != null) { isLookup = false; } String language = null; if( params != null) { language = params.getLanguage(); } if( userValue instanceof ArrayValue) { currentValue = userValue; } else if( field.isArray() && ( params == null || params.getPosition() == -1)) { MutableArrayValue mav; if( helper == null) { helper = new DBObjectHelper( this); } if( prevValue instanceof MutableArrayValue) { mav = (MutableArrayValue)prevValue; mav.clear(); } else if( prevValue instanceof StoredArrayValue) { mav = MutableArrayValue.create( this, field, (StoredArrayValue)prevValue, helper); } else { mav = MutableArrayValue.create( this, field, null, helper); } if( userValue == null) { currentValue = null; } else { mav.parse( userValue); currentValue = mav; } } else { currentValue = DBObjectHelper.makeCurrentValue( ds, field, userValue, prevValue, linkedGlobalKey, language, params); if( field.isArray()) { Object tempValue; if( linkedGlobalKey != null) { LinkedValue lv = new LinkedValue(); lv.value=currentValue; lv.gkey=linkedGlobalKey; tempValue = lv; } else { tempValue = currentValue; } int pos = params.getPosition(); // check if not changed. if( prevValue instanceof StoredArrayValue) { StoredArrayValue sav=(StoredArrayValue)prevValue; if( pos < sav.size()) { Object value = sav.get( pos); if( value == null && tempValue == null ) return; if( value != null && value.equals(tempValue ) ) return; } } MutableArrayValue mav; if( helper == null) { helper = new DBObjectHelper( this); } if( prevValue instanceof MutableArrayValue) { if( ((MutableArrayValue)prevValue).isSaved()) { mav = (MutableArrayValue)(( MutableArrayValue)prevValue).clone(); } else { mav = (MutableArrayValue)prevValue; } } else if( prevValue instanceof StoredArrayValue) { mav = MutableArrayValue.create( this, field, (StoredArrayValue)prevValue, helper); } else { mav = MutableArrayValue.create( this, field, null, helper); } mav.set( pos, tempValue); currentValue = mav; } } /* If the values are the same just return. Don't fire off events etc. */ if( prevValue.equals( currentValue)) { /* Wait one second if they specified a actual DBObject make sure we are pointing to that one */ if( linkedGlobalKey != null && ( userValue instanceof GlobalKey || userValue instanceof DBObject || ( userValue instanceof String && userValue.toString().indexOf( GlobalKey.SEPERATOR) != -1 ) ) ) { if( isLinked) { GlobalKey gk = getGlobalKey( field); if( gk != null && linkedGlobalKey.equals( gk)) { return; } } else { return; } } else { /* same value don't put into the updated field list */ if( isLookup == false) { return; } } } GlobalKey prevGlobalKey = null; if( isLinked && ( field.isArray() == false || ( params != null && params.getPosition() != -1))) { prevGlobalKey = getGlobalKey( field, params); } if( ds instanceof MutableDataSource == false) { throw new DBAccessException( getGlobalKey(), "Read Only" ); } touch(); MutableDataSource mds = (MutableDataSource)ds; if( field.isKey() ) { /* Check access */ if( isNew() == false) { /* The key could be created after the records were created. */ if( getRawValue( field) != null) { /** * I've put in a quick hack to check for save disable to * prevent a bug from being shown after saving an search screen */ if( mds.isSaveDisabled() == false) { throw new DBAccessException( getGlobalKey(), "Can't update key" ); } } } GlobalKey newKeyValue; newKeyValue = new GlobalKey( currentValue, getSrcLayerID(), dbClass.getGlobalKey().getValueId() ); mds.iUpdateCacheKey( newKeyValue, this); /* Update the fields of linked objects */ DBField inwardLinks[] = dbClass.getInwardLinks(); HashMap refs = null; for( int i = 0; i < inwardLinks.length; i++) { DBField sourceField = inwardLinks[i]; if( sourceField.isRuntimeEval() == false) { /* * TODO - we only interested in objects that are in the current universe * as these are the only things that could have been linked to the previous * key value */ DBResult r = getInwardLinkage(sourceField, null); if( r.hasMore()) { if( refs == null) { refs = new HashMap(); } refs.put( sourceField, r); } } } /* * Make sure that global key is null. * We don't need to store the global key if it is the key * since we can always generate it */ linkedGlobalKey = null; helper.cacheGlobalKey = newKeyValue; if( refs != null) { DBField fields[] = new DBField[ refs.size()]; refs.keySet().toArray( fields); /** * BUG FOUND: * When we created a new QUEUE the screen would have dummy records opened. These * records were getting set to USER CHANGED when we changed/entered the code for * the queue. */ FldParams subParams = FldParams.createNewObject(params); subParams.setIsAutoEntered( true); for( int i = 0; i < fields.length; i++) { DBField sourceField = fields[i]; DBResult r = (DBResult)refs.get( sourceField); while( true) { DBObject o; o = r.next(); if( o == null) break; o.setValue( sourceField, this, subParams); } } } } ModData md = (ModData)helper.updatedData.get( field.getGlobalKey().toString()); if( md == null) { md = new ModData( field, prevValue, prevGlobalKey ); helper.updatedData.put( md.getKey(), md); } md.setPreviousValue( prevValue); md.setPreviousKey( prevGlobalKey); md.setCurrentValue( currentValue); md.setCurrentKey( linkedGlobalKey); if( LOGGER.isDebugEnabled()) { String key = (isNew() ? getRowKey().toString() : getGlobalKey().toString()); String temp = linkedGlobalKey != null ? ( " { " + linkedGlobalKey + " }" ): ""; if( params == null || params.isChangedByUser()) { temp += " *USER CHANGED*";//NOPMD } LOGGER.debug( "DEBUG {" + key + "}: " + field + " " + prevValue + "->" + currentValue + temp); } boolean isAutoEntered = false; if( params != null) { isAutoEntered = params.isAutoEntered(); md.setChangedByUser( params.isChangedByUser()); } else { md.setChangedByUser( true); } if( mds.isInEventAction() || mds.isChangedByUserDisabled()) { md.setChangedByUser( false); } if( isAutoEntered) { /** * Special case when setting one value of a multilingual field. */ if( currentValue instanceof MultiLingualValue && userValue instanceof String) { Object previousDefaultValue = md.getDefaultValue(); if( previousDefaultValue instanceof MultiLingualValue) { MutableMultiLingualValue m = new MutableMultiLingualValue(); m.copyFrom( (MultiLingualValue)previousDefaultValue); m.setText( userValue.toString(), language); md.setDefaultValue( m); } else { md.setDefaultValue( currentValue); } } else { md.setDefaultValue( currentValue); } md.setDefaultKey( linkedGlobalKey); } FldParams tparams = params; // Pass lookup values into modifiedData so that validatefield // can check that we are not trying to link to more then one // record with same value if( params != null && params.getLookupFld() != null && params.getLookupNoSearch() == false && StringUtilities.isBlank(params.getLookupValue()) == false ) { DBClass cls = ds.findDBClass( params.getLookupClass()); DBField fld = cls.getDBField( params.getLookupFld()); md.setLookup( cls, fld, params.getLookupValue()); // Clone params so that lookup info does not get passed on subsequent updates tparams = FldParams.createNewObject( params); tparams.clearLookup(); } if( prevGlobalKey != null) { DBObjectHelper.raiseDependantRemovedEvent(ds, getGlobalKey(), prevGlobalKey, field.getGlobalKey()); } if( linkedGlobalKey != null) { DBObjectHelper.raiseDependantAddedEvent(ds, getGlobalKey(), linkedGlobalKey, field.getGlobalKey()); } if( helper.disableOnChange == false) { DBObjectHelper.fireOnChange(this, field, tparams); //#DEV_ONLY_START eventFieldUpdatedCalled = false; //#DEV_ONLY_END eventFieldUpdated(field, prevValue, prevGlobalKey, tparams); //#DEV_ONLY_START if( eventFieldUpdatedCalled == false) { LOGGER.error( "WARNING: overridden " + getClass().getName() + ".eventFieldUpdated(" + field + "," + prevValue + ") without calling super" ); } //#DEV_ONLY_END } } catch( Exception e) { LOGGER.error( getClass().getName() + ".iSetValue( " + field + "," + userValue + "," + params + ")", e ); throw e; } //#DEV_ONLY_START finally { if( params != null) { params.setLocked( fpLocked); } } //#DEV_ONLY_END } /** * Get the mutable array value * * @return The array value * @throws Exception must be mutable and an array field * @param name The name of the field */ public MutableArrayValue getMutableArrayValue( final String name) throws Exception { return getMutableArrayValue( dbClass.getDBField(name)); } /** * Get the mutable array value * * @param field the array field * @return The array value * @throws Exception must be mutable and an array field */ public MutableArrayValue getMutableArrayValue( final DBField field) throws Exception { if( field == null) { throw new IllegalArgumentException("field is null"); } if( field.isArray() == false) { throw new IllegalArgumentException( field.displayName() + " is not an array field"); } Object value; value = iGetRawValue( field); if( value instanceof MutableArrayValue) { return (MutableArrayValue)value; } else { if( helper == null) { helper = new DBObjectHelper( this); } MutableArrayValue mav; StoredArrayValue av = null; if( value instanceof StoredArrayValue) { av = (StoredArrayValue)value; } mav = MutableArrayValue.create( this, field, av, helper); return mav; } } /** * An optimised version of getRawField. * * @param field The field to get * @return The value of the field */ protected final Object iGetRawValue( final DBField field) { Object val = null; if( helper != null) { ModData md = (ModData)helper.updatedData.get( field.getGlobalKey().toString()); if( md != null) { val = md.getCurrentValue(); } else if( data != null) { val = data.getRawValue(ds.getDataBase(), field, null); } } else { if( data != null) { val = data.getRawValue(ds.getDataBase(), field, null); if( val instanceof LazyLoadValue) { val = ((LazyLoadValue)val).get(); } } else if( this instanceof DBRawClass) { return ((DBRawClass)this).extGetValue( field, NO_LOOP_PARAMS); } } if( val != null) { /** * We put into the cache table a blank string to null out a number. We need to return null not the string in this case. */ if( val instanceof String ) { int type = field.getType(); if( type != DBField.TYPE_STRING && type != DBField.TYPE_MULTILINGUAL && type != DBField.TYPE_TEXT ) { if( StringUtilities.isBlank( val)) { return null; } } } } return val; } /*=========================================================================================================================*/ /*==== PROGRAMMER EXTENDABLE METHODS =====*/ /*=========================================================================================================================*/ /** * OVERRIDE This method to be notified when a field changes. * This method should not trigger a save of this record because you may save a record in a half updated state.
* * TODO: Put in a programmer check for a save during this method call. * * @param field The field updated. * @param previous The previous value for this field. * @param previousKey The previous key * @param params The parameters used * * @throws Exception a serious problem */ protected void eventFieldUpdated( final DBField field, final Object previous, final GlobalKey previousKey, final FldParams params) throws Exception { //#DEV_ONLY_START eventFieldUpdatedCalled = true; //#DEV_ONLY_END } /** * OVERRIDE This method to specify fields should be mandatory under certain contions. * * @return true if the field should be treated as mandatory. * @param field The field to check */ protected boolean extIsMandatory( final DBField field) { return false; } /** * OVERRIDE This method to specify that when a field is updated it will affect other fields. * * @return true if the field affects others when changed * @param field The field to check */ protected boolean extIsOnChange( final DBField field) { return false; } /** * OVERRIDE This method for all objects with derived fields that are NOT linked. * A linked derived field should extend the extGetDerivedGlobalKey. * * @param params The parameters for this field eg. language= or default= * @param field The field to get * * @throws Exception a serious problem * * @return The value of the field. */ protected Object extGetDerivedValue( final DBField field, final FldParams params) throws Exception { return params != null ? params.getDefault( ds, field) : null; } /** * OVERRIDE This method to return a derived global key. This method is only checked if the * field is marked as being linked. * * @param field The field that is being changed * @param params The extra parameters * * @throws Exception A serious problem. In general validation is done later. * * @return The Global key */ protected GlobalKey extGetDerivedGlobalKey( final DBField field, final FldParams params) throws Exception { return null; } /** * OVERRIDE This method to Alter the default behaviour of check if we can remove a dependant object. * * The normal check to see if a dependant object can be deleted is if that object is new or is marked as "parentCanDeleteChild" and * that any object that depends on the dependant also complies. * * @param o The object to check * @return true if we can delete this object. */ protected boolean extCanDeleteDependantObject( final DBObject o) { return false; } /** * This is the PRIMARY "get" method which returns the processed field value for this object. * If additional processing is require for a field the normal way of achiving this would be to * declare it as derived and then add the processing to extGetDerivedValue but this method may be * also overridden to add this additional functionality.
*
* Please note: if a field is not declared DERIVED and the field value is changed * by the overriding this method, a database search for this field may return unexpected results. *
* When overriding the extGetValue method the SAME value should be return. * Examples of use are to blank fields that you don't have access to or to return ***** instead of the password. The * database search uses getPureField which is final so you could do a search for a field value * even if it is being blanked. Real security can only be given by creating an associated record * and supplying a ACL to restrict access to it. * * @return The value of the field. * * @param params The parameters for this field eg. language= or default= * @param field The field to get */ protected Object extGetValue(final DBField field, final FldParams params) { return getPureValue( field, params); } /** * The extended fix up routine * @throws Exception a serious problem */ protected void extFixUp() throws Exception { //#DEV_ONLY_START extFixUpCalled = true; //#DEV_ONLY_END } /** * Extend this method to add functionality when a new DBObject is created.
* You may need to create a FldParams, and setIsAutoEntered(true) * so that system does not misunderstand that this object is changed by user. * * @throws Exception A serious problem */ protected void extAutoEnterCreate() throws Exception { //#DEV_ONLY_START extAutoEnterCreateCalled = true; //#DEV_ONLY_END } /** * Extend this method to add validation to a record then deleted. * * @param list The validation list * * @throws Exception A serious problem */ protected void extValidateDelete(final ValidationList list) throws Exception { //#DEV_ONLY_START extValidateDeleteCalled = true; //#DEV_ONLY_END } /** * Additional functionality when an object is marked for deletion by calling delete(). * * @throws Exception A serious problem */ protected void extDelete() throws Exception { //#DEV_ONLY_START extDeleteCalled = true; //#DEV_ONLY_END } /** * Additional functionality when an object is undeleted. * * @throws Exception A serious problem */ protected void extUndelete() throws Exception { //#DEV_ONLY_START extUndeleteCalled = true; //#DEV_ONLY_END } /** * Additional functionality when an object is copied. * * @param target the target object * * @throws Exception A serious problem */ protected void extCopy( final DBObject target) throws Exception { //#DEV_ONLY_START extCopyCalled = true; //#DEV_ONLY_END } /** * Additional access checking for create access of this object. * * @throws DBAccessException No access to create */ protected void extCheckCreateAccess() throws DBAccessException { //#DEV_ONLY_START extCheckCreateAccessCalled = true; //#DEV_ONLY_END } /** * Additional access checking for delete access of this object. * * @throws DBAccessException No access to delete */ protected void extCheckDeleteAccess() throws DBAccessException { //#DEV_ONLY_START extCheckDeleteAccessCalled = true; //#DEV_ONLY_END } /** * Additional access checking for read access of this object. * * @throws DBAccessException No access to read */ protected void extCheckReadAccess() throws DBAccessException { //#DEV_ONLY_START boolean extCheckReadAccessCalled[] = (boolean[])localExtCheckReadAccessCalled.get(); if( extCheckReadAccessCalled != null) { extCheckReadAccessCalled[0] = true; } //#DEV_ONLY_END } /** * Additional access checking for write access of this object. * * @throws DBAccessException No access to modify */ protected void extCheckModifyAccess() throws DBAccessException { //#DEV_ONLY_START extCheckModifyAccessCalled = true; //#DEV_ONLY_END } /** * Additional access checking for write access for a field of this object. * * @param field Can we change this field ? * @throws DBAccessException No access to change */ protected void extCheckModifyAccess(final DBField field) throws DBAccessException { //#DEV_ONLY_START extCheckModifyAccessCalled = true; //#DEV_ONLY_END } /** * OVERRIDE this method to add functionallity to Super-Tracker BEFORE saving the record to the database. * * At this stage the final validation ( internally called by save) has NOT been performed. This is your chance to * create other associated records etc. This method is called for all created and modified records NOT deleted. * The database transaction has not been started yet. Your changes will NOT be rollback in case of failure. * * @throws Exception A Serious problem */ protected void extPreSaveRecord() throws Exception { //#DEV_ONLY_START extPreSaveRecordCalled = true; //#DEV_ONLY_END } /** * OVERRIDE this method to add functionality to Super-Tracker BEFORE deleting a record from the datbase. * * At this stage the final validation ( internally called by save) has NOT been performed. This is your chance to * create other associated records etc. This method is called for all created and modified records NOT deleted. * The database transaction has not been started yet. Your changes will NOT be rollback in case of failure. * * @throws Exception A Serious problem */ protected void extPreDeleteRecord() throws Exception { //#DEV_ONLY_START extPreDeleteRecordCalled = true; //#DEV_ONLY_END } /** * OVERRIDE this method to add functionality to Super-Tracker WHILE deleting the record from the database. * * At this stage we are within a database transaction. YOU MAY NOT CHANGE THE UNIVERSE AT THIS STAGE. * * @param transNr This transaction number that was just saved. * @throws Exception A serious Error */ protected void extDeleteRecord( final long transNr) throws Exception { //#DEV_ONLY_START extDeleteRecordCalled = true; //#DEV_ONLY_END } /** * OVERRIDE this method to add functionality to Super-Tracker WHILE saving the record to the database. * * At this stage we are within a database transaction. YOU MAY NOT CHANGE THE UNIVERSE AT THIS STAGE. * * @param transNr This transaction number that was just saved. * @throws Exception A serious Error */ protected void extSaveRecord( final long transNr) throws Exception { //#DEV_ONLY_START extSaveRecordCalled = true; //#DEV_ONLY_END } /** * OVERRIDE this method to add functionality to Super-Tracker AFTER deleting the record from the database. * * At this stage the database transaction has been committed. YOU MAY NOT CHANGE THE UNIVERSE AT THIS STAGE. * * @param transNr This transaction number that was just saved. */ protected void extPostDeleteRecord( final long transNr) { //#DEV_ONLY_START extPostDeleteRecordCalled = true; //#DEV_ONLY_END } /** * OVERRIDE this method to add functionality to Super-Tracker AFTER saving the record to the database. * * At this stage the database transaction has been committed. YOU MAY NOT CHANGE THE UNIVERSE AT THIS STAGE. * * @param transNr This transaction number that was just saved. */ protected void extPostSaveRecord( final long transNr) { //#DEV_ONLY_START extPostSaveRecordCalled = true; //#DEV_ONLY_END } /** * When the underlying DBData is changed/ loaded. This may be call via other * threads/servers saving the object. *
* OVERRIDE this method to add clear cache items on reload. */ protected void eventDataLoaded() { //#DEV_ONLY_START eventDataLoadedCount++; //#DEV_ONLY_END } /** * OVERRIDE This method to filter ALL public calls to SetValue. This method is called BEFORE the field is * changed.
*
* You can use this method to implement things like composite keys where the key value is made up of two or more * other fields. So when field1 or field2 is updated we call iSetValue to change the key value and in extSetValue we * ignore any value set by the user/screen for the key field. * * @param field The field that is being changed * @param currentValue The new value * @param params The extra parameters * * @throws Exception A serious problem. In general validation is done later. */ protected void extSetValue( final DBField field, final Object currentValue, final FldParams params) throws Exception { iSetValue( field, currentValue, params); } /** * OVERRIDE To add functionality to before validation is called.
*
* THIS IS YOUR LAST CHANCE TO MAKE CHANGES BEFORE VALIDATIONS. * @throws Exception a serious problem */ protected void extPreValidate() throws Exception { //#DEV_ONLY_START extPreValidateCalled = true; //#DEV_ONLY_END } /** * * OVERRIDE To add functionality to before validation is called.
*
* THIS IS YOUR LAST CHANCE TO MAKE CHANGES BEFORE VALIDATIONS FOR DELETED RECORDS. * @throws Exception a serious problem */ protected void extPreValidateDelete() throws Exception { //#DEV_ONLY_START extPreValidateCalled = true; //#DEV_ONLY_END } /** * raise the events * @throws Exception A serious problem */ protected void extRaiseEvents() throws Exception { //#DEV_ONLY_START extRaiseEventsCalled = true; //#DEV_ONLY_END } /** * Performs additional validations on this record. * * OVERRIDE this method to add additional validations to a record.
* The MutableDataSource is in READONLY mode at this stage. * @param list The validation list. * @throws Exception A serious problem */ protected void extValidateRecord(final ValidationList list) throws Exception { //#DEV_ONLY_START extValidateRecordCalled = true; //#DEV_ONLY_END } /** * Mark the save point which we can rollback to later. * @param id the save point id * @throws com.aspc.DBObj.Errors.NotInUniverseException DBObject had not been touched */ protected void extMarkSavePoint( final String id) throws NotInUniverseException { } /** * Rollback to save point. * * @param id the save point id * @throws NoSavePointException no save point found */ protected void extRollbackTo( final String id) throws NoSavePointException { } /** * Additional validation for particular field  OVERRIDE THIS METHOD TO ADD VALIDATIONS FOR A FIELD.
*
* OVERRIDE this method to add validation to a field but call iValidateField to perform * the full validation for a field.
*
* This method should be READ ONLY. Don't create DBObjects here.
* When overriding this method the following code stub should be used.
* ValidationError ve;
* ve = super.extValidateField( field, list);
* if( ve != null) return ve;
* if( field.getName().equalsIgnoreCase( DBFIELD_FIELD1))
* {
* return list.createError( DBMessage.LIST_DB_MY_ERROR, this, field);
* }
* else if( field.getName().equalsIgnoreCase( DBFIELD_FIELD2))
* {
* ....
* }
*
* @return the error or warning. * @param list The validation list * @param field The field to be validated * @throws Exception a serious error */ protected ValidationError extValidateField(final DBField field, final ValidationList list) throws Exception { //#DEV_ONLY_START extValidateFieldCalled = true; //#DEV_ONLY_END return null; } /* *================================================================================================= *== PRIVATE METHODS == *================================================================================================= */ /** * Validation for particular field. * * @return the error or warning. * @param possibleConflicts The list of rows matching key and unique field values. This is done by a batch select to improve performance. * @param field The field to be validated * * @throws Exception a serious error */ @SuppressWarnings({"empty-statement", "empty-statement"}) private ValidationError iValidateField(final DBField field, final ValidationList list, final HashMap possibleConflicts) throws Exception { Object value; value = getRawValue( field); boolean hasChanged = hasFieldChanged( field); boolean hasUserChanged = this.hasChangedByUserField( field); /** * Only check modify access on fields if the user has changed * This allows us to stop users from modifying fields but still allows * a default value */ if( hasUserChanged && isNew() == false) { try { checkModifyAccess( field); } catch( DBAccessException access) { boolean noRealChange = false; if( isNew() == false) { if( field.isLinked() == false) { Object o = getOriginalValue( field); if( o == null && value == null) { noRealChange=true; } else if( o != null && value != null) { if( o.equals( value)) { noRealChange=true; } } } } if( noRealChange == false) { list.add( access); } } } if( value instanceof MultiLingualValue) { MultiLingualValue mlv = (MultiLingualValue)value; value = mlv.getText(); } ModData tmpData = null; if( helper != null) { tmpData = (ModData)helper.updatedData.get( field.getGlobalKey().toString()); } if( tmpData != null && tmpData.getCurrentKey() == null && tmpData.getLookupFld() != null && StringUtilities.isBlank( tmpData.getLookupValue()) == false ) { DBClass linkedClass = field.getLinkedDBClass(); if( linkedClass == null) { throw new RuntimeException( "linked class for field:" + field.getName() + " is null, lookup value = " + tmpData.getLookupValue() + " fld:" + tmpData.getLookupFld() ); } DBField sfield = linkedClass.getDBField( tmpData.getLookupFld().getGlobalKey()); if( sfield == null) { throw new RuntimeException( "Lookup field:" + tmpData.getLookupFld().getName() + " does not exist in linked class " + linkedClass.getName()); } DBQuery q = new DBQuery( linkedClass, ds); if( sfield.getType() == DBField.TYPE_STRING || sfield.getType() == DBField.TYPE_MULTILINGUAL || sfield.getType() == DBField.TYPE_TEXT ) { q.addClause( tmpData.getLookupFld(), "like", tmpData.getLookupValue() +"*"); } else { q.addClause( tmpData.getLookupFld(), "=", tmpData.getLookupValue()); } try { q.findOne(); } catch( NotFoundException nf) { return list.createError( this, field, "There are no entries found that start with " + tmpData.getLookupValue() ); } catch( TooManyRowsException tm) { return list.createError( this, field, "There are too many entries that start with " + tmpData.getLookupValue() ); } } if( isMandatory(field) && ( this instanceof DBRawClass) == false) { if( StringUtilities.isBlank(value)) { return list.createError( this, field, field.displayName() + " is mandatory and must not be blank" ); } } if( value instanceof ArrayValue) { ArrayValue av = (ArrayValue)value; int size = av.size(); for( int i = 0; i < size; i++) { Object tempValue = av.get( i); /* Check that the data for each field is parsable. */ try { field.parse( ds, tempValue); } catch( Exception e) { return list.createError( this, field, e.getMessage() ); } } } else { /* Check that the data for each field is parsable. */ try { field.parse( ds, value); } catch( Exception e) { return list.createError( this, field, e.getMessage() ); } } /* If new check that new fields are unique. */ if( isNew()) { if( field.isKey()) { String temp = value.toString(); String msgID = DBObjUtilities.checkKey( temp, field, this); if( msgID != null) { return new ValidationError( //ds, msgID, this, //arg 0 field, //arg 1 temp //arg 2 ); } GlobalKey gk = getGlobalKey(); if( possibleConflicts == null) { /* Do it the slow way. */ try { ds.getDataBase().findKey( gk); /* If we found it check that it's not deleted in this universe */ DBObject o; o = ds.getDataBase().findKey( gk); if( o.isDeleted() == false ) { return list.createError( DBMessage.LIST_DB_OBJECT_DUPLICATE_KEY, this, field, gk.getValue() ); } } catch( NotFoundException nf) { /* This is good - no warning necessary */ ; } } else { ArrayList v = (ArrayList)possibleConflicts.get( field.getGlobalKey().toString()); for( int i = 0; v != null && i < v.size(); i++) { DBObject obj; obj = (DBObject)v.get(i); if( obj.isDeleted() == false && obj.getGlobalKey().equals( gk) && obj.getRowId() != getRowId() ) { return list.createError( DBMessage.LIST_DB_OBJECT_DUPLICATE_KEY, this, field, value ); } } } } } /** * If unique fields ( java class name ) maybe blank * * Bug found on 24 September 2004. * * The unique value check is only performed if the field changes. Marvin doesn't * detect an error if the field wasn't unique and we enter two records with the * same value and then set the field to be unique. * * We need to check if the field has changed or the index is dirty. */ boolean checkUnique = false; if( StringUtilities.isBlank( value) == false) { if( field.isUnique()) { if( hasChanged) { checkUnique = true; } else { if( ds.getAttribute("MARVIN") != null) { checkUnique=true; } VirtualDB layer = ds.getDataBase(); if( layer.isIndexed( dbClass, field) == false) { checkUnique = true; } } } } if( checkUnique ) { String str = getString( field); ArrayList objList = null; if( possibleConflicts != null) { objList = (ArrayList)possibleConflicts.get( field.getGlobalKey().toString()); } if( objList != null) { for( int i = 0; i < objList.size(); i++) { DBObject obj; obj = (DBObject)objList.get(i); if( obj != this && obj.isDeleted() == false && obj.getRowId() != getRowId() && obj.getString(field).equalsIgnoreCase( str) ) { return list.createError( this, field, "duplicate value '" + str + "'" ); } } } else { /* Do it the slow way. */ DBQuery q = new DBQuery( dbClass, ds); q.addClause( field, "=", str); DBResult r = q.search(); while( true) { /* If we found it check that it's not deleted in this universe */ DBObject o; o = r.next(); if( o == null) break; if( o.isDeleted() == false && o.getGlobalKey().equals( getGlobalKey()) == false) { return list.createError( this, field, "duplicate value '" + str + "' in " + dbClass ); } } } } if( field.isLinked()) { if( value instanceof ArrayValue) { int size = ((ArrayValue)value).size(); for( int p = 0; p < size; p++) { checkLinkValid(list, field, value, p); if( list.hasErrors()) { ValidationItem item = list.getWorstItem(); if( item instanceof ValidationError) { return (ValidationError)item; } } } } else if( StringUtilities.isBlank(value) == false) { checkLinkValid(list, field, value, -1); if( list.hasErrors()) { ValidationItem item = list.getWorstItem(); if( item instanceof ValidationError) { return (ValidationError)item; } } } } try { DBFormula formula = field.getValidationFormula(); if( formula != null) { try { DBFieldQuery query = new DBFieldQuery( ds, dbClass, this, null); Double res = (Double)formula.compute(query); if( res.shortValue() == 0) { String validationMsg = field.getString( "validationMsg"); if( validationMsg.equals( "")) { validationMsg = "Does not pass validation formula '" + field.getString ("validationFormula") + "'"; } return list.createError( this, field, validationMsg ); } } catch( NullValueException nv) { /* This is OK - no warning necessary */ ; } } } catch( Exception e) { String msg; msg = e.getMessage(); if( msg == null || msg.equals( "")) { msg = e.toString(); } return list.createError( this, field, msg ); } String format = field.getString( DBField.DBFIELD_DISPLAY_FORMAT); if( format.equalsIgnoreCase("mailto")) { if( StringUtilities.isBlank(value) == false) { String email = value.toString(); int atPos = email.indexOf("@"); int dotPos = email.lastIndexOf("."); if( atPos < 1 || atPos > dotPos) { return list.createError( this, field, "Invalid email"); } } } else if( format.equalsIgnoreCase("duration")) { if( StringUtilities.isBlank(value) == false) { try { TimeUtil.parseUserDuration( value.toString()); } catch( InvalidDataException ide) { return list.createError( this, field, ide.getMessage()); } } } int maxLen = field.getInt( DBField.DBFIELD_MAX_LENGTH, 0); if( maxLen > 0) { int type = field.getType(); if( StringUtilities.isBlank(value) == false) { if( type == DBField.TYPE_STRING || type == DBField.TYPE_MULTILINGUAL || type == DBField.TYPE_TEXT ) { if(value.toString().length() > maxLen) { return list.createError( this, field, "Value exceeds max length of " + maxLen); } } } } ValidationError err; //#DEV_ONLY_START extValidateFieldCalled = false; //#DEV_ONLY_END err = extValidateField( field, list); if( err != null) { list.add( err); return err; } //#DEV_ONLY_START if( extValidateFieldCalled == false) { return list.createError( this, field, "Programming error: overridden method " + getClass().getName() + ".extValidateField(" + field + ") never called super" ); } //#DEV_ONLY_END return null; } @SuppressWarnings("empty-statement") private void checkLinkValid( final ValidationList list, final DBField field, final Object value, final int pos ) { DBObject obj = null; GlobalKey gk = null; FldParams params = null; if( pos != -1) { params = new FldParams(); params.setPosition(pos); } try { gk = getGlobalKey( field, params); if( gk != null) { obj = ds.findKey( gk); } } catch( DBAccessException access) { Object prev; prev = getOriginalValue( field); if( prev == null || prev.equals( value) == false) { list.createError( this, field, field.getLinkedDBClass() + "{" + value + "} no access to foreign key " + access.getMessage() ); } try { obj = ds.getDataBase().findKey( gk); } catch( NotFoundException nf2) { ; } } catch( NotFoundException nf) { ; } if( obj == null) { if( hasFieldChanged(field)) { DBClass toClass = field.getLinkedDBClass(); list.createError( this, field, toClass + " '" + getString( field, params) + "' foreign key missing" ); } } } @SuppressWarnings("empty-statement") private void autoEnterCreate( final DBField field) { Object autoVal = null; MutableDataSource mds = ( MutableDataSource) ds; if( field.isIncremental()) { long nextNr; nextNr = ds.nextNumber( "FIELD:" + field.getGlobalKey().getValueId()); int value = ( int)nextNr; if( nextNr < 0 && value > 0) value = (0xf0000000 | value); autoVal = Integer.valueOf( value); } else { autoVal = field.getAutoFillValue(); if( StringUtilities.isBlank(autoVal)) { String predVal = ""; predVal = field.getAutoFillPredefinedValue(); if( predVal.equalsIgnoreCase(AutoEnterPredefined.LIST_CREATED_TIME)) { autoVal = new Date(); } else if( predVal.equalsIgnoreCase(AutoEnterPredefined.LIST_CREATED_BY_USER)) { Login login = mds.getRealLogin(); if( login.isSystemOrGuest() == false) { autoVal = login.getLinkedObject( Login.DBFIELD_PERSON_ID, null); } } else if(predVal.equalsIgnoreCase(AutoEnterPredefined.LIST_MODIFIED_TIME)) { autoVal = new Date(); } else if(predVal.equalsIgnoreCase(AutoEnterPredefined.LIST_MODIFIED_BY_USER)) { Login login = mds.getRealLogin(); if( login.isSystemOrGuest() == false) { autoVal = login.getLinkedObject( Login.DBFIELD_PERSON_ID, null); } } else if(predVal.equalsIgnoreCase(AutoEnterPredefined.LIST_CREATED_BY_BUS_UNIT)) { Login login = mds.getRealLogin(); autoVal = login.getLinkedObject( Login.DBFIELD_CURRENT_BUS_UNIT, null); } } if( StringUtilities.isBlank(autoVal)) { try { if( field.hasAutoEnterFormula()) { DBFormula formula = field.getAutoEnterFormula(); try { DBFieldQuery query = new DBFieldQuery( ds, dbClass, this, null); autoVal = formula.compute(query); } catch( NullValueException nv) { ;/* This is OK - no warning necessary */ } } } catch(Exception e) { LOGGER.error("Could not autoenter " + field + " with value '" + autoVal + "'", e); } } } if( StringUtilities.isBlank(autoVal) == false) { try { FldParams params = new FldParams(); params.setIsAutoEntered( true); setValue(field, autoVal, params); } catch(Exception e) { LOGGER.error("Could not autoenter " + field + " with value '" + autoVal + "'", e); } } } private void checkDelete( final Hashtable table) throws DBAccessException { if( isNew()) return; checkDeleteAccess(); GlobalKey key = getGlobalKey(); /* Check for recursion. */ if( table.get( key.toString() ) != null) return; table.put( key.toString(), ""); try { DBField inwardLinks[]; inwardLinks = dbClass.getInwardLinks(); /** * Check we have access to all objects pointing to this object. */ for( int i = 0; i < inwardLinks.length; i++) { DBField sourceField = inwardLinks[i]; /* * Derived fields are not classed as a foreign key restriction * as they are not stored in the database */ if( sourceField.isRuntimeEval() == true) continue; DBClassAbstract baseClassAbstract = sourceField.getBaseDBClassAbstract(); DBClass list[] = baseClassAbstract.listClass(); for( int j = 0; j < list.length; j++) { DBQuery q = new DBQuery( list[j], ds.getDataBase()); q.addClause( sourceField, "IS", this); DBResult r = q.search(); while( true) { DBObject o; o = r.next(); if( o == null) break; o.iCheckReadAccess( ds); } } } /* Check all links where we can't remove the children objects */ for( int i = 0; i < inwardLinks.length; i++) { DBField sourceField = inwardLinks[i]; if( sourceField.canParentRemoveChild() == true || sourceField.canParentClearChild() == true ) { continue; } /* * Derived fields are not classed as a foreign key restriction * as they are not stored in the database */ if( sourceField.isRuntimeEval() == true) continue; DBResult r = getInwardLinkage(sourceField, null); DBObject o; o = r.next(); if( o != null) { if( extCanDeleteDependantObject( o)) { continue; } if( table.get( o.getGlobalKey().toString()) == null) { throw new DBAccessFoundLinkedObjectException( this, o, sourceField ); } } } /* Check all links that we can remove the children objects */ for( int i = 0; i < inwardLinks.length; i++) { DBField sourceField = inwardLinks[i]; /** * Checking for derived fields takes too long. */ if( sourceField.isRuntimeEval() == true) continue; if( sourceField.canParentRemoveChild() == false && sourceField.canParentClearChild() == false ) { continue; } DBResult r = getInwardLinkage(sourceField,null); while( true) { DBObject o; o = r.next(); if( o == null) break; /* TODO: What happens if you don't have access to the linked objects ? */ o.checkDelete( table); } } } catch( DBAccessException access) { throw access; } catch( Exception e) { LOGGER.error( "canDelete()", e); throw new DBAccessException( getGlobalKey(), "Can't delete " + this + " - because of internal error: " + e ); } } /** * Displays the value of the default display field * * @return the display name */ public String displayValue() { String value; value = getString( "name"); if( StringUtilities.isBlank( value)) { value = getString( "label"); if( StringUtilities.isBlank( value)) { value = getString( "value"); } } return value; } /** * The display name * * @return the display name */ public String displayName() { String key; key = getKeyString(); String value = displayValue(); StringBuffer buffer = new StringBuffer(); buffer.append( dbClass.displayName()); buffer.append( ": "); if( StringUtilities.isBlank( key) == false) { buffer.append( key); if(StringUtilities.isBlank( value) == false) { buffer.append( "-"); } } if(StringUtilities.isBlank( value) == false) { value = value.trim(); if( value.length() > 40) { value = value.substring(0, 40).trim(); } buffer.append( value); } return buffer.toString(); } /** * Calls extended access checking and ensures that super access checking has * been called * * @throws DBAccessException No access to delete */ private void iExtCheckDeleteAccess() throws DBAccessException { //#DEV_ONLY_START extCheckDeleteAccessCalled = false; //#DEV_ONLY_END extCheckDeleteAccess( ); //#DEV_ONLY_START if( extCheckDeleteAccessCalled == false) { DBAccessException ae = new DBAccessException( getGlobalKey(), "Can't delete: " + getClass().getName() + ".extCheckDeleteAccess() overridden but super not called" ); LOGGER.error( "Programmer error", ae); throw ae; } //#DEV_ONLY_END } /** * Calls extended access checking and ensures that super access checking has * been called * * @throws DBAccessException No access to modify */ private void iExtCheckModifyAccess() throws DBAccessException { //#DEV_ONLY_START extCheckModifyAccessCalled = false; //#DEV_ONLY_END extCheckModifyAccess( ); //#DEV_ONLY_START if( extCheckModifyAccessCalled == false) { DBAccessException ae = new DBAccessException( getGlobalKey(), "Can't Modify: " + getClass().getName() + ".extCheckModifyAccess() overridden but super not called" ); LOGGER.error( "Programmer error", ae); throw ae; } //#DEV_ONLY_END } private Login getLogin() { if( helper != null) return helper.getLogin(); return ds.getLogin(); } /* TODO: Move most of this stuff off into a helper class */ /** The raw data for this object */ private DBDataInterface data; private ArrayList reloadEventListeners; private DBObjectHelper helper; /** A hard reference to the watched objects */ private Hashtable watchedObjects; /** has this record been deleted */ // private byte cacheDeleted; private Object cacheKeyValue; /** * ============================ Programmer Check Flags ========================== * Used to check that the programmer extending DBObjects calls the super method. * ============================================================================== */ //#DEV_ONLY_START private boolean extPreSaveRecordCalled; private boolean extPreValidateCalled; private boolean extValidateFieldCalled; private boolean extValidateDeleteCalled; private boolean extValidateRecordCalled; private boolean extPostSaveRecordCalled; private boolean extPostDeleteRecordCalled; private boolean extAutoEnterCreateCalled; private boolean extDeleteCalled; private boolean extUndeleteCalled; private boolean eventFieldUpdatedCalled; private int eventDataLoadedCount; private int clearCacheCount; private boolean extPreDeleteRecordCalled; private boolean extRaiseEventsCalled; private static final ThreadLocal localExtCheckReadAccessCalled = new ThreadLocal(); private boolean extCheckModifyAccessCalled; private boolean extCheckDeleteAccessCalled; private boolean extCheckCreateAccessCalled; private boolean extDeleteRecordCalled; private boolean extSaveRecordCalled; private boolean extFixUpCalled; private boolean extCopyCalled; //#DEV_ONLY_END /** * don't loop */ protected static final FldParams NO_LOOP_PARAMS=new FldParams(); /** * Prevent a stack overflow while relinking broken links that are used in the ACLs */ private static final Hashtable RELINKING_OBJECTS=new Hashtable(); private static final Log LOGGER = CLogger.getLog( "com.aspc.DBObj.DBObject");//#LOGGER-NOPMD static { //#DEV_ONLY_START LOGGER.fatal( "DEVELOPMENT ONLY VERSION of DBObject"); //#DEV_ONLY_END } } /* * Change Log: * * Revision 1.618 2005/10/28 08:39:52 nigel * fixed sudo. * * $Log: DBObject.java,v $ * Revision 1.807 2009/05/19 06:40:57 nigel * fixing. * * Revision 1.806 2009/05/18 12:01:00 nigel * working on archive perfomance. * * Revision 1.805 2009/05/17 08:44:57 nigel * fixed archive performance. * * Revision 1.804 2009/05/11 07:02:04 nigel * working on archive performance. * * Revision 1.803 2009/05/07 07:52:54 nigel * fixed archive check. * * Revision 1.802 2009/05/04 12:53:44 nigel * working on no inital record. * * Revision 1.801 2009/04/29 07:14:52 nigel * bulk load. * * Revision 1.800 2009/04/27 06:06:28 nigel * fixed undo * * Revision 1.799 2009/04/24 23:17:57 nigel * fixed caching issues. * * Revision 1.798 2009/04/22 04:00:01 nigel * working on erase * * Revision 1.797 2009/04/17 14:06:45 nigel * working on job manager. * * Revision 1.796 2009/04/16 11:10:18 nigel * handle duplicate keys. * * Revision 1.795 2009/04/16 08:00:48 nigel * working on erase. * * Revision 1.794 2009/04/15 07:00:38 nigel * include apt * * Revision 1.793 2009/04/14 11:42:17 nigel * working on erase * * Revision 1.792 2009/04/13 10:51:35 nigel * 1) standards * 2) transaction erase. * * Revision 1.791 2009/03/23 05:00:14 nigel * fixed secondary cache on getParentClass() * * Revision 1.790 2009/03/19 00:33:18 nigel * fixing archive problem. * * Revision 1.789 2009/03/18 05:49:04 nigel * fixing archive problem. * * Revision 1.788 2009/03/09 06:06:52 nigel * javadocs. * * Revision 1.787 2009/03/09 03:04:32 nigel * corrected journal. * * Revision 1.786 2009/03/09 00:04:36 nigel * javadocs. * * Revision 1.785 2009/02/20 04:43:47 lgao * comments * * Revision 1.784 2009/02/18 01:42:11 nigel * find bugs scan. * * Revision 1.783 2009/02/12 04:58:54 nigel * fixed has changed for arrays. * * Revision 1.782 2009/02/11 06:23:39 nigel * fixed tests. * * Revision 1.781 2009/02/10 13:23:24 build * Auto Generated constants * * Revision 1.780 2009/02/10 06:31:28 nigel * fixed has changed on multilingual fields. * * Revision 1.779 2009/02/08 06:52:29 nigel * fixed blank values for multilingual fields. * * Revision 1.778 2009/02/05 13:24:32 build * Auto Generated constants * * Revision 1.777 2009/02/05 11:50:20 nigel * fixed * * Revision 1.365 2009/02/05 07:26:35 nigel * check archive versus current. * * Revision 1.364 2009/02/05 04:48:00 nigel * archive check * * Revision 1.776 2009/02/05 04:37:58 nigel * archive check * * Revision 1.775 2009/02/04 05:22:54 nigel * fixed test cases. * * Revision 1.774 2009/02/02 04:27:43 nigel * fixed screen handling. * * Revision 1.773 2008/11/09 10:02:15 nigel * standards * * Revision 1.772 2008/10/06 00:19:20 nigel * working on arrays. * * Revision 1.771 2008/10/04 09:00:44 nigel * fixed array * * Revision 1.770 2008/10/02 10:57:40 nigel * fixes * * Revision 1.769 2008/10/02 07:40:04 nigel * working on array. * * Revision 1.768 2008/09/10 09:22:58 nigel * improved cache performance. * * Revision 1.767 2008/09/02 07:31:13 nigel * 1) working on arrays. * 2) working on memory manager. * * Revision 1.766 2008/08/29 06:20:43 lgao * flaged warn * * Revision 1.765 2008/08/25 10:33:58 nigel * fixed MemorManager. * * Revision 1.764 2008/08/25 06:28:13 nigel * performance. * * Revision 1.763 2008/08/13 06:29:25 nigel * find bugs. * * Revision 1.762 2008/08/13 04:21:08 nigel * find bugs. * * Revision 1.761 2008/07/25 08:34:33 nigel * working on arrays. * * Revision 1.760 2008/07/24 08:31:56 nigel * working on arrays * * Revision 1.759 2008/07/23 23:30:32 nigel * working on arrays. * * Revision 1.758 2008/07/23 14:27:24 nigel * working on arrays. * * Revision 1.757 2008/07/23 08:10:30 nigel * fixed rollback. * * Revision 1.756 2008/07/22 11:41:39 nigel * fixed array clear. * * Revision 1.755 2008/07/08 03:33:46 nigel * fixed stack overflow. * * Revision 1.754 2008/07/07 05:36:39 nigel * fixed array value. * * Revision 1.753 2008/06/16 07:49:08 nigel * array field fixes. * * Revision 1.752 2008/06/12 23:12:54 nigel * fixed array * * Revision 1.751 2008/06/12 21:39:51 nigel * fixed array * * Revision 1.750 2008/05/29 06:24:06 nigel * fixed alternative file stores. * * Revision 1.749 2008/05/24 04:55:56 nigel * fixed class cast exception * * Revision 1.748 2008/05/23 12:49:59 nigel * improved performance. * * Revision 1.747 2008/05/19 03:37:41 nigel * fixed class cast exception * * Revision 1.746 2008/05/16 06:35:34 nigel * fixed array search. * * Revision 1.745 2008/05/16 02:27:40 nigel * fixed array search. * * Revision 1.744 2008/05/15 05:35:05 nigel * 1) fixed linked array * 2) show the layer that the transaction occured. * * Revision 1.342 2008/05/14 12:06:03 nigel * fixed. * * Revision 1.341 2008/05/14 11:15:45 nigel * fixed linked array * * Revision 1.743 2008/05/14 09:41:06 nigel * fixed array clear. * * Revision 1.742 2008/05/11 10:46:44 nigel * working on linked array * * Revision 1.741 2008/05/10 11:35:40 nigel * working on linked array * * Revision 1.740 2008/05/06 11:33:25 nigel * working on test. * * Revision 1.739 2008/05/06 10:23:10 nigel * fixed. * * Revision 1.738 2008/05/05 20:41:21 nigel * working on test. * * Revision 1.737 2008/03/22 01:38:49 nigel * standards. * * Revision 1.736 2008/03/03 23:26:40 nigel * fixed NPE in field parse. * * Revision 1.735 2008/02/28 02:45:37 nigel * fixed. * * Revision 1.734 2008/02/18 02:44:49 nigel * working on template search. * * Revision 1.733 2008/02/12 22:30:04 nigel * fixed import file issue. * * Revision 1.732 2008/02/03 10:23:54 nigel * fixed search plan * * Revision 1.731 2008/01/30 23:45:57 nigel * performance. * * Revision 1.730 2008/01/22 06:07:34 nigel * fixing standards. * * Revision 1.729 2007/12/11 06:19:50 nigel * working on template. * * Revision 1.728 2007/12/10 22:28:22 nigel * working on templates. * * Revision 1.727 2007/12/04 22:35:24 nigel * 1) standards. * 2) performance. * * Revision 1.726 2007/11/28 19:22:53 nigel * error -> warn * * Revision 1.725 2007/11/14 05:50:55 nigel * fixed tests * * Revision 1.724 2007/11/13 05:35:28 nigel * fixed HA * * Revision 1.723 2007/11/07 09:31:59 nigel * fixed. * * Revision 1.722 2007/10/18 11:33:22 nigel * working on jmx * * Revision 1.721 2007/10/06 05:59:29 nigel * working on lazy load. * * Revision 1.720 2007/09/29 10:57:10 nigel * fixed test case. * * Revision 1.719 2007/09/29 10:12:03 nigel * fixed test case. * * Revision 1.718 2007/09/13 04:55:12 jason * Modify access should not be done if validateOnly = true * * Revision 1.717 2007/08/23 02:36:13 nigel * standard * * Revision 1.716 2007/08/06 20:58:02 nigel * standards. * * Revision 1.715 2007/07/17 06:29:58 nigel * 1) reload command * 2) standards. * 3) email tracking * 4) repeat rule classes. * * Revision 1.322 2007/07/17 06:21:02 nigel * 1) reload command * 2) standards. * 3) email tracking * 4) repeat rule classes. * * Revision 1.714 2007/07/17 05:22:51 nigel * 1) reload command * 2) standards. * * Revision 1.713 2007/06/26 07:51:59 nigel * reduce memory usage. * * Revision 1.712 2007/05/12 09:58:44 nigel * working on arrays * * Revision 1.711 2007/05/09 12:16:59 nigel * working on field arrays. * * Revision 1.710 2007/05/09 04:29:55 nigel * working on arrays. * * Revision 1.709 2007/05/05 08:06:36 nigel * working on arrays. * * Revision 1.708 2007/04/28 14:08:30 nigel * improved memory usage. * * Revision 1.707 2007/04/20 05:59:54 nigel * standards * * Revision 1.706 2007/04/18 05:32:35 nigel * allow instrument to run only when turned on . * * Revision 1.705 2007/04/17 06:17:19 nigel * fixed search plan * * Revision 1.704 2007/04/17 12:33:41 nigel * added. * * Revision 1.703 2007/04/04 05:04:17 nigel * working on bulk loading field caches * * Revision 1.702 2007/02/12 23:55:49 jason * Clear lookup params onced used for lookup * * Revision 1.701 2007/02/06 12:15:57 nigel * fixed searching on interfaces. * * Revision 1.700 2007/02/03 05:42:23 nigel * no message * * Revision 1.699 2007/02/01 04:45:24 build * Auto Generated constants * * Revision 1.698 2007/02/01 01:50:24 jason * New release * * Revision 1.697 2007/01/28 10:24:48 nigel * working on locks. * * Revision 1.696 2006/12/09 01:32:34 nigel * standards. * * Revision 1.695 2006/11/09 06:11:50 jason * Replaced duplicate message to use DBMessage * * Revision 1.694 2006/10/18 12:11:30 nigel * 1) fixed test cases. * 2) disposed of the datasources after use. * * Revision 1.693 2006/10/06 00:52:57 nigel * added error message if in development only mode. * * Revision 1.692 2006/10/06 00:37:38 nigel * added error message if in development only mode. * * Revision 1.691 2006/09/29 09:15:11 nigel * MT issues. * * Revision 1.690 2006/09/28 22:40:08 nigel * scan for TM * * Revision 1.689 2006/09/21 07:35:04 nigel * spelling * * Revision 1.688 2006/09/18 00:35:40 jason * Add option to disable hasChangedByUser flag for system processes * * Revision 1.687 2006/09/12 03:21:53 nigel * fixed access check. * * Revision 1.686 2006/09/04 06:22:39 nigel * performance improvements for Readonly data source. * * Revision 1.685 2006/09/02 06:02:23 nigel * fixed standards. * * Revision 1.684 2006/08/21 22:30:19 nigel * fixed * * Revision 1.683 2006/08/18 07:02:05 jason * Fixe recursion issue when updating foreign keys * * Revision 1.682 2006/08/14 05:44:41 nigel * Working on submission. * * Revision 1.681 2006/08/10 03:26:20 nigel * spelling * * Revision 1.680 2006/08/10 03:24:23 nigel * spelling * * Revision 1.679 2006/07/21 02:11:09 jason * Problems with lookup fields with nosearch set * * Revision 1.678 2006/07/20 15:07:05 build * Auto Generated constants * * Revision 1.677 2006/07/20 08:06:04 jason * Resolve case where stack overflow is caused when an inward linked object refers to the deleted object in the extGetReadAccess * * Revision 1.676 2006/07/20 05:26:26 nigel * fixed NPE * * Revision 1.675 2006/07/19 05:23:41 nigel * fixing race condition. * * Revision 1.674 2006/07/18 22:58:17 nigel * made all parameters final. * * Revision 1.673 2006/07/13 08:06:20 padma * Updated checkModifyAccess(), checkDeleteAccess() * * Revision 1.672 2006/07/11 09:30:35 nigel * spelling * * Revision 1.671 2006/07/05 21:27:45 nigel * file changes to never have partial files and to perform check sums before transfers * * Revision 1.670 2006/07/05 05:32:30 nigel * working on checksum. * * Revision 1.669 2006/07/01 22:42:28 nigel * cache the call to check modify access * * Revision 1.668 2006/06/28 03:48:14 ealbino * Added copyIncludeField() * * Revision 1.667 2006/06/14 22:40:24 nigel * added java docs * * Revision 1.666 2006/05/16 22:09:38 nigel * allowed timestamps to be formatted. * * Revision 1.665 2006/05/15 21:36:33 build * Auto Generated constants * * Revision 1.664 2006/05/15 05:35:58 jason * Added ability to override the exception that is thrown from checkModifyAccess * * Revision 1.663 2006/05/05 05:12:09 nigel * improved the performance of archive * * Revision 1.662 2006/04/29 10:36:57 nigel * fixed standards. * * Revision 1.661 2006/04/29 09:06:24 nigel * only set the data source. * * Revision 1.660 2006/04/28 11:33:11 nigel * fixed inward link search on dervied fields. * * Revision 1.659 2006/04/18 23:34:22 jason * Added comments to extValidateField * * Revision 1.658 2006/04/11 09:33:55 nigel * added thread mode. * * Revision 1.657 2006/03/28 22:16:00 nigel * got rid of false error message. * * Revision 1.656 2006/03/28 05:46:29 nigel * added a isBrokenLink method * * Revision 1.655 2006/03/27 02:41:16 nigel * fixed get the inward link for interfaces. * * Revision 1.654 2006/03/21 05:57:36 nigel * fixed stack overflow * * Revision 1.653 2006/03/12 09:07:02 nigel * fixed headers. * * Revision 1.652 2006/03/10 08:33:15 nigel * fixed TestBoolean * * Revision 1.651 2006/03/09 02:49:47 jason * Changed getFormattedString to be more efficient * * Revision 1.650 2006/03/09 02:46:33 jason * getFormattedString was not handling a mutilingual value for a field of type string. This can happen if a derived field returns this as a value. getString already handles this. * * Revision 1.649 2006/03/02 19:37:23 nigel * fixed standards. * * Revision 1.648 2006/03/01 05:22:12 nigel * fixing standards * * Revision 1.647 2006/02/24 06:25:22 mei * change hasChangedByUserField due to multilingual failuare * * Revision 1.646 2006/02/06 04:37:19 nigel * working on tests. * * Revision 1.645 2006/02/01 09:33:14 nigel * Only call check modify access if the object is not new. * * Revision 1.644 2006/01/31 04:25:37 nigel * fixes. * * Revision 1.643 2006/01/28 04:07:35 nigel * actions should be "auto entered" * * Revision 1.642 2006/01/27 05:19:33 michael * fix selfTest issue that set FldParams' value when it is locked * * Revision 1.641 2006/01/25 04:40:06 jason * Added locking functionality to field params * * Revision 1.640 2006/01/25 04:00:27 nigel * fixed auto enter. * * Revision 1.639 2006/01/06 03:55:33 nigel * updated header * * Revision 1.638 2005/12/15 14:05:12 build * Auto Generated constants * * Revision 1.637 2005/12/15 10:39:38 nigel * improved JMS. * * Revision 1.636 2005/12/08 10:53:18 nigel * fixed compile error. * * Revision 1.635 2005/11/30 07:56:47 nigel * fixed rollback issue. * * Revision 1.634 2005/11/30 03:44:37 nigel * changed event validation. * * Revision 1.633 2005/11/28 20:44:32 nigel * fixed imports. * * Revision 1.632 2005/11/26 04:00:37 build * changed to commons-loging * * Revision 1.631 2005/11/26 03:17:51 nigel * Changed to use Log interface * * Revision 1.630 2005/11/16 22:48:02 nigel * working on interfaces. * * Revision 1.629 2005/11/15 22:16:11 nigel * fixed standards * * Revision 1.628 2005/11/13 23:29:47 nigel * tests for searching on an interface. * * Revision 1.627 2005/11/13 09:20:01 nigel * implemeneted workflow object * * Revision 1.626 2005/11/12 09:55:22 nigel * upgrade to 4.0 * * Revision 1.625 2005/11/10 20:09:14 nigel * fixed caching issue. * * Revision 1.624 2005/11/10 05:40:16 nigel * fixed problem with not touching a record. * * Revision 1.623 2005/11/08 08:30:02 nigel * fixed the event framework. * * Revision 1.622 2005/11/01 08:12:32 nigel * performane improvements * * Revision 1.621 2005/10/31 03:07:34 nigel * fixed broken tests * * Revision 1.620 2005/10/29 10:48:50 nigel * working on logs * * Revision 1.619 2005/10/28 23:30:09 nigel * fixed up prevalidate. * * Revision 1.617 2005/10/24 08:35:02 nigel * 1) implemented SAVEPOINT * 2) coding standards * * Revision 1.616 2005/10/22 08:48:28 nigel * fixed PMD issues. * * Revision 1.615 2005/10/19 13:01:44 nigel * working on savepoint. * * Revision 1.614 2005/10/16 06:42:51 nigel * allowed multiple jobs to be executed. * * Revision 1.613 2005/10/11 10:03:29 nigel * 1) PMD changes * 2) working on applet * * Revision 1.612 2005/09/30 06:07:05 nigel * changed code generator to exclude the LOGGER from the PMD check * * Revision 1.611 2005/08/31 05:46:53 jason * Allow events to be dynamically raised based on conditions * * Revision 1.610 2005/06/06 07:47:20 nigel * added javadocs. * * Revision 1.609 2005/06/06 04:10:13 mei * change hasChangedByUserField method * * Revision 1.608 2005/06/02 02:31:43 jason * Allow display value to be displayed rather then key and value * * Revision 1.607 2005/05/27 03:16:35 jason * Fix hasUserChanged and hasAutoChanged to compare global keys if they are available * * Revision 1.606 2005/05/17 03:12:07 nigel * working on TASK HA. * * Revision 1.605 2005/04/28 22:46:54 jason * Don't send dependent remove notifications on derived fields * * Revision 1.604 2005/04/21 08:45:29 jason * Fixed generation of keys after changes to rowid * * Revision 1.603 2005/04/15 01:47:51 jason * Suppress messages for deleted records in getlinkedobject * * Revision 1.602 2005/04/05 03:18:31 nigel * fixed index problem * * Revision 1.601 2005/04/04 09:39:29 nigel * unsigned row IDs. * * Revision 1.600 2005/03/22 00:23:54 jason * Generate constants * * Revision 1.599 2005/03/17 06:47:50 mei * auto generated constants * * Revision 1.598 2005/03/16 22:23:21 jason * Replaced discontinue flag with a continuation method * * Revision 1.597 2005/03/11 05:04:17 mei * auto generated constants * * Revision 1.596 2005/01/18 03:38:37 nigel * improvements to journal tabs * * Revision 1.595 2005/01/06 03:03:55 nigel * fixed up of journal tab. * * Revision 1.594 2004/12/23 21:28:29 nigel * updated the javadocs. * * Revision 1.593 2004/12/22 00:06:47 nigel * removed TABs * * Revision 1.592 2004/12/18 20:34:09 nigel * corrected the check for excluded layers. * * Revision 1.591 2004/12/17 20:30:04 nigel * fixed test for modification of a record in excluded layer. * * Revision 1.590 2004/12/07 23:54:43 nigel * fixed bug with default string parameters * * Revision 1.589 2004/12/07 09:19:37 nigel * fixes for timezone. * * Revision 1.588 2004/11/22 06:23:13 nigel * fixed NPE. * * Revision 1.587 2004/11/21 11:46:29 nigel * fixed problem with boolean fields. * * Revision 1.586 2004/11/10 04:18:50 nigel * don't create transactions when reindexing. * * Revision 1.585 2004/11/10 01:33:33 nigel * Working on INDEXER. * * Revision 1.584 2004/11/08 06:10:52 nigel * java docs. * * Revision 1.583 2004/11/08 02:56:46 nigel * moved DBMessage. * * Revision 1.582 2004/11/03 02:01:52 nigel * added sudo method for getting system access. * * Revision 1.581 2004/10/27 02:40:47 nigel * uncomment development test flags. * * Revision 1.580 2004/10/26 22:23:04 jason * auto generated constants * * Revision 1.579 2004/10/20 08:13:06 nigel * working on logical locks. * * Revision 1.578 2004/10/17 22:03:01 nigel * wroking on database driven messages. * * Revision 1.577 2004/10/15 23:41:19 nigel * working on database driven messages. * * Revision 1.576 2004/10/14 01:33:14 nigel * working on data driven messages. * * Revision 1.575 2004/10/07 04:16:59 jason * hasAutoChanged( String) was not calling hasAutoChanged( DBField) * * Revision 1.574 2004/10/04 02:11:49 nigel * updated javadocs. * * Revision 1.573 2004/10/01 00:50:57 nigel * fixed unique field test when the index is dirty. * * Revision 1.572 2004/09/28 02:39:17 jason * Fixup hasAutoEntered * * Revision 1.571 2004/09/24 00:18:24 nigel * fixed a bug where we didn't check if a field is unique if it hadn't changed. but... If the index was "dirty" we needed to. * * Revision 1.570 2004/09/16 08:04:47 nigel * 1) fixed self test * 2) changed class tree. * * Revision 1.569 2004/09/14 05:54:38 nigel * fixed check of field change access. * * Revision 1.568 2004/09/08 07:55:48 nigel * pasted field parameters to DBObject.getLinkedObject() * * Revision 1.567 2004/09/03 03:12:59 nigel * allow parameters to be passed to the getLinkedOBject method * * Revision 1.566 2004/08/26 02:56:38 nigel * correcting dirty cache exception loops. * * Revision 1.565 2004/08/20 05:35:28 nigel * clean up. * * Revision 1.564 2004/08/17 01:54:13 nigel * java docs. * * Revision 1.563 2004/08/10 02:35:56 jason * Always return a boolean for a boolean field, ie return false when null * * Revision 1.562 2004/07/30 00:42:41 nigel * corrected portals * * Revision 1.561 2004/07/29 02:36:21 nigel * added constants * * Revision 1.560 2004/07/25 09:51:20 nigel * auto comment * * Revision 1.559 2004/07/23 02:32:35 nigel * auto comment. * * Revision 1.558 2004/07/22 23:38:33 nigel * auto comment * * Revision 1.557 2004/07/21 03:41:53 nigel * working on dcLite * * Revision 1.556 2004/07/19 06:19:29 jason * Handle option to return globalkey for getvalue * * Revision 1.555 2004/07/08 00:23:19 jason * Only update modified time and user if changed by a user not through code * * Revision 1.554 2004/07/06 06:53:13 nigel * fixed logical lock spin. * * Revision 1.553 2004/07/06 05:54:28 nigel * Fixed access controls on jobs/isql. * * Revision 1.552 2004/07/05 02:26:09 nigel * working on JOB. * * Revision 1.551 2004/06/22 01:28:12 nigel * fixed secondary cache problem in RootClassHolder. * * Revision 1.550 2004/06/09 02:17:07 webapps * Auto generated field constants * * Revision 1.549 2004/06/09 01:19:18 jason * Add comments * * Revision 1.548 2004/06/09 01:18:05 jason * Only check modify access if changed by user. * * Revision 1.547 2004/06/07 06:55:46 nigel * split READONLY screen mode into READONLY_SCREEN and READONLY_BASE * * Revision 1.546 2004/05/31 07:37:46 nigel * performance tuning. * * Revision 1.545 2004/05/27 23:35:04 jason * Handle missing field in isnull * * Revision 1.544 2004/05/21 00:15:44 jason * Pass field params to eventfieldupdated * * Revision 1.543 2004/05/19 06:16:09 jason * Fix hasautoenter method * * Revision 1.542 2004/05/19 02:55:57 jason * Provide method to determine if autoentered * * Revision 1.541 2004/05/11 04:48:07 jason * Don't do prevalidate if indexing * * Revision 1.540 2004/05/10 06:43:21 jason * Do not check inward links that are derived in checkdelete * * Revision 1.539 2004/05/10 00:01:22 nigel * 1) Fixed archive for abstract classes * 2) Fixed archive for deleted records. * 3) Fixed access controls. * * Revision 1.538 2004/05/06 05:44:04 nigel * bug fixes. * * Revision 1.537 2004/05/03 01:52:14 nigel * 1) removed thread contention in getRootHolder() * 2) used findDBClass instead of findKey() as it is faster. * * Revision 1.536 2004/04/28 01:41:43 nigel * Working on JOB command * * Revision 1.535 2004/04/27 01:13:39 nigel * Performance tuning. * * Revision 1.534 2004/04/21 22:31:50 jason * Don't copy unique fields in copyfields * * Revision 1.533 2004/04/21 01:03:32 nigel * working on Job command. * * Revision 1.532 2004/04/20 06:50:13 jason * Removed icopy * * Revision 1.531 2004/04/20 06:47:09 jason * Fix up copy * * Revision 1.530 2004/04/20 00:03:49 jason * Tidy up copy * * Revision 1.529 2004/04/19 23:09:33 jason * Add copy method * * Revision 1.528 2004/04/19 21:59:44 jason * Don't copy autoenteredpredefinedvalues in copyfields * * Revision 1.527 2004/04/19 00:23:39 nigel * performance tuning. * * 1) split cache into 16 segments * 2) reduced the function call overhead by using final variables * 3) Improved performance of getLinkedObject() * 4) Replaced most pooling algorithums with ThreadLocal. * * Revision 1.526 2004/04/16 05:24:35 nigel * the secondary cache on booleans use the primitive boolean not Boolean * * Revision 1.525 2004/04/15 21:24:36 jason * Findrow does not work on DBField * * Revision 1.524 2004/04/15 07:30:34 jason * Tidy up exception msgs * * Revision 1.523 2004/04/15 05:11:39 nigel * use row id instead of field id * * Revision 1.522 2004/04/15 01:26:26 nigel * performance tuning. * * Revision 1.521 2004/03/24 03:12:29 nigel * fixed isNull. * * Revision 1.520 2004/03/23 01:22:26 nigel * performance tuning. * * Revision 1.519 2004/03/17 09:51:51 nigel * added Secondard caches to PathGroup, Login, DBPermission and DBField. * * Revision 1.518 2004/03/16 05:31:34 nigel * added debug messages. * * Revision 1.517 2004/03/15 00:52:45 nigel * performance improvements * * Revision 1.516 2004/03/11 06:09:45 nigel * fixed archive check read access. * * Revision 1.515 2004/03/08 01:27:46 nigel * Working on benchmark program. * * Revision 1.514 2004/03/03 07:39:00 nigel * hacked around a bug in search screens. * * Revision 1.513 2004/02/25 05:51:35 nigel * fixed self tests. * * Revision 1.512 2004/02/25 01:39:03 jason * Call ext create in correct place * * Revision 1.511 2004/02/16 00:45:46 nigel * Changed logger calls to call log4j directly not via CLogger so that the Location feature of log4j can be used. * * Revision 1.510 2004/02/13 03:15:34 nigel * fixed marvin. * * Revision 1.509 2004/02/09 00:54:49 nigel * fixed timezone problems * * Revision 1.508 2004/02/05 05:36:44 nigel * fixed import * * Revision 1.507 2004/01/19 07:34:26 nigel * Changed System.out & System.err & CError.write to call CLogger * * Revision 1.506 2004/01/08 06:21:39 jason * Remove prevalidate from validaterecord since if we are just trying to validate the record from * marvin then we don't want it to make things valid so we fix them in marvin * * Revision 1.505 2004/01/05 00:40:16 nigel * working on remote.jar * * Revision 1.504 2003/12/11 20:07:46 jason * Display field name in ismandatory validation message * * Revision 1.503 2003/12/01 01:03:02 nigel * Added remote client * * Revision 1.502 2003/11/24 03:26:09 nigel * Fixed JMS problems. * * Revision 1.501 2003/11/23 23:42:05 nigel * Working on questionaire. * * Revision 1.500 2003/11/19 01:35:17 jason * Performance improvements in hasFieldChanged * * Revision 1.499 2003/11/18 02:24:54 nigel * Bug fixes. * * Revision 1.498 2003/11/17 08:43:41 nigel * module control * * Revision 1.497 2003/11/16 22:48:24 nigel * Bug fixes. * * Revision 1.496 2003/11/11 03:36:48 nigel * added screen test for portal isEmpty * * Revision 1.495 2003/11/10 01:04:28 jason * Use hasChangedByUser for isEmpty check * * Revision 1.494 2003/11/06 06:15:28 jason * Validate maxlength correctly * * Revision 1.493 2003/11/06 05:06:04 nigel * bug fix * * Revision 1.492 2003/11/05 00:58:52 jason * Support max length on dbfield * * Revision 1.491 2003/11/04 06:12:44 jason * Added busUnit to list of autoentered predefined values * * Revision 1.490 2003/10/28 05:30:26 jason * Support nosearch when processing lookup * * Revision 1.489 2003/10/13 00:18:29 nigel * Reduced number of objects created. * * Revision 1.488 2003/10/02 07:33:26 nigel * Search pars. * * Revision 1.487 2003/09/28 23:25:30 nigel * File permissions * * Revision 1.152 2003/09/26 21:29:27 sp91025 * Fix ClassCastException: do parsing for all objects * * Revision 1.486 2003/09/22 07:46:01 jason * isOnChange was checking fields that i change rather then fields that are changed by me * * Revision 1.485 2003/09/22 05:21:00 jason * Added isOnChange * * Revision 1.484 2003/09/19 01:27:26 nigel * Changed DBField.label -> DBField.displayName and got rid of the old displayName field. * * Revision 1.483 2003/09/16 00:19:54 nigel * Mail Sync. * * Revision 1.482 2003/09/15 08:09:55 nigel * Fixed delete cache. * * Revision 1.481 2003/09/15 07:24:01 nigel * Fixed tests * * Revision 1.480 2003/09/15 05:58:23 nigel * Mail Sync programs * * Revision 1.478 2003/09/11 00:21:37 nigel * bug fix * * Revision 1.477 2003/08/25 04:39:31 nigel * PMD Tidy up. * * Revision 1.475 2003/08/07 05:21:25 nigel * Fixes for Marvin. * * Revision 1.475 2003/08/07 02:14:22 nigel * 1) passed fld params from getFormattedString() * 2) Fixed overlay of boolean fields. * * Revision 1.474 2003/08/06 10:16:40 nigel * Fixes for Marvin. * * Revision 1.473 2003/07/20 12:27:03 nigel * bug fixes * * Revision 1.470 2003/05/31 05:22:08 nigel * added hasChangedByUser method. * * Revision 1.469 2003/05/28 13:05:48 nigel * working on Login expiry * * Revision 1.468 2003/05/28 09:04:45 nigel * Working on expiry password. * * Revision 1.467 2003/05/27 10:41:29 nigel * 1) undelete method added to DBObject * 2) ValidationItem constructor changed to take DBObject instead of GlobalKey. So that I can find it later if deleted. * 3) Fixed portal to detect rows that are deleted from a screen pluggin * * Revision 1.465 2003/05/09 12:49:42 nigel * IN clause cache. * Clear cache and load data before calling extPostSave * * Revision 1.464 2003/05/09 07:11:30 jason * Call overload for readaccess before resetting login * * Revision 1.463 2003/05/08 05:14:09 nigel * - fixed long URLs problem in portals. * - refixed the relink up bug. * * Revision 1.462 2003/05/04 13:29:29 nigel * 1) performance * 2) conditional mandatory fields * 3) portal fixes * * Revision 1.461 2003/05/02 04:52:00 jason * Handle lookup 'createismissing' flag * * Revision 1.460 2003/05/01 07:54:47 nigel * 1) Additional criteria * 2) allowUnload in IE5.5 * * Revision 1.127 2003/05/01 02:37:38 jl30806 * Bug 1552: not using default value * * Revision 1.126 2003/05/01 00:09:19 sp91025 * Support conditional mandatory fields * * Revision 1.460 2003/04/29 03:44:23 nigel * 1) Fixes for Marvin * 2) Working on portals * 3) improved performance * * Revision 1.459 2003/05/01 07:36:16 jason * Remove code to auto create linked object if cancreateobject is selected on field * * Revision 1.458 2003/04/28 23:35:11 nigel * 1) Performance * 2) Fxied SQL error * 3) join on http command. * * Revision 1.457 2003/04/27 11:19:36 nigel * 1) Multiple POSTs from IE are joined into 1 request * 2) Pages are now generated multiple times and must generate the same code each time. * * Revision 1.456 2003/04/24 11:41:01 nigel * fixed duplicate key problems. * * Revision 1.455 2003/04/24 03:22:35 jason * If linked object is missing create if canCreateOutwardLinks is set on * * Revision 1.454 2003/04/23 06:17:23 jason * Only relink fields if they have a value * * Revision 1.453 2003/04/21 20:50:39 nigel * bug fixes for duplicate key problem. * * Revision 1.452 2003/04/19 14:02:26 nigel * 1) Fixed cache bug. * 2) Allow cache search to be verbose and write to the timings file. * 3) Removed old debug messages. * * Revision 1.450 2003/04/03 14:01:21 webapps * Auto generated field constants * * Revision 1.449 2003/04/02 22:43:08 nigel * allow a designer to select the default screens * * Revision 1.446 2003/03/28 05:22:55 nigel * put in DEV_ONLY * * Revision 1.445 2003/03/26 20:08:12 nigel * 1) limit number of records loaded for sorting reports * 2) Fixed cache bug ( optimizer removed instructions) * * Revision 1.444 2003/03/25 10:53:52 nigel * fixed up cache * * Revision 1.443 2003/03/21 06:32:49 jason * Handle Edata/multi select correctly * * Revision 1.442 2003/03/20 10:54:40 nigel * bug fixes * * Revision 1.441 2003/03/13 20:27:47 nigel * ACLs fixes * * Revision 1.439 2003/03/10 23:17:56 jason * Pass previous global key in eventfieldupdated * * Revision 1.438 2003/03/04 23:59:22 jason * If we get an access exception when validating fields then add the error to the validation list. * * Revision 1.437 2003/02/20 21:10:00 nigel * added method fixUp() to DBObject. * * Revision 1.435 2003/02/07 00:47:20 jason * Speed up importing Import * * Revision 1.434 2003/02/05 21:50:20 nigel * bug fixes * * Revision 1.433 2003/01/31 13:02:14 nigel * performance improvements * * Revision 1.90 2003/01/30 02:05:32 pf86842 * bug #190 - changed union language API to behave more like an iterator and not create memory inefficient arrays * * Revision 1.432 2003/01/30 01:44:44 jason * call extended access checks on modify and delete on virtualdb object * * Revision 1.431 2003/01/29 20:33:42 nigel * Don't check for derived fields in foreign key restrictions * * Revision 1.430 2003/01/25 03:57:06 nigel * Handle access mode. * * Revision 1.429 2003/01/21 01:27:57 jason * Include criteria info in access denied messages * * Revision 1.428 2003/01/21 00:48:36 jason * Remove old messages * * Revision 1.427 2003/01/19 00:40:59 nigel * Trying to fix TestLogin. * * Revision 1.426 2003/01/18 06:37:23 nigel * reduced the number of SQL statements required to load objects and classes * * Revision 1.425 2003/01/17 06:11:57 jason * Update hasFieldChanged so that it deal correctly with null or empty values * * Revision 1.424 2003/01/16 21:57:53 nigel * Reworked SoapSession * * Revision 1.423 2003/01/15 23:11:54 jason * iGetValue should return null instead of empty string for non text fields * * Revision 1.83 2003/01/16 18:23:03 dj53590 * isInValidateUniverse checked before seeting value during relinking * * Revision 1.422 2003/01/15 03:11:44 jason * Login needs to be set on global in checkCreateAccess since the access control needs * to get values such as Globals.currentPerson fromthe currect login. * * Revision 1.421 2003/01/15 01:52:47 jason * For lookup fields only do like compare if it is a string otherwise check by using equals * * Revision 1.420 2003/01/14 04:00:13 jason * Performance improvement in checkReadAccess * * Revision 1.419 2003/01/13 11:27:05 nigel * performance improvements * * Revision 1.418 2003/01/13 05:43:05 jason * Set login in globals so that we can retrieve it from a virtualdb globals when checking access * * Revision 1.417 2003/01/12 22:07:37 nigel * Cache improvements * * Revision 1.416 2003/01/10 05:27:15 jason * Clear lookup from params so that autoenter fields do not get it set * * Revision 1.415 2003/01/09 11:50:31 nigel * Search plan * * Revision 1.414 2003/01/08 21:12:46 nigel * performnace * * Revision 1.413 2003/01/08 21:10:54 nigel * performance improments * * Revision 1.412 2003/01/08 04:00:20 jason * Added check for clear links flag in checkdelete * * Revision 1.411 2003/01/06 05:37:59 jason * Handle weak references on delete * * Revision 1.410 2003/01/06 04:16:51 jason * Change checkAccess methods so that they correctly use either virtualdb or mutable datasources * * Revision 1.71 2003/01/07 00:06:23 mp29766 * Now Always checking for ModifyAccess in iValidateRecord. * * Revision 1.409 2002/12/23 11:43:25 nigel * Removed debug messages. * * Revision 1.408 2002/12/21 07:15:56 nigel * Fixed bug when updating boolean fields from "" -> "N" don't mark the record as changed. * * Revision 1.407 2002/12/19 05:56:44 jason * Change validation message for lookup * * Revision 1.406 2002/12/19 01:49:24 jason * Support lookup option so that we can enter values into a search field * * Revision 1.405 2002/12/12 19:47:34 nigel * Improvements to the MemoryManager. * * Revision 1.404 2002/12/12 06:18:08 jason * Added layerId to anchors * * Revision 1.403 2002/12/10 01:52:12 nigel * New Memory Manager. * * Revision 1.402 2002/12/07 05:02:48 nigel * Auto generated field constants * * Revision 1.401 2002/12/07 04:00:31 nigel * Working on new Memory Manager. * * Revision 1.400 2002/12/05 10:56:49 nigel * Improved memory manager. * * Revision 1.397 2002/12/01 21:44:33 nigel * Extended validation procedures * * Revision 1.396 2002/11/30 05:31:47 nigel * Performance improvements * * Revision 1.395 2002/11/26 10:01:25 nigel * 1) Fixed to detect changes during save * 2) Java Doc * 3) Added tests * * Revision 1.394 2002/11/25 02:00:22 jason * Pass ds to getCriteria methods * * Revision 1.393 2002/11/21 19:26:53 nigel * bug fixes. * * Revision 1.392 2002/11/20 19:44:35 nigel * tidy up * * Revision 1.61 2002/11/21 02:00:24 jl30806 * added calculateValue methods using fieldname string * * Revision 1.391 2002/11/12 11:11:25 nigel * java docs * * Revision 1.390 2002/11/12 06:02:22 jason * Handle layer excluded in create access * * Revision 1.389 2002/11/11 21:15:37 nigel * Java Docs * * Revision 1.388 2002/11/11 09:58:42 nigel * 1) Set the methods hashCode() and equals() final so that they can't be overloaded. * 2) Fixed isChanged. * * Revision 1.387 2002/11/09 13:42:23 nigel * removed suspendeddt * * Revision 1.386 2002/11/08 02:39:50 jason * HasChangedField should simply return false on runtime evaluated fields. * * Revision 1.385 2002/11/06 06:33:02 jason * Added todo * * Revision 1.384 2002/11/01 11:22:03 nigel * Memory Listener interface * * Revision 1.383 2002/10/27 21:18:47 nigel * moved DBClause and DBCriteria to com.aspc.DBObj.Query * * Revision 1.382 2002/10/27 09:41:15 nigel * renamed DBQueryClause-> DBClause * * Revision 1.381 2002/10/27 04:06:53 nigel * debugging * * Revision 1.380 2002/10/25 07:38:32 jason * Change DBClause class structure * * Revision 1.379 2002/10/23 23:18:45 nigel * 1) DBField.parse and DateUtil.parseUserDate returned slightly different dates for the same string. Now returns the same * 2) DateUtil.getTimeDiff has been moved to TimeUtil.getDiff Timestamps and Dates are quite different I don't want to confuse the two * 3) DateUtil.getToday() has been removed. I was wrong ( needs a TimeZone passed in to return the correct day) * * Revision 1.378 2002/10/22 14:01:17 webapps * Auto generated field constants * * Revision 1.377 2002/10/22 03:17:58 jason * Enhancements to ACL * * Revision 1.376 2002/10/19 01:11:50 jason * and/or clauses * * Revision 1.375 2002/10/18 12:37:27 nigel * Bug fix for creating a class, delete it and create again * * Revision 1.374 2002/10/16 10:19:19 nigel * javadocs * * Revision 1.373 2002/10/13 09:19:58 nigel * 1) Changed Method name extGetDerived() -> extGetDerivedValue() * 2) extGetDerivedValue now throws an exception. * 3) The internal classes DBPersonal Loader & Result are no longer required/different from server version * * Revision 1.372 2002/10/10 21:44:47 nigel * Improved the Java doc. * * Revision 1.371 2002/10/10 11:15:07 nigel * 1) Added more javadoc * 2) renamed a few methods in DBObject * 3) moved some code out of DBObject to a Helper class * * Revision 1.370 2002/10/08 20:48:09 nigel * JavaDocs changes. * * Revision 1.369 2002/10/08 20:40:29 nigel * Allow java class name to overriden * * Revision 1.368 2002/10/07 19:44:07 nigel * javadoc. * * Revision 1.367 2002/10/06 02:06:43 nigel * 1) Changed validateField and validateRecord to be final * 2) Changed constructor of ValidationList to be () * 3) Pass the ValidationList to extValidateRecord and extValidateField to reduce the chance of a programmer error * 4) MutableDataSource now checks that the universe is not modified during the validation process. * 5) Javadoc changes. * * Revision 1.366 2002/10/05 01:28:21 nigel * 1) Javadocs. * 2) fixed creating of base tables when modifing records. * 3) Bug fix: multiple calls to iValidateRecord * 4) changed getValue, getString and setValue to accept "Field Parameters" * * Revision 1.365 2002/10/03 00:15:39 nigel * added new method extValidateDelete * * Revision 1.364 2002/10/02 21:52:52 nigel * Corrected spelling mistake "Original" * * Revision 1.363 2002/10/02 12:04:04 nigel * Allow parameters to be passed to derived fields. * * Revision 1.362 2002/09/23 23:04:30 jason * Expanded on noFieldFound error in setValue * * Revision 1.361 2002/09/20 06:06:58 nigel * fixed compile error. * * Revision 1.360 2002/09/20 06:05:40 nigel * convert 16.0 -> 16@1 * * Revision 1.359 2002/09/16 12:07:01 nigel * performance improvements * * Revision 1.358 2002/09/16 09:36:12 nigel * fixed up import statements * * Revision 1.357 2002/09/13 22:52:20 nigel * javadoc * * Revision 1.356 2002/09/13 11:33:02 nigel * multiple new rows with duplicate keys * * Revision 1.352 2002/09/01 03:49:31 nigel * Added methods setInt, SetLong, setDouble to DBObject * * Revision 1.351 2002/09/01 03:28:07 nigel * Changed DBObject method updateField -> setValue * * Revision 1.350 2002/09/01 03:12:47 nigel * Improved db version upgrade. * * Revision 1.349 2002/08/30 22:55:30 nigel * improved naming convension of method in DBObject and Started on multilanguage support. * * Revision 1.348 2002/08/28 21:50:57 nigel * Changed DBObject's method listChangeFields -> getChangedFields and now returns a wrapper. * * Revision 1.347 2002/08/28 13:14:57 nigel * Renamed all extendable methods in DBObject to be prefixed with ext * * Revision 1.346 2002/08/23 19:28:53 nigel * Remove obsotele import. * * Revision 1.345 2002/08/03 00:35:39 nigel * *** empty log message *** * * Revision 1.344 2002/08/03 00:32:42 nigel * Changed ValidationError to accept DBField not the name * * Revision 1.342 2002/07/19 23:28:51 nigel * bug fix * * Revision 1.341 2002/07/19 06:02:52 jason * Tidy Up * * Revision 1.340 2002/07/19 05:58:18 jason * Check default keys in hasFieldChanged instead of just checking default values. * This was causing incorrect comparisons. * * Revision 1.339 2002/07/16 04:12:40 jason * Handle durations * * Revision 1.338 2002/07/15 10:58:35 nigel * *** empty log message *** * * Revision 1.337 2002/07/15 10:55:03 nigel * *** empty log message *** * * Revision 1.336 2002/07/12 20:25:09 nigel * Performance improvements * * Revision 1.331 2002/07/01 02:30:43 jason * Ignore derived fields when checking delete for inward links * * Revision 1.330 2002/06/30 22:33:54 nigel * *** empty log message *** * * Revision 1.329 2002/06/29 00:49:38 nigel * changed iValidateField to be private * * Revision 1.328 2002/06/25 22:26:41 nigel * used field name constants. * * Revision 1.327 2002/06/25 04:43:05 jason * Fixed autoenter values in presave * * Revision 1.326 2002/06/24 02:39:01 jason * Allowed a null value to be set for a particular level * * Revision 1.325 2002/06/23 12:22:38 nigel * Put back the code for RECORD NO JOURNAL DATA * * Revision 1.324 2002/06/23 09:22:59 nigel * Changed journal data to be populated by a copy rather than inserts. Which has the * effect of reducing the number of SQL statements for larger transactions. * * Revision 1.323 2002/06/21 23:56:29 nigel * Maded checkXXXXAccess methods final and called extCheckXXXXAccess for each. * * Revision 1.322 2002/06/21 11:12:16 nigel * commets * * Revision 1.321 2002/06/16 07:30:25 nigel * Added record no journal data flag. * * Revision 1.320 2002/06/15 02:52:14 nigel * improved performance * * Revision 1.319 2002/06/14 00:00:11 jason * Fixed isEmpty * * Revision 1.318 2002/06/12 20:15:48 nigel * Added method getRowKey * * Revision 1.317 2002/06/12 07:24:17 jason * hasChanged was returning false when a field had been changed instead of true * * Revision 1.316 2002/06/09 13:04:55 nigel * Renamed packages. * * Revision 1.315 2002/06/08 02:49:50 nigel * improved bulk load performance. * * Revision 1.314 2002/06/07 01:26:59 nigel * Validation messages * * Revision 1.313 2002/05/28 00:47:30 jason * Handle bad indexes where something cannot be indexed because it has invalid data. * * Revision 1.312 2002/05/26 08:00:43 nigel * Improved reindex performance * * Revision 1.311 2002/05/22 20:22:18 nigel * Bug fixes for master/slave * * Revision 1.308 2002/05/09 22:11:34 nigel * Memory efficiency * * Revision 1.307 2002/05/09 06:55:06 nigel * Fixed deleted of test classes. * * Revision 1.306 2002/05/06 20:01:53 nigel * changed method name isUnique() -> isRuntimeEval() * * Revision 1.305 2002/05/01 06:55:33 jason * added hasChanged method * * Revision 1.304 2002/04/29 21:53:30 nigel * javadoc.... * * Revision 1.303 2002/04/28 20:40:08 nigel * Java Doc. * * Revision 1.302 2002/04/28 09:33:09 nigel * Additional javadoc comments * * Revision 1.301 2002/04/18 04:22:49 jason * Add check if derived field back in * * Revision 1.300 2002/04/17 04:24:50 nigel * extra doco * * Revision 1.299 2002/04/14 23:33:20 jason * Validate emails * * Revision 1.298 2002/04/05 00:53:23 jason * update of transid missing from delete from upper layer * * Revision 1.297 2002/04/03 11:21:02 nigel * javadocs * * Revision 1.296 2002/04/01 11:29:36 nigel * Performance improvements. * * Revision 1.295 2002/03/26 09:20:44 nigel * performance improvements * * Revision 1.294 2002/03/25 09:17:16 nigel * Wrong around duplicate key bug. Not sure how or why it happens but I've fixed anyhow. * * Revision 1.293 2002/03/24 02:34:22 nigel * Implemented Archive Search * * Revision 1.292 2002/03/23 03:34:10 jason * allowed onchange to set the field to "NULL" * * Revision 1.291 2002/03/19 08:45:22 nigel * Added archiveDataSource support. * * Revision 1.290 2002/03/16 07:32:00 nigel * Perfromance improvements. * * Revision 1.289 2002/03/14 09:19:50 nigel * prevented the eventDataLoaded method from being overridden by another programmer. * * Revision 1.288 2002/03/13 18:32:51 nigel * *** empty log message *** * * Revision 1.287 2002/03/12 09:43:07 nigel * BUG FIX: When a linked field is saved and then changed to be a derived field. Foregien key error * on saving. * * Revision 1.286 2002/03/08 02:23:40 nigel * Take a save lock on all records within a database to reduce concurrency ( Dirty Cache ) problems. * This still needs to be handled for updates from another server. * * Revision 1.285 2002/03/05 10:03:20 nigel * Removed Obsolete packages. * * Revision 1.284 2002/03/02 03:00:17 nigel * *** empty log message *** * * Revision 1.283 2002/03/01 20:13:33 nigel * Changed isIndexable to check for derived fields. * * Revision 1.282 2002/02/28 19:43:27 nigel * Bug fixes. * * Revision 1.281 2002/02/27 09:15:28 nigel * Moved key_global into field table. * * Revision 1.280 2002/02/25 19:06:55 nigel * Postgres will not use the index for row_uid unless we cast the number 999182 to a bigint 999182::bigint * very much faster once casted. * * Revision 1.279 2002/02/23 23:36:59 nigel * Fixed NP when registering. * * Revision 1.278 2002/02/20 04:56:46 jason * Action is now Action_cd in trans_record * * Revision 1.277 2002/02/19 09:34:47 nigel * Allow an object set that only points to itself to be deleted. * * Revision 1.276 2002/02/19 02:02:26 nigel * Bug Fix checking for dirty cache on old records. * * Revision 1.275 2002/02/19 01:20:48 nigel * Allowed public access to getRawField * * Revision 1.274 2002/02/18 22:59:02 nigel * Changed data caching to be based on the trans_id field. * * Revision 1.273 2002/02/15 09:41:47 nigel * Use the trans id to check for concurrency. * * Revision 1.272 2002/02/09 05:38:45 nigel * Added method to test for System logins. * * Revision 1.271 2002/02/08 18:42:28 nigel * Bug Fix: for Key lock. * * Revision 1.270 2002/02/08 09:52:11 nigel * Fix CR/LF * * Revision 1.268 2002/02/02 06:00:26 nigel * Changed person_id in the raw table to be a globalKeyId also removed the raw field owner_id * * Revision 1.267 2002/01/31 22:33:31 jason * Dont store global key for key field when updating so that checks are consisten. * * Revision 1.266 2002/01/30 05:37:06 jason * go back one revision * * Revision 1.264 2002/01/28 22:01:41 nigel * Work around for SYBASE not handling varchars correctly. * * Revision 1.263 2002/01/27 23:34:34 nigel * POSTGRES escapes the SQL string and SYBASE doesn't. Handle both. * * Revision 1.262 2002/01/27 21:56:36 nigel * Tidied up SQL statements. * * Revision 1.261 2002/01/23 09:50:25 nigel * update recentLinks for all indexed fields. * * Revision 1.260 2002/01/21 20:37:43 nigel * *** empty log message *** * * Revision 1.259 2002/01/21 18:15:58 nigel * Reduced the size of the SQL statements. eg A save of a SSB savesheet changed from 3.4m of * statements to 2.3m. * * Revision 1.258 2002/01/20 03:32:26 nigel * Bug fixes for batch duplicate field and key checking. * * Revision 1.257 2002/01/20 01:06:34 nigel * Performance improvement: Key and unique field checking is now a batch select. * * Revision 1.256 2002/01/16 22:50:17 jason * Convert timestamp fields to long by using new long fields deleted_ms and trans_ms * * Revision 1.255 2002/01/15 05:40:11 jason * Field value has been changed to the_val * * Revision 1.254 2002/01/09 10:39:21 nigel * After batch save supply hints for reloading. * * Revision 1.253 2002/01/09 10:05:16 nigel * Fixed Reindexing bug due to batch updates. * * Revision 1.252 2002/01/09 09:10:00 nigel * Allowed for batch updates * * Revision 1.251 2002/01/07 20:08:23 nigel * changes for Sybase * * Revision 1.250 2002/01/05 11:36:19 nigel * Fixed SQL error. * * Revision 1.249 2002/01/05 11:13:08 nigel * Added debug messages * * Revision 1.248 2002/01/02 20:03:26 nigel * Changes to TimeUtil. * * Revision 1.247 2001/12/17 10:39:59 nigel * If a field is updated to an DBObject then accept it as a link. * * Revision 1.246 2001/12/14 21:43:47 nigel * Added getDate method and Java Doc. * * Revision 1.245 2001/12/11 18:20:30 nigel * Added more javaDoc. * * Revision 1.244 2001/12/10 09:20:22 nigel * Optimized * * Revision 1.243 2001/12/08 06:03:19 nigel * PERFORMANCE: Greatly improved the dependance notification * * Revision 1.242 2001/12/06 18:56:54 nigel * BUG FIX: When multiple objects are created for the same key (and not saved) and the * common link object is marked for deletion the findOne method failed in checkDelete * * Revision 1.241 2001/12/05 03:57:07 jason * Return value of derivedfield if it returns a global key * * Revision 1.240 2001/12/02 22:24:27 jason * Find global key after value has been parsed since there was a case where 3.0 was passed as the value from formula and the global key ended up being 3.0@dbnum~50@1 * * Revision 1.239 2001/11/27 08:31:58 nigel * Changed validateField to return error or warning * * Revision 1.238 2001/11/25 19:33:15 nigel * Allowed stricter update field to throw exception when no field found. * * Revision 1.237 2001/11/22 19:37:56 nigel * More java doc comments * * Revision 1.236 2001/11/20 10:17:11 nigel * cOMMENTS * * Revision 1.235 2001/11/18 02:33:20 nigel * Added JavaDoc Comments * * Revision 1.234 2001/11/14 02:28:36 jason * Convert data to correct type before returning results from formula * * Revision 1.233 2001/10/31 04:46:03 jason * Check if derived field returns global key * * Revision 1.232 2001/10/29 23:39:55 nigel * ValidateKeys * * Revision 1.231 2001/10/29 08:45:28 nigel * *** empty log message *** * * Revision 1.230 2001/10/29 02:53:45 jason * Store most recent in correct virtualdb * * Revision 1.229 2001/10/25 01:04:48 jason * Check for bad field in getLinkedObject * * Revision 1.228 2001/10/24 21:59:58 nigel * Fixed Null Pointer Error * * Revision 1.227 2001/10/24 05:56:58 jason * Add extra check for recent link maintenance to make sure that we are saving a recent link that is availalble from current layer * * Revision 1.226 2001/10/21 23:51:55 jason * Allowed outward links to be create if specified in field definition. * * Revision 1.225 2001/10/14 12:24:42 nigel * Fixes for Payments * * Revision 1.224 2001/10/10 23:53:14 jason * Stopped IsEmpty from only checking if field changed when it is null * * Revision 1.223 2001/10/03 12:42:04 nigel * *** empty log message *** * * Revision 1.222 2001/10/01 04:39:02 jason * Cached global keys in updates were not being cleared if new value is null * * Revision 1.221 2001/09/29 00:06:27 nigel * Comments * * Revision 1.220 2001/09/26 12:46:46 nigel * Allowed search for NULLs. * * Revision 1.219 2001/09/26 07:22:55 jason * Recycle dbclass so that it has the correct datasource * * Revision 1.218 2001/09/21 07:09:38 nigel * Corrected hasFieldChanged method. * * Revision 1.217 2001/09/19 00:00:48 jason * fixed bug in isempty * * Revision 1.216 2001/09/17 07:15:41 nigel * The need for speed. Performance enhancements. * * Revision 1.215 2001/09/12 04:10:56 jason * parse no longer accepts a timezone * * Revision 1.214 2001/09/10 07:53:03 jason * Added copyInwardLinks * * Revision 1.213 2001/09/07 23:31:03 jason * Correctly handle time zones * * Revision 1.212 2001/08/29 05:59:22 jason * tidy up * * Revision 1.211 2001/08/27 05:11:01 nigel * Handle of Object reset. * * Revision 1.210 2001/08/21 04:19:57 nigel * Fixed isEmpty method. * * Revision 1.209 2001/08/16 23:22:55 jason * *** empty log message *** * * Revision 1.208 2001/08/15 06:51:03 jason * Support duplication warning * * Revision 1.207 2001/08/15 00:12:57 jason * Fix removal of last recent_link if > 200 * * Revision 1.206 2001/08/14 03:43:43 jason * Add isEmpty which will check if the object has been changed. Default values are stored so that they can be compared against actuall changes to determine if the object has actually changed. * * Revision 1.205 2001/08/10 05:51:37 jason * Restructured field value formatting * * Revision 1.204 2001/08/10 05:30:41 nigel * *** empty log message *** * * Revision 1.203 2001/07/31 05:34:05 nigel * *** empty log message *** * * Revision 1.202 2001/07/31 04:33:46 jason * Maintain list of most recent selections for linked fields * * Revision 1.201 2001/07/30 07:35:57 nigel * Fixed Journal * * Revision 1.200 2001/07/29 02:57:45 nigel * *** empty log message *** * * Revision 1.199 2001/07/25 03:48:24 nigel * Fixed audit trial * * Revision 1.198 2001/07/23 05:48:10 nigel * *** empty log message *** * * Revision 1.197 2001/07/22 13:38:16 nigel * *** empty log message *** * * Revision 1.196 2001/07/19 12:00:38 nigel * Check indexes when virtual db is loaded. * * Revision 1.195 2001/07/18 04:21:50 nigel * Made iupdate protected and final * * Revision 1.194 2001/07/16 04:02:11 jason * Handle duplication and deletion of rows as well as the option to have additional blank rows. * * Revision 1.193 2001/07/04 05:26:48 nigel * *** empty log message *** * * Revision 1.192 2001/06/17 05:33:12 nigel * *** empty log message *** * * Revision 1.191 2001/06/17 02:43:32 nigel * Tidy Up * * Revision 1.190 2001/06/16 06:37:55 nigel * Allow onChangeEnter to be turned off * * Revision 1.189 2001/06/14 09:31:44 nigel * Fixed Bug when updating a field from a value that didn't exist * * Revision 1.188 2001/06/14 08:00:36 nigel * Tidy up * * Revision 1.187 2001/06/12 08:27:25 jason * added validation formula * * Revision 1.186 2001/06/10 23:58:06 nigel * Added hints to the DBData * * Revision 1.185 2001/06/07 05:03:56 nigel * Don't allow keys with spaces or other special characters * * Revision 1.184 2001/06/06 07:02:25 jason * Allocate rowid for new objects when they are created instead of when it is requested so that when sorting is done on rowid is returns the objects in the order that they were created * * Revision 1.183 2001/05/30 02:14:27 jason * Update a key only updated the first linked object found * * Revision 1.182 2001/05/29 08:07:51 nigel * Changed Copyright notice. * * Revision 1.181 2001/05/25 07:49:06 jason * For new objects update inward links if key changes * * Revision 1.180 2001/05/21 06:52:18 nigel * Fixed NP * * Revision 1.179 2001/05/21 03:58:20 nigel * Performance improvments * * Revision 1.178 2001/05/19 06:18:58 nigel * Added notify when a object is reloaded. * * Revision 1.177 2001/05/17 03:32:11 nigel * Fixed Bug: Allow DBFormulas for dates etc. * * Revision 1.176 2001/05/16 11:54:52 nigel * The RawField AutoEnterPreDefined not defined as linked. Also Fixed up the constants in DBRawClass * * Revision 1.175 2001/05/16 04:03:26 nigel * Fixed Bug security * * Revision 1.174 2001/05/15 08:57:15 nigel * *** empty log message *** * * Revision 1.173 2001/05/15 07:45:00 jason * added canwrite method * * Revision 1.172 2001/05/15 07:23:02 nigel * *** empty log message *** * * Revision 1.171 2001/05/15 07:17:54 nigel * *** empty log message *** * * Revision 1.170 2001/05/15 06:09:56 nigel * Change the register process * * Revision 1.169 2001/05/15 02:41:25 jason * hasWriteAccess now throws an Exception * * Revision 1.168 2001/05/14 05:38:47 nigel * Added getFormatString * * Revision 1.167 2001/05/14 03:13:10 nigel * Fixed messages * * Revision 1.166 2001/05/13 14:10:52 nigel * *** empty log message *** * * Revision 1.165 2001/05/13 13:54:23 nigel * Changed Access control checks to throw exceptions so that I can get the messages * * Revision 1.164 2001/05/12 02:36:06 nigel * *** empty log message *** * * Revision 1.163 2001/05/12 00:52:44 nigel * Fixing auto refreshing * * Revision 1.161 2001/05/11 08:29:44 nigel * Fixed reindex problems * * Revision 1.160 2001/05/11 06:59:49 nigel * Allow screens to be used for frame data entry * * Revision 1.159 2001/05/11 05:16:42 nigel * Allow paths to not only follow links * * Revision 1.158 2001/05/11 05:02:16 jason * Fixed problem with createdtime autofill vlaue was not being picked up as a predefined option * * Revision 1.157 2001/05/11 03:42:00 nigel * *** empty log message *** * * Revision 1.156 2001/05/10 09:07:53 nigel * *** empty log message *** * * Revision 1.155 2001/05/10 05:33:07 nigel * Fixed bug: Overlaying fields with blanks and also to be the same as fields below * * Revision 1.154 2001/05/10 04:45:51 jason * Fixed description in validateRecord in hasCreateAccess check * * Revision 1.153 2001/05/10 02:59:58 jason * Fixed up candelete to use hasdeleteaccess * * Revision 1.152 2001/05/10 00:15:23 nigel * *** empty log message *** * * Revision 1.151 2001/05/08 08:25:21 jason * Moved security checking into validation record * * Revision 1.150 2001/05/08 07:53:57 jason * Added code to hasCreateAccess so that in now uses acls * * Revision 1.149 2001/05/07 22:50:37 nigel * *** empty log message *** * * Revision 1.148 2001/05/07 14:06:34 nigel * Added finalFg support * * Revision 1.147 2001/05/07 05:11:50 nigel * Fixed Bugs when the stored value not parsable by the field type * * Revision 1.146 2001/05/06 08:52:33 nigel * Fixed dependant object delete bug * * Revision 1.145 2001/05/04 08:29:20 nigel * Bug Fixes * * Revision 1.144 2001/05/04 06:07:36 jason * Impelemented further ACl support - handling access withing dbobject through hasRight methods * * Revision 1.143 2001/05/04 04:57:30 nigel * *** empty log message *** * * Revision 1.142 2001/05/04 03:10:36 jason * Began implementing access control - started in hasSelectAccess * * Revision 1.141 2001/05/03 08:15:03 jason * Added canSelect method * * Revision 1.140 2001/05/02 12:09:37 nigel * Changed the DataSource to be an interface and * MutableDataSource to be based on Login * * Revision 1.139 2001/04/26 06:33:05 nigel * Moved ClientAccess to com.aspc * * Revision 1.138 2001/04/26 05:19:27 jason * Fixed to return default value if calculatefield is null * * Revision 1.137 2001/04/26 02:35:22 jason * Remove fields from updatedfields table if they are updated to equal original value * * Revision 1.136 2001/04/25 06:31:37 jason * Changed so you could change a field from one value and then back to the original * * Revision 1.135 2001/04/25 03:32:28 jason * Made mandatory field validation error clearer. * * Revision 1.134 2001/04/24 14:51:46 nigel * 1) Changed the order of globalkey parameters to match findKey() order * 2) Fixed bug the associated DBClass of DBData should change for each layer * * Revision 1.133 2001/04/24 10:20:22 jason * *** empty log message *** * * Revision 1.132 2001/04/23 07:05:57 jason * Auto entry for created by user not working due to value not being uppercase. * * Revision 1.131 2001/04/22 10:31:26 nigel * Improved performance * * Revision 1.130 2001/04/22 06:31:22 nigel * Changed Cache table mehod getNoThrow() -> get() * * Revision 1.129 2001/04/20 13:58:58 nigel * Changed method of getting inward links * * Revision 1.128 2001/04/20 05:36:08 nigel * Fixed Bug: Not able to edit raw classes * * Revision 1.127 2001/04/20 02:03:35 nigel * Made static final GlobalKeys * * Revision 1.126 2001/04/18 07:18:08 jason * Fixes for invoice * * Revision 1.125 2001/04/18 05:08:21 nigel * Performance Enhancemens * * Revision 1.124 2001/04/17 10:10:31 nigel * Added DataLoaded Event and DependantAdded/Removed events * * Revision 1.123 2001/04/17 07:23:51 jason * Some fixes. Added miscellaneous screen. Changed url of logo.gif to use doc_key. * * Revision 1.122 2001/04/10 03:46:22 nigel * Perfromance improvements * * Revision 1.121 2001/04/07 08:23:30 nigel * Moved the field link logic into field and removed FieldLink. * This firms up the one to one linkage of field and fieldLinks * * Revision 1.120 2001/04/06 05:27:06 nigel * Bug Fix * * Revision 1.119 2001/04/06 03:24:11 nigel * Fixed problem with rawfield and normal fields * getting mixed up * * Revision 1.118 2001/04/05 12:16:27 nigel * working * * Revision 1.117 2001/04/05 05:52:04 jason * Layer fix * * Revision 1.116 2001/04/05 05:29:49 jason * More fixes for layers * * Revision 1.115 2001/04/05 04:48:55 nigel * Fixed global key caching problem * * Revision 1.114 2001/04/04 12:09:18 nigel * Fixed Cache problems. * * Revision 1.113 2001/04/04 06:47:11 nigel * Make the keys case insensive * * Revision 1.112 2001/04/04 04:28:30 nigel * Working on linkage bugs * * Revision 1.111 2001/04/04 02:55:42 nigel * Fixing layering bugs * * Revision 1.110 2001/04/04 01:32:35 jason * Handle delete in layers * * Revision 1.109 2001/04/03 03:34:20 nigel * bug fix: couldn't blank fields * * Revision 1.108 2001/04/03 02:43:56 nigel * Fixed cache problem * * Revision 1.107 2001/04/02 21:57:00 nigel * Removed old style getLinkage changed * to doSearch which uses normal paths * * Revision 1.106 2001/04/02 06:13:58 jason * Fixed cacheing in layers. * * Revision 1.105 2001/04/02 05:01:45 nigel * Fixed missing global key bugs * * Revision 1.104 2001/04/02 03:39:46 jason * More changes for creating new objects in layers. * * Revision 1.103 2001/04/02 00:24:08 jason * Some fixes for layering * * Revision 1.102 2001/03/30 07:14:15 nigel * Working on layering bugs * * Revision 1.101 2001/03/30 07:03:13 jason * Change dbase in globalkey to be long. * * Revision 1.99 2001/03/29 12:29:23 nigel * Fixing bug with findKey for GlobalKey * or GlobalId only * * Revision 1.98 2001/03/29 07:22:30 jason * Added GlobalId as class and changed findKey to accept only globalKey or globalId * * Revision 1.97 2001/03/27 07:03:37 jason * Worked on layering * * Revision 1.96 2001/03/24 02:53:53 nigel * Rename for patent * * Revision 1.95 2001/03/23 06:35:24 jason * Added get Target to path * * Revision 1.94 2001/03/21 05:56:48 nigel * Fixed canDelete recursive call * * Revision 1.93 2001/03/21 02:50:03 nigel * Fixed NP on blank link field * * Revision 1.92 2001/03/21 00:56:50 nigel * Fixed Missing fields bug * * Revision 1.91 2001/03/20 23:02:24 nigel * Fixed NP * * Revision 1.90 2001/03/20 11:49:59 nigel * *** empty log message *** * * Revision 1.89 2001/03/20 10:20:15 nigel * Changed CLASS_.I.D -> CLASS_KEY ( made all global keys) * * Revision 1.88 2001/03/20 06:14:37 jason * More stuff on layers mainly to do with paths. * * Revision 1.87 2001/03/20 04:07:37 nigel * layering * * Revision 1.86 2001/03/20 04:01:03 jason * Changes to handle multiple layers. * * Revision 1.84 2001/03/19 01:37:52 nigel * Fixed Cache problem * * Revision 1.83 2001/03/19 00:51:04 jason * Reindexing works accross layers. * * Revision 1.82 2001/03/17 05:20:05 nigel * Working on layers * * Revision 1.81 2001/03/16 05:20:12 nigel * Bug Fix * * Revision 1.80 2001/03/16 00:53:20 jason * Hand back to nigel * * Revision 1.79 2001/03/15 00:45:14 jason * Login works correctly * * Revision 1.78 2001/03/14 23:53:39 jason * Clear cache in datasource when creating a new record. * * Revision 1.77 2001/03/14 04:27:05 jason * Screens now showing but problem with login. * * Revision 1.76 2001/03/13 06:29:13 jason * Added more cacheing and buttons are now showing for screens. * * Revision 1.75 2001/03/12 06:57:23 jason * Linkage working ok. Nearly there. * * Revision 1.74 2001/03/11 21:02:05 nigel * working on layers * * Revision 1.73 2001/03/11 05:06:41 nigel * Working * * Revision 1.72 2001/03/09 04:20:07 nigel * Fixed transaction * * Revision 1.71 2001/03/09 03:54:55 nigel * *** empty log message *** * * Revision 1.70 2001/03/09 02:30:24 nigel * Handed over to J. * * Revision 1.68 2001/03/09 01:13:44 nigel * Fixed NullPointer Error * * Revision 1.67 2001/03/09 00:07:51 nigel * working on access * * Revision 1.66 2001/03/08 21:11:00 jason * DBRawClass now works without recursion. * * Revision 1.65 2001/03/08 04:37:12 nigel * Changes for layers * * Revision 1.64 2001/03/08 01:46:08 jason * Removed access to db_class table. * * Revision 1.63 2001/03/07 09:27:04 nigel * Working on layers * * Revision 1.62 2001/03/07 05:51:11 jason * Working * * Revision 1.61 2001/03/07 05:34:26 nigel * Working * * Revision 1.60 2001/03/07 01:36:55 jason * Working on layers * * Revision 1.59 2001/03/07 01:25:52 nigel * Added access control * * Revision 1.57 2001/03/06 02:41:24 nigel * Working on foregin keys * * Revision 1.56 2001/03/06 02:18:07 jason * Simplify globalKey constructors and implemented getLinkedObject * * Revision 1.55 2001/03/05 23:08:36 jason * Convert usage of GlobalId to GlobalKey * * Revision 1.54 2001/03/05 21:32:01 jason * Change usage of GlobalId to GlobalKey * * Revision 1.53 2001/03/02 07:51:29 jason * Added GlobalKey and added logic to handle loading these through DBQuery. * * Revision 1.52 2001/03/01 10:12:04 nigel * Fixed compile errors. * * Revision 1.51 2001/03/01 06:36:18 jason * Remove compilation errors from layering changes. * * Revision 1.50 2001/02/28 03:30:20 jason * Hand back to Nigel * * Revision 1.49 2001/02/27 11:57:23 nigel * Passed over to J. * * Revision 1.48 2001/02/27 00:43:30 nigel * Working on global keys * * Revision 1.47 2001/02/26 00:32:24 nigel * working on global keys * * Revision 1.46 2001/02/25 23:52:52 nigel * Working on global keys * * Revision 1.45 2001/02/25 21:44:26 nigel * Working on global keys * * Revision 1.44 2001/02/24 10:21:05 nigel * Working on global keys * * Revision 1.43 2001/02/24 08:07:11 nigel * Changes for made link fields an DBObject * * Revision 1.42 2001/02/24 07:41:54 jason * Changes for Global Keys * * Revision 1.41 2001/02/22 05:17:46 jason * Changed classIds and fieldIds to be longs so that they can also store the source database id. * * Revision 1.40 2001/02/22 02:08:27 nigel * This time I have really removed ALL reference * to z.o.n.e * * Revision 1.39 2001/02/22 00:06:35 nigel * Bug Fixes for the GLUE * * Revision 1.38 2001/02/20 01:24:04 nigel * Added todo's * * Revision 1.37 2001/02/18 12:47:40 nigel * Changes for Virtual DB * * Revision 1.36 2001/02/17 09:41:52 nigel * Added Standard Header comments * * Revision 1.35 2001/02/16 04:54:06 jason * CSQL() now returns exception due to finding defualt database. This caused other functions to be altered to handle an exception being thrown. * * Revision 1.34 2001/02/16 04:19:01 nigel * Working copy only * * Revision 1.33 2001/02/16 03:59:33 jason * Removed reference to zo.ne so that we are working in current virtual database. * * Revision 1.32 2001/02/13 10:33:55 nigel * Changed the underlying table structure * * Revision 1.31 2001/02/12 10:11:03 jason * Changed RowId to be A long * * Revision 1.30 2001/02/11 11:31:36 nigel * Fixed bug TEXT Wasn't being handled like * a String * * Revision 1.29 2001/02/11 01:28:21 jason * added feature to update a secondary field * on change * * Revision 1.28 2001/02/08 22:44:23 nigel * Change parameter OBJID -> CLASS_.I.D * * Revision 1.27 2001/02/08 00:50:04 jason * *** empty log message *** * * Revision 1.26 2001/02/07 23:12:47 nigel * Added method doPreSave to DBObject which * gets called before validation * * Revision 1.25 2001/02/06 03:47:43 nigel * Changed DBObjectDef -> DBClass * * Revision 1.24 2001/02/05 21:20:48 nigel * Fixed Validation * * Revision 1.23 2001/02/05 01:11:38 jason * Stop validateRecord if record is deleted. * * Revision 1.22 2001/01/31 09:10:55 nigel * Changed to use indexes * * Revision 1.21 2001/01/31 07:23:54 nigel * Changed to use indexes * * Revision 1.20 2001/01/28 11:54:38 nigel * Corrected getLinkage behaviour when noSave * is set and Object is new ( Don't read * from DB for inwards links) * * Revision 1.19 2001/01/28 05:29:53 nigel * Fixed bug when updating a null field * * Revision 1.18 2001/01/27 02:09:15 nigel * DataSource Bug Fix * * Revision 1.17 2001/01/26 21:52:08 nigel * DataSource bug fixes * * Revision 1.16 2001/01/26 07:34:59 nigel * Made DataSource hold the Universe for * each user. * * Revision 1.15 2001/01/25 04:02:18 nigel * Changed DataSource to be the primary DB * contact */