Piotr Kliczewski has uploaded a new change for review.

Change subject: [WIP] engine : 998980 Generic mechanism for update diffs in 
audit
......................................................................

[WIP] engine : 998980 Generic mechanism for update diffs in audit

Mechanism provides audit information about the values modified during
update command for DC. Cluster, VM, Template, Storage, Network and Disk.
In order to enable command to generate events containing diff it is
required to implement UpdateValuesProvider interface.

Bug-Url: https://bugzilla.redhat.com/show_bug.cgi?id=998980

Change-Id: If3362f9bfffe921df44103239ece8348001feca5
Signed-off-by: pkliczewski <piotr.kliczew...@gmail.com>
---
M 
backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/CommandBase.java
A 
backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/UpdateValuesProvider.java
M 
backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/UpdateVdsGroupCommand.java
M 
backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/UpdateVmCommand.java
M 
backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/UpdateVmDiskCommand.java
M 
backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/UpdateVmTemplateCommand.java
M 
backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/network/dc/UpdateNetworkCommand.java
M 
backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/storage/UpdateStorageDomainCommand.java
M 
backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/storage/UpdateStoragePoolCommand.java
M 
backend/manager/modules/bll/src/test/java/org/ovirt/engine/core/bll/CommandBaseTest.java
M 
backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/AuditLogType.java
M 
backend/manager/modules/compat/src/main/java/org/ovirt/engine/core/compat/backendcompat/TypeCompat.java
M 
backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dal/dbbroker/auditloghandling/AuditLogDirector.java
M 
backend/manager/modules/dal/src/main/resources/bundles/AuditLogMessages.properties
M 
backend/manager/modules/dal/src/test/java/org/ovirt/engine/core/dal/dbbroker/auditloghandling/AuditLogDirectorTest.java
A 
backend/manager/modules/utils/src/main/java/org/ovirt/engine/core/utils/JsonUtils.java
M 
backend/manager/modules/utils/src/main/java/org/ovirt/engine/core/utils/ObjectIdentityChecker.java
M 
backend/manager/modules/utils/src/main/java/org/ovirt/engine/core/utils/ReflectionUtils.java
A 
backend/manager/modules/utils/src/test/java/org/ovirt/engine/core/utils/JsonUtilsTest.java
M 
backend/manager/modules/utils/src/test/java/org/ovirt/engine/core/utils/ObjectIdentityCheckerTest.java
20 files changed, 597 insertions(+), 112 deletions(-)


  git pull ssh://gerrit.ovirt.org:29418/ovirt-engine refs/changes/65/20265/1

diff --git 
a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/CommandBase.java
 
b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/CommandBase.java
index 630107e..64e68a0 100644
--- 
a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/CommandBase.java
+++ 
b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/CommandBase.java
@@ -1,5 +1,10 @@
 package org.ovirt.engine.core.bll;
 
+import static 
org.ovirt.engine.core.dal.dbbroker.auditloghandling.AuditLogDirector.UPDATE_PARAMS;
+import static org.ovirt.engine.core.utils.JsonUtils.buildJsonStringFromMaps;
+import static 
org.ovirt.engine.core.utils.ObjectIdentityChecker.GetChangedFields;
+import static org.ovirt.engine.core.utils.ObjectIdentityChecker.getValues;
+
 import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -1316,10 +1321,17 @@
         return returnValue;
     }
 
