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