1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package android.hardware.camera2.dispatch; 17 18 import android.hardware.camera2.utils.UncheckedThrow; 19 20 import java.lang.reflect.Method; 21 import java.util.concurrent.ConcurrentHashMap; 22 23 import static com.android.internal.util.Preconditions.*; 24 25 /** 26 * Invoke a method on a dispatchable by its name (without knowing the {@code Method} ahead of time). 27 * 28 * @param <T> destination dispatch type, methods will be looked up in the class of {@code T} 29 */ 30 public class MethodNameInvoker<T> { 31 32 private final Dispatchable<T> mTarget; 33 private final Class<T> mTargetClass; 34 private final ConcurrentHashMap<String, Method> mMethods = 35 new ConcurrentHashMap<>(); 36 37 /** 38 * Create a new method name invoker. 39 * 40 * @param target destination dispatch type, invokes will be redirected to this dispatcher 41 * @param targetClass destination dispatch class, the invoked methods will be from this class 42 */ 43 public MethodNameInvoker(Dispatchable<T> target, Class<T> targetClass) { 44 mTargetClass = targetClass; 45 mTarget = target; 46 } 47 48 /** 49 * Invoke a method by its name. 50 * 51 * <p>If more than one method exists in {@code targetClass}, the first method with the right 52 * number of arguments will be used, and later calls will all use that method.</p> 53 * 54 * @param methodName 55 * The name of the method, which will be matched 1:1 to the destination method 56 * @param params 57 * Variadic parameter list. 58 * @return 59 * The same kind of value that would normally be returned by calling {@code methodName} 60 * statically. 61 * 62 * @throws IllegalArgumentException if {@code methodName} does not exist on the target class 63 * @throws Throwable will rethrow anything that the target method would normally throw 64 */ 65 @SuppressWarnings("unchecked") 66 public <K> K invoke(String methodName, Object... params) { 67 checkNotNull(methodName, "methodName must not be null"); 68 69 Method targetMethod = mMethods.get(methodName); 70 if (targetMethod == null) { 71 for (Method method : mTargetClass.getMethods()) { 72 // TODO future: match types of params if possible 73 if (method.getName().equals(methodName) && 74 (params.length == method.getParameterTypes().length) ) { 75 targetMethod = method; 76 mMethods.put(methodName, targetMethod); 77 break; 78 } 79 } 80 81 if (targetMethod == null) { 82 throw new IllegalArgumentException( 83 "Method " + methodName + " does not exist on class " + mTargetClass); 84 } 85 } 86 87 try { 88 return (K) mTarget.dispatch(targetMethod, params); 89 } catch (Throwable e) { 90 UncheckedThrow.throwAnyException(e); 91 // unreachable 92 return null; 93 } 94 } 95 } 96