Allow an InvocationListener interface to extend another InvocationListener

interface. The way this works is a little tricky, but it all works out.

We have a service SceneService with SceneMoveListener declaration. You can make
FooSceneService and have a method in that service take a FooMoveListener which
extends SceneMoveListener. An instance of FooMoveMarshaller will only be
created if you call the method on FooSceneService and that will result in an
object on the server side that implements SceneMoveListener, but calls to the
SceneMoveListener response methods will result in the FooSceneService response
codes being marshalled and sent back to the caller.

So you can pass the FooMoveListener around to code on the server that expects a
SceneMoveListener and it will magically do the right thing when server code
calls through the SceneMoveListener interface. You can even turn around and
pass the FooMoveMarshaller to another invocation service method (on a peer
perhaps) that takes SceneMoveListener and it will work because the SceneService
call will generate a SceneMoveMarshaller on the remote server, which will use
the SceneMoveMarshaller's codes to communicate the response back to the first
peer, which will unmap those and call the methods on the SceneMoveListener
interface which will remarshal them with the FooMoveListener's codes and send
them back to the client, and bob is everyone's uncle.


git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@5891 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
Michael Bayne
2009-07-28 21:34:13 +00:00
parent 5dc71a9b8e
commit c0499674e9
@@ -24,7 +24,7 @@ package com.threerings.presents.tools;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashSet;
import java.util.Set;
import java.io.File;
import java.io.StringWriter;
@@ -74,26 +74,46 @@ public class GenServiceTask extends InvocationTask
public ServiceListener (Class<?> service, Class<?> listener)
{
this.listener = listener;
Method[] methdecls = listener.getDeclaredMethods();
for (Method m : methdecls) {
// service interface methods must be public and abstract
if (!Modifier.isPublic(m.getModifiers()) &&
!Modifier.isAbstract(m.getModifiers())) {
continue;
}
if (_verbose) {
System.out.println("Adding " + m + ", imports are " +
StringUtil.toString(imports));
}
methods.add(new ServiceMethod(m, imports));
if (_verbose) {
System.out.println("Added " + m + ", imports are " +
StringUtil.toString(imports));
// compute the union of all InvocationListener extensions implemented by this interface
Set<Class<?>> ifaces = Sets.newHashSet();
addInterfaces(listener, ifaces);
// add method marshallers for all methods in all interfaces (the marshaller will not
// extend the marshallers for its parent interfaces and will use its own codes)
for (Class<?> iface : ifaces) {
Method[] methdecls = iface.getDeclaredMethods();
for (Method m : methdecls) {
// service interface methods must be public and abstract
if (!Modifier.isPublic(m.getModifiers()) &&
!Modifier.isAbstract(m.getModifiers())) {
continue;
}
if (_verbose) {
System.out.println("Adding " + m + ", imports are " +
StringUtil.toString(imports));
}
methods.add(new ServiceMethod(m, imports));
if (_verbose) {
System.out.println("Added " + m + ", imports are " +
StringUtil.toString(imports));
}
}
}
methods.sort();
}
protected void addInterfaces (Class<?> listener, Set<Class<?>> ifaces)
{
if (!_ilistener.isAssignableFrom(listener) || _ilistener.equals(listener)) {
return;
}
ifaces.add(listener);
for (Class<?> iface : listener.getInterfaces()) {
addInterfaces(iface, ifaces);
}
}
/**
* Checks whether any of our methods have parameterized types.
*/
@@ -668,10 +688,10 @@ public class GenServiceTask extends InvocationTask
protected File _asroot;
/** Services for which we should not generate provider interfaces. */
protected HashSet<String> _providerless = Sets.newHashSet();
protected Set<String> _providerless = Sets.newHashSet();
/** Services for which we should generate actionscript listener adapters. */
protected HashSet<String> _aslistenerAdapters = Sets.newHashSet();
protected Set<String> _aslistenerAdapters = Sets.newHashSet();
/** Specifies the path to the marshaller template. */
protected static final String MARSHALLER_TMPL =