19730f15ebbf4b64cd48e0777850e56cb516a9ed4Hugo Hudson/* 29730f15ebbf4b64cd48e0777850e56cb516a9ed4Hugo Hudson * Copyright (C) 2011 The Android Open Source Project 39730f15ebbf4b64cd48e0777850e56cb516a9ed4Hugo Hudson * 49730f15ebbf4b64cd48e0777850e56cb516a9ed4Hugo Hudson * Licensed under the Apache License, Version 2.0 (the "License"); 59730f15ebbf4b64cd48e0777850e56cb516a9ed4Hugo Hudson * you may not use this file except in compliance with the License. 69730f15ebbf4b64cd48e0777850e56cb516a9ed4Hugo Hudson * You may obtain a copy of the License at 79730f15ebbf4b64cd48e0777850e56cb516a9ed4Hugo Hudson * 89730f15ebbf4b64cd48e0777850e56cb516a9ed4Hugo Hudson * http://www.apache.org/licenses/LICENSE-2.0 99730f15ebbf4b64cd48e0777850e56cb516a9ed4Hugo Hudson * 109730f15ebbf4b64cd48e0777850e56cb516a9ed4Hugo Hudson * Unless required by applicable law or agreed to in writing, software 119730f15ebbf4b64cd48e0777850e56cb516a9ed4Hugo Hudson * distributed under the License is distributed on an "AS IS" BASIS, 129730f15ebbf4b64cd48e0777850e56cb516a9ed4Hugo Hudson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139730f15ebbf4b64cd48e0777850e56cb516a9ed4Hugo Hudson * See the License for the specific language governing permissions and 149730f15ebbf4b64cd48e0777850e56cb516a9ed4Hugo Hudson * limitations under the License. 159730f15ebbf4b64cd48e0777850e56cb516a9ed4Hugo Hudson */ 169730f15ebbf4b64cd48e0777850e56cb516a9ed4Hugo Hudson 179730f15ebbf4b64cd48e0777850e56cb516a9ed4Hugo Hudsonpackage com.android.ex.variablespeed; 189730f15ebbf4b64cd48e0777850e56cb516a9ed4Hugo Hudson 199730f15ebbf4b64cd48e0777850e56cb516a9ed4Hugo Hudsonimport java.lang.reflect.InvocationHandler; 209730f15ebbf4b64cd48e0777850e56cb516a9ed4Hugo Hudsonimport java.lang.reflect.InvocationTargetException; 219730f15ebbf4b64cd48e0777850e56cb516a9ed4Hugo Hudsonimport java.lang.reflect.Method; 229730f15ebbf4b64cd48e0777850e56cb516a9ed4Hugo Hudsonimport java.lang.reflect.Proxy; 239730f15ebbf4b64cd48e0777850e56cb516a9ed4Hugo Hudson 249730f15ebbf4b64cd48e0777850e56cb516a9ed4Hugo Hudson/** 259730f15ebbf4b64cd48e0777850e56cb516a9ed4Hugo Hudson * Contains a utility method for adapting a given interface against a real implementation. 269730f15ebbf4b64cd48e0777850e56cb516a9ed4Hugo Hudson * <p> 279730f15ebbf4b64cd48e0777850e56cb516a9ed4Hugo Hudson * This class is thead-safe. 289730f15ebbf4b64cd48e0777850e56cb516a9ed4Hugo Hudson */ 299730f15ebbf4b64cd48e0777850e56cb516a9ed4Hugo Hudsonpublic class DynamicProxy { 309730f15ebbf4b64cd48e0777850e56cb516a9ed4Hugo Hudson /** 319730f15ebbf4b64cd48e0777850e56cb516a9ed4Hugo Hudson * Dynamically adapts a given interface against a delegate object. 329730f15ebbf4b64cd48e0777850e56cb516a9ed4Hugo Hudson * <p> 339730f15ebbf4b64cd48e0777850e56cb516a9ed4Hugo Hudson * For the given {@code clazz} object, which should be an interface, we return a new dynamic 349730f15ebbf4b64cd48e0777850e56cb516a9ed4Hugo Hudson * proxy object implementing that interface, which will forward all method calls made on the 359730f15ebbf4b64cd48e0777850e56cb516a9ed4Hugo Hudson * interface onto the delegate object. 369730f15ebbf4b64cd48e0777850e56cb516a9ed4Hugo Hudson * <p> 379730f15ebbf4b64cd48e0777850e56cb516a9ed4Hugo Hudson * In practice this means that you can make it appear as though {@code delegate} implements the 389730f15ebbf4b64cd48e0777850e56cb516a9ed4Hugo Hudson * {@code clazz} interface, without this in practice being the case. As an example, if you 399730f15ebbf4b64cd48e0777850e56cb516a9ed4Hugo Hudson * create an interface representing the {@link android.media.MediaPlayer}, you could pass this 409730f15ebbf4b64cd48e0777850e56cb516a9ed4Hugo Hudson * interface in as the first argument, and a real {@link android.media.MediaPlayer} in as the 419730f15ebbf4b64cd48e0777850e56cb516a9ed4Hugo Hudson * second argument, and now calls to the interface will be automatically sent on to the real 429730f15ebbf4b64cd48e0777850e56cb516a9ed4Hugo Hudson * media player. The reason you may be interested in doing this in the first place is that this 439730f15ebbf4b64cd48e0777850e56cb516a9ed4Hugo Hudson * allows you to test classes that have dependencies that are final or cannot be easily mocked. 449730f15ebbf4b64cd48e0777850e56cb516a9ed4Hugo Hudson */ 459730f15ebbf4b64cd48e0777850e56cb516a9ed4Hugo Hudson // This is safe, because we know that proxy instance implements the interface. 469730f15ebbf4b64cd48e0777850e56cb516a9ed4Hugo Hudson @SuppressWarnings("unchecked") 479730f15ebbf4b64cd48e0777850e56cb516a9ed4Hugo Hudson public static <T> T dynamicProxy(Class<T> clazz, final Object delegate) { 489730f15ebbf4b64cd48e0777850e56cb516a9ed4Hugo Hudson InvocationHandler invoke = new InvocationHandler() { 499730f15ebbf4b64cd48e0777850e56cb516a9ed4Hugo Hudson @Override 509730f15ebbf4b64cd48e0777850e56cb516a9ed4Hugo Hudson public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 519730f15ebbf4b64cd48e0777850e56cb516a9ed4Hugo Hudson try { 529730f15ebbf4b64cd48e0777850e56cb516a9ed4Hugo Hudson return delegate.getClass() 539730f15ebbf4b64cd48e0777850e56cb516a9ed4Hugo Hudson .getMethod(method.getName(), method.getParameterTypes()) 549730f15ebbf4b64cd48e0777850e56cb516a9ed4Hugo Hudson .invoke(delegate, args); 559730f15ebbf4b64cd48e0777850e56cb516a9ed4Hugo Hudson } catch (InvocationTargetException e) { 569730f15ebbf4b64cd48e0777850e56cb516a9ed4Hugo Hudson throw e.getCause(); 579730f15ebbf4b64cd48e0777850e56cb516a9ed4Hugo Hudson } 589730f15ebbf4b64cd48e0777850e56cb516a9ed4Hugo Hudson } 599730f15ebbf4b64cd48e0777850e56cb516a9ed4Hugo Hudson }; 609730f15ebbf4b64cd48e0777850e56cb516a9ed4Hugo Hudson return (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class<?>[] { clazz }, invoke); 619730f15ebbf4b64cd48e0777850e56cb516a9ed4Hugo Hudson } 629730f15ebbf4b64cd48e0777850e56cb516a9ed4Hugo Hudson} 63