OW2 Wildcat User Guide

version 2.3.0


Table of Contents

1. Getting WildCAT
License
Prerequisite
Download WildCAT
Build WildCAT
2. Modeling Data
Resource hierarchy
Example
The Context interface
Instantiating the BasicContext Class
Creating a context through a ContextFactory
3. Inspecting Data
WILDCAT EVENT MODEL
WHierarchyEvent
WAttributeEvent
PULL MODE
Getting and setting attributes
LISTING HIERARCHY CONTENT
CREATING SYMBOLIC LINKS
EXAMPLE
PUSH MODE
EVENT QUERY LANGUAGE
WRITING QUERIES
LISTENING TO QUERIES
SPECIAL QUERY ATTRIBUTES
PERIODIC ATTRIBUTE POLLING
EXAMPLE
4. WILDCAT SENSORS
THE SENSORS LIBRARY
DESIGNING A NEW SENSOR
EXAMPLE 1: THE RNGSensor
EXAMPLE 2: THE IPSensor
USING A NEW SENSOR
5. DISTRIBUTED CONTEXTS
COMMUNICATION BETWEEN REMOTE CONTEXTS
RMI-JMS DISPATCHER
FULL JMS DISPATCHER
EXAMPLE

Chapter 1. Getting WildCAT

License

WildCAT project is released under the GPL v2 License.

Prerequisite

The WildCAT framework needs a Java Virtual Machine to run. You can download it here.

Download WildCAT

WildCAT distribution is available in the download page of the project. The distribution contains the following directories:

  • src : wildcat source code

  • doc : wildcat documentation (javadoc and userguide)

  • lib : wildcat libraries

  • ext : wildcat dependencies

  • examples : a set of ready to use examples

Build WildCAT

WildCAT sources are managed by Apache Maven. Source code can be obtained from the project subversion repository. Once source code checked out,run the following commands in a shell from the root directory to build WildCAT:

mvn install

Chapter 2. Modeling Data

This chapter shows how to organize data sources within the WildCAT framework.

Resource hierarchy

WildCAT let developers organize data sources inside a Context. A WildCAT context is an oriented tree structure with two types of nodes:

  • Attributes nodes that hold some value. Attributes nodes are always leaf nodes, and every attribute has a unique parent node. There exist 3 types of attributes:

    • Basic attributes holds static values. Their values do not evolve unless programmatically modified.

    • Active attributes (sensors).

    • Synthetic attributes are the results of expressions on other attributes.

  • Resources nodes that can have zero or more children assuming every child’s name is unique. A resource may have more than one parent. There are two types of resources:

    • Basic resources.

    • Symbolic links are special resources that alter path resolution by pointing to another resource.

Example

The example hierarchy presents three resources (blue circles) and five attributes (red squares).

Every WildCAT Context has a unique entry point: the ROOT resource. Moreover, a Context must never contain a cycle. When manipulating a WildCAT context, developers reference resources and attributes by their path from the ROOT resource. WildCAT paths are a convenient way for users to denote resources and attributes. Exception made from the ROOT node, a node may be resolved through multiple paths: in our example, both paths "self://consts/maths" and "self://maths" denotes the same resource and the bottom left attribute may be resolved by "self://#pi", "self://maths#pi" or "self://consts/maths#pi". Paths ending with «#name» denote attributes. The context name "self" is a reserved name that is an equivalent of "localhost" in networking.

The Context interface

The Context interface is the one and only entry point for WildCAT developers to organize, inspect and register notification handlers on context data provided by sensors. WildCAT provides two different ways of instantiating the Context interface:

  • Instantiating the BasicContext class

  • Creating a Context through a ContextFactory

Instantiating the BasicContext Class

WildCAT provides a default implementation of the Context interface, the BasicContext class. (Note: WildCAT also contains the RemoteContext class. This class should never be manipulated directly and serves only the purpose of inter-context communication through Java Messaging Service). The BasicContext class presents a no-argument constructor:

