[jboss-svn-commits] JBoss Common SVN: r4212 - invokablecontainer/trunk/api/src/main/java/org/jboss/invokable.

jboss-svn-commits at lists.jboss.org jboss-svn-commits at lists.jboss.org
Wed Mar 31 23:08:39 EDT 2010


Author: david.lloyd at jboss.com
Date: 2010-03-31 23:08:38 -0400 (Wed, 31 Mar 2010)
New Revision: 4212

Added:
   invokablecontainer/trunk/api/src/main/java/org/jboss/invokable/InvocationProcessorFactory.java
   invokablecontainer/trunk/api/src/main/java/org/jboss/invokable/InvocationProcessors.java
   invokablecontainer/trunk/api/src/main/java/org/jboss/invokable/MethodIdentifier.java
Modified:
   invokablecontainer/trunk/api/src/main/java/org/jboss/invokable/Invocation.java
   invokablecontainer/trunk/api/src/main/java/org/jboss/invokable/InvocationProperties.java
   invokablecontainer/trunk/api/src/main/java/org/jboss/invokable/InvocationReply.java
   invokablecontainer/trunk/api/src/main/java/org/jboss/invokable/Keys.java
   invokablecontainer/trunk/api/src/main/java/org/jboss/invokable/ProcessingInvocationDispatcher.java
   invokablecontainer/trunk/api/src/main/java/org/jboss/invokable/ProxyInvocationHandler.java
Log:
More changes: add method identifier type which can be used as a hash key; invocation processor factory for assembly of interceptor chains

Modified: invokablecontainer/trunk/api/src/main/java/org/jboss/invokable/Invocation.java
===================================================================
--- invokablecontainer/trunk/api/src/main/java/org/jboss/invokable/Invocation.java	2010-03-30 21:51:51 UTC (rev 4211)
+++ invokablecontainer/trunk/api/src/main/java/org/jboss/invokable/Invocation.java	2010-04-01 03:08:38 UTC (rev 4212)
@@ -43,75 +43,128 @@
     /**
      * This field contains the method-call arguments.
      */
-    private transient final Object[] args;
-
+    private final Object[] args;
     /**
-     * This field specifies the target method.
+     * This field contains the declaring class of the method that was invoked.
      */
-    private transient final Method targetMethod;
-
+    private final Class<?> declaringClass;
     /**
-     * This field contains the invocation context.  As a special case, if the context is empty at serialization
+     * This field contains the identifier of the method which was invoked.
+     */
+    private final MethodIdentifier methodIdentifier;
+    /**
+     * This field contains the invocation properties.  As a special case, if the properties is empty at serialization
      * time, it is written as {@code null} to conserve bandwidth.
      */
     private transient volatile InvocationProperties properties;
+    /**
+     * This field contains the target method of the invocation.
+     */
+    private transient final Method targetMethod;
 
     private static final Object[] NO_OBJECTS = new Object[0];
-    private static final Class<?>[] NO_CLASSES = new Class[0];
 
-    private static final FieldSetter<Invocation> argsSetter = FieldSetter.forField(Invocation.class, "args");
     private static final FieldSetter<Invocation> targetMethodSetter = FieldSetter.forField(Invocation.class, "targetMethod");
-    private static final FieldSetter<Invocation> propertiesSetter = FieldSetter.forField(Invocation.class, "properties");
 
+    private Invocation(final InvocationProperties properties, final Class<?> declaringClass, final MethodIdentifier methodIdentifier, final Method targetMethod, final Object[] args) {
+        if (declaringClass == null) {
+            throw new IllegalArgumentException("declaringClass is null");
+        }
+        if (methodIdentifier == null) {
+            throw new IllegalArgumentException("methodIdentifier is null");
+        }
+        this.args = defaulted(args, NO_OBJECTS);
+        this.declaringClass = declaringClass;
+        this.methodIdentifier = methodIdentifier;
+        this.properties = defaulted(properties, InvocationProperties.EMPTY);
+        this.targetMethod = targetMethod;
+    }
+
+    private static Method methodFor(MethodIdentifier methodIdentifier, Class<?> declaringClass) throws IllegalArgumentException {
+        try {
+            return methodIdentifier.getPublicMethod(declaringClass);
+        } catch (NoSuchMethodException e) {
+            throw new IllegalArgumentException("Cannot find " + methodIdentifier + " on " + declaringClass);
+        }
+    }
+
     /**
      * Construct a new instance.
      *
-     * @param properties the invocation context to use
-     * @param targetMethod the method being invoked
-     * @param args the arguments
+     * @param properties the initial invocation properties
+     * @param declaringClass the declaring class of the invoked method
+     * @param methodIdentifier the identifier of the invoked method
+     * @param args the arguments of the original invocation
      */
