// // ======================================================================== // Copyright (c) 1995-2017 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 // and Apache License v2.0 which accompanies this distribution. // // The Eclipse Public License is available at // http://www.eclipse.org/legal/epl-v10.html // // The Apache License v2.0 is available at // http://www.opensource.org/licenses/apache2.0.php // // You may elect to redistribute this code under either of these licenses. // ======================================================================== // package org.eclipse.jetty.websocket.common.events.annotated; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Objects; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.websocket.common.util.ReflectUtils; /** * A Callable Method */ public class CallableMethod { private static final Logger LOG = Log.getLogger(CallableMethod.class); protected final Class<?> pojo; protected final Method method; protected Class<?>[] paramTypes; public CallableMethod(Class<?> pojo, Method method) { Objects.requireNonNull(pojo, "Pojo cannot be null"); Objects.requireNonNull(method, "Method cannot be null"); this.pojo = pojo; this.method = method; this.paramTypes = method.getParameterTypes(); } public Object call(Object obj, Object... args) { if ((this.pojo == null) || (this.method == null)) { LOG.warn("Cannot execute call: pojo={}, method={}",pojo,method); return null; // no call event method determined } if (obj == null) { String err = String.format("Cannot call %s on null object", this.method); LOG.warn(new RuntimeException(err)); return null; } if (args.length < paramTypes.length) { throw new IllegalArgumentException("Call arguments length [" + args.length + "] must always be greater than or equal to captured args length [" + paramTypes.length + "]"); } try { return this.method.invoke(obj,args); } catch (Throwable t) { String err = formatMethodCallError(args); throw unwrapRuntimeException(err,t); } } private RuntimeException unwrapRuntimeException(String err, final Throwable t) { Throwable ret = t; while (ret instanceof InvocationTargetException) { ret = ((InvocationTargetException)ret).getCause(); } if (ret instanceof RuntimeException) { return (RuntimeException)ret; } return new RuntimeException(err,ret); } public String formatMethodCallError(Object... args) { StringBuilder err = new StringBuilder(); err.append("Cannot call method "); err.append(ReflectUtils.toString(pojo,method)); err.append(" with args: ["); boolean delim = false; for (Object arg : args) { if (delim) { err.append(", "); } if (arg == null) { err.append("<null>"); } else { err.append(arg.getClass().getName()); } delim = true; } err.append("]"); return err.toString(); } public Method getMethod() { return method; } public Class<?>[] getParamTypes() { return paramTypes; } public Class<?> getPojo() { return pojo; } @Override public String toString() { return String.format("%s[%s]",this.getClass().getSimpleName(),method.toGenericString()); } }