/*******************************************************************************
* Copyright (C) 2011 by Harry Blauberg
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
package org.jaml.util;
import java.lang.reflect.Method;
import org.jaml.api.IDelegate;
import org.jaml.exceptions.DelegateException;
import org.jaml.exceptions.DelegateInvalidException;
/**
* Implementation of the IDelegate interface
*
* @param <T>
* Class of the method owner
* @param <P>
* Parameter of the targeted method
*/
public class Delegate<T, P> implements IDelegate<T, P> {
private T object;
private Class<?> objectClass;
private String methodName;
private Class<P> paramClass;
private Method method;
public static <T, P> IDelegate<T, P> create(T object, String methodName,
Class<P> paramClass) {
return new Delegate<T, P>(object, methodName, paramClass);
}
public static <T, P> IDelegate<T, P> create(Class<T> objectClass,
String methodName, Class<P> paramClass) {
return new Delegate<T, P>(objectClass, methodName, paramClass);
}
private Delegate(T object, Class<T> objectClass, String methodName,
Class<P> paramClass) {
this.object = object;
this.objectClass = object == null ? objectClass : object.getClass();
this.methodName = methodName;
this.paramClass = paramClass;
}
public Delegate(T object, String methodName, Class<P> paramClass) {
this(object, null, methodName, paramClass);
}
public Delegate(Class<T> objectClass, String methodName, Class<P> paramClass) {
this(null, objectClass, methodName, paramClass);
}
@Override
public boolean isValid() {
method = method == null ? searchMethod(paramClass) : method;
method = method == null ? searchMethod() : method;
return method != null;
}
private Method findMethod(Class<P> paramClass) throws Exception {
for (Method method : objectClass.getDeclaredMethods()) {
if (method.getName().equalsIgnoreCase(methodName)
&& ((paramClass == null) || (method.getParameterTypes().length > 0 && paramClass
.equals(method.getParameterTypes()[0])))) {
method.setAccessible(true);
return method;
}
}
return paramClass == null ? objectClass.getMethod(methodName)
: objectClass.getMethod(methodName, paramClass);
}
private Method searchMethod(Class<P> paramClass) {
try {
return findMethod(paramClass);
} catch (Exception e) {
return null;
}
}
private Method searchMethod() {
try {
Method method = findMethod(null);
return method.getReturnType().equals(paramClass) ? method : null;
} catch (Exception e) {
return null;
}
}
@Override
public void invoke(P value) {
if (isValid()) {
try {
method.invoke(object, value);
return;
} catch (Exception exception) {
throw new DelegateException(objectClass, method, value,
exception);
}
}
throw new DelegateInvalidException(objectClass, methodName);
}
@SuppressWarnings("unchecked")
@Override
public P invoke() {
if (isValid()) {
try {
return (P) method.invoke(object);
} catch (Exception exception) {
throw new DelegateException(objectClass, method, object,
exception);
}
}
throw new DelegateInvalidException(objectClass, methodName);
}
@Override
public boolean needsParameter() {
return method != null ? method.getParameterTypes().length > 0 : false;
}
@Override
public String toString() {
return String.format(
"Delegate of class '%s' --> %s",
objectClass.getName(),
method == null ? String.format(
"should be method %s of type %s!", methodName,
paramClass.getName()) : method);
}
}