-    public Invocation(final InvocationProperties properties, final Method targetMethod, final Object... args) {
-        if (targetMethod == null) {
-            throw new IllegalArgumentException("targetMethod is null");
-        }
-        this.targetMethod = targetMethod;
-        this.args = defaulted(args, NO_OBJECTS);
-        this.properties = defaulted(properties, InvocationProperties.EMPTY);
+    public Invocation(final InvocationProperties properties, final Class<?> declaringClass, final MethodIdentifier methodIdentifier, final Object... args) {
+        this(properties, declaringClass, methodIdentifier, methodFor(methodIdentifier, declaringClass), args);
     }
 
     /**
      * Construct a new instance.
      *
-     * @param targetMethod the method being invoked
-     * @param args the arguments
+     * @param declaringClass the declaring class of the invoked method
+     * @param methodIdentifier the identifier of the invoked method
+     * @param args the arguments of the original invocation
      */
-    public Invocation(final Method targetMethod, final Object... args) {
-        this(InvocationProperties.EMPTY, targetMethod, args);
+    public Invocation(final Class<?> declaringClass, final MethodIdentifier methodIdentifier, final Object... args) {
+        this(null, declaringClass, methodIdentifier, (Object[]) args);
     }
 
     /**
      * Construct a new instance with no arguments.
      *
-     * @param targetMethod the method being invoked
+     * @param declaringClass the declaring class of the invoked method
+     * @param methodIdentifier the identifier of the invoked method
      */
-    public Invocation(final Method targetMethod) {
-        this(InvocationProperties.EMPTY, targetMethod, NO_OBJECTS);
+    public Invocation(final Class<?> declaringClass, final MethodIdentifier methodIdentifier) {
+        this(null, declaringClass, methodIdentifier, (Object[]) null);
     }
 
+    /**
+     * Construct a new instance.
+     *
+     * @param properties the initial invocation properties
+     * @param method the method which was invoked
+     * @param args the arguments of the original invocation
+     */
+    public Invocation(final InvocationProperties properties, final Method method, final Object... args) {
+        this(properties, method.getDeclaringClass(), MethodIdentifier.getIdentifierForMethod(method), method, args);
+    }
+
+    /**
+     * Construct a new instance.
+     *
+     * @param method the method which was invoked
+     * @param args the arguments of the original invocation
+     */
+    public Invocation(final Method method, final Object... args) {
+        this(null, method.getDeclaringClass(), MethodIdentifier.getIdentifierForMethod(method), method, args);
+    }
+
     //-------------------------------------------------------------------------------------||
     // Contracts --------------------------------------------------------------------------||
     //-------------------------------------------------------------------------------------||
 
     /**
-     * Obtains the target method requested of the invocation.
+     * Get the declaring class of the method which was invoked.
      *
-     * @return the target method
+     * @return the declaring class
      */
-    public Method getTargetMethod() {
-        return targetMethod;
+    public Class<?> getDeclaringClass() {
+        return declaringClass;
     }
 
     /**
+     * Get the identifier of the method which was invoked.
+     *
+     * @return the identifier
+     */
+    public MethodIdentifier getMethodIdentifier() {
+        return methodIdentifier;
+    }
+
+    /**
      * Returns the arguments to be passed along to this method invocation
      *
      * @return the method call arguments
@@ -139,48 +192,66 @@
         this.properties = properties;
     }
 
+    /**
+     * Get the target method which was invoked upon.
+     *
+     * @return the target method
+     */
+    public Method getTargetMethod() {
+        return targetMethod;
+    }
+
+    /**
+     * Get a string representation of this object.
+     *
+     * @return the string
+     */
+    public String toString() {
+        final StringBuilder b = new StringBuilder();
+        b.append("Invocation of ").append(methodIdentifier.toString()).append(" of ").append(declaringClass);
+        b.append(" with arguments (");
+        for (int i = 0; i < args.length; i++) {
+            b.append(args[i]);
+            if (i < args.length - 1) {
+                b.append(',');
+            }
+        }
+        b.append(')');
+        return b.toString();
+    }
+
     //-------------------------------------------------------------------------------------||
     // Serialization ----------------------------------------------------------------------||
     //-------------------------------------------------------------------------------------||
 
     private void writeObject(ObjectOutputStream oos) throws IOException {
         oos.defaultWriteObject();
-        final Method targetMethod = this.targetMethod;
-        oos.writeObject(targetMethod.getDeclaringClass());
-        oos.writeUTF(targetMethod.getName());
-        final Class<?>[] parameterTypes = targetMethod.getParameterTypes();
-        oos.writeObject(parameterTypes.length == 0 ? null : parameterTypes);
-        final Object[] args = this.args;
-        oos.writeObject(args.length == 0 ? null : args);
         final InvocationProperties properties = this.properties;
         oos.writeObject(properties.isEmpty() ? null : properties);
     }
 
     private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
         ois.defaultReadObject();
-        final Class<?> declaringClass = nonNull((Class<?>) ois.readObject());
-        final String name = ois.readUTF();
-        final Class<?>[] parameterTypes = defaulted((Class<?>[]) ois.readObject(), NO_CLASSES);
-        final Method targetMethod;
+        if (properties == null) {
+            throw new InvalidObjectException("properties is null");
+        }
+        if (args == null) {
+            throw new InvalidObjectException("args is null");
+        }
+        if (methodIdentifier == null) {
+            throw new InvalidObjectException("methodIdentifier is null");
+        }
+        if (declaringClass == null) {
+            throw new InvalidObjectException("declaringClass is null");
+        }
+        properties = defaulted((InvocationProperties) ois.readObject(), InvocationProperties.EMPTY);
         try {
-            targetMethod = declaringClass.getMethod(name, parameterTypes);
+            targetMethodSetter.set(this, methodIdentifier.getPublicMethod(declaringClass));
         } catch (NoSuchMethodException e) {
-            throw new InvalidObjectException("Invocation references a missing method");
+            throw new InvalidObjectException("Cannot find " + methodIdentifier + " on " + declaringClass);
         }
-        targetMethodSetter.set(this, targetMethod);
-        final Object[] args = defaulted((Object[]) ois.readObject(), NO_OBJECTS);
-        argsSetter.set(this, args);
-        final InvocationProperties properties = defaulted((InvocationProperties) ois.readObject(), InvocationProperties.EMPTY);
-        propertiesSetter.set(this, properties);
     }
 
-    private static <T> T nonNull(T value) throws InvalidObjectException {
-        if (value == null) {
-            throw new InvalidObjectException("unexpected null value");
-        }
-        return value;
-    }
-
     private static <T> T defaulted(T value, T defaultValue) {
         return value == null ? defaultValue : value;
     }

Added: invokablecontainer/trunk/api/src/main/java/org/jboss/invokable/InvocationProcessorFactory.java
===================================================================
--- invokablecontainer/trunk/api/src/main/java/org/jboss/invokable/InvocationProcessorFactory.java	                        (rev 0)
+++ invokablecontainer/trunk/api/src/main/java/org/jboss/invokable/InvocationProcessorFactory.java	2010-04-01 03:08:38 UTC (rev 4212)
@@ -0,0 +1,39 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.jboss.invokable;
+
+/**
+ * A factory for invocation processors, used for assembling interceptor chains.
+ *
+ * @author <a href="mailto:david.lloyd at redhat.com">David M. Lloyd</a>
+ */
+public interface InvocationProcessorFactory {
+
+    /**
+     * Create an invocation processor.
+     *
+     * @param next the next-in-line processor
+     * @return the new invocation processor
+     */
+    InvocationProcessor createProcessor(InvocationProcessor next);
+}

Added: invokablecontainer/trunk/api/src/main/java/org/jboss/invokable/InvocationProcessors.java
===================================================================
--- invokablecontainer/trunk/api/src/main/java/org/jboss/invokable/InvocationProcessors.java	                        (rev 0)
+++ invokablecontainer/trunk/api/src/main/java/org/jboss/invokable/InvocationProcessors.java	2010-04-01 03:08:38 UTC (rev 4212)
@@ -0,0 +1,85 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.jboss.invokable;
+
+import java.util.Iterator;
+
+/**
+ * Invocation processor utilities.
+ *
+ * @author <a href="mailto:david.lloyd at redhat.com">David M. Lloyd</a>
+ */
+public final class InvocationProcessors {
+
+    private InvocationProcessors() {
+    }
+
+    /**
+     * Create an invocation processor chain from a collection of factories.  The last processor in the chain is always
+     * {@link org.jboss.invokable.InvocationProcessor#DISPATCHING}, and need not be specified.
+     *
+     * @param factories the factories
+     * @return the invocation processor
+     */
+    public static InvocationProcessor createInvocationProcessor(final Iterable<InvocationProcessorFactory> factories) {
+        return createInvocationProcessor(factories.iterator());
+    }
+
+    /**
+     * Create an invocation processor chain from a collection of factories.
+     *
+     * @param factories the factories
+     * @param last the last processor in the chain
+     * @return the invocation processor
+     */
+    public static InvocationProcessor createInvocationProcessor(final Iterable<InvocationProcessorFactory> factories, final InvocationProcessor last) {
+        return createInvocationProcessor(factories.iterator(), last);
+    }
+
+    /**
+     * Create an invocation processor chain from an iterator of factories.  The last processor in the chain is always
+     * {@link org.jboss.invokable.InvocationProcessor#DISPATCHING}, and need not be specified.
+     *
+     * @param factories the factories
+     * @return the invocation processor
+     */
+    public static InvocationProcessor createInvocationProcessor(final Iterator<InvocationProcessorFactory> factories) {
+        return createInvocationProcessor(factories, InvocationProcessor.DISPATCHING);
+    }
+
+    /**
+     * Create an invocation processor chain from an iterator of factories.
+     *
+     * @param factories the factories
+     * @param last the last dispatcher in the chain
+     * @return the invocation processor
+     */
+    public static InvocationProcessor createInvocationProcessor(final Iterator<InvocationProcessorFactory> factories, final InvocationProcessor last) {
+        if (factories.hasNext()) {
+            final InvocationProcessorFactory factory = factories.next();
+            return factory.createProcessor(createInvocationProcessor(factories, last));
+        } else {
+            return last;
+        }
+    }
+}

Modified: invokablecontainer/trunk/api/src/main/java/org/jboss/invokable/InvocationProperties.java
===================================================================
--- invokablecontainer/trunk/api/src/main/java/org/jboss/invokable/InvocationProperties.java	2010-03-30 21:51:51 UTC (rev 4211)
+++ invokablecontainer/trunk/api/src/main/java/org/jboss/invokable/InvocationProperties.java	2010-04-01 03:08:38 UTC (rev 4212)
@@ -54,12 +54,13 @@
     private InvocationProperties(final Map<Object, Object> backingMap) {
         this.backingMap = backingMap;
     }
+
     //-------------------------------------------------------------------------------------||
     // Contracts --------------------------------------------------------------------------||
     //-------------------------------------------------------------------------------------||
 
     /**
-     * Obtains the context property associated with the specified key, or null if not found
+     * Obtains the context property associated with the specified key, or {@code null} if not found
      *
      * @param key
      *
@@ -75,7 +76,7 @@
     }
 
     /**
-     * Obtains the context property associated with the specified key, or null if not found
+     * Obtains the context property associated with the specified key, or {@code null} if not found
      *
      * @param <T> Type of the object to be returned
      * @param key

Modified: invokablecontainer/trunk/api/src/main/java/org/jboss/invokable/InvocationReply.java
===================================================================
--- invokablecontainer/trunk/api/src/main/java/org/jboss/invokable/InvocationReply.java	2010-03-30 21:51:51 UTC (rev 4211)
+++ invokablecontainer/trunk/api/src/main/java/org/jboss/invokable/InvocationReply.java	2010-04-01 03:08:38 UTC (rev 4212)
@@ -26,39 +26,82 @@
 import java.io.ObjectInputStream;
 import java.io.Serializable;
 
+/**
+ * An invocation reply.  Includes the return value, along with any attachments that may have been set along the way.
+ */
 public final class InvocationReply implements Serializable {
 
     private static final long serialVersionUID = 4330152364952496586L;
 
-    private static final FieldSetter<InvocationReply> replySetter = FieldSetter.forField(InvocationReply.class, "reply");
-
-    private transient final Object reply;
+    /**
+     * The method return value.
+     *
+     * @serial
+     */
+    private final Object reply;
+    /**
+     * The invocation properties.
+     */
     private transient volatile InvocationProperties properties;
 
+    /**
+     * Construct a new instance.
+     *
+     * @param reply the reply
+     */
     public InvocationReply(final Object reply) {
         this.reply = reply;
     }
 
+    /**
+     * Construct a new instance.
+     *
+     * @param reply the reply
+     * @param properties the initial invocation properties
+     */
     public InvocationReply(final Object reply, final InvocationProperties properties) {
         this.reply = reply;
         this.properties = properties;
     }
 
+    /**
+     * Get the reply.
+     *
+     * @return the reply
+     */
     public Object getReply() {
         return reply;
     }
 
+    /**
+     * Get the invocation properties.
+     *
+     * @return the invocation properties
+     */
     public InvocationProperties getProperties() {
         return properties;
     }
 
+    /**
+     * Replace the invocation properties.
+     *
+     * @param properties the invocation properties
+     */
     public void setProperties(final InvocationProperties properties) {
         this.properties = properties;
     }
 
+    /**
+     * Get the string representation of this object.
+     *
+     * @return the string representation
+     */
+    public String toString() {
+        return "Invocation reply with value (" + reply + ")";
+    }
+
     private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
         ois.defaultReadObject();
-        replySetter.set(this, ois.readObject());
         properties = defaulted((InvocationProperties) ois.readObject(), InvocationProperties.EMPTY);
     }
 

Modified: invokablecontainer/trunk/api/src/main/java/org/jboss/invokable/Keys.java
===================================================================
--- invokablecontainer/trunk/api/src/main/java/org/jboss/invokable/Keys.java	2010-03-30 21:51:51 UTC (rev 4211)
+++ invokablecontainer/trunk/api/src/main/java/org/jboss/invokable/Keys.java	2010-04-01 03:08:38 UTC (rev 4212)
@@ -30,12 +30,11 @@
 public enum Keys {
 
     /**
-     * The security principal associated with the invocation.  Should yield a value
-     * of type {@link java.security.Principal}.
+     * The security principal associated with the invocation.
      */
     PRINCIPAL,
     /**
-     * The transaction associated with this invocation.  Should yield a {@link javax.transaction.Transaction} (?).
+     * The transaction associated with this invocation.
      */
     TRANSACTION,
     /**

Added: invokablecontainer/trunk/api/src/main/java/org/jboss/invokable/MethodIdentifier.java
===================================================================
--- invokablecontainer/trunk/api/src/main/java/org/jboss/invokable/MethodIdentifier.java	                        (rev 0)
+++ invokablecontainer/trunk/api/src/main/java/org/jboss/invokable/MethodIdentifier.java	2010-04-01 03:08:38 UTC (rev 4212)
@@ -0,0 +1,140 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.jboss.invokable;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.Serializable;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+
+/**
+ * A unique identification of a method within some class or interface.  Suitable for usage as a hash table key.
+ *
+ * @author <a href="mailto:david.lloyd at redhat.com">David M. Lloyd</a>
+ */
+public final class MethodIdentifier implements Serializable {
+
+    private static final long serialVersionUID = -4303462176794600579L;
+
+    private static final FieldSetter<MethodIdentifier> hashCodeSetter = FieldSetter.forField(MethodIdentifier.class, "hashCode");
+
+    private final String name;
+    private final Class<?>[] parameterTypes;
+    private final transient int hashCode;
+
+    private static final Class<?>[] NO_CLASSES = new Class<?>[0];
+
+    private MethodIdentifier(final String name, final Class<?>... parameterTypes) {
+        if (name == null) {
+            throw new IllegalArgumentException("name is null");
+        }
+        if (parameterTypes == null) {
+            throw new IllegalArgumentException("parameterTypes is null");
+        }
+        this.name = name;
+        this.parameterTypes = parameterTypes == null || parameterTypes.length == 0 ? NO_CLASSES : parameterTypes.clone();
+        hashCode = calculateHash(name, parameterTypes);
+    }
+
+    private MethodIdentifier(final Method method) {
+        final String name = (this.name = method.getName());
+        final Class<?>[] methodParameterTypes = method.getParameterTypes();
+        final Class<?>[] parameterTypes = (this.parameterTypes = methodParameterTypes.length == 0 ? NO_CLASSES : methodParameterTypes);
+        hashCode = calculateHash(name, parameterTypes);
+    }
+
+    private static int calculateHash(final String name, final Class<?>[] parameterTypes) {
+        return name.hashCode() * 7 + Arrays.hashCode(parameterTypes);
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public Class<?>[] getParameterTypes() {
+        return parameterTypes.clone();
+    }
+
+    public boolean equals(final Object o) {
+        return o instanceof MethodIdentifier && equals((MethodIdentifier) o);
+    }
+
+    public boolean equals(final MethodIdentifier o) {
+        return o == this || o != null && name.equals(o.name) && Arrays.equals(parameterTypes, o.parameterTypes);
+    }
+
+    public int hashCode() {
+        return hashCode;
+    }
+
+    public Method getPublicMethod(final Class<?> clazz) throws NoSuchMethodException {
+        return clazz.getMethod(name, parameterTypes);
+    }
+
+    private static void appendType(final Class<?> type, final StringBuilder b) {
+        if (type.isPrimitive()) {
+            b.append(type.getName());
+        } else if (type.isArray()) {
+            b.append('[');
+            appendType(type, b);
+        } else {
+            b.append('L').append(type.getName().replace('.', '/')).append(';');
+        }
+    }
+
+    public String toString() {
+        final StringBuilder b = new StringBuilder();
+        b.append("Method ").append(name).append('(');
+        for (Class<?> type : parameterTypes) {
+            appendType(type, b);
+        }
+        return b.append(')').toString();
+    }
+
+    private void readObject(final ObjectInputStream ois) throws ClassNotFoundException, IOException {
+        ois.defaultReadObject();
+        hashCodeSetter.setInt(this, calculateHash(name, parameterTypes));
+    }
+
+    public static MethodIdentifier getIdentifierForMethod(final Method method) throws IllegalArgumentException {
+        return new MethodIdentifier(method);
+    }
+
+    public static MethodIdentifier getIdentifier(final String name, final Class<?>... parameterTypes) {
+        return new MethodIdentifier(name, parameterTypes);
+    }
+
+    /**
+     * The method identifier for {@code Object.equals()}.
+     */
+    public static final MethodIdentifier EQUALS = getIdentifier("equals", Object.class);
+    /**
+     * The method identifier for {@code Object.hashCode()}.
+     */
+    public static final MethodIdentifier HASH_CODE = getIdentifier("hashCode");
+    /**
+     * The method identifier for {@code Object.toString()}.
+     */
+    public static final MethodIdentifier TO_STRING = getIdentifier("toString");
+}

Modified: invokablecontainer/trunk/api/src/main/java/org/jboss/invokable/ProcessingInvocationDispatcher.java
===================================================================
--- invokablecontainer/trunk/api/src/main/java/org/jboss/invokable/ProcessingInvocationDispatcher.java	2010-03-30 21:51:51 UTC (rev 4211)
+++ invokablecontainer/trunk/api/src/main/java/org/jboss/invokable/ProcessingInvocationDispatcher.java	2010-04-01 03:08:38 UTC (rev 4212)
@@ -71,6 +71,7 @@
         return processor.processInvocation(dispatcher, invocation);
     }
 
+    /** {@inheritDoc} */
     public <I> void accept(final Visitor<InvocationDispatcher, I> visitor, final I param) {
         visitor.visit(this, param);
         dispatcher.accept(visitor, param);

Modified: invokablecontainer/trunk/api/src/main/java/org/jboss/invokable/ProxyInvocationHandler.java
===================================================================
--- invokablecontainer/trunk/api/src/main/java/org/jboss/invokable/ProxyInvocationHandler.java	2010-03-30 21:51:51 UTC (rev 4211)
+++ invokablecontainer/trunk/api/src/main/java/org/jboss/invokable/ProxyInvocationHandler.java	2010-04-01 03:08:38 UTC (rev 4212)
@@ -72,14 +72,21 @@
      * @throws Throwable the exception to thrown from the method invocation on the proxy instance, if any
      */
     public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
-        try {
-            return processor.processInvocation(dispatcher, new Invocation(method, args));
+        final MethodIdentifier id = MethodIdentifier.getIdentifierForMethod(method);
+        if (id.equals(MethodIdentifier.EQUALS)) {
+            return Boolean.valueOf(proxy.equals(args[0]));
+        } else if (id.equals(MethodIdentifier.HASH_CODE)) {
+            return Integer.valueOf(System.identityHashCode(proxy));
+        } else if (id.equals(MethodIdentifier.TO_STRING)) {
+            return "Proxy via " + dispatcher;
+        } else try {
+            return processor.processInvocation(dispatcher, new Invocation(method.getDeclaringClass(), id, (Object[]) args));
         } catch (InvocationException e) {
             throw e.getCause();
         }
     }
 
-    private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
+    private void readObject(final ObjectInputStream ois) throws ClassNotFoundException, IOException {
         ois.defaultReadObject();
         final SecurityManager sm = System.getSecurityManager();
         if (sm != null) {



More information about the jboss-svn-commits mailing list