Author: david.lloyd(a)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();
}