ExternalEvents offer a way to communicate with a running XMA application by sending am event to it. At an XMA session a listener for ExternalEvents can be registered. As of now, the only implemented means of communication are Named Windows Pipes (see MSDN Pipes). The XMA application starts a named pipe server process listening for pipe clients if the application was started with the parameter at.spardat.xma.pipename set to some value, which thus identifies the pipe. The pipe name has to follow the Windows file name conventions, usually a pipe name should be unique for an application (like the URL starting an application).
A pipe client, which can send messages to an XMA application is not yet part of the XMA distribution. If needed it has to be implemented. Typically this pipe client could be implemented in the program launching the XMA application. Before a new Java VM is started the launcher checks via a named pipe if there is already an application running, which is listening at this named pipe. In that case, instead of starting the VM, the existing application is conntacted by the pipe and an ExternalEvent can be executed at it.
The pipe communication from the client follows this simple protocol:
transferred are bytes representing chars, encoded in the default platform encoding
this char stream has to consist of key - value pairs
as delimiter between each key and value serves the char '\b':
[<name>'\b'<value>['\b'<name>'\b'<value>]*].
In the ExternalEvent this key value pairs are then available as Java properties.
A value with the name at.spardat.xma.evenName is set as event name (and not available in the properties). This can be used to distinguish between different "types" of ExternalEvents.
In the external event processing by an ExternalEventListener Java properties can be returned. These are transferred back to the pipe client in the protocol as described above (chars encoded in the default platform encoding): [<name>'\b'<value>['\b'<name>'\b'<value>]*].
For implementing the ExternalEvent processing these
classes are used:
Class | Description |
| Represents the event received by the XMA client.
|
| The external event listener interface which has to be implemented by a listener class. This class can be registered at the XMASessionClient.
|
| Provides methods to register and deregister an ExternalEventListener.
|
Table 6.15. External Event Classes
The registered ExternalEventListener classes are
notified by an incoming ExternalEvent . This notification
is performed in a Display.asyncExec(). That means that if the XMA
application is busy with a GUI thread it waits for the notification of
the listeners until this GUI thread is finished. Once the notification
is started the XMA application (and therefore the XMA caller) waits
for the completion of the code initiated by the listeners. XMA calls
from COM wait only as long for ExternalEvent completion
as long as the caller's timeout permits.
The following snippet shows how to implement an
ExternalEventListener. A listener could be a
DialogPage:
public MyPage extends MyPageGen implements ExternalEventListener{
...
Properties externalEvent(ExternalEvent event){
String eventName = event.getEventName();
String idClient = event.getProperty("idClient");
//do something, e.g show values on GUI
...
//active page (brings page to foreground on desktop):
activatePage();
return null;
}
}If an XMA launcher is used, which is able to deal with Windows pipes as described, then an already running XMA application (implementing the code above and registering the listener) could be activated (reused) by an URL such as below.
http://localhost:7001/krimicee/KrimiShell.xma?idClient=34235&at.spardat.xma.pipename=krimice&t.spardat.xma.evenName=KrimiShell
The following values would be returned:
getEventName(): "KrimiShell"
getProperty("idClient"): "34235"
An XMA application is usually running in the background when an
ExternalEvent is fired. If the XMA application should be
activated (brought to the foreground) this can be done by the call
PageClient.activatePage()
Note that when a Page or XMA Component is registered as listener, the life cycle of an XMA PageClient/Component has to be considered. It is recommended to use a Page or Component which exists as long as the application is running (like the AppShell).
GlobalEvent s offer a mechanism to notify XMA clients
actively from the server side. An incoming GlobalEvent can
be used to initiate a client to show a message or to refresh some
resource etc. The GlobalEvent mechanism has to be activated
by the XProperty xma.runtime.activateGlobalEvents . Any
other value than false (which is the default value) will
activate the GlobalEvent mechanism and define a
GlobalEvent scope. GlobalEvents are only written and read
in the scope set by xma.runtime.activateGlobalEvents (e.g.
xma.runtime.activateGlobalEvents=samplespar) . This
mechanism prevents that GlobalEvents of different applications are
mixed. For details of the XMA Runtime properties see:
XMA Runtime Properties(Appendix A: XMA Runtime Properties)
A GlobalEvent is produced and fired at a server where
an XMA application is deployed (usually by a request to this server). If
the server exist in a cluster environment the event is distributed to
all servers and so to all clients of all servers. Recipients of a
GlobalEvent are XMA servers and XMA clients, which have
registered GlobalEventListener . A GlobalEvent
can be sent to the server itself (actually to all servers in the
cluster) and/or to all XMA clients connected to a server in the cluster.
It is also possible to send the event only to a client identified by a
given session ID.
For implementing the GlobalEvent processing the
following classes are used, only methods are described which are
important for the application programmer:
Class | Description |
| Represents the global event received by the XMA client.
|
| The
|
| This singleton class serves for creating, sending
and polling
|
| Provides a method to register and deregister an
|
Table 6.16. Global Event Classes
First the event is created (by
GlobalEventManager.createGlobalEvent(..) ) at the XMA
server, where the name, the recipients and the time to live of the
event is determined. If the event should only reach a special client,
this client's session ID can be stated.
Usually, after creation the event is filled with properties,
then the event is sent (by GlobalEventManager.send(..) ).
To send an event means to incorporate it in a global data structure
which can be accessed by all servers in the cluster (actually the
event is bound to an JNDI tree).
The transmission of sent events to registered listeners is
initiated by an RPC between XMA server and XMA client. An RPC reply
(from server to client) polls at the server side for new (still
undelivered) GlobalEvents. If the GlobalEvent is of the recipient type
RECIPIENT_ALL_SERVERS the server side registered
GlobalEventListener are notified.
If the GlobalEvent is of the recipient type
RECIPIENT_ALL_CLIENTS or RECIPIENT_BY_ID (in
this case the event's session ID has to match the RPC's session ID)
the GlobalEvent is transmitted as RPC parameter to the client.
At the client side the GlobalEvent s are read from
the RPC and are delivered to the client's GlobalEventListener classes.
This notification is performed in a Display.asyncExec() before the RPC
itself is routed to the application code.
Only GlobalEvent s are transmitted to the listeners
which are still valid and which were not yet delivered (to the server,
or to the client, depending on the recipient type).
A GlobalEventListener at the server side may seem
pointless as the server is contacted for GlobalEvent
creation anyway. But as a new event is distributed to all servers in
the cluster it may be necessary to notify all the servers of the new
event and to perform some action on each of them (like resource
refreshing).
Note, that when there are no RPC's no
GlobalEvents are delivered. So if a client
should be notified by - let's say - the end of some batch process, the
client has to poll the server actively by RPCs. If no user interaction
can be assumed at the XMA client, RPC's could be sent in an own
polling task.
The following snippets demonstrate creation, sending of
GlobalEvent s and implementing of
GlobalEventListener.
//some server side class
//creates an event with default recipients (RECIPIENT_ALL_CLIENTS_ALL_SERVERS), valid one hour
GlobalEvent event = GlobalEventManager.getInstance().createGlobalEventTTL("mytype1",1000*60*60);
...
//creates an event with recipient "all clients", valid default timespan (one day from now)
GlobalEvent event = GlobalEventManager.getInstance().createGlobalEventTTL("mytype2",GlobalEvent.RECIPIENT_ALL_CLIENTS);
...
//creates an event with recipient the client idetified by the session id, valid one day from now
GlobalEvent event = GlobalEventManager.getInstance().
createGlobalEventTTL("mytype3",GlobalEvent.RECIPIENT_BY_ID,1000*60*60*24,((XMASessionServer) XMASessionServer
.getXMASession()).getHttpSession().getId());
...
//set property and send event
event.setProperty("somekey", "somevalue");
GlobalEventManager.getInstance().send(event);
...
public class MyListener implements GlobalEventListener{
public MyListener() {
GlobalEventManager.getInstance().addGlobalEventListener(this);
}
public void globalEvent(GlobalEvent event) {
System.out.println("New GlobalEvent at sever " + event.getName());
}
}
public class MyComponent extends MyComponentGen implements GlobalEventListener{
public MyComponent(XMASessionClient session) {
session.addGlobalEventListener(this);
}
...
public void globalEvent(GlobalEvent event) {
if(event.getName().equals("mytype1")){
//do something
} else if(event.getName().equals("mytype2")){
//do something
}
}
}
Note that when a Page or XMA Component is registered as listener, the life cycle of an XMA PageClient/Component has to be considered. It is recommended to use a Page or Component which exists as long as the application is running (like the AppShell).