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 java.lang.reflect.*; 020 021import org.apache.juneau.cp.*; 022import org.apache.juneau.reflect.*; 023 024/** 025 * A wrapper around a {@link Method#invoke(Object, Object...)} method that allows for basic instrumentation. 026 */ 027public class MethodInvoker { 028 private final MethodInfo m; 029 private final MethodExecStats stats; 030 031 /** 032 * Constructor. 033 * 034 * @param m The method being wrapped. 035 * @param stats The instrumentor. 036 */ 037 public MethodInvoker(Method m, MethodExecStats stats) { 038 this.m = MethodInfo.of(m); 039 this.stats = stats; 040 } 041 042 /** 043 * Returns the inner method. 044 * 045 * @return The inner method. 046 */ 047 public MethodInfo inner() { 048 return m; 049 } 050 051 /** 052 * Invokes the underlying method. 053 * 054 * @param o The object the underlying method is invoked from. 055 * @param args The arguments used for the method call. 056 * @return The result of dispatching the method represented by this object on {@code obj} with parameters {@code args} 057 * @throws IllegalAccessException If method cannot be accessed. 058 * @throws IllegalArgumentException If wrong arguments were passed to method. 059 * @throws InvocationTargetException If method threw an exception. 060 */ 061 public Object invoke(Object o, Object...args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { 062 long startTime = System.nanoTime(); 063 stats.started(); 064 try { 065 return m.inner().invoke(o, args); 066 } catch (IllegalAccessException|IllegalArgumentException e) { 067 stats.error(e); 068 throw e; 069 } catch (InvocationTargetException e) { 070 stats.error(e.getTargetException()); 071 throw e; 072 } finally { 073 stats.finished(System.nanoTime() - startTime); 074 } 075 } 076 077 /** 078 * Invokes the wrapped method using parameters from the specified bean store. 079 * 080 * @param beanStore The bean store to use to resolve parameters. 081 * @param o The object to invoke the method on. 082 * @return The result of invoking the method. 083 * @throws IllegalAccessException If method cannot be accessed. 084 * @throws IllegalArgumentException If wrong arguments were passed to method. 085 * @throws InvocationTargetException If method threw an exception. 086 */ 087 public Object invoke(BeanStore beanStore, Object o) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { 088 if (beanStore.hasAllParams(m)) 089 return invoke(o, beanStore.getParams(m)); 090 throw new IllegalArgumentException("Could not find prerequisites to invoke method '"+getFullName()+"': "+beanStore.getMissingParams(m)); 091 } 092 093 /** 094 * Convenience method for calling <c>inner().getDeclaringClass()</c> 095 * 096 * @return The declaring class of the method. 097 */ 098 public ClassInfo getDeclaringClass() { 099 return m.getDeclaringClass(); 100 } 101 102 /** 103 * Convenience method for calling <c>inner().getName()</c> 104 * 105 * @return The name of the method. 106 */ 107 public String getFullName() { 108 return m.getFullName(); 109 } 110 111 /** 112 * Returns the stats of this method invoker. 113 * 114 * @return The stats of this method invoker. 115 */ 116 public MethodExecStats getStats() { 117 return stats; 118 } 119}