[jboss-remoting-commits] JBoss Remoting SVN: r4716 - remoting3/trunk/transporter/src/main/java/org/jboss/remoting/transporter.

jboss-remoting-commits at lists.jboss.org jboss-remoting-commits at lists.jboss.org
Wed Nov 19 20:27:28 EST 2008


Author: david.lloyd at jboss.com
Date: 2008-11-19 20:27:27 -0500 (Wed, 19 Nov 2008)
New Revision: 4716

Added:
   remoting3/trunk/transporter/src/main/java/org/jboss/remoting/transporter/TransporterMethodDescriptor.java
Modified:
   remoting3/trunk/transporter/src/main/java/org/jboss/remoting/transporter/TransporterInvocation.java
   remoting3/trunk/transporter/src/main/java/org/jboss/remoting/transporter/TransporterInvocationHandler.java
   remoting3/trunk/transporter/src/main/java/org/jboss/remoting/transporter/TransporterRequestListener.java
Log:
Transporter: cache method descriptors to reduce net traffic; update javadoc; switch to externalizer

Modified: remoting3/trunk/transporter/src/main/java/org/jboss/remoting/transporter/TransporterInvocation.java
===================================================================
--- remoting3/trunk/transporter/src/main/java/org/jboss/remoting/transporter/TransporterInvocation.java	2008-11-20 01:08:06 UTC (rev 4715)
+++ remoting3/trunk/transporter/src/main/java/org/jboss/remoting/transporter/TransporterInvocation.java	2008-11-20 01:27:27 UTC (rev 4716)
@@ -26,73 +26,101 @@
 import java.io.ObjectOutput;
 import java.io.IOException;
 import java.io.ObjectInput;
+import java.io.InvalidClassException;
+import org.jboss.marshalling.Creator;
 
 /**
- *
+ * An invocation made on a transporter.  Instances of this class are used internally by transporters to represent
+ * a method call that is being forwarded to a remote instance.  This class is not part of the public API and should
+ * not be used directly, as members may be added or removed without notice.
  */
