package org.ovirt.engine.core.utils; import java.util.List; import org.ovirt.engine.core.common.queries.ValueObjectMap; import org.ovirt.engine.core.common.utils.EnumUtils; import org.ovirt.engine.core.common.utils.IObjectDescriptorContainer; import org.ovirt.engine.core.compat.LogCompat; import org.ovirt.engine.core.compat.LogFactoryCompat; import org.ovirt.engine.core.compat.backendcompat.PropertyInfo; import org.ovirt.engine.core.compat.backendcompat.TypeCompat; public class ObjectIdentityChecker { private IObjectDescriptorContainer mContainer; private static java.util.HashMap<String, java.lang.Class> mAliases = new java.util.HashMap<String, java.lang.Class>(); private static java.util.HashMap<java.lang.Class, ObjectIdentityChecker> mIdentities = new java.util.HashMap<java.lang.Class, ObjectIdentityChecker>(); private static java.util.HashMap<java.lang.Class, java.lang.Class> mStatusTypes = new java.util.HashMap<java.lang.Class, java.lang.Class>(); private java.util.HashMap<Enum, java.util.ArrayList<String>> mDictionary = new java.util.HashMap<Enum, java.util.ArrayList<String>>(); private java.util.ArrayList<String> mPermitted = new java.util.ArrayList<String>(); public ObjectIdentityChecker(java.lang.Class type) { mIdentities.put(type, this); } public ObjectIdentityChecker(java.lang.Class type, Iterable<String> aliases) { this(type); for (String alias : aliases) { mAliases.put(alias, type); } } public ObjectIdentityChecker(java.lang.Class type, Iterable<String> aliases, java.lang.Class enumType) { this(type, aliases); mStatusTypes.put(type, enumType); } public final void setContainer(IObjectDescriptorContainer value) { mContainer = value; } public static boolean CanUpdateField(Object fieldContainer, String fieldName, Enum status) { return CanUpdateField(fieldContainer.getClass().getSimpleName(), fieldName, status, fieldContainer); } public static boolean CanUpdateField(String objectType, String fieldName, Enum status, Object fieldContainer) { java.lang.Class type = null; if ((type = mAliases.get(objectType)) != null) { return CanUpdateField(type, fieldName, status, fieldContainer); } else { throw new RuntimeException(String.format("status type %1$s not exist", type)); } } public static boolean CanUpdateField(java.lang.Class objectType, String fieldName, Enum status, Object fieldContainer) { ObjectIdentityChecker checker = null; if ((checker = mIdentities.get(objectType)) != null) { return checker.IsFieldUpdatable(status, fieldName, fieldContainer); } return true; } public static boolean CanUpdateField(String objectType, String fieldName, String status) { java.lang.Class type = null; if ((type = mAliases.get(objectType)) != null) { java.lang.Class statusType = null; if ((statusType = mStatusTypes.get(type)) != null) { Enum currentStatus; try { currentStatus = (Enum) EnumUtils.valueOf(statusType, status, true); } catch (IllegalArgumentException e) { throw new RuntimeException(String.format("status type %1$s not contain type %2$s", statusType, status)); } return CanUpdateField(type, fieldName, currentStatus); } else { throw new RuntimeException(String.format("status type %1$s not exist", type)); } } else { throw new RuntimeException(String.format("object type %1$s not exist", objectType)); } } public final void AddField(Enum status, String fieldName) { java.util.ArrayList<String> values = null; if (!((values = mDictionary.get(status)) != null)) { values = new java.util.ArrayList<String>(); mDictionary.put(status, values); } if (!values.contains(fieldName)) { values.add(fieldName); } } public final void AddField(Iterable<Enum> statuses, String fieldName) { for (Enum status : statuses) { AddField(status, fieldName); } } public final void AddFields(Iterable<Enum> statuses, Iterable<String> fields) { for (String field : fields) { AddField(statuses, field); } } public final void AddPermittedField(String fieldName) { if (!mPermitted.contains(fieldName)) { mPermitted.add(fieldName); } } public final void AddPermittedFields(String[] fieldNames) { for (String fieldName : fieldNames) { AddPermittedField(fieldName); } } public final boolean IsFieldUpdatable(String name) { return mPermitted.contains(name); } private boolean IsFieldUpdatable(Enum status, String name, Object fieldContainer) { boolean returnValue = true; if (!IsFieldUpdatable(name)) { if (fieldContainer != null && mContainer != null && !mContainer.CanUpdateField(fieldContainer, name, status)) { returnValue = false; } else { java.util.ArrayList<String> values = null; if ((values = mDictionary.get(status)) != null && values != null) { returnValue = values.contains(name); } else { returnValue = false; } } if (!returnValue) { LogError(name, status); } } return returnValue; } public final boolean IsUpdateValid(Object source, Object destination) { if (source.getClass() != destination.getClass()) { return false; } for (String fieldName : GetChangedFields(source, destination)) { if (!IsFieldUpdatable(fieldName)) { return false; } } return true; } public final boolean IsUpdateValid(Object source, Object destination, Enum status) { if (source.getClass() != destination.getClass()) { return false; } for (String fieldName : GetChangedFields(source, destination)) { if (!IsFieldUpdatable(status, fieldName, null)) { log.warn(String.format("ObjectIdentityChecker.IsUpdateValid:: Not updatable field '%1$s' was updated", fieldName)); return false; } } return true; } public final boolean IsFieldsUpdated(Object source, Object destination, Iterable<String> fields) { java.util.ArrayList<String> changedFields = GetChangedFields(source, destination); for (String field : fields) { if (changedFields.contains(field)) { return true; } } return false; } public static java.util.ArrayList<String> GetChangedFields(Object source, Object destination) { java.util.ArrayList<String> returnValue = new java.util.ArrayList<String>(); if (source.getClass().isInstance(destination)) { Class objectType = source.getClass(); List<PropertyInfo> properties = TypeCompat.GetProperties(objectType); for (PropertyInfo property : properties) { Object sourceValue = property.GetValue(source, null); Object destinationValue = property.GetValue(destination, null); if (!(property.isPropertyInstanceOf(ValueObjectMap.class)) && property.getCanWrite() && sourceValue != null && !sourceValue.equals(destinationValue) || ((sourceValue == null && destinationValue != null))) { returnValue.add(property.getName()); } } } return returnValue; } /** * Logs the error. * * @param name * The name. * @param status * The status. */ private static void LogError(String name, Enum status) { log.errorFormat("Field {0} can not be updated when status is {1}", name, status); } private static LogCompat log = LogFactoryCompat.getLog(ObjectIdentityChecker.class); }