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