-public final class TransporterInvocation implements Externalizable {
+public final class TransporterInvocation {
 
-    private static final long serialVersionUID = -1643169469978213945L;
-    private String name;
-    private Class<?>[] parameterTypes;
-    private Object[] args;
+    private final TransporterMethodDescriptor methodDescriptor;
+    private final Object[] args;
 
-    public TransporterInvocation() {
-    }
-
-    public TransporterInvocation(final String name, final Class<?>[] parameterTypes, final Object[] args) {
-        if (parameterTypes.length != args.length) {
+    /**
+     * Construct an intialized instance.
+     *
+     * @param methodDescriptor
+     * @param args the arguments
+     */
+    public TransporterInvocation(final TransporterMethodDescriptor methodDescriptor, final Object[] args) {
+        if (methodDescriptor.getParameterTypes().length != args.length) {
             throw new IllegalArgumentException("parameter type array length differs from arg array length");
         }
-        this.name = name;
-        this.parameterTypes = parameterTypes;
+        this.methodDescriptor = methodDescriptor;
         this.args = args;
     }
 
-    public void writeExternal(final ObjectOutput out) throws IOException {
-        out.writeObject(name);
-        final Class<?>[] parameterTypes = this.parameterTypes;
-        final Object[] args = this.args;
-        final int len = parameterTypes.length;
-        if (len != args.length) {
-            throw new IllegalStateException("parameter types and/or args length changed");
-        }
-        if (len > 0xffff) {
-            throw new IllegalArgumentException("too many parameters");
-        }
-        out.writeShort(len);
-        for (Class<?> type : parameterTypes) {
-            out.writeObject(type);
-        }
-        for (Object arg : args) {
-            out.writeObject(arg);
-        }
+    /**
+     * Get the method descriptor.
+     *
+     * @return the method descriptor
+     */
+    public TransporterMethodDescriptor getMethodDescriptor() {
+        return methodDescriptor;
     }
 
-    public void readExternal(final ObjectInput in) throws IOException, ClassNotFoundException {
-        name = (String) in.readObject();
-        final int cnt = in.readShort() & 0xffff;
-        final Class<?>[] parameterTypes = new Class<?>[cnt];
-        for (int i = 0; i < cnt; i ++) {
-            parameterTypes[i] = (Class<?>) in.readObject();
+    /**
+     * Get the method call arguments.
+     *
+     * @return the method call arguments
+     */
+    public Object[] getArgs() {
+        return args;
+    }
+
+    /**
+     * An externalizer for a transporter invocation.
+     */
+    public static final class Externalizer implements org.jboss.marshalling.Externalizer, Externalizable {
+
+        private static final long serialVersionUID = 6676707007545161200L;
+
+        /** {@inheritDoc} */
+        public void writeExternal(final Object o, final ObjectOutput output) throws IOException {
+            if (o instanceof TransporterInvocation) {
+                final TransporterInvocation invocation = (TransporterInvocation) o;
+                final TransporterMethodDescriptor methodDescriptor = invocation.methodDescriptor;
+                output.writeObject(methodDescriptor);
+                final Object[] args = invocation.args;
+                final int len = methodDescriptor.getParameterTypes().length;
+                if (len != args.length) {
+                    throw new IllegalStateException("argument length mismatch");
+                }
+                for (Object arg : args) {
+                    output.writeObject(arg);
+                }
+            } else {
+                throw new InvalidClassException(o.getClass().getName(), "Wrong class for externalizer");
+            }
         }
-        final Object[] args = new Object[cnt];
-        for (int i = 0; i < cnt; i ++) {
-            args[i] = in.readObject();
+
+        /** {@inheritDoc} */
+        public Object createExternal(final Class<?> objectClass, final ObjectInput input, final Creator creator) throws IOException, ClassNotFoundException {
+            final TransporterMethodDescriptor methodDescriptor = (TransporterMethodDescriptor) input.readObject();
+            final int cnt = methodDescriptor.getParameterTypes().length;
+            final Object[] args = new Object[cnt];
+            for (int i = 0; i < cnt; i ++) {
+                args[i] = input.readObject();
+            }
+            return new TransporterInvocation(methodDescriptor, args);
         }
-        this.parameterTypes = parameterTypes;
-        this.args = args;
-    }
 
-    public String getName() {
-        return name;
-    }
+        /** {@inheritDoc} */
+        public void readExternal(final Object o, final ObjectInput input) throws IOException, ClassNotFoundException {
+            // already initialized
+        }
 
-    public Class<?>[] getParameterTypes() {
-        return parameterTypes;
-    }
+        /** {@inheritDoc} */
+        public void writeExternal(final ObjectOutput out) throws IOException {
+            // no fields
+        }
 
-    public Object[] getArgs() {
-        return args;
+        /** {@inheritDoc} */
+        public void readExternal(final ObjectInput in) throws IOException, ClassNotFoundException {
+            // no fields
+        }
     }
 }

Modified: remoting3/trunk/transporter/src/main/java/org/jboss/remoting/transporter/TransporterInvocationHandler.java
===================================================================
--- remoting3/trunk/transporter/src/main/java/org/jboss/remoting/transporter/TransporterInvocationHandler.java	2008-11-20 01:08:06 UTC (rev 4715)
+++ remoting3/trunk/transporter/src/main/java/org/jboss/remoting/transporter/TransporterInvocationHandler.java	2008-11-20 01:27:27 UTC (rev 4716)
@@ -25,15 +25,18 @@
 import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.Method;
 import java.io.IOException;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ConcurrentHashMap;
 import org.jboss.remoting.Client;
 import org.jboss.remoting.RemoteExecutionException;
 import org.jboss.xnio.IoUtils;
 
 /**
- *
+ * The transporter reflection invocation handler.
  */
 public final class TransporterInvocationHandler implements InvocationHandler {
     private final Client<TransporterInvocation, Object> client;
+    private final ConcurrentMap<Method, TransporterMethodDescriptor> descriptorCache = new ConcurrentHashMap<Method, TransporterMethodDescriptor>();
 
     public TransporterInvocationHandler(final Client<TransporterInvocation, Object> client) {
         this.client = client;
@@ -41,7 +44,20 @@
 
     public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
         try {
-            return client.invoke(new TransporterInvocation(method.getName(), method.getParameterTypes(), args));
+            final TransporterMethodDescriptor descriptor;
+            final TransporterMethodDescriptor cachedDescriptor = descriptorCache.get(method);
+            if (cachedDescriptor == null) {
+                final TransporterMethodDescriptor newDescriptor = new TransporterMethodDescriptor(method.getName(), method.getParameterTypes());
+                final TransporterMethodDescriptor suddenDescriptor = descriptorCache.putIfAbsent(method, newDescriptor);
+                if (suddenDescriptor != null) {
+                    descriptor = suddenDescriptor;
+                } else {
+                    descriptor = newDescriptor;
+                }
+            } else {
+                descriptor = cachedDescriptor;
+            }
+            return client.invoke(new TransporterInvocation(descriptor, args));
         } catch (RemoteExecutionException e) {
             throw e.getCause();
         } catch (IOException e) {

Added: remoting3/trunk/transporter/src/main/java/org/jboss/remoting/transporter/TransporterMethodDescriptor.java
===================================================================
--- remoting3/trunk/transporter/src/main/java/org/jboss/remoting/transporter/TransporterMethodDescriptor.java	                        (rev 0)
+++ remoting3/trunk/transporter/src/main/java/org/jboss/remoting/transporter/TransporterMethodDescriptor.java	2008-11-20 01:27:27 UTC (rev 4716)
@@ -0,0 +1,139 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2008, 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.remoting.transporter;
+
+import java.util.Arrays;
+import java.io.ObjectOutput;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.Externalizable;
+import java.io.InvalidClassException;
+import java.io.InvalidObjectException;
+import org.jboss.marshalling.Creator;
+
+/**
+ * A method descriptor.
+ */
+public final class TransporterMethodDescriptor {
+    private final String name;
+    private final Class<?>[] parameterTypes;
+
+    /**
+     * Create a new instance.
+     *
+     * @param name the method name
+     * @param parameterTypes the method parameter types
+     */
+    public TransporterMethodDescriptor(final String name, final Class<?>[] parameterTypes) {
+        this.name = name;
+        this.parameterTypes = parameterTypes;
+    }
+
+    /**
+     * Get the method name.
+     *
+     * @return the method name
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Get the parameter types.
+     *
+     * @return the parameter types
+     */
+    public Class<?>[] getParameterTypes() {
+        return parameterTypes;
+    }
+
+    /** {@inheritDoc} */
+    public boolean equals(final Object o) {
+        if (this == o) return true;
+        if (! (o instanceof TransporterMethodDescriptor)) return false;
+        final TransporterMethodDescriptor that = (TransporterMethodDescriptor) o;
+        if (!name.equals(that.name)) return false;
+        if (!Arrays.equals(parameterTypes, that.parameterTypes)) return false;
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    public int hashCode() {
+        int result = name.hashCode();
+        result = 31 * result + Arrays.hashCode(parameterTypes);
+        return result;
+    }
+
+    /**
+     * The externalizer for {@code TransporterMethodDescriptor}.
+     */
+    public static final class Externalizer implements org.jboss.marshalling.Externalizer, Externalizable {
+
+        private static final long serialVersionUID = 8081458273093788910L;
+
+        /** {@inheritDoc} */
+        public void writeExternal(final Object o, final ObjectOutput output) throws IOException {
+            if (o instanceof TransporterMethodDescriptor) {
+                final TransporterMethodDescriptor descriptor = (TransporterMethodDescriptor) o;
+                output.writeObject(descriptor.name);
+                final Class<?>[] types = descriptor.parameterTypes;
+                final int len = types.length;
+                if (len > 0xffff) {
+                    throw new InvalidObjectException("Too many parameter types");
+                }
+                output.writeShort(len);
+                for (Class<?> type : descriptor.parameterTypes) {
+                    output.writeObject(type);
+                }
+            } else {
+                throw new InvalidClassException(o.getClass().getName(), "Wrong class for externalizer");
+            }
+        }
+
+        /** {@inheritDoc} */
+        public Object createExternal(final Class<?> aClass, final ObjectInput input, final Creator creator) throws IOException, ClassNotFoundException {
+            final String name = (String) input.readObject();
+            final int len = input.readShort() & 0xffff;
+            final Class<?>[] types = new Class<?>[len];
+            for (int i = 0; i < len; i ++) {
+                types[i] = (Class<?>) input.readObject();
+            }
+            return new TransporterMethodDescriptor(name, types);
+        }
+
+        /** {@inheritDoc} */
+        public void readExternal(final Object o, final ObjectInput input) throws IOException, ClassNotFoundException {
+            // already initialized
+        }
+
+        /** {@inheritDoc} */
+        public void writeExternal(final ObjectOutput out) throws IOException {
+            // no fields
+        }
+
+        /** {@inheritDoc} */
+        public void readExternal(final ObjectInput in) throws IOException, ClassNotFoundException {
+            // no fields
+        }
+    }
+}

Modified: remoting3/trunk/transporter/src/main/java/org/jboss/remoting/transporter/TransporterRequestListener.java
===================================================================
--- remoting3/trunk/transporter/src/main/java/org/jboss/remoting/transporter/TransporterRequestListener.java	2008-11-20 01:08:06 UTC (rev 4715)
+++ remoting3/trunk/transporter/src/main/java/org/jboss/remoting/transporter/TransporterRequestListener.java	2008-11-20 01:27:27 UTC (rev 4716)
@@ -30,7 +30,7 @@
 import java.io.IOException;
 
 /**
- *
+ * Transporter request listener.  Used to implement the receiving end of a transporter invocation.
  */
 public final class TransporterRequestListener<T> extends AbstractRequestListener<TransporterInvocation,Object> {
     private final T target;
@@ -41,7 +41,8 @@
 
     public void handleRequest(final RequestContext<Object> context, final TransporterInvocation request) throws RemoteExecutionException {
         try {
-            final Method method = target.getClass().getMethod(request.getName(), request.getParameterTypes());
+            final TransporterMethodDescriptor methodDescriptor = request.getMethodDescriptor();
+            final Method method = target.getClass().getMethod(methodDescriptor.getName(), methodDescriptor.getParameterTypes());
             method.invoke(target, request.getArgs());
         } catch (NoSuchMethodException e) {
             doSendFailure(context, new NoSuchMethodError("No such method on the remote side: " + e.getMessage()));
@@ -52,9 +53,9 @@
         }
     }
 
-    private void doSendFailure(final RequestContext<Object> context, final Throwable throwable) {
+    private static void doSendFailure(final RequestContext<Object> context, final Throwable throwable) {
         try {
-            context.sendFailure(null, throwable);
+            context.sendFailure("", throwable);
         } catch (IOException e) {
             e.printStackTrace();
         }




More information about the jboss-remoting-commits mailing list