-    private void logCommand() {
+    void logCommand() {
         Class<?> type = getClass();
         InternalCommandAttribute annotation = 
type.getAnnotation(InternalCommandAttribute.class);
         if (annotation == null) {
+            if (UpdateValuesProvider.class.isInstance(this)) {
+                UpdateValuesProvider<?> provider = (UpdateValuesProvider<?>) 
this;
+                List<String> list = GetChangedFields(provider.getOldObject(), 
provider.getNewObject());
+                Map<String, String> oldValues = 
getValues(provider.getOldObject(), list);
+                Map<String, String> newValues = 
getValues(provider.getNewObject(), list);
+                this.addCustomValue(UPDATE_PARAMS, 
buildJsonStringFromMaps(list, oldValues, newValues));
+            }
             log();
         }
     }
diff --git 
a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/UpdateValuesProvider.java
 
b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/UpdateValuesProvider.java
new file mode 100644
index 0000000..7da4167
--- /dev/null
+++ 
b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/UpdateValuesProvider.java
@@ -0,0 +1,6 @@
+package org.ovirt.engine.core.bll;
+
+public interface UpdateValuesProvider<T> {
+    T getOldObject();
+    T getNewObject();
+}
diff --git 
a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/UpdateVdsGroupCommand.java
 
b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/UpdateVdsGroupCommand.java
index be33823..942ce28 100644
--- 
a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/UpdateVdsGroupCommand.java
+++ 
b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/UpdateVdsGroupCommand.java
@@ -22,6 +22,8 @@
 import org.ovirt.engine.core.common.businessentities.network.Network;
 import org.ovirt.engine.core.common.businessentities.network.NetworkCluster;
 import org.ovirt.engine.core.common.businessentities.network.NetworkStatus;
+import org.ovirt.engine.core.common.config.Config;
+import org.ovirt.engine.core.common.config.ConfigValues;
 import org.ovirt.engine.core.common.errors.VdcBllMessages;
 import org.ovirt.engine.core.common.gluster.GlusterFeatureSupported;
 import org.ovirt.engine.core.common.utils.ListUtils;
@@ -34,11 +36,9 @@
 import org.ovirt.engine.core.dao.VdsStaticDAO;
 import org.ovirt.engine.core.dao.network.NetworkDao;
 import org.ovirt.engine.core.utils.NetworkUtils;
-import org.ovirt.engine.core.common.config.Config;
-import org.ovirt.engine.core.common.config.ConfigValues;
 
 public class UpdateVdsGroupCommand<T extends VdsGroupOperationParameters> 
extends
-        VdsGroupOperationCommandBase<T>  implements RenamedEntityInfoProvider{
+        VdsGroupOperationCommandBase<T>  implements RenamedEntityInfoProvider, 
UpdateValuesProvider<VDSGroup> {
 
     private List<VDS> allForVdsGroup;
     private VDSGroup oldGroup;
@@ -384,4 +384,14 @@
     public void setEntityId(AuditLogableBase logable) {
         logable.setVdsGroupId(oldGroup.getId());
     }
+
+    @Override
+    public VDSGroup getOldObject() {
+        return this.oldGroup;
+    }
+
+    @Override
+    public VDSGroup getNewObject() {
+        return getParameters().getVdsGroup();
+    }
 }
diff --git 
a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/UpdateVmCommand.java
 
b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/UpdateVmCommand.java
index ed78f79..be7a590 100644
--- 
a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/UpdateVmCommand.java
+++ 
b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/UpdateVmCommand.java
@@ -56,7 +56,7 @@
 
 @LockIdNameAttribute
 public class UpdateVmCommand<T extends VmManagementParametersBase> extends 
VmManagementCommandBase<T>
-        implements QuotaVdsDependent, RenamedEntityInfoProvider{
+        implements QuotaVdsDependent, RenamedEntityInfoProvider, 
UpdateValuesProvider<VM> {
     private VM oldVm;
     private boolean quotaSanityOnly = false;
 
@@ -530,4 +530,14 @@
         return virtioScsiEnabled != null ? virtioScsiEnabled :
                 VmDeviceUtils.isVirtioScsiControllerAttached(getVmId());
     }
+
+    @Override
+    public VM getOldObject() {
+        return this.oldVm;
+    }
+
+    @Override
+    public VM getNewObject() {
+        return getParameters().getVm();
+    }
 }
diff --git 
a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/UpdateVmDiskCommand.java
 
b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/UpdateVmDiskCommand.java
index 76fa063..593da63 100644
--- 
a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/UpdateVmDiskCommand.java
+++ 
b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/UpdateVmDiskCommand.java
@@ -48,7 +48,7 @@
 @LockIdNameAttribute(isReleaseAtEndOfExecute = false)
 @NonTransactiveCommandAttribute(forceCompensation = true)
 public class UpdateVmDiskCommand<T extends UpdateVmDiskParameters> extends 
AbstractDiskVmCommand<T>
-        implements QuotaStorageDependent {
+        implements QuotaStorageDependent, UpdateValuesProvider<Disk> {
 
     private List<PermissionSubject> listPermissionSubjects;
     private Map<Guid, List<Disk>> otherVmDisks = new HashMap<Guid, 
List<Disk>>();
@@ -573,4 +573,14 @@
         
getReturnValue().getCanDoActionMessages().addAll(internalReturnValue.getCanDoActionMessages());
         getReturnValue().setCanDoAction(internalReturnValue.getCanDoAction());
     }
+
+    @Override
+    public Disk getOldObject() {
+        return getOldDisk();
+    }
+
+    @Override
+    public Disk getNewObject() {
+        return getNewDisk();
+    }
 }
diff --git 
a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/UpdateVmTemplateCommand.java
 
b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/UpdateVmTemplateCommand.java
index 66aeb58..ba400a7 100644
--- 
a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/UpdateVmTemplateCommand.java
+++ 
b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/UpdateVmTemplateCommand.java
@@ -33,7 +33,7 @@
 import org.ovirt.engine.core.dal.dbbroker.auditloghandling.AuditLogDirector;
 
 public class UpdateVmTemplateCommand<T extends UpdateVmTemplateParameters> 
extends VmTemplateCommand<T>
-        implements QuotaVdsDependent, RenamedEntityInfoProvider{
+        implements QuotaVdsDependent, RenamedEntityInfoProvider, 
UpdateValuesProvider<VmTemplate> {
     private VmTemplate mOldTemplate;
 
     public UpdateVmTemplateCommand(T parameters) {
@@ -245,4 +245,14 @@
         return permissionList;
     }
 
+    @Override
+    public VmTemplate getOldObject() {
+        return this.mOldTemplate;
+    }
+
+    @Override
+    public VmTemplate getNewObject() {
+        return getParameters().getVmTemplateData();
+    }
+
 }
diff --git 
a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/network/dc/UpdateNetworkCommand.java
 
b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/network/dc/UpdateNetworkCommand.java
index 93ca3af..853b552 100644
--- 
a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/network/dc/UpdateNetworkCommand.java
+++ 
b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/network/dc/UpdateNetworkCommand.java
@@ -4,6 +4,7 @@
 
 import org.apache.commons.lang.ObjectUtils;
 import org.ovirt.engine.core.bll.RenamedEntityInfoProvider;
+import org.ovirt.engine.core.bll.UpdateValuesProvider;
 import org.ovirt.engine.core.bll.ValidationResult;
 import org.ovirt.engine.core.bll.network.cluster.NetworkClusterHelper;
 import org.ovirt.engine.core.bll.validator.NetworkValidator;
@@ -17,7 +18,8 @@
 import org.ovirt.engine.core.dal.dbbroker.auditloghandling.AuditLogableBase;
 import org.ovirt.engine.core.utils.NetworkUtils;
 
-public class UpdateNetworkCommand<T extends AddNetworkStoragePoolParameters> 
extends NetworkCommon<T> implements RenamedEntityInfoProvider{
+public class UpdateNetworkCommand<T extends AddNetworkStoragePoolParameters> 
extends NetworkCommon<T>
+        implements RenamedEntityInfoProvider, UpdateValuesProvider<Network> {
     private Network oldNetwork;
 
     public UpdateNetworkCommand(T parameters) {
@@ -143,4 +145,14 @@
     public void setEntityId(AuditLogableBase logable) {
 
     }
+
+    @Override
+    public Network getOldObject() {
+        return getOldNetwork();
+    }
+
+    @Override
+    public Network getNewObject() {
+        return getParameters().getNetwork();
+    }
 }
diff --git 
a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/storage/UpdateStorageDomainCommand.java
 
b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/storage/UpdateStorageDomainCommand.java
index f346203..03224e8 100644
--- 
a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/storage/UpdateStorageDomainCommand.java
+++ 
b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/storage/UpdateStorageDomainCommand.java
@@ -5,9 +5,11 @@
 import org.apache.commons.lang.StringUtils;
 import org.ovirt.engine.core.bll.Backend;
 import org.ovirt.engine.core.bll.RenamedEntityInfoProvider;
+import org.ovirt.engine.core.bll.UpdateValuesProvider;
 import org.ovirt.engine.core.common.AuditLogType;
 import org.ovirt.engine.core.common.VdcObjectType;
 import org.ovirt.engine.core.common.action.StorageDomainManagementParameter;
+import org.ovirt.engine.core.common.businessentities.StorageDomain;
 import org.ovirt.engine.core.common.businessentities.StorageDomainStatic;
 import org.ovirt.engine.core.common.businessentities.StorageDomainStatus;
 import org.ovirt.engine.core.common.errors.VdcBllMessages;
@@ -19,7 +21,7 @@
 import org.ovirt.engine.core.utils.ObjectIdentityChecker;
 
 public class UpdateStorageDomainCommand<T extends 
StorageDomainManagementParameter> extends
-        StorageDomainManagementCommandBase<T>  implements 
RenamedEntityInfoProvider {
+        StorageDomainManagementCommandBase<T>  implements 
RenamedEntityInfoProvider, UpdateValuesProvider<StorageDomain> {
     public UpdateStorageDomainCommand(T parameters) {
         super(parameters);
     }
@@ -115,4 +117,14 @@
     public void setEntityId(AuditLogableBase logable) {
         logable.setStorageDomainId(oldDomain.getId());
     }
+
+    @Override
+    public StorageDomain getOldObject() {
+        return 
DbFacade.getInstance().getStorageDomainDao().get(getStorageDomain().getId());
+    }
+
+    @Override
+    public StorageDomain getNewObject() {
+        return getStorageDomain();
+    }
 }
diff --git 
a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/storage/UpdateStoragePoolCommand.java
 
b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/storage/UpdateStoragePoolCommand.java
index 4244341..bc0fc2f 100644
--- 
a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/storage/UpdateStoragePoolCommand.java
+++ 
b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/storage/UpdateStoragePoolCommand.java
@@ -7,6 +7,7 @@
 import org.ovirt.engine.core.bll.Backend;
 import org.ovirt.engine.core.bll.NonTransactiveCommandAttribute;
 import org.ovirt.engine.core.bll.RenamedEntityInfoProvider;
+import org.ovirt.engine.core.bll.UpdateValuesProvider;
 import org.ovirt.engine.core.bll.utils.VersionSupport;
 import org.ovirt.engine.core.common.AuditLogType;
 import org.ovirt.engine.core.common.VdcObjectType;
@@ -37,7 +38,7 @@
 
 @NonTransactiveCommandAttribute
 public class UpdateStoragePoolCommand<T extends 
StoragePoolManagementParameter> extends
-        StoragePoolManagementCommandBase<T>  implements 
RenamedEntityInfoProvider{
+        StoragePoolManagementCommandBase<T>  implements 
RenamedEntityInfoProvider, UpdateValuesProvider<StoragePool> {
     public UpdateStoragePoolCommand(T parameters) {
         super(parameters);
     }
@@ -267,4 +268,14 @@
     public void setEntityId(AuditLogableBase logable) {
         logable.setStoragePoolId(_oldStoragePool.getId());
     }
+
+    @Override
+    public StoragePool getOldObject() {
+        return this._oldStoragePool;
+    }
+
+    @Override
+    public StoragePool getNewObject() {
+        return getParameters().getStoragePool();
+    }
 }
diff --git 
a/backend/manager/modules/bll/src/test/java/org/ovirt/engine/core/bll/CommandBaseTest.java
 
b/backend/manager/modules/bll/src/test/java/org/ovirt/engine/core/bll/CommandBaseTest.java
index 7870da8..fd5db70 100644
--- 
a/backend/manager/modules/bll/src/test/java/org/ovirt/engine/core/bll/CommandBaseTest.java
+++ 
b/backend/manager/modules/bll/src/test/java/org/ovirt/engine/core/bll/CommandBaseTest.java
@@ -9,14 +9,21 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
+import static 
org.ovirt.engine.core.dal.dbbroker.auditloghandling.AuditLogDirector.UPDATE_PARAMS;
+import static org.ovirt.engine.core.utils.JsonUtils.NEW_VALUE;
+import static org.ovirt.engine.core.utils.JsonUtils.OLD_VALUE;
+import static org.ovirt.engine.core.utils.JsonUtils.buildTypeFromJson;
 import static org.ovirt.engine.core.utils.MockConfigRule.mockConfig;
 
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.lang.RandomStringUtils;
+import org.codehaus.jackson.type.TypeReference;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.ClassRule;
@@ -24,6 +31,7 @@
 import org.ovirt.engine.core.bll.session.SessionDataContainer;
 import org.ovirt.engine.core.bll.tasks.SPMAsyncTaskHandler;
 import org.ovirt.engine.core.bll.utils.PermissionSubject;
+import org.ovirt.engine.core.common.AuditLogType;
 import org.ovirt.engine.core.common.action.VdcActionParametersBase;
 import org.ovirt.engine.core.common.businessentities.DbUser;
 import org.ovirt.engine.core.common.config.ConfigValues;
@@ -76,6 +84,63 @@
         @Override
         protected void logRollbackedTask() {
             return;
+        }
+
+        @Override
+        protected void log() {
+            // do nothing
+        }
+    }
+
+    public class TestObject {
+        public static final String PARAM_NAME = "name";
+        private String name;
+
+        public TestObject(String name) {
+            this.name = name;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public void setName(String name) {
+            this.name = name;
+        }
+    }
+
+    private class CommandBaseWithUpdateValues extends 
CommandBase<VdcActionParametersBase> implements 
UpdateValuesProvider<TestObject> {
+        private TestObject oldTestObject = new TestObject("oldValue");
+        private TestObject newTestObject = new TestObject("newValue");
+
+        @Override
+        public TestObject getOldObject() {
+            return oldTestObject;
+        }
+
+        @Override
+        public TestObject getNewObject() {
+            return newTestObject;
+        }
+
+        @Override
+        protected void executeCommand() {
+            setSucceeded(true);
+        }
+
+        @Override
+        public List<PermissionSubject> getPermissionCheckSubjects() {
+            return Collections.emptyList();
+        }
+
+        @Override
+        public AuditLogType getAuditLogTypeValue() {
+            return AuditLogType.USER_UPDATE_VDS;
+        }
+
+        @Override
+        protected void log() {
+            // do nothing
         }
     }
 
@@ -207,9 +272,43 @@
     }
 
     @Test
+    public void testAuditCommand() {
+        // given
+        CommandBase<VdcActionParametersBase> command = new 
CommandBaseWithUpdateValues();
+
+        // when
+        command.logCommand();
+
+        // then
+        Map<String, String> values = command.getCustomValues();
+        String json = values.get(UPDATE_PARAMS);
+        assertTrue("Json should be not empty", json != null && 
!"".equals(json.trim()));
+        Map<String, Map<String, String>> result =
+                buildTypeFromJson(json, new TypeReference<HashMap<String, 
Map<String, String>>>() {
+                });
+        assertTrue("Should be one param", result.get(TestObject.PARAM_NAME) != 
null);
+        assertEquals("newValue", 
result.get(TestObject.PARAM_NAME).get(NEW_VALUE));
+        assertEquals("oldValue", 
result.get(TestObject.PARAM_NAME).get(OLD_VALUE));
+    }
+
+    @Test
+    public void testAuditWithNotUpdateCommand() {
+        //given
+        VdcActionParametersBase parameterMock = 
mock(VdcActionParametersBase.class);
+        CommandBase<VdcActionParametersBase> command = new 
CommandBaseDummy(parameterMock);
+
+        // when
+        command.logCommand();
+
+        // then
+        Map<String, String> values = command.getCustomValues();
+        assertTrue("Have to be empty", values.isEmpty());
+    }
+
+    @Test
     public void testExtractVariableDeclarationsForStaticMsgs() {
         VdcActionParametersBase parameterMock = 
mock(VdcActionParametersBase.class);
-        CommandBase<VdcActionParametersBase>command = new 
CommandBaseDummy(parameterMock);
+        CommandBase<VdcActionParametersBase> command = new 
CommandBaseDummy(parameterMock);
         List<String> msgs = Arrays.asList(
                 "ACTION_TYPE_FAILED_TEMPLATE_IS_USED_FOR_CREATE_VM",
                 "IRS_FAILED_RETRIEVING_SNAPSHOT_INFO");
@@ -221,10 +320,10 @@
     @Test
     public void testExtractVariableDeclarationsForDynamicMsgs() {
         VdcActionParametersBase parameterMock = 
mock(VdcActionParametersBase.class);
-        CommandBase<VdcActionParametersBase>command = new 
CommandBaseDummy(parameterMock);
+        CommandBase<VdcActionParametersBase> command = new 
CommandBaseDummy(parameterMock);
         String msg1_1 = "ACTION_TYPE_FAILED_TEMPLATE_IS_USED_FOR_CREATE_VM";
         String msg1_2 = "$VmName Vm1";
-        String msg2   = "IRS_FAILED_CREATING_SNAPSHOT";
+        String msg2 = "IRS_FAILED_CREATING_SNAPSHOT";
         String msg3_1 = "ACTION_TYPE_FAILED_VM_SNAPSHOT_HAS_NO_CONFIGURATION";
         String msg3_2 = "$VmName Vm2";
         String msg3_3 = "$SnapshotName Snapshot";
diff --git 
a/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/AuditLogType.java
 
b/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/AuditLogType.java
index 1f69f7c..164c3f3 100644
--- 
a/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/AuditLogType.java
+++ 
b/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/AuditLogType.java
@@ -822,6 +822,7 @@
     // External tasks
     USER_ADD_EXTERNAL_JOB(11000),
     USER_ADD_EXTERNAL_JOB_FAILED(11001),
+    UPDATE_PARAMS(11002),
 
     //network Qos
     USER_ADDED_NETWORK_QOS(10100),
diff --git 
a/backend/manager/modules/compat/src/main/java/org/ovirt/engine/core/compat/backendcompat/TypeCompat.java
 
b/backend/manager/modules/compat/src/main/java/org/ovirt/engine/core/compat/backendcompat/TypeCompat.java
index 13e808a..a90e2aa 100644
--- 
a/backend/manager/modules/compat/src/main/java/org/ovirt/engine/core/compat/backendcompat/TypeCompat.java
+++ 
b/backend/manager/modules/compat/src/main/java/org/ovirt/engine/core/compat/backendcompat/TypeCompat.java
@@ -1,8 +1,10 @@
 package org.ovirt.engine.core.compat.backendcompat;
 
+import java.beans.IntrospectionException;
 import java.beans.Introspector;
 import java.beans.PropertyDescriptor;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -18,16 +20,13 @@
 
     public static List<PropertyInfo> GetProperties(Class<?> type) {
         List<PropertyInfo> returnValue = new ArrayList<PropertyInfo>();
-        try {
-            PropertyDescriptor[] pds = 
Introspector.getBeanInfo(type).getPropertyDescriptors();
-            for (PropertyDescriptor pd : pds) {
-                // Class is a bogus property, remove it
-                if (!CLASS.equals(pd.getName())) {
-                    returnValue.add(new PropertyInfo(pd));
-                }
+
+        PropertyDescriptor[] pds = getPropertyDescriptors(type);
+        for (PropertyDescriptor pd : pds) {
+            // Class is a bogus property, remove it
+            if (!CLASS.equals(pd.getName())) {
+                returnValue.add(new PropertyInfo(pd));
             }
-        } catch (Exception e) {
-            throw new RuntimeException(e);
         }
         return returnValue;
     }
@@ -39,30 +38,63 @@
      * @param values - a map which will contains all values of properties
      */
     public static void getPropertyValues(Object obj, Set<String> properties, 
Map<String, String> values) {
-        try {
-            PropertyDescriptor[] pds = 
Introspector.getBeanInfo(obj.getClass()).getPropertyDescriptors();
-            int hitCount = 0;
-            for (PropertyDescriptor pd : pds) {
-                String propertyName = pd.getName().toLowerCase();
-                if (properties.contains(propertyName)) {
-                    Object value = null;
-                    hitCount++;
-                    if(!values.containsKey(propertyName))  {
-                        try {
-                            value = pd.getReadMethod().invoke(obj);
-                            String stringValue = value != null ? 
value.toString() : null;
-                            values.put(propertyName, stringValue);
-                        } catch (Exception e) {
-                            log.warn("Unable to get value of property: " + 
pd.getDisplayName() + " for class "
-                                    + obj.getClass().getName());
-                        }
-                    }
-                    if (hitCount == properties.size()) {
-                        break;
+        PropertyDescriptor[] pds = getPropertyDescriptors(obj.getClass());
+        int hitCount = 0;
+        for (PropertyDescriptor pd : pds) {
+            String propertyName = pd.getName().toLowerCase();
+            if (properties.contains(propertyName)) {
+                Object value = null;
+                hitCount++;
+                if(!values.containsKey(propertyName))  {
+                    try {
+                        value = pd.getReadMethod().invoke(obj);
+                        String stringValue = value != null ? value.toString() 
: null;
+                        values.put(propertyName, stringValue);
+                    } catch (Exception e) {
+                        log.warn("Unable to get value of property: " + 
pd.getDisplayName() + " for class "
+                                + obj.getClass().getName());
                     }
                 }
+                if (hitCount == properties.size()) {
+                    break;
+                }
             }
-        } catch (Exception e) {
+        }
+    }
+
+    /**
+     * Returns values for provided properties and respects the case for 
property names.
+     *
+     * @param obj Source object which contains the values.
+     * @param properties {@link List} of properties for which values are 
returned.
+     * @return {@link Map} of values for properties provided in the list.
+     */
+    public static Map<String, String> getPropertyValues(Object obj, 
List<String> properties) {
+        Map<String, String> map = new HashMap<String, String>();
+        PropertyDescriptor[] pds = getPropertyDescriptors(obj.getClass());
+        int hitCount = 0;
+        for (PropertyDescriptor pd : pds) {
+            String propertyName = pd.getName();
+            if (properties.contains(propertyName)) {
+                try {
+                    Object value = pd.getReadMethod().invoke(obj);
+                    map.put(propertyName, value != null ? value.toString() : 
null);
+                } catch (Exception e) {
+                    log.warn("Unable to get value of property: " + 
pd.getDisplayName() + " for class "
+                            + obj.getClass().getName());
+                }
+                if (hitCount == properties.size()) {
+                    break;
+                }
+            }
+        }
+        return map;
+    }
+
+    private static PropertyDescriptor[] getPropertyDescriptors(Class<? extends 
Object> clazz) {
+        try {
+            return Introspector.getBeanInfo(clazz).getPropertyDescriptors();
+        } catch (IntrospectionException e) {
             throw new RuntimeException(e);
         }
     }
diff --git 
a/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dal/dbbroker/auditloghandling/AuditLogDirector.java
 
b/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dal/dbbroker/auditloghandling/AuditLogDirector.java
index 85ce98a..b0af050 100644
--- 
a/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dal/dbbroker/auditloghandling/AuditLogDirector.java
+++ 
b/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dal/dbbroker/auditloghandling/AuditLogDirector.java
@@ -22,6 +22,7 @@
 
 
 public final class AuditLogDirector {
+    public static final String UPDATE_PARAMS = "update_params";
     private static final Log log = LogFactory.getLog(AuditLogDirector.class);
     private static final Map<AuditLogType, String> messages = new 
EnumMap<AuditLogType, String>(AuditLogType.class);
     private static final Map<AuditLogType, AuditLogSeverity> severities =
@@ -969,7 +970,13 @@
                     auditLogable.getEventFloodInSec(),
                     auditLogable.getCustomData());
         } else if ((message = messages.get(logType)) != null) { // Application 
log message from AuditLogMessages
-            resolvedMessage = resolveMessage(message, auditLogable);
+            String updatedProperties = "";
+            if (!auditLogable.getCustomValues().isEmpty()) {
+                Map<String, String> logMap = new HashMap<>();
+                logMap.put(UPDATE_PARAMS, 
auditLogable.getCustomValue(UPDATE_PARAMS));
+                updatedProperties = 
resolveMessage(messages.get(AuditLogType.UPDATE_PARAMS), logMap);
+            }
+            resolvedMessage = resolveMessage(message, auditLogable) + 
updatedProperties;
             auditLog = new AuditLog(logType, severity, resolvedMessage, 
auditLogable.getUserId(),
                     auditLogable.getUserName(), auditLogable.getVmIdRef(), 
auditLogable.getVmName(),
                     auditLogable.getVdsIdRef(), auditLogable.getVdsName(), 
auditLogable.getVmTemplateIdRef(),
diff --git 
a/backend/manager/modules/dal/src/main/resources/bundles/AuditLogMessages.properties
 
b/backend/manager/modules/dal/src/main/resources/bundles/AuditLogMessages.properties
index b167ec3..898c301 100644
--- 
a/backend/manager/modules/dal/src/main/resources/bundles/AuditLogMessages.properties
+++ 
b/backend/manager/modules/dal/src/main/resources/bundles/AuditLogMessages.properties
@@ -714,3 +714,4 @@
 DISK_ALIGNMENT_SCAN_START=Starting alignment scan of disk '${DiskAlias}'.
 DISK_ALIGNMENT_SCAN_FAILURE=Alignment scan of disk '${DiskAlias}' failed.
 DISK_ALIGNMENT_SCAN_SUCCESS=Alignment scan of disk '${DiskAlias}' is complete.
+UPDATE_PARAMS= Update parameters are ${update_params}.
diff --git 
a/backend/manager/modules/dal/src/test/java/org/ovirt/engine/core/dal/dbbroker/auditloghandling/AuditLogDirectorTest.java
 
b/backend/manager/modules/dal/src/test/java/org/ovirt/engine/core/dal/dbbroker/auditloghandling/AuditLogDirectorTest.java
index 05769f8..dc41c01 100644
--- 
a/backend/manager/modules/dal/src/test/java/org/ovirt/engine/core/dal/dbbroker/auditloghandling/AuditLogDirectorTest.java
+++ 
b/backend/manager/modules/dal/src/test/java/org/ovirt/engine/core/dal/dbbroker/auditloghandling/AuditLogDirectorTest.java
@@ -1,87 +1,126 @@
 package org.ovirt.engine.core.dal.dbbroker.auditloghandling;
 
-/**
- * TODO:
- * Commented out test class in order to cancel dependency on PowerMock
- * This should be revisited.
- */
+import static junit.framework.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyLong;
+import static org.mockito.Matchers.anyString;
 import static org.mockito.Mockito.RETURNS_DEFAULTS;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
+import static 
org.ovirt.engine.core.dal.dbbroker.auditloghandling.AuditLogDirector.UPDATE_PARAMS;
+import static org.ovirt.engine.core.utils.ReflectionUtils.setStaticField;
 
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.concurrent.TimeUnit;
 
-import junit.framework.Assert;
-
+import org.infinispan.Cache;
+import org.infinispan.manager.CacheContainer;
+import org.junit.After;
+import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.ovirt.engine.core.common.AuditLogType;
+import org.ovirt.engine.core.common.businessentities.AuditLog;
+import org.ovirt.engine.core.dal.dbbroker.DbFacade;
+import org.ovirt.engine.core.dal.dbbroker.DbFacadeLocator;
+import org.ovirt.engine.core.dao.AuditLogDAO;
+import org.ovirt.engine.core.utils.ejb.BeanProxyType;
+import org.ovirt.engine.core.utils.ejb.BeanType;
+import org.ovirt.engine.core.utils.ejb.EJBUtilsStrategy;
+import org.ovirt.engine.core.utils.ejb.EjbUtils;
 
-
-//@RunWith(PowerMockRunner.class)
-//@PrepareForTest({ AuditLogDirector.class })
+@RunWith(MockitoJUnitRunner.class)
 public class AuditLogDirectorTest {
-//
-//    @Mock
-//    DbFacade dbFacade;
-//    @Mock
-//    AuditLogDAO auditLogDao;
-//
-//    @Before
-//    public void initMocks() {
-//        initAuditLogDirectorMock();
-//        initDbFacadeMock();
-//    }
-//
-//    private void initDbFacadeMock() {
-//        when(dbFacade.getAuditLogDAO()).thenReturn(auditLogDao);
-//    }
-//
-//    private void initAuditLogDirectorMock() {
-//        PowerMockito.spy(AuditLogDirector.class);
-//        
PowerMockito.when(AuditLogDirector.getDbFacadeInstance()).thenReturn(dbFacade);
-//    }
-//
-//
-//    /**
-//     * The test assures that audit loggable objects with timeout, which were 
created without an explicit log type, with
-//     * a common key parts, except of the log type, are treated 
separately.<br>
-//     * The test invokes two {@Code AuditLogDirector.log()} calls and 
verifies that each call insert an entry into
-//     * the database.<br>
-//     */
-    // @Test
-    // public void testLegalAuditLog() {
-    // AuditLogableBase logableObject1 = new AuditLogableBase();
-    // AuditLogDirector.log(logableObject1, AuditLogType.IRS_DISK_SPACE_LOW);
-    //
-    // AuditLogableBase logableObject2 = new AuditLogableBase();
-    // AuditLogDirector.log(logableObject2, 
AuditLogType.IRS_DISK_SPACE_LOW_ERROR);
-    // Mockito.verify(auditLogDao, 
Mockito.times(2)).save(Mockito.any(AuditLog.class));
-    // }
-//
-//    /**
-//     * The test assures that audit loggable objects with timeout, which were 
created without an explicit log type and
-//     * share the same key are treated in respect to each other by the 
timeout gaps between events.<br>
-//     * The test invokes two {@Code AuditLogDirector.log()} calls and verify 
that only one call inserts an entry
-//     * into the database.
-//     */
-//    @Test
-//    public void testIllegalAuditLog() {
-//        AuditLogableBase logableObject1 = new AuditLogableBase();
-//        AuditLogDirector.log(logableObject1, 
AuditLogType.VDS_SLOW_STORAGE_RESPONSE_TIME);
-//        Mockito.verify(auditLogDao, 
Mockito.times(1)).save(Mockito.any(AuditLog.class));
-//
-//        AuditLogDirector.log(logableObject1, 
AuditLogType.VDS_SLOW_STORAGE_RESPONSE_TIME);
-//        Mockito.verify(auditLogDao, 
Mockito.times(1)).save(Mockito.any(AuditLog.class));
-//    }
-//
+
+    @Mock
+    private DbFacade dbFacade;
+
+    @Mock
+    private AuditLogDAO auditLogDao;
+
+    @Mock
+    private EJBUtilsStrategy strategy;
+
+    @Mock
+    private CacheContainer cacheContainer;
+
+    @Before
+    public void setup() throws NoSuchFieldException, SecurityException, 
IllegalArgumentException,
+            IllegalAccessException {
+        when(dbFacade.getAuditLogDao()).thenReturn(auditLogDao);
+        when(strategy.findBean(BeanType.CACHE_CONTAINER, 
BeanProxyType.LOCAL)).thenReturn(cacheContainer);
+        setStaticField(DbFacadeLocator.class, "dbFacade", dbFacade);
+        setStaticField(EjbUtils.class, "strategy", strategy);
+    }
+
+    @After
+    public void tearDown() {
+        reset(auditLogDao);
+    }
+
+    /**
+     * The test assures that audit loggable objects with timeout, which were 
created without an explicit log type, with
+     * a common key parts, except of the log type, are treated separately.<br>
+     * The test invokes two {@Code AuditLogDirector.log()} calls and verifies 
that each call insert an entry into
+     * the database.<br>
+     */
+    @Test
+    public void testLegalAuditLog() {
+        // given
+        AuditLogableBase logableObject1 = spy(new AuditLogableBase());
+        doReturn(true).when(logableObject1).getLegal();
+        AuditLogableBase logableObject2 = spy(new AuditLogableBase());
+        doReturn(true).when(logableObject2).getLegal();
+
+        // when
+        AuditLogDirector.log(logableObject1, AuditLogType.IRS_DISK_SPACE_LOW);
+        AuditLogDirector.log(logableObject2, 
AuditLogType.IRS_DISK_SPACE_LOW_ERROR);
+
+        // then
+        verify(auditLogDao, times(2)).save(any(AuditLog.class));
+    }
+
+    /**
+     * The test assures that audit loggable objects with timeout, which were 
created without an explicit log type and
+     * share the same key are treated in respect to each other by the timeout 
gaps between events.<br>
+     * The test invokes two {@Code AuditLogDirector.log()} calls and verify 
that only one call inserts an entry
+     * into the database.
+     */
+    @Test
+    @SuppressWarnings("unchecked")
+    public void testIllegalAuditLog() {
+        // given
+        AuditLogableBase logableObject1 = new AuditLogableBase();
+        Cache<Object, Object> cache = mock(Cache.class);
+        when(cache.putIfAbsent(anyString(), anyString(), anyLong(), 
any(TimeUnit.class))).thenReturn(logableObject1)
+                .thenReturn(null);
+        when(cacheContainer.getCache("timeout-base")).thenReturn(cache);
+
+        // when
+        AuditLogDirector.log(logableObject1, 
AuditLogType.VDS_SLOW_STORAGE_RESPONSE_TIME);
+        AuditLogDirector.log(logableObject1, 
AuditLogType.VDS_SLOW_STORAGE_RESPONSE_TIME);
+
+        // then
+        verify(auditLogDao, times(1)).save(any(AuditLog.class));
+    }
+
     @Test
     public void testResolveUnknownVariable() {
         final String message = "This is my ${Variable}";
         final String expectedResolved = String.format("This is my %1s", 
AuditLogDirector.UNKNOWN_VARIABLE_VALUE);
         Map<String, String> values = Collections.emptyMap();
         String resolvedMessage = AuditLogDirector.resolveMessage(message, 
values);
-        Assert.assertEquals(expectedResolved, resolvedMessage);
+        assertEquals(expectedResolved, resolvedMessage);
     }
 
     @Test
@@ -90,7 +129,7 @@
         final String expectedResolved = "This is my value";
         Map<String, String> values = Collections.singletonMap("variable", 
"value");
         String resolvedMessage = AuditLogDirector.resolveMessage(message, 
values);
-        Assert.assertEquals(expectedResolved, resolvedMessage);
+        assertEquals(expectedResolved, resolvedMessage);
     }
 
     @Test
@@ -105,7 +144,7 @@
         values.put("second", "two");
         values.put("blank", " ");
         String resolvedMessage = AuditLogDirector.resolveMessage(message, 
values);
-        Assert.assertEquals(expectedResolved, resolvedMessage);
+        assertEquals(expectedResolved, resolvedMessage);
     }
 
     @Test
@@ -125,6 +164,29 @@
         when(logable.getVmName()).thenReturn("TestVM");
 
         String resolvedMessage = AuditLogDirector.resolveMessage(message, 
logable);
-        Assert.assertEquals(expectedResolved, resolvedMessage);
+        assertEquals(expectedResolved, resolvedMessage);
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testAuditUpdate() throws NoSuchFieldException, 
SecurityException, IllegalArgumentException,
+            IllegalAccessException {
+        // given
+        AuditLogableBase auditLogableBase = mock(AuditLogableBase.class);
+        when(auditLogableBase.getLegal()).thenReturn(true);
+        Map<String, String> map = mock(Map.class);
+        when(map.isEmpty()).thenReturn(false);
+        when(auditLogableBase.getCustomValues()).thenReturn(map);
+        
when(auditLogableBase.getCustomValue(UPDATE_PARAMS)).thenReturn("{\"propertyName1\":{\"new\":\"value1\",\"old\":\"value2\"}}");
+        ArgumentCaptor<AuditLog> captor = 
ArgumentCaptor.forClass(AuditLog.class);
+
+        // when
+        AuditLogDirector.log(auditLogableBase, AuditLogType.USER_UPDATE_VDS, 
"");
+
+        // then
+        verify(auditLogDao).save(captor.capture());
+        AuditLog log = captor.getValue();
+        assertEquals("Host <UNKNOWN> configuration was updated by 
<UNKNOWN>.Update parameters are 
{\"propertyName1\":{\"new\":\"value1\",\"old\":\"value2\"}}.",
+                log.getmessage());
     }
 }
diff --git 
a/backend/manager/modules/utils/src/main/java/org/ovirt/engine/core/utils/JsonUtils.java
 
b/backend/manager/modules/utils/src/main/java/org/ovirt/engine/core/utils/JsonUtils.java
new file mode 100644
index 0000000..cebef4c
--- /dev/null
+++ 
b/backend/manager/modules/utils/src/main/java/org/ovirt/engine/core/utils/JsonUtils.java
@@ -0,0 +1,68 @@
+package org.ovirt.engine.core.utils;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.codehaus.jackson.map.ObjectMapper;
+import org.codehaus.jackson.type.TypeReference;
+import org.ovirt.engine.core.utils.log.Log;
+import org.ovirt.engine.core.utils.log.LogFactory;
+
+public class JsonUtils {
+
+    public final static String NEW_VALUE = "new";
+
+    public final static String OLD_VALUE = "old";
+
+    private static Log log = LogFactory.getLog(JsonUtils.class);
+
+    /**
+     * Builds json string from properties provided in the list and new and old 
values provide in the maps. Json example:
+     * 
<code>{"propertyName1":{"new":"value1","old":"value2"},"propertyName2":{"new":"value1","old":"value2"}}</code>
+     *
+     * @param properties
+     *            {@link List} with properties
+     * @param oldMap
+     *            {@link Map} containing old values for the properties
+     * @param newMap
+     *            {@link Map} containing new values for the properties
+     * @return Json string like in the example.
+     */
+    public static String buildJsonStringFromMaps(List<String> properties,
+            Map<String, String> oldMap,
+            Map<String, String> newMap) {
+
+        try {
+            ObjectMapper mapper = new ObjectMapper();
+            return mapper.writeValueAsString(prepareJsonMap(properties, 
oldMap, newMap));
+        } catch (IOException e) {
+            log.warn("JsonUtils :: buildJsonStringFromMaps unable to marshall 
map to json");
+            return "";
+        }
+    }
+
+    public static <T> T buildTypeFromJson(String json, TypeReference<T> 
typeReference) {
+        ObjectMapper mapper = new ObjectMapper();
+        try {
+            return mapper.readValue(json, typeReference);
+        } catch (IOException e) {
+            log.warn("JsonUtils :: buildTypeFromJson unable to marshall json 
to type");
+            return null;
+        }
+    }
+
+    private static Map<String, Map<String, String>> 
prepareJsonMap(List<String> properties,
+            Map<String, String> oldMap,
+            Map<String, String> newMap) {
+        Map<String, Map<String, String>> map = new HashMap<>();
+        for (String property : properties) {
+            Map<String, String> propertyMap = new HashMap<>();
+            propertyMap.put(OLD_VALUE, oldMap.get(property));
+            propertyMap.put(NEW_VALUE, newMap.get(property));
+            map.put(property, propertyMap);
+        }
+        return map;
+    }
+}
diff --git 
a/backend/manager/modules/utils/src/main/java/org/ovirt/engine/core/utils/ObjectIdentityChecker.java
 
b/backend/manager/modules/utils/src/main/java/org/ovirt/engine/core/utils/ObjectIdentityChecker.java
index a009719..9aa8685 100644
--- 
a/backend/manager/modules/utils/src/main/java/org/ovirt/engine/core/utils/ObjectIdentityChecker.java
+++ 
b/backend/manager/modules/utils/src/main/java/org/ovirt/engine/core/utils/ObjectIdentityChecker.java
@@ -194,6 +194,10 @@
         return returnValue;
     }
 
+    public static Map<String, String> getValues(Object source, List<String> 
properties){
+        return TypeCompat.getPropertyValues(source, properties);
+    }
+
     /**
      * Logs the error.
      *
diff --git 
a/backend/manager/modules/utils/src/main/java/org/ovirt/engine/core/utils/ReflectionUtils.java
 
b/backend/manager/modules/utils/src/main/java/org/ovirt/engine/core/utils/ReflectionUtils.java
index 708ecae..a572afc 100644
--- 
a/backend/manager/modules/utils/src/main/java/org/ovirt/engine/core/utils/ReflectionUtils.java
+++ 
b/backend/manager/modules/utils/src/main/java/org/ovirt/engine/core/utils/ReflectionUtils.java
@@ -1,6 +1,7 @@
 package org.ovirt.engine.core.utils;
 
 import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
 
 
 
@@ -89,4 +90,18 @@
             throw new IllegalStateException(e);
         }
     }
+
+    /**
+     * Replace an object in static filed for provided class.
+     *
+     * @param clazz Class holds static field.
+     * @param fieldName Name of the field to be replaced.
+     * @param newObject Object which is used as replacement.
+     */
+    public static void setStaticField(Class<?> clazz, String fieldName, Object 
newObject) throws NoSuchFieldException,
+            SecurityException, IllegalArgumentException, 
IllegalAccessException {
+        Field field = clazz.getDeclaredField(fieldName);
+        field.setAccessible(true);
+        field.set(null, newObject);
+    }
 }
diff --git 
a/backend/manager/modules/utils/src/test/java/org/ovirt/engine/core/utils/JsonUtilsTest.java
 
b/backend/manager/modules/utils/src/test/java/org/ovirt/engine/core/utils/JsonUtilsTest.java
new file mode 100644
index 0000000..6c79a77
--- /dev/null
+++ 
b/backend/manager/modules/utils/src/test/java/org/ovirt/engine/core/utils/JsonUtilsTest.java
@@ -0,0 +1,82 @@
+package org.ovirt.engine.core.utils;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.ovirt.engine.core.utils.JsonUtils.NEW_VALUE;
+import static org.ovirt.engine.core.utils.JsonUtils.OLD_VALUE;
+import static org.ovirt.engine.core.utils.JsonUtils.buildJsonStringFromMaps;
+import static org.ovirt.engine.core.utils.JsonUtils.buildTypeFromJson;
+import static 
org.ovirt.engine.core.utils.ObjectIdentityChecker.GetChangedFields;
+import static org.ovirt.engine.core.utils.ObjectIdentityChecker.getValues;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.codehaus.jackson.JsonParseException;
+import org.codehaus.jackson.map.JsonMappingException;
+import org.codehaus.jackson.type.TypeReference;
+import org.junit.Test;
+
+public class JsonUtilsTest {
+
+    @Test
+    public void testBuildingJsonFromMaps() throws JsonParseException, 
JsonMappingException, IOException {
+        // given
+        Jedi jedi1 = new Jedi();
+        Jedi jedi2 = new Jedi();
+        jedi2.saberColor = "red";
+        List<String> changes = GetChangedFields(jedi1, jedi2);
+
+        // when
+        String json = buildJsonStringFromMaps(changes, getValues(jedi1, 
changes), getValues(jedi2, changes));
+
+        // then
+        Map<String, Map<String, String>> result =
+                buildTypeFromJson(json, new TypeReference<HashMap<String, 
Map<String, String>>>() {
+                });
+        assertTrue("Map should have only one property", result.keySet().size() 
== 1);
+        assertEquals("red", result.get("saberColor").get(NEW_VALUE));
+        assertEquals("Blue", result.get("saberColor").get(OLD_VALUE));
+    }
+
+    @Test
+    public void testBuildingJsonFromMapsWithMultipleProperties() throws 
JsonParseException, JsonMappingException,
+            IOException {
+        // given
+        Jedi jedi1 = new Jedi();
+        jedi1.name = "Yoda";
+        Jedi jedi2 = new Jedi();
+        jedi2.saberColor = "red";
+        List<String> changes = GetChangedFields(jedi1, jedi2);
+
+        // when
+        String json = buildJsonStringFromMaps(changes, getValues(jedi1, 
changes), getValues(jedi2, changes));
+
+        // then
+        Map<String, Map<String, String>> result =
+                buildTypeFromJson(json, new TypeReference<HashMap<String, 
Map<String, String>>>() {
+                });
+        assertTrue("Map should have two properties", result.keySet().size() == 
2);
+        assertEquals("red", result.get("saberColor").get(NEW_VALUE));
+        assertEquals("Yoda", result.get("name").get(OLD_VALUE));
+    }
+
+    @Test
+    public void testBuildingJsonFromPamsWithNoChanges() throws 
JsonParseException, JsonMappingException, IOException {
+        // given
+        Jedi jedi1 = new Jedi();
+        Jedi jedi2 = new Jedi();
+        List<String> changes = GetChangedFields(jedi1, jedi2);
+
+        // when
+        String json = buildJsonStringFromMaps(changes, getValues(jedi1, 
changes), getValues(jedi2, changes));
+
+        // then
+        Map<String, Map<String, String>> result =
+                buildTypeFromJson(json, new TypeReference<HashMap<String, 
Map<String, String>>>() {
+                });
+        assertTrue("Map should have no properties", result.keySet().isEmpty());
+    }
+}
diff --git 
a/backend/manager/modules/utils/src/test/java/org/ovirt/engine/core/utils/ObjectIdentityCheckerTest.java
 
b/backend/manager/modules/utils/src/test/java/org/ovirt/engine/core/utils/ObjectIdentityCheckerTest.java
index cdd01b6..6092687 100644
--- 
a/backend/manager/modules/utils/src/test/java/org/ovirt/engine/core/utils/ObjectIdentityCheckerTest.java
+++ 
b/backend/manager/modules/utils/src/test/java/org/ovirt/engine/core/utils/ObjectIdentityCheckerTest.java
@@ -1,10 +1,12 @@
 package org.ovirt.engine.core.utils;
 
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
 import java.util.Arrays;
 import java.util.List;
+import java.util.Map;
 
 import org.junit.Test;
 
@@ -48,4 +50,23 @@
         changed = oic.IsFieldsUpdated(jedi1, jedi2, 
Arrays.asList("saberColor"));
         assertTrue("1 Change", changed);
     }
+
+    @Test
+    public void testValuesUpdated() {
+        // given
+        Jedi jedi1 = new Jedi();
+        Jedi jedi2 = new Jedi();
+        jedi2.saberColor = "red";
+        List<String> changes = ObjectIdentityChecker.GetChangedFields(jedi1, 
jedi2);
+
+        // when
+        Map<String, String> oldValues = ObjectIdentityChecker.getValues(jedi1, 
changes);
+        Map<String, String> newValues = ObjectIdentityChecker.getValues(jedi2, 
changes);
+
+        // then
+        assertTrue("Should be 1 value", oldValues.size() == 1);
+        assertEquals("Blue", oldValues.get("saberColor"));
+        assertTrue("Should be 1 value", newValues.size() == 1);
+        assertEquals("red", newValues.get("saberColor"));
+    }
 }


-- 
To view, visit http://gerrit.ovirt.org/20265
To unsubscribe, visit http://gerrit.ovirt.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: If3362f9bfffe921df44103239ece8348001feca5
Gerrit-PatchSet: 1
Gerrit-Project: ovirt-engine
Gerrit-Branch: master
Gerrit-Owner: Piotr Kliczewski <piotr.kliczew...@gmail.com>
_______________________________________________
Engine-patches mailing list
Engine-patches@ovirt.org
http://lists.ovirt.org/mailman/listinfo/engine-patches

Reply via email to