Hi Mike,
> I am growing to believe I need to deploy each plug-in as a separate
> WAR on a web-server. Is this true, or have I missed something?
In the case of my architecture, it is even a requirement that every
plugin will be deployed as an own WAR file. It allows different teams
working in parallel in completely independent applications (plugins)
which have a common "message data model". When inside the plugins
container, they receive messages with this "common data model". When
out of the plugins container, the show a simplified UI to let the
developer pass a "message" generated by hand and therefore test the
application.
> I am also using gwt-exporter to make the JSNI messaging mechanism;
> i.e. I just write an "Exportable" class and use the resulting JS API
> from my plugins. I am hoping to use gwt-api-interop to remove the need
> to use the JS API.
I have seen gwt-exporter but do not know gwt-api-interop.
> I assume the JS "bridge" between GWT applications handles the
> messaging between them (i.e. plugins register callbacks to handle
> messages sent from the "host"?)
Yes.
> If I understand correctly, adding additional script tags to my
> "loader" page and having each plug-in as a separate WAR I avoid the
> need to inherit in my gwt.xml file?
My common model and plugin base classes live in a common GWT module
that each plugin inherits.
> An example of your use of JavaScriptObject in your messaging sub-
> system would be interesting....
// Application specific common model
public final class CustomerInfo extends ModuleInfo {
protected CustomerInfo() {
}
public native String getId() /*-{
return
this.id;
}-*/;
public native void setId(String id) /*-{
this.id = id;
}-*/;
}
// Base class for common models - no functionality as of now
public class ModuleInfo extends JavaScriptObject {
protected ModuleInfo() {
}
}
// To be implemented by every module
public interface IModule<T extends ModuleInfo> {
public String getName();
public void dispatch(String containerId, T moduleInfo);
}
// To be implemented by the main module or classes interested in
module lifecycle events
public interface IModuleAware<T extends ModuleInfo> {
public void onModuleAttached(Module<T> module);
}
// Durable callback implementation - Because it uses JSNI, can be
inherited from GWT modules but it is interoperable. Avoids using gwt-
exporter
public final class ModuleListener<T extends ModuleInfo> extends
JavaScriptObject {
protected ModuleListener() {
}
public void onModuleAttached(Module<T> module) {
invokeCallback(getCallback(), module);
}
private native void invokeCallback(JavaScriptObject callback,
Module<T> module) /*-{
this.callback(module);
}-*/;
private native JavaScriptObject getCallback() /*-{
return this.callback;
}-*/;
public native void setCallback(JavaScriptObject callback) /*-{
this.callback = callback;
}-*/;
}
// Support for common modules functionality (static methods)
public abstract class ModulesSupport {
public static <T extends ModuleInfo> boolean
registerAsListener(IModuleAware<T> instance) {
ModulesConfig<T> modulesConfig = getModulesConfig();
boolean result = null != modulesConfig;
if (result) {
modulesConfig.registerListener(createListener(instance));
}
return result;
}
public static <T extends ModuleInfo> boolean
registerAsModule(IModule<T> module) {
ModulesConfig modulesConfig = ModulesConfig.get();
boolean result = null != modulesConfig;
if (result) {
modulesConfig.attach(module.getName(),
createDispatchCallback(module));
}
return result;
}
public static <T extends ModuleInfo> ModulesConfig<T>
getModulesConfig() {
return ModulesConfig.get();
}
private static <T extends ModuleInfo> ModuleListener<T>
createListener(IModuleAware<T> instance) {
ModuleListener<T> result =
JavaScriptObject.createObject().cast();
result.setCallback(createListenerCallback(instance));
return result;
}
private static native JavaScriptObject
createListenerCallback(IModuleAware instance) /*-{
return function(module) {
instance.@org.myexample.modules.client.IModuleAware::onModuleAttached(Lorg/
myexample/modules/client/Module;)(module);
};
}-*/;
private static native JavaScriptObject
createDispatchCallback(IModule instance) /*-{
return function(containerId, moduleInfo) {
instance.@org.myexample.modules.client.IModule::dispatch(Ljava/lang/
String;Lorg/myexample/modules/client/ModuleInfo;)(containerId,
moduleInfo);
};
}-*/;
}
Hope it helps,
Berto