Context ctx = new BasicContext ();

The BasicContext instantiated here is a local only context named "anonymous". Local only contexts present all capabilities of contexts on the exception of inter-contexts communications even in between two local only contexts. Hence, developers should prefer the second way of instantiating contexts.

Creating a context through a ContextFactory

The ContextFactory class permits to easily instantiate a context. A default ContextFactory is accessible in the ContextFactory class, through the static method getDefaultFactory(). The default ContextFactory is configured according to the properties configration file pointed by the "org.ow2.wildcat.configuration" system property. One can also instantiate ContextFactory according to a String pointing a properties configuration file or according to a property object:

/*
* The default ContextFactory instantiated without parameters
*/
public static ContextFactory getDefaultFactory () ...

/*
* Instantiate a factory according to the properties configuration
* file pointed by the "org.ow2.wildcat.configuration" system
* property.
*/
public ContextFactory () ...

/*
* Instantiate a factory according to the properties configuration
* file pointed "configuration".
*/
public ContextFactory (String configuration) ...

/*
* Instantiate a factory according to the properties object
* "configuration".
*/
public ContextFactory (Properties configuration) ...

/*
* Instantiate a factory according to the properties configuration
* file pointed by "url".
*/
public ContextFactory (URL url) ...

/*
* Creates a new BasicContext instance
*/ 
public Context createContext () ...

/*
* Creates a new named BasicContext instance
*/
public Context createContext (String name) ...

A typical configuration file contains (when the full‐JMS dispatcher is used):

#The Context name as exported to remote contexts
org.ow2.wildcat.context_name=context
#the name of the dispatcher
org.ow2.wildcat.remote.dispatcher_name=dispatche
#JMS provider URL
org.ow2.wildcat.remote.jms_provider_url=tcp://localhost:3035
#JMS Queue/Topic connection factory name
org.ow2.wildcat.remote.queue_connection_factory="QueueConnectionFactory"
org.ow2.wildcat.remote.topic_connection_factory="TopicConnectionFactory"

Once instantiated, properties configuring a context creation and behaviour are resolved in the following order, resolving stops with the first match:

  • From the initial properties configuration file

  • From the System properties (Those can be configured programmatically or by command line option)

  • From default values set in the ContextFactory class

Chapter 3. Inspecting Data

WildCAT proposes two modes to inspect the content of a Context: PULL and PUSH. In PULL mode, developers programmatically get and set attributes. The Context interface provides the get and set operations. This mode is described in section PULL MODE. In PUSH mode, developers register listeners on queries expressed over the event generated in the Context. The Context interface provides operations to create queries and to register listeners on queries. This mode is described in section PUSH MODE.

WILDCAT EVENT MODEL

WildCAT lets developers to inspect the content of a context by registering queries on the event generated by the hierarchy. In WildCAT, every event implements the WEvent interface. It allows to determine for every event, the node in the hierarchy which emitted the event (see: JavaDocs for String WEvent::getSource()). There are two kinds of event emitted by a WildCAT context. Firstly, events emitted by resources: they instantiate the WHierarchyEvent Class and informs about the operation performed on the structure of the hierarchy. or example, such an event may indicate the addition of an attribute or the creation of a symbolic link. Secondly, events emitted by attributes: they instantiate the WAttributeEvent class and indicates the modification of that attribute and holds its new value.

WHierarchyEvent

WHierarchyEvents reports on the operations performed on the hierarchy. They contains three attributes:

  • The path of the resource that emitted the event.

  • The type of operation performed. There are 6 different types: corresponding to the addition/removal of a resource/attribute/softlink.

  • The subject of the operation. It corresponds to the name of the resource/attribute/softlink added or removed.

Let's see an example.

The creation of the hierarchy presented in the image above would have generated 4 events. First, a WHierarchyEvent emitted by the ROOT node to indicate the creation of the resource "const". Then, the newly created resource would have emitted a WHierarchyEvent reporting the creation of the resource "strings". Then, the latter resource would have emitted a WHierarchyEvent for the creation of the attribute "hello". Finally, the attribute "self://consts/strings#hello" would have emitted a WAttributeEvent containing its initial value.

