blob: 39c6e128ed1dad7ccf5918a2fb672f15ddc6a715 [file] [log] [blame]
/**
* Copyright (c) 2011, 2015 - Lunifera GmbH (Gross Enzersdorf, Austria), Loetz GmbH&Co.KG (69115 Heidelberg, Germany)
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Florian Pirchner - Initial implementation
*/
package org.eclipse.osbp.runtime.common.annotations;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.lang.reflect.MethodUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The Class DtoUtils.
*/
public class DtoUtils {
/** The Constant LOGGER. */
private static final Logger LOGGER = LoggerFactory.getLogger(DtoUtils.class);
/** The infos. */
private static Map<Class<?>, Info> INFOS = Collections.synchronizedMap(new HashMap<Class<?>, DtoUtils.Info>());
/**
* Returns the dispose field. Field annotated with {@link Dispose}.
*
* @param clazz
* the clazz
* @return the dispose field
*/
public static Field getDisposeField(Class<?> clazz) {
Info info = getInfo(clazz);
return info.getDisposeField();
}
/**
* Returns the dispose field. Field annotated with {@link Dirty}.
*
* @param clazz
* the clazz
* @return the dirty field
*/
public static Field getDirtyField(Class<?> clazz) {
Info info = getInfo(clazz);
return info.getDirtyField();
}
/**
* Returns the domain key field. Field annotated with {@link DomainKey}.
*
* @param clazz
* the clazz
* @return the domain key field
*/
public static Field getDomainKeyField(Class<?> clazz) {
Info info = getInfo(clazz);
return info.getDomainKeyField();
}
/**
* Returns the id field. Field annotated with {@link Id}.
*
* @param clazz
* the clazz
* @return the id field
*/
public static Field getIdField(Class<?> clazz) {
Info info = getInfo(clazz);
return info.getIdField();
}
/**
* Returns the id key field. Field annotated with {@link Id}.
*
* @param instance
* the instance
* @param idProperty
* the id property
* @return the value
*/
public static Object getValue(Object instance, String idProperty) {
try {
BeanInfo beanInfo = Introspector.getBeanInfo(instance.getClass());
for (PropertyDescriptor pd : beanInfo.getPropertyDescriptors()) {
if (pd.getName().equals(idProperty)) {
Method idMethod = pd.getReadMethod();
return idMethod.invoke(instance);
}
}
} catch (Exception e) {
LOGGER.error("{}", e);
}
return null;
}
/**
* Returns the domain description field. Field annotated with
* #DomainDescription.
*
* @param clazz
* the clazz
* @return the domain description field
*/
public static Field getDomainDescriptionField(Class<?> clazz) {
Info info = getInfo(clazz);
return info.getDomainDescriptionField();
}
/**
* Returns the dispose field. Field annotated with {@link Dirty}.
*
* @param clazz
* the clazz
* @return the dirty getter
*/
public static Method getDirtyGetter(Class<?> clazz) {
Info info = getInfo(clazz);
return info.getDirtyGetter();
}
/**
* Returns the dispose field. Field annotated with {@link Dirty}.
*
* @param clazz
* the clazz
* @return the dirty setter
*/
public static Method getDirtySetter(Class<?> clazz) {
Info info = getInfo(clazz);
return info.getDirtySetter();
}
/**
* Returns the dispose method. Method annotated with {@link Dispose}.
*
* @param clazz
* the clazz
* @return the dispose method
*/
public static Method getDisposeMethod(Class<?> clazz) {
Info info = getInfo(clazz);
return info.getDisposeMethod();
}
/**
* Returns true, if the given field is a dispose field.
*
* @param clazz
* the clazz
* @param fieldName
* the field name
* @return true, if is dispose field
*/
public static boolean isDisposeField(Class<?> clazz, String fieldName) {
Info info = getInfo(clazz);
return info.getDisposeField() != null ? info.getDisposeField().getName().equals(fieldName) : false;
}
/**
* Returns true, if the given field is a dirty field. Dirty fields indicate
* that the dto is dirty.
*
* @param clazz
* the clazz
* @param fieldName
* the field name
* @return true, if is dirty field
*/
public static boolean isDirtyField(Class<?> clazz, String fieldName) {
Info info = getInfo(clazz);
return info.getDirtyField() != null ? info.getDirtyField().getName().equals(fieldName) : false;
}
/**
* Returns true, if the given method is a dispose method.
*
* @param clazz
* the clazz
* @param methodName
* the method name
* @return true, if is dispose method
*/
public static boolean isDisposeMethod(Class<?> clazz, String methodName) {
Info info = getInfo(clazz);
return info.getDisposeField() != null ? info.getDisposeMethod().getName().equals(methodName) : false;
}
/**
* Tries to invoke the dispose method.
*
* @param obj
* the obj
* @return true, if the method could be invoked. False otherwise.
*/
public static boolean invokeDisposeMethod(Object obj) {
Info info = getInfo(obj.getClass());
if (info != null && info.getDisposeMethod() != null) {
try {
info.getDisposeMethod().invoke(obj, new Object[0]);
} catch (IllegalAccessException e) {
return false;
} catch (IllegalArgumentException e) {
return false;
} catch (InvocationTargetException e) {
return false;
}
}
return true;
}
/**
* Tries to invoke the setDirty method.
*
* @param obj
* the obj
* @param value
* the value
* @return true, if the method could be invoked. False otherwise.
*/
public static boolean invokeDirtySetter(Object obj, boolean value) {
Info info = getInfo(obj.getClass());
if (info != null && info.getDirtySetter() != null) {
try {
info.getDirtySetter().invoke(obj, new Object[] { value });
} catch (IllegalAccessException e) {
return false;
} catch (IllegalArgumentException e) {
return false;
} catch (InvocationTargetException e) {
return false;
}
}
return true;
}
/**
* Tries to invoke the dirty getter. If there is no dirty getter available,
* the method throws an {@link IllegalAccessException}.
*
* @param obj
* the obj
* @return true, if is dirty
* @throws IllegalAccessException
* the illegal access exception
*/
public static boolean isDirty(Object obj) throws IllegalAccessException {
return invokeDirtyGetter(obj);
}
/**
* Tries to invoke the isDirty method.
*
* @param obj
* the obj
* @return true, if the method could be invoked. False otherwise.
* @throws IllegalAccessException
* the illegal access exception
*/
public static boolean invokeDirtyGetter(Object obj) throws IllegalAccessException {
Info info = getInfo(obj.getClass());
if (info != null && info.getDirtySetter() != null) {
try {
return (Boolean) info.getDirtyGetter().invoke(obj, new Object[0]);
} catch (IllegalAccessException e) {
} catch (IllegalArgumentException e) {
} catch (InvocationTargetException e) {
}
}
throw new IllegalAccessException("Not a valid call");
}
/**
* Returns the info for the given class.
*
* @param clazz
* the clazz
* @return the info
*/
protected static Info getInfo(Class<?> clazz) {
Info info = INFOS.get(clazz);
if (info == null) {
info = createInfo(clazz);
}
return info;
}
/**
* Creates a new info.
*
* @param clazz
* the clazz
* @return info
*/
private static Info createInfo(Class<?> clazz) {
Info info = new Info();
applyFieldInfo(clazz, info);
applyMethodInfo(clazz, info);
INFOS.put(clazz, info);
return info;
}
/**
* Returns the adapter which has proper type from the given dto. Or
* <code>null</code> if no adapter is available.
*
* @param <A>
* the generic type
* @param type
* the type
* @param dto
* the dto
* @return the adapter
*/
@SuppressWarnings("unchecked")
public static <A> A getAdapter(Class<A> type, Object dto) {
if (type == null || dto == null) {
return null;
}
Info info = getInfo(dto.getClass());
if (info.getPropertyChangeSupportField() == null) {
return null;
}
try {
info.getPropertyChangeSupportField().setAccessible(true);
PropertyChangeSupport changeSupport = (PropertyChangeSupport) info.getPropertyChangeSupportField().get(dto);
if (changeSupport == null) {
return null;
}
for (PropertyChangeListener listener : changeSupport.getPropertyChangeListeners()) {
if (type.isAssignableFrom(listener.getClass())) {
return (A) listener;
}
}
} catch (IllegalArgumentException e) {
LOGGER.error("{}", e);
} catch (IllegalAccessException e) {
LOGGER.error("{}", e);
}
return null;
}
/**
* Registers the adapter as a property changed listener.
*
* @param adapter
* the adapter
* @param dto
* the dto
*/
public static void registerAdapter(PropertyChangeListener adapter, Object dto) {
if (adapter == null || dto == null) {
return;
}
try {
MethodUtils.invokeMethod(dto, "addPropertyChangeListener", adapter);
} catch (SecurityException e) {
LOGGER.info("Observer for dirtyState handling could not be added for " + dto.getClass().getName());
} catch (IllegalAccessException e) {
LOGGER.info("Observer for dirtyState handling could not be added for " + dto.getClass().getName());
} catch (IllegalArgumentException e) {
LOGGER.info("Observer for dirtyState handling could not be added for " + dto.getClass().getName());
} catch (InvocationTargetException e) {
LOGGER.info("Observer for dirtyState handling could not be added for " + dto.getClass().getName());
} catch (NoSuchMethodException e) {
LOGGER.info("Observer for dirtyState handling could not be added for " + dto.getClass().getName());
}
}
/**
* Applies all required field infos to the info object.
*
* @param clazz
* the clazz
* @param info
* the info
*/
private static void applyFieldInfo(Class<?> clazz, Info info) {
try {
for (Field field : clazz.getDeclaredFields()) {
if (field.getAnnotation(Dispose.class) != null) {
info.disposeField = field;
}
if (field.getAnnotation(DomainKey.class) != null) {
info.domainKeyField = field;
}
if (field.getAnnotation(DomainDescription.class) != null) {
info.domainDescriptionField = field;
}
if (field.getAnnotation(Id.class) != null) {
info.idField = field;
}
if (field.getType() == PropertyChangeSupport.class) {
info.propertyChangeSupportField = field;
}
if (field.getAnnotation(Dirty.class) != null) {
info.dirtyField = field;
try {
BeanInfo beanInfo = Introspector.getBeanInfo(clazz);
for (PropertyDescriptor pd : beanInfo.getPropertyDescriptors()) {
if (pd.getName().equals(info.dirtyField.getName())) {
info.dirtyPropertyDescriptor = pd;
break;
}
}
} catch (IntrospectionException e) {
LOGGER.error("{}", e);
}
}
if (info.disposeField != null && info.dirtyField != null && info.domainKeyField != null
&& info.domainDescriptionField != null && info.idField != null) {
break;
}
}
if (info.disposeField == null || info.domainKeyField == null || info.domainDescriptionField == null
|| info.idField == null) {
Class<?> superClass = clazz.getSuperclass();
if (superClass != null) {
applyFieldInfo(superClass, info);
}
}
} catch (SecurityException e) {
LOGGER.error("{}", e);
}
}
/**
* Applies all required field infos to the info object.
*
* @param clazz
* the clazz
* @param info
* the info
*/
private static void applyMethodInfo(Class<?> clazz, Info info) {
try {
for (Method method : clazz.getDeclaredMethods()) {
if (method.getAnnotation(Dispose.class) != null) {
info.disposeMethod = method;
break;
}
}
if (info.disposeMethod == null) {
Class<?> superClass = clazz.getSuperclass();
if (superClass != null) {
applyMethodInfo(superClass, info);
}
}
} catch (SecurityException e) {
LOGGER.error("{}", e);
}
}
/**
* Find field.
*
* @param clazz
* the clazz
* @param name
* the name
* @return the field
*/
protected Field findField(Class<?> clazz, String name) {
try {
Field field = clazz.getDeclaredField(name);
return field;
} catch (NoSuchFieldException e) {
Class<?> superClass = clazz.getSuperclass();
if (superClass != null) {
return findField(superClass, name);
}
} catch (SecurityException e) {
LOGGER.error("{}", e);
}
return null;
}
/**
* The Class Info.
*/
private static class Info {
/** The property change support field. */
private Field propertyChangeSupportField;
/** The dispose field. */
private Field disposeField;
/** The dispose method. */
private Method disposeMethod;
/** The id field. */
private Field idField;
/** The dirty field. */
private Field dirtyField;
/** The dirty property descriptor. */
private PropertyDescriptor dirtyPropertyDescriptor;
/** The domain key field. */
private Field domainKeyField;
/** The domain description field. */
private Field domainDescriptionField;
/**
* Gets the dispose field.
*
* @return the dispose field
*/
public Field getDisposeField() {
return disposeField;
}
/**
* Gets the dirty field.
*
* @return the dirty field
*/
public Field getDirtyField() {
return dirtyField;
}
/**
* Gets the dirty getter.
*
* @return the dirty getter
*/
public Method getDirtyGetter() {
return dirtyPropertyDescriptor != null ? dirtyPropertyDescriptor.getReadMethod() : null;
}
/**
* Gets the dirty setter.
*
* @return the dirty setter
*/
public Method getDirtySetter() {
return dirtyPropertyDescriptor != null ? dirtyPropertyDescriptor.getWriteMethod() : null;
}
/**
* Gets the dispose method.
*
* @return the dispose method
*/
public Method getDisposeMethod() {
return disposeMethod;
}
/**
* Gets the domain key field.
*
* @return the domain key field
*/
public Field getDomainKeyField() {
return domainKeyField;
}
/**
* Gets the domain description field.
*
* @return the domain description field
*/
public Field getDomainDescriptionField() {
return domainDescriptionField;
}
/**
* Gets the property change support field.
*
* @return the property change support field
*/
public Field getPropertyChangeSupportField() {
return propertyChangeSupportField;
}
public Field getIdField() {
return idField;
}
}
}