001: /*
002: * The contents of this file are subject to the Sapient Public License
003: * Version 1.0 (the "License"); you may not use this file except in compliance
004: * with the License. You may obtain a copy of the License at
005: * http://carbon.sf.net/License.html.
006: *
007: * Software distributed under the License is distributed on an "AS IS" basis,
008: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
009: * the specific language governing rights and limitations under the License.
010: *
011: * The Original Code is The Carbon Component Framework.
012: *
013: * The Initial Developer of the Original Code is Sapient Corporation
014: *
015: * Copyright (C) 2003 Sapient Corporation. All Rights Reserved.
016: */
017:
018: package org.sape.carbon.core.util.reflection;
019:
020: import java.lang.reflect.InvocationHandler;
021: import java.lang.reflect.Method;
022:
023: /**
024: * <p>This generic implementation of a <code>DynamicProxy</code>
025: * invocation handler will provide the basics of object method handling
026: * for the methods hashCode, equals and toString. Any other method calls
027: * will be forwarded to subclasses for implementation.
028: * </p>
029: *
030: * <P>Invocation handlers wishing to provide specialized implementations of
031: * the follow methods: { hashCode, toString, equals} should override those
032: * versions of the methods defined in this class that start with the
033: * key <code>proxy</code>.
034: *
035: * Copyright 2002 Sapient
036: * @author Greg Hinkle, December 2001
037: * @version $Revision: 1.3 $($Author: dvoet $ / $Date: 2003/05/05 21:21:23 $)
038: */
039: public abstract class GenericProxy implements InvocationHandler {
040:
041: /** Preloaded Method object for the hashCode method of java.lang.Object */
042: private static Method hashCodeMethod;
043:
044: /** Preloaded Method object for the equals method of java.lang.Object */
045: private static Method equalsMethod;
046:
047: /** Preloaded Method object for the toString method of java.lang.Object */
048: private static Method toStringMethod;
049:
050: // Statically load the Method objects for the basic java.lang.Object
051: // methods.
052: static {
053: try {
054: hashCodeMethod = Object.class.getMethod("hashCode", null);
055: equalsMethod = Object.class.getMethod("equals",
056: new Class[] { Object.class });
057: toStringMethod = Object.class.getMethod("toString", null);
058: } catch (NoSuchMethodException e) {
059: throw new NoSuchMethodError(e.getMessage());
060: }
061: }
062:
063: /**
064: * This method is called through by the JVM generated
065: * DynamicProxy for all calls to the represented object.
066: * This method then manages delegating those calls the
067: * appropriate implementation. This implementation
068: * specially handles the default <code>Object</code>
069: * class methods and forwards all other method calls to
070: * the abstract <code>handleInvoke</code> method.
071: * @param proxy the object that is being represented
072: * @param m the method descriptor for the method called
073: * @param args an array of arguments passed to that method
074: * @throws java.lang.Throwable when there is an exception thrown from the
075: * delegated method. This may be a Checked
076: * exception if the implemented interface declares
077: * the exception. Otherwise checked exceptions will
078: * be automatically wrapped in an
079: * <code>UndeclaredThrowableException</code>.
080: * Runtime exceptions are thrown as is.
081: * @return the return value of the delegated method.
082: */
083: public Object invoke(Object proxy, Method m, Object[] args)
084: throws Throwable {
085: Class declaringClass = m.getDeclaringClass();
086:
087: if (declaringClass == Object.class) {
088: if (m.equals(hashCodeMethod)) {
089: return proxyHashCode(proxy);
090: } else if (m.equals(equalsMethod)) {
091: return proxyEquals(proxy, args[0]);
092: } else if (m.equals(toStringMethod)) {
093: return proxyToString(proxy);
094: } else {
095: throw new InternalError(
096: "unexpected Object method dispatched: " + m);
097: }
098: } else {
099: return handleInvoke(proxy, m, args);
100: }
101: }
102:
103: /**
104: * This abstract method should be implemented to handle the specific
105: * functionality for an invocation handler.
106: *
107: * @param proxy the object that is being represented
108: * @param m the method descriptor for the method called
109: * @param args an array of arguments passed to that method
110: * @throws java.lang.Throwable when there is an exception thrown from the
111: * delegated method. This may be a Checked
112: * exception if the implemented interface declares
113: * the exception. Otherwise checked exceptions will
114: * be automatically wrapped in an
115: * <code>UndeclaredThrowableException</code>.
116: * Runtime exceptions are thrown as is.
117: * @return the return value of the delegated method.
118: */
119: protected abstract Object handleInvoke(Object proxy, Method m,
120: Object[] args) throws Throwable;
121:
122: /**
123: * Implements the standard hashCode method with a
124: * simple call to System.identityHashCode().
125: * @param proxy the object for which a hashcode should
126: * be returned
127: * @return the hash code of the provided object
128: */
129: protected Integer proxyHashCode(Object proxy) {
130: return new Integer(System.identityHashCode(proxy));
131: }
132:
133: /**
134: * This method implements the standard proxyEquals
135: * method for subclassed invocation handler
136: * dynamic proxies.
137: * @param proxy the proxy object for which equals is
138: * being handled
139: * @param other the other object being compared too
140: * @return true if they are symantically equal,
141: * false otherwise
142: */
143: protected Boolean proxyEquals(Object proxy, Object other) {
144: return (proxy == other ? Boolean.TRUE : Boolean.FALSE);
145: }
146:
147: /**
148: * Prints out a string representation of the proxy object in the
149: * standard Java Object toString format of
150: * <classname>@<hashcode>
151: *
152: * @param proxy the proxy object to toString
153: * @return the String representation of the proxy object
154: */
155: protected String proxyToString(Object proxy) {
156: return proxy.getClass().getName() + '@'
157: + Integer.toHexString(proxy.hashCode());
158: }
159: }
|