WAttributeEvent

WAttributeEvents are events emitted by attributes when their value changes. They indicate the path of the attribute emitting the event, and hold the new value of the attribute. As indicated before, attributes values are Plain Old Java Object. When following JavaBean naming conventions, attributes value may be introspected, i.e. given an attribute value Object with a "getName()" method, "name" can be accessed as an attribute of the Event. This introspection mechanism allows writing complex queries.

PULL MODE

Getting and setting attributes

To organize attributes (basics, sensors, synthetic attributes) in the WildCAT framework, one has to know only about a single Java Interface, the Context interface. Creating WildCAT context is detailed in chapter 'Modeling Data' . Here, we are going to create a context through the ContextFactory.

Context ctx = ContextFactory.getDefaultFactory.createContext();

The Context interface provides methods to manipulate the WildCAT hierarchy, ie: creating resources and attributes, getting and setting attributes values. For example:

ctx.createAttribute("self://constants#hello", "Hello");

creates a primitive attribute with initial value "Hello". In the path "self://constants#hello", "self://" denotes the current context, "constants" is a resource mounted at top level, and the "hello" identifier following the '#' sign, is the name of the attribute attached to the resource "constants". Despite the resource "constants" did not exist beforehand, the "createAttribute" method will create every missing resource along the path as long as it complies with the WildCAT hierarchy constraints (Attributes and resources attached to a given resource must be unique). Once created,

System.out.println("self://constants#hello = " + ctx.getValue("self://constants#hello"));

would output: "self://constants#hello = Hello". Now, let's change that attribute value:

System.out.println("self://constants#hello = " + ctx.setValue("self://constants#hello", "Hello World !!!"));
System.out.println("self://constants#hello = " + ctx.getValue("self://constants#hello"));

The first statement has the same output: "self://constants#hello = hello". Indeed, the "setValue" method of the Context Interface returns the previous value of the attribute. After executing the "setValue" method, the second statement outputs "self://constants#hello = Hello World !!!".

LISTING HIERARCHY CONTENT

The Context interface permits user to list resource content, i.e. the code below:

System.out.println("self:// :: " + ctx.list("self://"));

lists subresources and attributes attached to the root resource. In our example, only the "constants" resource is attached to the root resource.

CREATING SYMBOLIC LINKS

Symbolic links (also known as symlinks or soft links) are special resources that hold a reference to another resource. Symbolic links transparently alters path resolution by pointing to another resource. The Context interface allows an easy creation of symbolik links, the following code:

ctx.createSymbolicLink("self://demo/soft/link/toConstant", "self://constants");

creates a symbolic link at position "self://demo/soft/link/toConstant" pointing to "self://constants". From now, every path resolution entering resource "self://demo/soft/link/toConstant" will be redirected to "self://constants". Thus, the following code:

System.out.println("self://demo/soft/link/toConstant#hello = " + ctx.getValue("self://demo/soft/link/toConstant#hello"));

will output the value of the attribute at "self://constants#hello" which is "Hello World !!!".

EXAMPLE

Let’s assume that we are monitoring the status of some computers and printers. To simplify, we suppose that such devices are identified by a unique name and can be in one of the following status: {ON, OFF, Standby}. Here is a full code example explaining the usage of PULL mode operations on a context.

package org.ow2.wildcat.examples.pull;

import org.ow2.wildcat.Context;
import org.ow2.wildcat.ContextException;
import org.ow2.wildcat.ContextFactory;

public class PULLModeExample {
	
