All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.eclipse.jkube.kit.common.util.UserConfigurationCompare Maven / Gradle / Ivy
/**
* Copyright (c) 2019 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at:
*
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.jkube.kit.common.util;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.validation.constraints.NotNull;
import io.fabric8.kubernetes.api.model.ObjectMeta;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Helper methods to compare the user configuration on entities
*/
public class UserConfigurationCompare {
private static final Logger LOG = LoggerFactory.getLogger(UserConfigurationCompare.class);
protected static final Set ignoredProperties = new HashSet<>(Collections.singletonList("status"));
private UserConfigurationCompare() { }
/**
* This method detects if the user has changed the configuration of an entity.
*
* It compares the user configuration of 2 object trees ignoring any
* runtime status or timestamp information.
*
* @param entity1 first Object
* @param entity2 second Object
* @return true if the configurations are equal.
*/
public static boolean configEqual(Object entity1, Object entity2) {
if (entity1 == entity2) {
return true;
} else if (entity1 == null || entity2 == null) {
return false;
} else if ((entity1 instanceof Map) || (entity2 instanceof Map)) {
return configEqualMap(castTo(Map.class, entity1), castTo(Map.class, entity2));
} else if ((entity1 instanceof ObjectMeta) || (entity2 instanceof ObjectMeta)) {
return configEqualObjectMeta(castTo(ObjectMeta.class, entity1), castTo(ObjectMeta.class, entity2));
} else if (entity1 instanceof Collection && entity2 instanceof Collection) {
return collectionsEqual((Collection) entity1, (Collection) entity2);
} else {
Class aClass = getCommonDenominator(entity1.getClass(), entity2.getClass());
if (aClass != null) {
Object castEntity2 = castTo(aClass, entity2);
if (castEntity2 == null) {
return false;
} else if (aClass.getPackage().getName().startsWith("org.eclipse.jkube")) {
return configEqualKubernetesDTO(entity1, entity2, aClass);
}
}
return java.util.Objects.equals(entity1, entity2);
}
}
static boolean collectionsEqual(Collection left, Collection right) {
return subCollection(left, right) && subCollection(right, left);
}
static boolean itemExists(L item, Collection collection) {
for (R candidate : collection) {
if (configEqual(item, candidate)) {
return true;
}
}
return false;
}
static boolean subCollection(Collection left, Collection right) {
for (L candidate : left) {
if (!itemExists(candidate, right)) {
return false;
}
}
return true;
}
static Class getCommonDenominator(Class left, Class right) {
if (left.equals(right)) {
return left;
} else if (left.isAssignableFrom(right)) {
return getCommonDenominator(left, right.getSuperclass());
} else if (right.isAssignableFrom(left)) {
return getCommonDenominator(left.getSuperclass(), right);
} else {
//no match
return null;
}
}
/**
* Compares 2 instances of the given Kubernetes DTO class to see if the user has changed their configuration.
*
* This method will ignore properties {@link #ignoredProperties} such as status or timestamp properties
*
* @param entity1 first entity
* @param entity2 second entity
* @param clazz class name
* @return returns boolean value indicating equality or not.
*/
protected static boolean configEqualKubernetesDTO(@NotNull Object entity1, @NotNull Object entity2, @NotNull Class clazz) {
// let's iterate through the objects making sure we've not
BeanInfo beanInfo = null;
try {
beanInfo = Introspector.getBeanInfo(clazz);
} catch (IntrospectionException e) {
LOG.warn("Failed to get beanInfo for " + clazz.getName() + ". " + e, e);
return false;
}
try {
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
String name = propertyDescriptor.getName();
if (ignoredProperties.contains(name)) {
continue;
}
Method readMethod = propertyDescriptor.getReadMethod();
if (readMethod != null) {
Object value1 = invokeMethod(entity1, readMethod);
Object value2 = invokeMethod(entity2, readMethod);
if (value1 != null && value2 != null && !configEqual(value1, value2)) {
return false;
}
}
}
return true;
} catch (Exception e) {
return false;
}
}
protected static Object invokeMethod(@NotNull Object entity, Method readMethod) throws InvocationTargetException, IllegalAccessException {
try {
return readMethod.invoke(entity);
} catch (Exception e) {
LOG.warn("Failed to invoke method " + readMethod + " on " + entity + ". " + e, e);
throw e;
}
}
protected static boolean configEqualObjectMeta(ObjectMeta entity1, ObjectMeta entity2) {
if (entity1 == entity2) {
return true;
} else if (entity1 == null || entity2 == null) {
return false;
}
// TODO should we ignore annotations?
return java.util.Objects.equals(entity1.getName(), entity2.getName()) &&
java.util.Objects.equals(entity1.getNamespace(), entity2.getNamespace()) &&
configEqualMap(entity1.getLabels(), entity2.getLabels()) &&
configEqualMap(entity1.getAnnotations(), entity2.getAnnotations());
}
private static T castTo(Class clazz, Object entity) {
if (clazz.isInstance(entity)) {
return clazz.cast(entity);
} else {
if (entity != null) {
LOG.warn("Invalid class {} when expecting {} for instance: {}",
entity.getClass().getName(),
clazz.getName(),
entity);
}
return null;
}
}
protected static boolean configEqualMap(Map entity1, Map entity2) {
if (entity1 == entity2) {
return true;
} else if (entity1 == null || entity2 == null) {
return false;
}
int size1 = size(entity1);
int size2 = size(entity2);
if (size1 != size2) {
return false;
}
Set entries = entity1.entrySet();
for (Map.Entry entry : entries) {
Object key = entry.getKey();
Object value = entry.getValue();
Object value2 = entity2.get(key);
if (!configEqual(value, value2)) {
return false;
}
}
return true;
}
protected static int size(Map map) {
return (map == null) ? 0 : map.size();
}
protected static int size(Collection coll) {
return (coll == null) ? 0 : coll.size();
}
}