/* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.hardware.camera2.dispatch; import android.hardware.camera2.utils.UncheckedThrow; import java.lang.reflect.Method; import java.util.concurrent.ConcurrentHashMap; import static com.android.internal.util.Preconditions.*; /** * Invoke a method on a dispatchable by its name (without knowing the {@code Method} ahead of time). * * @param destination dispatch type, methods will be looked up in the class of {@code T} */ public class MethodNameInvoker { private final Dispatchable mTarget; private final Class mTargetClass; private final ConcurrentHashMap mMethods = new ConcurrentHashMap<>(); /** * Create a new method name invoker. * * @param target destination dispatch type, invokes will be redirected to this dispatcher * @param targetClass destination dispatch class, the invoked methods will be from this class */ public MethodNameInvoker(Dispatchable target, Class targetClass) { mTargetClass = targetClass; mTarget = target; } /** * Invoke a method by its name. * *

If more than one method exists in {@code targetClass}, the first method with the right * number of arguments will be used, and later calls will all use that method.

* * @param methodName * The name of the method, which will be matched 1:1 to the destination method * @param params * Variadic parameter list. * @return * The same kind of value that would normally be returned by calling {@code methodName} * statically. * * @throws IllegalArgumentException if {@code methodName} does not exist on the target class * @throws Throwable will rethrow anything that the target method would normally throw */ @SuppressWarnings("unchecked") public K invoke(String methodName, Object... params) { checkNotNull(methodName, "methodName must not be null"); Method targetMethod = mMethods.get(methodName); if (targetMethod == null) { for (Method method : mTargetClass.getMethods()) { // TODO future: match types of params if possible if (method.getName().equals(methodName) && (params.length == method.getParameterTypes().length) ) { targetMethod = method; mMethods.put(methodName, targetMethod); break; } } if (targetMethod == null) { throw new IllegalArgumentException( "Method " + methodName + " does not exist on class " + mTargetClass); } } try { return (K) mTarget.dispatch(targetMethod, params); } catch (Throwable e) { UncheckedThrow.throwAnyException(e); // unreachable return null; } } }