	public static void main(final String[] args) {
		/*
		 * Creating a context through the ContextFactory
		 */
		Context ctx = ContextFactory.getDefaultFactory().createContext("TechnicalResources");
		/*
		 * Getting the context name
		 */
		System.out.println("Context name = " + ctx.getName());
		try {
			/*
			 * Creating some resources
			 */
			ctx.createResource("self://computers/pc1");
			ctx.createResource("self://computers/pc2");
			ctx.createResource("self://printers/ColorPrinter");
			ctx.createResource("self://printers/BWPrinter");
			/*
			 * Creating and initializing attributes
			 */
			ctx.createAttribute("self://computers/pc1#name", "pc1");
			ctx.createAttribute("self://computers/pc1#status", "ON");
			ctx.createAttribute("self://computers/pc2#name", "pc2");
			ctx.createAttribute("self://computers/pc2#status", "OFF");
			ctx.createAttribute("self://printers/ColorPrinter#name", "colorprinter");
			ctx.createAttribute("self://printers/ColorPrinter#status","Standby");
			ctx.createAttribute("self://printers/BWPrinter#name", "bwprinter");
			ctx.createAttribute("self://printers/BWPrinter#status", "Standby");
			/*
			 * Listing all printers
			 */
			System.out.println("Printers = " + ctx.list("self://printers"));
			/*
			 * Getting pc2 status attribute
			 */
			System.out.println("pc2 status is : "
					+ ctx.getValue("self://computers/pc2#status"));
			/*
			 * Setting pc1 status attribute to OFF
			 */
			ctx.setValue("self://computers/pc1#status", "OFF");
			System.out.println("pc1 status is : "
					+ ctx.getValue("self://computers/pc1#status"));
			/*
			 * Creating a symbolic link to the Black and White printer
			 */
			ctx.createSymlink("self://bwp", "self://printers/BWPrinter");
			/*
			 * Getting BWPrinter status attribute using the symbolic link
			 */
			System.out.println("BWPrinter status is : "
					+ ctx.getValue("self://bwp#status"));
		} catch (ContextException e) {
			e.printStackTrace();
		}
	}// end main
}// end PULLModeExample

The expected output is the following:

Context name = TechnicalResources
Printers = [ColorPrinter, BWPrinter]
pc2 status is : OFF
pc1 status is : OFF
BWPrinter status is : Standby

PUSH MODE

EVENT QUERY LANGUAGE

To perform query processing, WildCAT relies on the Esper Complex Event Processing Engine. Queries are described in the Event Query Language (EQL). It is very similar to the SQL Language. While SQL queries works on Database tables, EQL works on sliding windows of Events. Esper EQL provides many interesting features among which: sliding windows (in time and space), JOIN, WHERE, GROUP BY, HAVING AND SORT CLAUSE, output limitations. Those willing to fully exploit the EQL (Event Query Language) should refer to the Esper documentation and tutorials.

WRITING QUERIES

The Context interface provides method to create queries. The following code:

Query query = ctx.createQuery("select * from WEvent");

returns a query reference for "select * from WEvent". This query will catch every event traversing WildCAT. WildCAT automatically starts queries upon creation.

LISTENING TO QUERIES

WildCAT push mode allows developers to register listeners to queries. These listeners contain the Java code for the action to be performed if these queries are triggered. Handlers must implement the WAction abstract class. The onEvent method of this class is the one triggered when new events are available for the associated query. Here is an example of how to create a new simple WAction :

public class SimpleAction extends WAction {

	public SimpleAction(String name,String description) {
		super(name,description);
	}
	
	public void onEvent() {
		System.err.println( "action " + name + " performed");
	}

}

In our example, we must now register an action to execute if the newly created Query is triggered. The Context Interface provides the registerActions method that takes a query instance and an array of WAction.

WAction action = new SimpleAction("myAction","simple action to perform");
ctx.registerActions(query, action);

Similarly, the Context interface provides means to remove listeners and to destroy queries and their listeners:

/*
* detaching an action
*/
ctx.removeActions(query, actions);
/*
* destroying a query and its listeners
*/
ctx.destroyQuery(query);

SPECIAL QUERY ATTRIBUTES

