Author: jonesde
Date: Tue Apr 29 19:02:29 2008 New Revision: 652226 URL: http://svn.apache.org/viewvc?rev=652226&view=rev Log: Added feature to entity engine to support generic audit log that can be used for any field; values are converted to a string and l using the enable-audit-log attribute on the entity->field element; the Testing entity uses it now for the testName; this also has functionality to associate user info like the userLoginId with the thread so that the EE knows about it automatically, and uses a stack for flexibility Modified: ofbiz/trunk/framework/entity/dtd/entitymodel.xsd ofbiz/trunk/framework/entity/entitydef/entitygroup.xml ofbiz/trunk/framework/entity/entitydef/entitymodel.xml ofbiz/trunk/framework/entity/entitydef/entitymodel_test.xml ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericDelegator.java ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericEntity.java ofbiz/trunk/framework/entity/src/org/ofbiz/entity/datasource/GenericDAO.java ofbiz/trunk/framework/entity/src/org/ofbiz/entity/jdbc/DatabaseUtil.java ofbiz/trunk/framework/entity/src/org/ofbiz/entity/model/ModelEntity.java ofbiz/trunk/framework/entity/src/org/ofbiz/entity/model/ModelField.java ofbiz/trunk/framework/service/src/org/ofbiz/service/ServiceDispatcher.java ofbiz/trunk/framework/webapp/src/org/ofbiz/webapp/control/ControlServlet.java Modified: ofbiz/trunk/framework/entity/dtd/entitymodel.xsd URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/dtd/entitymodel.xsd?rev=652226&r1=652225&r2=652226&view=diff ============================================================================== --- ofbiz/trunk/framework/entity/dtd/entitymodel.xsd (original) +++ ofbiz/trunk/framework/entity/dtd/entitymodel.xsd Tue Apr 29 19:02:29 2008 @@ -133,6 +133,15 @@ </xs:restriction> </xs:simpleType> </xs:attribute> + <xs:attribute name="enable-audit-log" default="false"> + <xs:annotation><xs:documentation>If this is set to true then whenever the value for this field on a record changes the Entity Engine will record the change in the EntityAuditLog entity. Defaults to false.</xs:documentation></xs:annotation> + <xs:simpleType> + <xs:restriction base="xs:token"> + <xs:enumeration value="true"/> + <xs:enumeration value="false"/> + </xs:restriction> + </xs:simpleType> + </xs:attribute> </xs:attributeGroup> <xs:element name="validate"> <xs:complexType> Modified: ofbiz/trunk/framework/entity/entitydef/entitygroup.xml URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/entitydef/entitygroup.xml?rev=652226&r1=652225&r2=652226&view=diff ============================================================================== --- ofbiz/trunk/framework/entity/entitydef/entitygroup.xml (original) +++ ofbiz/trunk/framework/entity/entitydef/entitygroup.xml Tue Apr 29 19:02:29 2008 @@ -21,16 +21,7 @@ <entitygroup xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://ofbiz.apache.org/dtds/entitygroup.xsd"> - <!-- ========================================================= --> - <!-- org.ofbiz.entity.sequence --> - <!-- ========================================================= --> - - <entity-group group="org.ofbiz" entity="SequenceValueItem" /> - - <!-- ========================================================= --> - <!-- org.ofbiz.entity.crypto --> - <!-- ========================================================= --> - + <entity-group group="org.ofbiz" entity="EntityAuditLog" /> <entity-group group="org.ofbiz" entity="EntityKeyStore" /> + <entity-group group="org.ofbiz" entity="SequenceValueItem" /> </entitygroup> - Modified: ofbiz/trunk/framework/entity/entitydef/entitymodel.xml URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/entitydef/entitymodel.xml?rev=652226&r1=652225&r2=652226&view=diff ============================================================================== --- ofbiz/trunk/framework/entity/entitydef/entitymodel.xml (original) +++ ofbiz/trunk/framework/entity/entitydef/entitymodel.xml Tue Apr 29 19:02:29 2008 @@ -32,31 +32,30 @@ <!-- ========================================================= --> <!-- ======================== Data Model ===================== --> <!-- The modules in this file are as follows: --> - <!-- - org.ofbiz.entity.sequence --> + <!-- - org.ofbiz.entity.audit --> <!-- - org.ofbiz.entity.crypto --> + <!-- - org.ofbiz.entity.sequence --> <!-- ========================================================= --> - <!-- ========================================================= --> - <!-- org.ofbiz.entity.sequence --> - <!-- ========================================================= --> - - <entity entity-name="SequenceValueItem" - package-name="org.ofbiz.entity.sequence" - title="Sequence Entity"> + <entity entity-name="EntityAuditLog" package-name="org.ofbiz.entity.audit" title="Entity Audit Log"> + <field name="auditHistorySeqId" type="id-ne"><description>Sequenced primary key</description></field> + <field name="changedEntityName" type="long-varchar"></field> + <field name="changedFieldName" type="long-varchar"></field> + <field name="pkCombinedValueText" type="long-varchar"></field> + <field name="oldValueText" type="long-varchar"></field> + <field name="newValueText" type="long-varchar"></field> + <field name="changedDate" type="date-time"></field> + <field name="changedByInfo" type="long-varchar"><description>This should contain whatever information about the user or system that changed the value that is available. This could be a userLoginId, but could be something else too, so there is no foreign key.</description></field> + <prim-key field="auditHistorySeqId"/> + </entity> + <entity entity-name="EntityKeyStore" package-name="org.ofbiz.entity.crypto" title="Entity Key Store Entity"> + <field name="keyName" type="id-vlong-ne"></field> + <field name="keyText" type="long-varchar"></field> + <prim-key field="keyName"/> + </entity> + <entity entity-name="SequenceValueItem" package-name="org.ofbiz.entity.sequence" title="Sequence Value Item Entity"> <field name="seqName" type="id-long-ne"></field> <field name="seqId" type="numeric"></field> <prim-key field="seqName"/> </entity> - - <!-- ========================================================= --> - <!-- org.ofbiz.entity.crypto --> - <!-- ========================================================= --> - - <entity entity-name="EntityKeyStore" - package-name="org.ofbiz.entity.crypto" - title="Entity Key Entity"> - <field name="keyName" type="id-vlong-ne"></field> - <field name="keyText" type="long-varchar"></field> - <prim-key field="keyName"/> - </entity> </entitymodel> Modified: ofbiz/trunk/framework/entity/entitydef/entitymodel_test.xml URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/entitydef/entitymodel_test.xml?rev=652226&r1=652225&r2=652226&view=diff ============================================================================== --- ofbiz/trunk/framework/entity/entitydef/entitymodel_test.xml (original) +++ ofbiz/trunk/framework/entity/entitydef/entitymodel_test.xml Tue Apr 29 19:02:29 2008 @@ -52,7 +52,7 @@ title="Testing Entity"> <field name="testingId" type="id-ne"/> <field name="testingTypeId" type="id-ne"/> - <field name="testingName" type="name"/> + <field name="testingName" type="name" enable-audit-log="true"/> <field name="description" type="description"/> <field name="comments" type="comment"/> <field name="testingSize" type="numeric"/> Modified: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericDelegator.java URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericDelegator.java?rev=652226&r1=652225&r2=652226&view=diff ============================================================================== --- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericDelegator.java (original) +++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericDelegator.java Tue Apr 29 19:02:29 2008 @@ -41,6 +41,7 @@ import org.ofbiz.base.util.Debug; import org.ofbiz.base.util.GeneralRuntimeException; +import org.ofbiz.base.util.UtilDateTime; import org.ofbiz.base.util.UtilFormatOut; import org.ofbiz.base.util.UtilMisc; import org.ofbiz.base.util.UtilValidate; @@ -92,13 +93,16 @@ protected Cache cache = null; - // keeps a list of field key sets used in the by and cache, a Set (of Sets of fieldNames) for each entityName + /** keeps a list of field key sets used in the by and cache, a Set (of Sets of fieldNames) for each entityName */ protected Map andCacheFieldSets = FastMap.newInstance(); protected DistributedCacheClear distributedCacheClear = null; protected EntityEcaHandler<?> entityEcaHandler = null; protected SequenceUtil sequencer = null; protected EntityCrypto crypto = null; + + /** A ThreadLocal variable to allow other methods to specify an identifier (usually the userLoginId, though technically the Entity Engine doesn't know anything about the UserLogin entity) */ + protected static ThreadLocal<List<Object>> userIdentifierStack = new ThreadLocal<List<Object>>(); public static GenericDelegator getGenericDelegator(String delegatorName) { if (delegatorName == null) { @@ -130,6 +134,47 @@ return delegator; } + protected static List<Object> getUserIdentifierStack() { + List<Object> curValList = userIdentifierStack.get(); + if (curValList == null) { + curValList = FastList.newInstance(); + userIdentifierStack.set(curValList); + } + return curValList; + } + + public static String getCurrentUserIdentifier() { + List<Object> curValList = getUserIdentifierStack(); + Object curVal = curValList.get(0); + if (curVal == null) { + return null; + } else { + return curVal.toString(); + } + } + + public static void pushUserIdentifier(String userIdentifier) { + if (userIdentifier == null) { + return; + } + List<Object> curValList = getUserIdentifierStack(); + curValList.add(0, userIdentifier); + } + + public static String popUserIdentifier() { + List<Object> curValList = getUserIdentifierStack(); + if (curValList.size() == 0) { + return null; + } else { + return (String) curValList.remove(0); + } + } + + public static void clearUserIdentifierStack() { + List<Object> curValList = getUserIdentifierStack(); + curValList.clear(); + } + /** Only allow creation through the factory method */ protected GenericDelegator() {} @@ -250,7 +295,7 @@ public String getDelegatorName() { return this.delegatorName; } - + protected DelegatorInfo getDelegatorInfo() { if (delegatorInfo == null) { delegatorInfo = EntityConfigUtil.getDelegatorInfo(this.delegatorName); @@ -618,6 +663,12 @@ value.setDelegator(this); this.encryptFields(value); + + // if audit log on for any fields, save new value with no old value because it's a create + if (value != null && value.getModelEntity().getHasFieldWithAuditLog()) { + createEntityAuditLogAll(value, false, false); + } + try { value = helper.create(value); } catch (GenericEntityException e) { @@ -651,6 +702,7 @@ } ecaRunner.evalRules(EntityEcaHandler.EV_RETURN, EntityEcaHandler.OP_CREATE, value, false); + return value; } catch (GenericEntityException e) { String errMsg = "Failure in create operation for entity [" + value.getEntityName() + "]: " + e.toString() + ". Rolling back transaction."; @@ -668,7 +720,7 @@ TransactionUtil.commit(beganTransaction); } } - + /** Creates a Entity in the form of a GenericValue and write it to the datasource *@param value The GenericValue to create a value in the datasource from *@param doCacheClear boolean that specifies whether or not to automatically clear cache entries related to this operation @@ -693,6 +745,12 @@ value.setDelegator(this); this.encryptFields(value); + + // if audit log on for any fields, save new value with no old value because it's a create + if (value != null && value.getModelEntity().getHasFieldWithAuditLog()) { + createEntityAuditLogAll(value, false, false); + } + value = helper.create(value); if (value != null) { @@ -708,6 +766,7 @@ } ecaRunner.evalRules(EntityEcaHandler.EV_RETURN, EntityEcaHandler.OP_CREATE, value, false); + return value; } catch (GenericEntityException e) { String errMsg = "Failure in create operation for entity [" + value.getEntityName() + "]: " + e.toString() + ". Rolling back transaction."; @@ -836,10 +895,17 @@ } ecaRunner.evalRules(EntityEcaHandler.EV_RUN, EntityEcaHandler.OP_REMOVE, primaryKey, false); + + // if audit log on for any fields, save old value before removing so it's still there + if (primaryKey != null && primaryKey.getModelEntity().getHasFieldWithAuditLog()) { + createEntityAuditLogAll(this.findByPrimaryKey(primaryKey), true, true); + } + int num = helper.removeByPrimaryKey(primaryKey); this.saveEntitySyncRemoveInfo(primaryKey); ecaRunner.evalRules(EntityEcaHandler.EV_RETURN, EntityEcaHandler.OP_REMOVE, primaryKey, false); + return num; } catch (GenericEntityException e) { String errMsg = "Failure in removeByPrimaryKey operation for entity [" + primaryKey.getEntityName() + "]: " + e.toString() + ". Rolling back transaction."; @@ -890,10 +956,17 @@ } ecaRunner.evalRules(EntityEcaHandler.EV_RUN, EntityEcaHandler.OP_REMOVE, value, false); + + // if audit log on for any fields, save old value before actual remove + if (value != null && value.getModelEntity().getHasFieldWithAuditLog()) { + createEntityAuditLogAll(value, true, true); + } + int num = helper.removeByPrimaryKey(value.getPrimaryKey()); this.saveEntitySyncRemoveInfo(value.getPrimaryKey()); ecaRunner.evalRules(EntityEcaHandler.EV_RETURN, EntityEcaHandler.OP_REMOVE, value, false); + return num; } catch (GenericEntityException e) { String errMsg = "Failure in removeValue operation for entity [" + value.getEntityName() + "]: " + e.toString() + ". Rolling back transaction."; @@ -1147,6 +1220,12 @@ ecaRunner.evalRules(EntityEcaHandler.EV_RUN, EntityEcaHandler.OP_STORE, value, false); this.encryptFields(value); + + // if audit log on for any fields, save old value before the update so we still have both + if (value != null && value.getModelEntity().getHasFieldWithAuditLog()) { + createEntityAuditLogAll(value, true, false); + } + int retVal = helper.store(value); // refresh the valueObject to get the new version @@ -1155,6 +1234,7 @@ } ecaRunner.evalRules(EntityEcaHandler.EV_RETURN, EntityEcaHandler.OP_STORE, value, false); + return retVal; } catch (GenericEntityException e) { String errMsg = "Failure in store operation for entity [" + value.getEntityName() + "]: " + e.toString() + ". Rolling back transaction."; @@ -3001,6 +3081,73 @@ return cache; } + protected void createEntityAuditLogAll(GenericValue value, boolean isUpdate, boolean isRemove) throws GenericEntityException { + for (ModelField mf: value.getModelEntity().getFieldsUnmodifiable()) { + if (mf.getEnableAuditLog()) { + createEntityAuditLogSingle(value, mf, isUpdate, isRemove); + } + } + } + + protected void createEntityAuditLogSingle(GenericValue value, ModelField mf, boolean isUpdate, boolean isRemove) throws GenericEntityException { + if (value == null || mf == null || !mf.getEnableAuditLog()) { + return; + } + + GenericValue entityAuditLog = this.makeValue("EntityAuditLog"); + entityAuditLog.set("auditHistorySeqId", this.getNextSeqId("EntityAuditLog")); + entityAuditLog.set("changedEntityName", value.getEntityName()); + entityAuditLog.set("changedFieldName", mf.getName()); + + String pkCombinedValueText = value.getPkShortValueString(); + if (pkCombinedValueText.length() > 250) { + // uh-oh, the string is too long! + pkCombinedValueText = pkCombinedValueText.substring(0, 250); + } + entityAuditLog.set("pkCombinedValueText", pkCombinedValueText); + + GenericValue oldGv = null; + if (isUpdate) { + // it's an update, get it from the database + oldGv = this.findByPrimaryKey(value.getPrimaryKey()); + } else if (isRemove) { + oldGv = value; + } + if (oldGv == null) { + if (isUpdate || isRemove) { + entityAuditLog.set("oldValueText", "[ERROR] Old value not found even though it was an update or remove"); + } + } else { + // lookup old value + String oldValueText = null; + Object oldValue = oldGv.get(mf.getName()); + if (oldValue != null) { + oldValueText = oldValue.toString(); + if (oldValueText.length() > 250) { + oldValueText = oldValueText.substring(0, 250); + } + } + entityAuditLog.set("oldValueText", oldValueText); + } + + if (!isRemove) { + String newValueText = null; + Object newValue = value.get(mf.getName()); + if (newValue != null) { + newValueText = newValue.toString(); + if (newValueText.length() > 250) { + newValueText = newValueText.substring(0, 250); + } + } + entityAuditLog.set("newValueText", newValueText); + } + + entityAuditLog.set("changedDate", UtilDateTime.nowTimestamp()); + entityAuditLog.set("changedByInfo", getCurrentUserIdentifier()); + + this.create(entityAuditLog); + } + public GenericDelegator cloneDelegator(String delegatorName) { // creates an exact clone of the delegator; except for the sequencer // note that this will not be cached and should be used only when Modified: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericEntity.java URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericEntity.java?rev=652226&r1=652225&r2=652226&view=diff ============================================================================== --- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericEntity.java (original) +++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericEntity.java Tue Apr 29 19:02:29 2008 @@ -316,9 +316,7 @@ } public boolean isPrimaryKey(boolean requireValue) { TreeSet<String> fieldKeys = new TreeSet<String>(this.fields.keySet()); - Iterator<ModelField> pkIter = getModelEntity().getPksIterator(); - while (pkIter.hasNext()) { - ModelField curPk = pkIter.next(); + for (ModelField curPk: this.getModelEntity().getPkFieldsUnmodifiable()) { String fieldName = curPk.getName(); if (requireValue) { if (this.fields.get(fieldName) == null) return false; @@ -337,9 +335,7 @@ } public boolean containsPrimaryKey(boolean requireValue) { //TreeSet fieldKeys = new TreeSet(fields.keySet()); - Iterator pkIter = getModelEntity().getPksIterator(); - while (pkIter.hasNext()) { - ModelField curPk = (ModelField) pkIter.next(); + for (ModelField curPk: this.getModelEntity().getPkFieldsUnmodifiable()) { String fieldName = curPk.getName(); if (requireValue) { if (this.fields.get(fieldName) == null) return false; @@ -349,6 +345,17 @@ } return true; } + + public String getPkShortValueString() { + StringBuffer sb = new StringBuffer(); + for (ModelField curPk: this.getModelEntity().getPkFieldsUnmodifiable()) { + if (sb.length() > 0) { + sb.append("::"); + } + sb.append(this.get(curPk.getName())); + } + return sb.toString(); + } /** Sets the named field to the passed value, even if the value is null * @param name The field name to set Modified: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/datasource/GenericDAO.java URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/datasource/GenericDAO.java?rev=652226&r1=652225&r2=652226&view=diff ============================================================================== --- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/datasource/GenericDAO.java (original) +++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/datasource/GenericDAO.java Tue Apr 29 19:02:29 2008 @@ -108,7 +108,7 @@ SQLProcessor sqlP = new SQLProcessor(helperName); try { - return singleInsert(entity, modelEntity, modelEntity.getFieldsCopy(), sqlP); + return singleInsert(entity, modelEntity, modelEntity.getFieldsUnmodifiable(), sqlP); } catch (GenericEntityException e) { sqlP.rollback(); // no need to create nested, just throw original which will have all info: throw new GenericEntityException("Exception while inserting the following entity: " + entity.toString(), e); @@ -259,7 +259,7 @@ } String sql = "UPDATE " + modelEntity.getTableName(datasourceInfo) + " SET " + modelEntity.colNameString(fieldsToSave, "=?, ", "=?", false) + " WHERE " + - SqlJdbcUtil.makeWhereStringFromFields(modelEntity.getPksCopy(), entity, "AND"); + SqlJdbcUtil.makeWhereStringFromFields(modelEntity.getPkFieldsUnmodifiable(), entity, "AND"); int retVal = 0; @@ -461,7 +461,7 @@ * If not all member entities can be updated, then none should be updated */ if (meResult.size() == 0) { - retVal += singleInsert(meGenericValue, memberModelEntity, memberModelEntity.getFieldsCopy(), sqlP); + retVal += singleInsert(meGenericValue, memberModelEntity, memberModelEntity.getFieldsUnmodifiable(), sqlP); } else { if (meFieldsToSave.size() > 0) { retVal += singleUpdate(meGenericValue, memberModelEntity, meFieldsToSave, sqlP); @@ -508,7 +508,7 @@ } sqlBuffer.append(SqlJdbcUtil.makeFromClause(modelEntity, datasourceInfo)); - sqlBuffer.append(SqlJdbcUtil.makeWhereClause(modelEntity, modelEntity.getPksCopy(), entity, "AND", datasourceInfo.joinStyle)); + sqlBuffer.append(SqlJdbcUtil.makeWhereClause(modelEntity, modelEntity.getPkFieldsUnmodifiable(), entity, "AND", datasourceInfo.joinStyle)); try { sqlP.prepareStatement(sqlBuffer.toString(), true, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); @@ -577,7 +577,7 @@ sqlBuffer.append("*"); } sqlBuffer.append(SqlJdbcUtil.makeFromClause(modelEntity, datasourceInfo)); - sqlBuffer.append(SqlJdbcUtil.makeWhereClause(modelEntity, modelEntity.getPksCopy(), entity, "AND", datasourceInfo.joinStyle)); + sqlBuffer.append(SqlJdbcUtil.makeWhereClause(modelEntity, modelEntity.getPkFieldsUnmodifiable(), entity, "AND", datasourceInfo.joinStyle)); SQLProcessor sqlP = new SQLProcessor(helperName); @@ -650,7 +650,7 @@ throw new GenericModelException("In selectListIteratorByCondition invalid field names specified: " + tempKeys.toString()); } } else { - selectFields = modelEntity.getFieldsCopy(); + selectFields = modelEntity.getFieldsUnmodifiable(); } StringBuilder sqlBuffer = new StringBuilder("SELECT "); @@ -1007,7 +1007,7 @@ throw new org.ofbiz.entity.GenericNotImplementedException("Operation delete not supported yet for view entities"); } - String sql = "DELETE FROM " + modelEntity.getTableName(datasourceInfo) + " WHERE " + SqlJdbcUtil.makeWhereStringFromFields(modelEntity.getPksCopy(), entity, "AND"); + String sql = "DELETE FROM " + modelEntity.getTableName(datasourceInfo) + " WHERE " + SqlJdbcUtil.makeWhereStringFromFields(modelEntity.getPkFieldsUnmodifiable(), entity, "AND"); int retVal; Modified: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/jdbc/DatabaseUtil.java URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/jdbc/DatabaseUtil.java?rev=652226&r1=652225&r2=652226&view=diff ============================================================================== --- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/jdbc/DatabaseUtil.java (original) +++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/jdbc/DatabaseUtil.java Tue Apr 29 19:02:29 2008 @@ -1320,9 +1320,7 @@ } if (pkCount == 0) { Debug.logInfo("Searching in " + tableNames.size() + " tables for primary key fields ...", module); - Iterator it = tableNames.iterator(); - while (it.hasNext()) { - String curTable = (String) it.next(); + for (String curTable: tableNames) { curTable = curTable.substring(curTable.indexOf('.') + 1); //cut off schema name ResultSet rsPks = dbData.getPrimaryKeys(null, lookupSchemaName, curTable); pkCount += checkPrimaryKeyInfo(rsPks, lookupSchemaName, needsUpperCase, colInfo, messages); @@ -1765,7 +1763,7 @@ sqlBuf.append(pkName); } sqlBuf.append(" PRIMARY KEY ("); - sqlBuf.append(entity.colNameString(entity.getPksCopy())); + sqlBuf.append(entity.colNameString(entity.getPkFieldsUnmodifiable())); sqlBuf.append(")"); if (addFks) { @@ -2597,7 +2595,7 @@ sqlBuf.append(pkName); } sqlBuf.append(" PRIMARY KEY ("); - sqlBuf.append(entity.colNameString(entity.getPksCopy())); + sqlBuf.append(entity.colNameString(entity.getPkFieldsUnmodifiable())); sqlBuf.append(")"); if (Debug.verboseOn()) Debug.logVerbose("[createPrimaryKey] sql=" + sqlBuf.toString(), module); Modified: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/model/ModelEntity.java URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/model/ModelEntity.java?rev=652226&r1=652225&r2=652226&view=diff ============================================================================== --- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/model/ModelEntity.java (original) +++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/model/ModelEntity.java Tue Apr 29 19:02:29 2008 @@ -22,6 +22,7 @@ import java.io.Serializable; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -116,6 +117,8 @@ protected boolean autoClearCache = true; + protected Boolean hasFieldWithAuditLog = null; + /** The location of this entity's definition */ protected String location = ""; @@ -382,6 +385,20 @@ public void setAutoClearCache(boolean autoClearCache) { this.autoClearCache = autoClearCache; } + + public boolean getHasFieldWithAuditLog() { + if (this.hasFieldWithAuditLog == null) { + this.hasFieldWithAuditLog = false; + for (ModelField mf: this.fields) { + if (mf.getEnableAuditLog()) { + this.hasFieldWithAuditLog = true; + } + } + return this.hasFieldWithAuditLog; + } else { + return this.hasFieldWithAuditLog; + } + } /* Get the location of this entity's definition */ public String getLocation() { @@ -466,11 +483,18 @@ return this.pks.iterator(); } + /** + * @deprecated Use getPkFieldsUnmodifiable instead. + */ public List<ModelField> getPksCopy() { List<ModelField> newList = FastList.newInstance(); newList.addAll(this.pks); return newList; } + + public List<ModelField> getPkFieldsUnmodifiable() { + return Collections.unmodifiableList(this.pks); + } public String getFirstPkFieldName() { List<String> pkFieldNames = this.getPkFieldNames(); @@ -517,12 +541,19 @@ return this.fields.iterator(); } + /** + * @deprecated Use getFieldsUnmodifiable instead. + */ public List<ModelField> getFieldsCopy() { List<ModelField> newList = FastList.newInstance(); newList.addAll(this.fields); return newList; } + public List<ModelField> getFieldsUnmodifiable() { + return Collections.unmodifiableList(this.fields); + } + /** The col-name of the Field, the alias of the field if this is on a view-entity */ public String getColNameOrAlias(String fieldName) { ModelField modelField = this.getField(fieldName); Modified: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/model/ModelField.java URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/model/ModelField.java?rev=652226&r1=652225&r2=652226&view=diff ============================================================================== --- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/model/ModelField.java (original) +++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/model/ModelField.java Tue Apr 29 19:02:29 2008 @@ -43,6 +43,7 @@ protected boolean isPk = false; protected boolean encrypt = false; protected boolean isAutoCreatedInternal = false; + protected boolean enableAuditLog = false; /** validators to be called when an update is done */ protected List<String> validators = new ArrayList<String>(); @@ -52,15 +53,16 @@ /** Fields Constructor */ public ModelField(String name, String type, String colName, boolean isPk) { - this(name, type, colName, isPk, false); + this(name, type, colName, isPk, false, false); } - public ModelField(String name, String type, String colName, boolean isPk, boolean encrypt) { + public ModelField(String name, String type, String colName, boolean isPk, boolean encrypt, boolean enableAuditLog) { this.name = name; this.type = type; this.setColName(colName); this.isPk = isPk; this.encrypt = encrypt; + this.enableAuditLog = enableAuditLog; } /** XML Constructor */ @@ -71,6 +73,7 @@ this.isPk = false; // is set elsewhere this.encrypt = UtilXml.checkBoolean(fieldElement.getAttribute("encrypt"), false); this.description = UtilXml.childElementValue(fieldElement, "description"); + this.enableAuditLog = UtilXml.checkBoolean(fieldElement.getAttribute("enable-audit-log"), false); NodeList validateList = fieldElement.getElementsByTagName("validate"); @@ -138,6 +141,10 @@ public void setEncrypt(boolean encrypt) { this.encrypt = encrypt; } + + public boolean getEnableAuditLog() { + return this.enableAuditLog; + } public boolean getIsAutoCreatedInternal() { return this.isAutoCreatedInternal; Modified: ofbiz/trunk/framework/service/src/org/ofbiz/service/ServiceDispatcher.java URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/service/src/org/ofbiz/service/ServiceDispatcher.java?rev=652226&r1=652225&r2=652226&view=diff ============================================================================== --- ofbiz/trunk/framework/service/src/org/ofbiz/service/ServiceDispatcher.java (original) +++ ofbiz/trunk/framework/service/src/org/ofbiz/service/ServiceDispatcher.java Tue Apr 29 19:02:29 2008 @@ -313,7 +313,6 @@ } try { - int lockRetriesRemaining = LOCK_RETRIES; boolean needsLockRetry = false; @@ -341,12 +340,17 @@ //Debug.logInfo("After [" + modelService.name + "] pre-auth ECA, before auth; isFailure=" + isFailure + ", isError=" + isError, module); context = checkAuth(localName, context, modelService); - Object userLogin = context.get("userLogin"); + GenericValue userLogin = (GenericValue) context.get("userLogin"); if (modelService.auth && userLogin == null) { throw new ServiceAuthException("User authorization is required for this service: " + modelService.name + modelService.debugInfo()); } + // now that we have authed, if there is a userLogin, set the EE userIdentifier + if (userLogin != null && userLogin.getString("userLoginId") != null) { + GenericDelegator.pushUserIdentifier(userLogin.getString("userLoginId")); + } + // pre-validate ECA if (eventMap != null) ServiceEcaUtil.evalRules(modelService.name, eventMap, "in-validate", ctx, context, result, isError, isFailure); @@ -539,6 +543,9 @@ // call notifications -- event is determined from the result (success, error, fail) modelService.evalNotifications(this.getLocalContext(localName), context, result); + + // clear out the EE userIdentifier + GenericDelegator.popUserIdentifier(); } } catch (GenericTransactionException te) { Debug.logError(te, "Problems with the transaction", module); Modified: ofbiz/trunk/framework/webapp/src/org/ofbiz/webapp/control/ControlServlet.java URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/webapp/src/org/ofbiz/webapp/control/ControlServlet.java?rev=652226&r1=652225&r2=652226&view=diff ============================================================================== --- ofbiz/trunk/framework/webapp/src/org/ofbiz/webapp/control/ControlServlet.java (original) +++ ofbiz/trunk/framework/webapp/src/org/ofbiz/webapp/control/ControlServlet.java Tue Apr 29 19:02:29 2008 @@ -108,6 +108,11 @@ GenericValue userLogin = (GenericValue) session.getAttribute("userLogin"); //Debug.log("Cert Chain: " + request.getAttribute("javax.servlet.request.X509Certificate"), module); + // set the Entity Engine user info if we have a userLogin + if (userLogin != null) { + GenericDelegator.pushUserIdentifier(userLogin.getString("userLoginId")); + } + // workaraound if we are in the root webapp String webappName = UtilHttp.getApplicationName(request); @@ -176,7 +181,7 @@ // setup some things that should always be there UtilHttp.setInitialRequestInfo(request); VisitHandler.getVisitor(request, response); - + // display details on the servlet objects if (Debug.verboseOn()) { logRequestInfo(request); @@ -255,7 +260,7 @@ } } - // sanity check; make sure we don't have any transactions in place + // sanity check: make sure we don't have any transactions in place try { // roll back current TX first if (TransactionUtil.isTransactionInPlace()) { @@ -271,6 +276,9 @@ } catch (GenericTransactionException e) { Debug.logWarning(e, module); } + + // sanity check 2: make sure there are no user infos in the delegator, ie clear the thread + GenericDelegator.clearUserIdentifierStack(); // run these two again before the ServerHitBin.countRequest call because on a logout this will end up creating a new visit if (response.isCommitted() && request.getSession(false) == null) { |
Free forum by Nabble | Edit this page |