001    /*
002    // This software is subject to the terms of the Common Public License
003    // Agreement, available at the following URL:
004    // http://www.opensource.org/licenses/cpl.html.
005    // Copyright (C) 2007-2007 Julian Hyde
006    // All Rights Reserved.
007    // You must accept the terms of that agreement to use this software.
008    */
009    package mondrian.util;
010    
011    import java.lang.reflect.*;
012    
013    /**
014     * A class derived from <code>DelegatingInvocationHandler</code> handles a
015     * method call by looking for a method in itself with identical parameters. If
016     * no such method is found, it forwards the call to a fallback object, which
017     * must implement all of the interfaces which this proxy implements.
018     *
019     * <p>It is useful in creating a wrapper class around an interface which may
020     * change over time.</p>
021     *
022     * <p>Example:
023     *
024     * <blockquote>
025     * <pre>import java.sql.Connection;
026     * Connection connection = ...;
027     * Connection tracingConnection = (Connection) Proxy.newProxyInstance(
028     *     null,
029     *     new Class[] {Connection.class},
030     *     new DelegatingInvocationHandler() {
031     *         protected Object getTarget() {
032     *             return connection;
033     *         }
034     *         Statement createStatement() {
035     *             System.out.println("statement created");
036     *             return connection.createStatement();
037     *         }
038     *     });</pre>
039     * </blockquote>
040     * </p>
041     *
042     * @author jhyde
043     * @version $Id: //open/mondrian/src/main/mondrian/util/DelegatingInvocationHandler.java#6 $
044     */
045    public abstract class DelegatingInvocationHandler
046        implements InvocationHandler
047    {
048        public Object invoke(
049            Object proxy,
050            Method method,
051            Object [] args)
052            throws Throwable
053        {
054            Class clazz = getClass();
055            Method matchingMethod;
056            try {
057                matchingMethod =
058                    clazz.getMethod(
059                        method.getName(),
060                        method.getParameterTypes());
061            } catch (NoSuchMethodException e) {
062                matchingMethod = null;
063            } catch (SecurityException e) {
064                matchingMethod = null;
065            }
066            try {
067                if (matchingMethod != null) {
068                    // Invoke the method in the derived class.
069                    return matchingMethod.invoke(this, args);
070                }
071                final Object target = getTarget();
072                if (target == null) {
073                    throw new UnsupportedOperationException(
074                        "method: " + method);
075                }
076                return method.invoke(
077                    target,
078                    args);
079            } catch (InvocationTargetException e) {
080                throw e.getTargetException();
081            }
082        }
083    
084        /**
085         * Returns the object to forward method calls to, should the derived class
086         * not implement the method. Generally, this object will be a member of the
087         * derived class, supplied as a parameter to its constructor.
088         *
089         * <p>The default implementation returns null, which will cause the
090         * {@link #invoke(Object, java.lang.reflect.Method, Object[])} method
091         * to throw an {@link UnsupportedOperationException} if the derived class
092         * does not have the required method.
093         *
094         * @return object to forward method calls to
095         */
096        protected Object getTarget() {
097            return null;
098        }
099    }
100    
101    // End DelegatingInvocationHandler.java