WildCAT provides means to create attributes that holds the result of a query. These special attributes called "query attributes", are associated with a query. Query attributes can be used as normal attributes, i.e. their content can be accessed in PULL mode, it returns the last result of the query; and one can reference them in PUSH mode as part of a query. The following code snippet creates such an attribute:

QueryAttribute qa = new QueryAttribute("select avg(cast(value.load,int))
	from WAttributeEvent(source='self://an#attribute').win:time(5 sec)");

The new attribute "qa" will hold the average of the field "value.load" of "attribute" over the last 5 seconds.

PERIODIC ATTRIBUTE POLLING

WildCAT provides means to simulate an active sensor based on a passive one by periodically crafting an event with the current value of a given attribute. The following code snippet will create a new event containing the current value of the attribute "self://path/to/an#attribute" every 2 seconds:

ctx.createPeriodicAttributePoller("self://path/to/an#attribute", 2, TimeUnit.Second);

EXAMPLE

Here is a full code example for using the PUSH mode. First, we create an attribute poller to pick up information from the JavaRuntime sensor (provided by default in WildCAT sensors package) such as the free memory, the total memory or the maximum amount of memory that the Java virtual machine will attempt to use. Then, we'll create a query attribute to hold the used amount of memory. Finally, we register a listener to a query giving the maximum of the used amount of memory for the last 5 seconds.

package org.ow2.wildcat.examples.push;

import org.ow2.wildcat.Context;
import org.ow2.wildcat.ContextException;
import org.ow2.wildcat.ContextFactory;
import org.ow2.wildcat.Query;
import org.ow2.wildcat.WAction;
import org.ow2.wildcat.hierarchy.attribute.QueryAttribute;
import org.ow2.wildcat.sensors.JavaRuntimeSensor;
import java.util.concurrent.TimeUnit;

public class PUSHModeExample {

	public static void main(String[] args) {
		/*
		 * Creating a context through the ContextFactory
		 */
		Context ctx = ContextFactory.getDefaultFactory().createContext();
		
		try {
			/*
			 * Creating and attaching a JavaRuntuime Sensor to a specific attribute
			 */
			ctx.attachAttribute("self://jvm#javaRuntime", new JavaRuntimeSensor());
			
			/*
			 * Creating a periodic attribute poller for the "self://jvm#javaRuntime"
			 * attribute
			 */
			ctx.createPeriodicAttributePoller("self://jvm#javaRuntime", 1 , TimeUnit.SECONDS);
			
			/*
			 * Creating a query attribute holding the (jvm) used memory
			 */
			QueryAttribute usedMemory = new QueryAttribute(
			"select ((cast(value('total-memory')?,long))-(cast(value('free-memory')?,long)))" +
			"as usedMemory from WAttributeEvent(source = 'self://jvm#javaRuntime')");
			
			/*
			 * Attaching the query attribute "usedMemory" to the hierarchy
			 */
			ctx.attachAttribute("self://jvm#usedMemory", usedMemory);
			
			/*
			 *Creating a query to select the maximum of (jvm) used memory for the last *5 seconds
			 */
			Query query = ctx.createQuery("select max(cast(value('usedMemory')?,long))" +
			" as MaxUsedMemory from WAttributeEvent(source = 'self://jvm#usedMemory').win:time(5 sec)");
			
			/*
			 * Registering a simple action to the query
			 */
			ctx.registerActions(query, new WAction() {
				@Override
				public void onEvent() {
					System.out.println("Maximum of used memory for the last 5 seconds = " +
					getListener().getNewEvents()[0].get("MaxUsedMemory"));
				}
			});
			
		} catch (ContextException e) {
				e.printStackTrace();
		}

	}// end main
}// end PUSHModeExample

Chapter 4. WILDCAT SENSORS

In this chapter, we introduce the various existing sensors shipped with WildCAT. Then we describe how to easily implement new sensors compatible with the WildCAT framework. WildCAT team main objective is not to develop sensors, but to provide a generic framework to organize and inspect monitoring sources. Nevertheless, we distribute along with the WildCAT framework a sensors library that we extend as we develop new sensors for our own experiment. Moreover, external contributions are welcome.

THE SENSORS LIBRARY

WildCAT provides the following sensors (available in the org.ow2.wildcat.sensors package):

  • Java related sensors

    • JavaRuntimeSensor provides information relative to the current JVM (processor, memory, etc)

    • SystemPropertiesSensor provides a wrapper for Java System Properties

    • MBeanCMDSensor allows for gathering of any JMX related information (defined in synergy with the JASMINe project)

    • DateTimeSensor provides system current time

  • System related sensors (Linux-only)

    • KernelVersionSensor provides system kernel version

    • CPUSensor provides information (model, version, etc) of the CPU

    • CPULoadSensor provides instant CPU load

DESIGNING A NEW SENSOR

Implementing a WildCAT sensor is a matter of very few lines of code. Every Java class that implements the Attribute interface can be used as a WildCAT sensor. The POJOAttribute class provides a default implementation of the Attribute interface. Nevertheless, we can refine the behavior of the new sensor by extending the POJOAttribute class and overriding its "getValue" and "setValue" methods. When one access the content of the sensor through the "getValue" method from the "Context" interface, the "getValue" method of the sensor class is triggered. This is the same for the setValue method, but in addition, a new WAttributeEvent is triggered to notify the value change of the attribute and return its old value.

EXAMPLE 1: THE RNGSensor

To illustrate the design of new sensors, we'll create a simple sensor generating random Integer numbers. To do it, we overload the POJOAttribute class:

import java.util.Random;

import org.ow2.wildcat.hierarchy.attribute.POJOAttribute;

public class RNGSensor extends POJOAttribute {
	
	public RNGSensor(Object value) {
		super(value);
	}

	protected Random random = new Random(System.currentTimeMillis());

	@Override
	public Object getValue() {
		this.setValue(this.random.nextInt());
		return this.value;
	}
}

The RNGSensor class extends the POJOAttribute class that is the most common type of attribute. We add the "random" field to hold a random number generator. To keep it simple, we only overload the "getValue" method from the "POJOAttribute" class. When one access the content of this sensor through the "getValue" method from the "Context" interface, the "getValue" method of the "RNGSensor" class is triggered. It changes the sensor current value with a newly picked random Integer, and launch a new WAttributeEvent to notify the value change. Then, it returns that new value.

EXAMPLE 2: THE IPSensor

This second example of sensor can be used in a distributed context. Here is a WildCAT sensor that returns the hostname and the IP address for a remote machine. In this case, the "getValue" method returns couples of (key,value) for hostname and IP address in a Java HashMap.

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.Map;

import org.ow2.wildcat.hierarchy.attribute.POJOAttribute;

public class IPSensor extends POJOAttribute {
	public IPSensor() {
		super(null);
	}

	@Override
	public Object getValue() {
		Map<String, Object> m = new HashMap<String, Object>();
		InetAddress localhost;
		try {
			localhost = InetAddress.getLocalHost();
			m.put("HostName", localhost.getHostName());
			m.put("HostAddress", localhost.getHostAddress());
		} catch (UnknownHostException e) {
			return null;
		}
		return m;
	}
}

USING A NEW SENSOR

WildCAT sensors should be attached to a context hierarchy using the "attachAttribute" method of the context interface. The code snippet below:

Context ctx = ContextFactory.getDefaultFactory().createContext();
Attribute myIPSensor = new IPSensor();
ctx.attachAttribute("self://#myIdentity", myIPSensor);
System.out.println("My Identity is = " + ctx.getValue("self://#myIdentity"));

would output:

My Identity is = {HostAddress=yourIPaddress, HostName=yourHostname}

Chapter 5. DISTRIBUTED CONTEXTS

In this chapter, after describing the different communication protocols used between the remote contexts, we describe the code and the configuration of two contexts running on different JVMs and interacting.

COMMUNICATION BETWEEN REMOTE CONTEXTS

According to the mode, the communication protocol varies:

  • Pull mode relies on a synchronous communication;

  • Push mode relies on an asynchronous communication.

RMI-JMS DISPATCHER

Each WildCAT context is connected to a collocated registry in which it binds its own RMI stub identified by its context name. Thanks to CMI, all the stubs and topics can be retrieved by simply looking up into its own registry!

FULL JMS DISPATCHER

Each WildCAT context is connected to a remote registry in which it retrieves the connection factories needed to connect itself to topics and queues.

EXAMPLE

Let's consider the example hierarchy presented in the image.

The hierarchy shows two distinct contexts named node1 and node2. The link from context node1 to context node2 depicts a symbolic link.

Here we assume, a JMS provider is up and running and accepts connections at rmi://jmshost:jmsport. The JMS provider must expose both a Queue and a Topic connection factory. (Supposing the factories are exposed as JQCF and respectively JTCF).

Numerous implementations of JMS providers exist. The actual process of setting up and running a JMS provider is out of the scope of this tutorial. As a note, we are successfully using both the openJMS and the Joram provider with WildCAT.

Let's consider the very simple code for creating and building both hierarchies. First the code of the node2:

public class Node2 {

public static void main (String[] args) {

System.setProperty("org.ow2.wildcat.configuration","/wildcat.node2.properties");

Context ctx = ContextFactory.getDefaultFactory().createContext("node2");

ctx.registerListeners("select * from WEvent", new UpdateListener () {
void update (EventBean[] nevents, EventBean[] oevents) {
for (EventBean bean : nevents) {
System.out.println("---> " + bean.getUnderlying().toString());
}}});

ctx.export();

ctx.createResource("self://creating/node2/dummy/hierarchy");

}
}

The code first sets the "org.ow2.wildcat.configuration" system properties to point node2 hierarchy configuration file. Then it instantiate a context named "node2" through the default ContextFactory. Then it registers the "usual" "show me everything" listener. After that, the "export" method renders the context visible to remote contexts. The code of the node1 is the following:

public class Node1 {

public static void main (String[] args) {

System.setProperty("org.ow2.wildcat.configuration","/wildcat.node1.properties");

Context ctx = ContextFactory.getDefaultFactory().createContext("node1");

ctx.registerListeners("select * from WEvent", new UpdateListener () {

void update (EventBean[] nevents, EventBean[] oevents) {
for (EventBean bean : nevents) {
System.out.println("---> " + bean.getUnderlying().toString());
}
}});

ctx.export();

ctx.createResource("self://creating/node1/dummy/hierarchy");

ctx.createSymlink("self://node2","node2://any/resource/in/node2/hierarchy");
}
}

node1's code is very similar to node2's one. Indeed, context creation and configuration are identical. The code also must export the context using the "export" method. Finally the interaction between, node1 and node2 is made by the creation of the symlink between the two. Let's now consider the two configuration files (when the full‐JMS dispatcher is used): Node2:

org.ow2.wildcat.remote.jms_provider_url=tcp://jmshost:jmsport
org.ow2.wildcat.remote.queue_connection_factory=JMSQueueConnectionFactory
org.ow2.wildcat.remote.topic_connection_factory=JMSTopicConnectionFactory
org.ow2.wildcat.remote.dispatcher_name=dispatcher2

Node1:

org.ow2.wildcat.remote.jms_provider_url=tcp://jmshost:jmsport
org.ow2.wildcat.remote.queue_connection_factory=JMSQueueConnectionFactory
org.ow2.wildcat.remote.topic_connection_factory=JMSTopicConnectionFactory
org.ow2.wildcat.remote.dispatcher_name=dispatcher1

Both file first defines the JMS provider url and both Topic and Queue connection factory names. Finally and most importantly is the name of the dispatcher. A dispatcher is the JMS frontend used in between communicating contexts. Each dispatcher must have a unique name and dispatcher and context must not have identical names. Here, we simply named our dispatcher dispatcher1 and dispatcher2.