View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
4   //  ------------------------------------------------------------------------
5   //  All rights reserved. This program and the accompanying materials
6   //  are made available under the terms of the Eclipse Public License v1.0
7   //  and Apache License v2.0 which accompanies this distribution.
8   //
9   //      The Eclipse Public License is available at
10  //      http://www.eclipse.org/legal/epl-v10.html
11  //
12  //      The Apache License v2.0 is available at
13  //      http://www.opensource.org/licenses/apache2.0.php
14  //
15  //  You may elect to redistribute this code under either of these licenses.
16  //  ========================================================================
17  //
18  
19  package org.eclipse.jetty.websocket.common.events.annotated;
20  
21  import java.lang.reflect.InvocationTargetException;
22  import java.lang.reflect.Method;
23  import java.util.Objects;
24  
25  import org.eclipse.jetty.util.log.Log;
26  import org.eclipse.jetty.util.log.Logger;
27  import org.eclipse.jetty.websocket.common.util.ReflectUtils;
28  
29  /**
30   * A Callable Method
31   */
32  public class CallableMethod
33  {
34      private static final Logger LOG = Log.getLogger(CallableMethod.class);
35      protected final Class<?> pojo;
36      protected final Method method;
37      protected Class<?>[] paramTypes;
38  
39      public CallableMethod(Class<?> pojo, Method method)
40      {
41          Objects.requireNonNull(pojo, "Pojo cannot be null");
42          Objects.requireNonNull(method, "Method cannot be null");
43          this.pojo = pojo;
44          this.method = method;
45          this.paramTypes = method.getParameterTypes();
46      }
47  
48      public Object call(Object obj, Object... args)
49      {
50          if ((this.pojo == null) || (this.method == null))
51          {
52              LOG.warn("Cannot execute call: pojo={}, method={}",pojo,method);
53              return null; // no call event method determined
54          }
55  
56          if (obj == null)
57          {
58              String err = String.format("Cannot call %s on null object", this.method);
59              LOG.warn(new RuntimeException(err));            
60              return null;
61          }
62  
63          if (args.length < paramTypes.length)
64          {
65              throw new IllegalArgumentException("Call arguments length [" + args.length + "] must always be greater than or equal to captured args length ["
66                      + paramTypes.length + "]");
67          }
68  
69          try
70          {
71              return this.method.invoke(obj,args);
72          }
73          catch (Throwable t)
74          {
75              String err = formatMethodCallError(args);
76              throw unwrapRuntimeException(err,t);
77          }
78      }
79  
80      private RuntimeException unwrapRuntimeException(String err, final Throwable t)
81      {
82          Throwable ret = t;
83  
84          while (ret instanceof InvocationTargetException)
85          {
86              ret = ((InvocationTargetException)ret).getCause();
87          }
88  
89          if (ret instanceof RuntimeException)
90          {
91              return (RuntimeException)ret;
92          }
93  
94          return new RuntimeException(err,ret);
95      }
96  
97      public String formatMethodCallError(Object... args)
98      {
99          StringBuilder err = new StringBuilder();
100         err.append("Cannot call method ");
101         err.append(ReflectUtils.toString(pojo,method));
102         err.append(" with args: [");
103 
104         boolean delim = false;
105         for (Object arg : args)
106         {
107             if (delim)
108             {
109                 err.append(", ");
110             }
111             if (arg == null)
112             {
113                 err.append("<null>");
114             }
115             else
116             {
117                 err.append(arg.getClass().getName());
118             }
119             delim = true;
120         }
121         err.append("]");
122         return err.toString();
123     }
124 
125     public Method getMethod()
126     {
127         return method;
128     }
129 
130     public Class<?>[] getParamTypes()
131     {
132         return paramTypes;
133     }
134 
135     public Class<?> getPojo()
136     {
137         return pojo;
138     }
139 
140     @Override
141     public String toString()
142     {
143         return String.format("%s[%s]",this.getClass().getSimpleName(),method.toGenericString());
144     }
145 }