001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.juneau.rest.stats; 018 019import static org.apache.juneau.commons.utils.ThrowableUtils.*; 020 021import java.lang.reflect.*; 022 023import org.apache.juneau.commons.reflect.*; 024import org.apache.juneau.cp.*; 025 026/** 027 * A wrapper around a {@link Method#invoke(Object, Object...)} method that allows for basic instrumentation. 028 */ 029public class MethodInvoker { 030 private final MethodInfo m; 031 private final MethodExecStats stats; 032 033 /** 034 * Constructor. 035 * 036 * @param m The method being wrapped. 037 * @param stats The instrumentor. 038 */ 039 public MethodInvoker(Method m, MethodExecStats stats) { 040 this.m = MethodInfo.of(m); 041 this.stats = stats; 042 } 043 044 /** 045 * Convenience method for calling <c>inner().getDeclaringClass()</c> 046 * 047 * @return The declaring class of the method. 048 */ 049 public ClassInfo getDeclaringClass() { return m.getDeclaringClass(); } 050 051 /** 052 * Convenience method for calling <c>inner().getName()</c> 053 * 054 * @return The name of the method. 055 */ 056 public String getFullName() { return m.getFullName(); } 057 058 /** 059 * Returns the stats of this method invoker. 060 * 061 * @return The stats of this method invoker. 062 */ 063 public MethodExecStats getStats() { return stats; } 064 065 /** 066 * Returns the inner method. 067 * 068 * @return The inner method. 069 */ 070 public MethodInfo inner() { 071 return m; 072 } 073 074 /** 075 * Invokes the wrapped method using parameters from the specified bean store. 076 * 077 * @param beanStore The bean store to use to resolve parameters. 078 * @param o The object to invoke the method on. 079 * @return The result of invoking the method. 080 * @throws IllegalAccessException If method cannot be accessed. 081 * @throws IllegalArgumentException If wrong arguments were passed to method. 082 * @throws InvocationTargetException If method threw an exception. 083 */ 084 public Object invoke(BeanStore beanStore, Object o) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { 085 if (beanStore.hasAllParams(m)) 086 return invoke(o, beanStore.getParams(m)); 087 throw illegalArg("Could not find prerequisites to invoke method ''{0}'': {1}", getFullName(), beanStore.getMissingParams(m)); 088 } 089 090 /** 091 * Invokes the underlying method. 092 * 093 * @param o The object the underlying method is invoked from. 094 * @param args The arguments used for the method call. 095 * @return The result of dispatching the method represented by this object on {@code obj} with parameters {@code args} 096 * @throws IllegalAccessException If method cannot be accessed. 097 * @throws IllegalArgumentException If wrong arguments were passed to method. 098 * @throws InvocationTargetException If method threw an exception. 099 */ 100 public Object invoke(Object o, Object...args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { 101 long startTime = System.nanoTime(); 102 stats.started(); 103 try { 104 return m.inner().invoke(o, args); 105 } catch (IllegalAccessException | IllegalArgumentException e) { 106 stats.error(e); 107 throw e; 108 } catch (InvocationTargetException e) { 109 stats.error(e.getTargetException()); 110 throw e; 111 } finally { 112 stats.finished(System.nanoTime() - startTime); 113 } 114 } 115}