Overview of Apama JMon applications

Info
Apama’s in-process API for Java (JMon) is deprecated and will be removed in a future release. The JMon migration guide post in https://apamacommunity.com will help you to port your JMon applications.

This part provides information and instructions for using Apama’s in-process API for Java, called JMon, to write applications that run on the correlator. To develop an Apama application you can use the correlator’s native Event Processing Language (EPL) or JMon. This part focuses exclusively on how to use JMon to write an application that runs on the correlator.

JMon reference documentation is provided in Javadoc format.

Important
Apama provides both EPL and JMon as ways to create powerful Complex Event Processing (CEP) applications. Both types of application can use Apama’s event expressions to set up listeners that detect patterns of events. With JMon, however, there are restrictions on the Apama capabilities that can be used. Therefore, for new applications it is strongly recommend to choose the more powerful EPL language over JMon. A common pattern for writing the main logic and event expressions for a CEP application is to use EPL (not JMon), with the EPL code calling Java plug-ins (see Writing EPL plug-ins in Java) as needed for specific operations such as invoking a third-party library. Keep in mind that a Java plug-in is not the same as a JMon application, and JMon should be considered a legacy feature. Any future enhancements in this area will be made to the Java plug-in mechanism and not to JMon. Any customer application that needs to tightly integrate CEP logic with Java libraries should use the more modern pattern of EPL calling into Java plug-ins.

JMon restrictions include:

  • Streams cannot be defined.
  • Multiple contexts are not supported.
  • Channels are not supported.
  • Decimal data types are not supported.
  • Other EPL plug-ins cannot be called.

The correlator is Apama’s core event processing and correlation engine. Interfaces to the correlator let you inject monitors that

  • Analyze incoming event streams to find patterns of interest
  • Specify the actions to undertake when the correlator identifies such patterns

You can use the Apama JMon API to write applications that are to be deployed on the correlator.

The correlator embeds a Java Virtual Machine in which Apama JMon applications can be loaded and run.

The JMon API provides a suite of Java classes that allow a developer to build a Java application, and then inject it into the correlator. Apama JMon applications can define listeners, which specify patterns and sequences of events to look for and actions to carry out when the correlator detects those events.

You can develop Apama JMon applications in Apama Plugin for Eclipse. When you use Apama Plugin for Eclipse to develop an application, it can automatically generate a framework for your JMon event and JMon monitor files.

For more information on developing JMon applications in Apama Plugin for Eclipse, see, Adding a new JMon application, Adding a JMon monitor, and Adding a JMon event.

Info
Apama includes the in-process API for Java (JMon) and the client API for Java. In most cases, the context makes it clear which API the discussion is addressing. When this is not clear, the APIs are referred to as the JMon API or Apama client API for Java.

Introducing JMon API concepts

This section introduces the main concepts behind programming the functionality within Apama using JMon. It describes how events are modeled in JMon and how they are used to drive and trigger listeners within JMon monitor classes.

Apama is designed to fit within an event (or message) driven world. In event driven systems information is propagated through units of information termed events or messages. Conceptually, an event typically represents an occurrence of a particular item of interest at a specific time, and is usually encoded as an asynchronous network message.

Apama is designed to process thousands of these event messages per second, and to sift through them for sequences of interest based on their contents as well as their temporal relationships to each other. When writing Apama applications using JMon, the Java code you write informs the correlator of the sequences of interest and, when matching event sequences are detected, these are passed to your JMon code for handling. Apama’s correlator component is capable of looking for hundreds of thousands of different event sequences concurrently.

In order to program the correlator using JMon, a developer must write their application as a set of Java classes that implement the JMon APIs. This programming model is similar to writing Enterprise JavaBeans intended for use in an application server. These Java classes then need to be loaded (or “injected”) into the correlator, which instantiates and executes them immediately.

Almost all of the standard language functionality provided by Java and its libraries can be used in JMon applications, just as in any other Java applications. However, the power of the correlator is only truly leveraged by invoking its event matching, correlation and event generation capabilities. As streams of events are passed into a correlator, the listeners defined in JMon applications sift through the events looking for specific sequences of interest matching a variety of temporal constraints. Once a listener triggers, a method is invoked on a Java object, the Match Listener object. The developer specifies this object when the listener is created.

Three kinds of Java class objects can be loaded into the correlator; event types, monitors and match listeners.

  • Event type classes serve to define the event types that the correlator can accept from external sources and carry out correlations on.
  • Monitor classes program the correlator. They define what event patterns the correlator must look for and allow arbitrary Java code to be executed.
  • Match listeners provide a method that is called when a specific event sequence is detected.

These three Java class types will be now be discussed in detail.

About event types

Apama events are strongly typed. Each event must be of a specific known type, henceforth called the event type. An event type defines the name of the event, and its particular set of parameters. Every parameter is named and can be one of a selection of types. Every event instance of a given event type is therefore identical in structure; every instance has the same set (and order) of parameters.

Before the correlator can understand and process events of a specific event type, it needs to have been provided with an event type definition. This allows it to understand the event messages it is passed, create optimal indexing structures, and allows listeners to be set up to look for event sequences involving events of that type.

An event type definition defines the event type’s name and the name, type and order of each of its parameters. Parameters can be of any of the following types:

  • Java standard types String, long, double, boolean or Map.
  • Java arrays.
  • com.apama.jmon.Location type — This type corresponds to either a spatial point represented by two coordinates, or a rectangular space expressed in terms of its two bounding corners.

Apama’s JMon API supports Java generic maps. Apama recommends that you use these when possible instead of the Event.getMapFieldTypes() method. Doing so lets you gain the benefits of compile-time type safety as well as a simpler class definition.

However, while it is valid to declare a parameter to be an array of generic maps, assignment of values to the map elements is not type-safe, and will be rejected by the Java compiler. If you need a parameter that is an array of maps, use the Event.getMapFieldTypes() method instead of generic maps.

You can nest a plain Map as a value (not a key) at any depth in a parameterized Map. You cannot nest a parameterized Map in a plain Map. This is because you would not be able to specify the parameterized types to be returned from the getMapFieldTypes() method. Of course, you can nest a parameterized Map as a value (but not a key) in a parameterized Map. For example:

EPL:

event BadComplexEventExample {
   dictionary <string, dictionary <string, SimpleEvent>>  complex;
}

Java:

import java.util.Map;
import java.util.HashMap;
import com.apama.jmon.Event;
public class BadComplexEventExample extends Event {
   // By using a non-parameterized map you lose the information that the
   // field is a dictionary with values that are also dictionaries.
   public Map complex;

   public BadComplexEventExample() {
      this(new HashMap());
   }

   public BadComplexEventExample(Map complex) {
      this.complex = complex;
   }
}

See also the definition of ComplexEvent in About event parameters that are complex types.

An event can embed an event (potentially of a different type) as a parameter.

Simple example of an event type

An event type is defined as a Java class as per the following example,

/*
 * Tick.java
 *
 * Class to abstract an Apama stock tick event. A stock tick event
 * describes the trading of a stock, as described by the symbol
 * of the stock being traded, and the price at which the stock was
 * traded
 */

import com.apama.jmon.Event;

public class Tick extends Event {
   /** The stock tick symbol */
   public String name;

   /** The traded price of the stock tick */
   public double price;

   /**
    * No argument constructor
    */
   public Tick() {
      this("", 0);
   }

   /**
    * Construct a tick object and set the name and price
    * instance variables
    *
    * @param name  The stock symbol of the traded stock
    * @param price The price at which the stock was traded
    */
   public Tick(String name, double price){
      this.name = name;
      this.price = price;
   }
}

By Java programming conventions, the previous definition would need to be provided on its own in a stand-alone file, for example, Tick.java.

The definition must import the definition of the Event class. This is provided as part of the com.apama.jmon package provided with your Apama distribution. See Developing and deploying JMon applications on installation and deployment for details of where to locate this package.

Event is the abstract superclass of all user classes implementing desired event types. Then we must define our new event class as a subclass of the Event type.

The user-defined event class must have three primary elements:

  • A set of public variables that define the event’s parameters
  • A “no argument” constructor, whose purpose is to construct an instance of the event with the parameters set to default values
  • A constructor whose parameter list corresponds (in type and order) to the event’s parameters. This constructor allows creation of an instance of the event with specific parameter values.

In the above example the event is called Tick, and it has two parameters, name, of type String, and price, of type double. The previous definition may be considered a simple template for how to write all event definitions.

Info
Non-public (like private and protected) variables are not considered to be part of the event schema.

Extended example of a JMon event type

Let us now consider an extended example:

package test.jmon.example;

import java.util.Map;
import com.apama.jmon.*;

/*
 * TestEvent.java
 *
 * Class to abstract an Apama event whose primary purpose is to
 * showcase how to define an event class containing parameters of
 * all the allowed types, including arrays and Maps.
 */

public class TestEvent extends Event {

   // example of parameters of the basic types
   public long primitiveInteger;
   public double primitiveFloat;
   public boolean primitiveBoolean;
   public String referenceString;

   // example of parameters consisting of arrays of the basic types
   public long[] sequenceInteger;
   public double[] sequenceFloat;
   public boolean[] sequenceBoolean;
   public String[] sequenceString;

   // a nested event of type EmbeddedTestEvent
   public EmbeddedTestEvent referenceNestedTestEvent;

   // a parameter of type Location
   public Location referenceLocation;

   // a parameter of type Map
   public Map<long, String> dictionaryIntegerString;
...

}

Comparing JMon and EPL event type parameters

You might already be familiar with EPL, the Apama complex event processing scripting language through which the correlator can be programmed as an alternative to JMon. Event types defined in JMon can be used in EPL, and vice-versa. JMon event type parameters map to EPL parameter types as follows:

JMon Type Equivalent EPL Type
long integer
double float
boolean boolean
String string
Location location
array sequence (of the same type)
Map dictionary (with the same key and value types)
com.apama.jmon.Event or its subclass event (with the same equivalent subset of fields as defined in this table)

The correlator’s performance can be optimized by wildcarding event type definitions where appropriate. This procedure is described in Optimizing event types.

About event parameters that are complex types

It is possible in both EPL and JMon to declare a field of an event definition to be a complex type. For example, the SequenceEvent definition below defines an event that is constructed from a sequence of DataHolder events, which in turn contain a string and an integer. This is defined in EPL in two events thus:

event DataHolder {
   string name;
   integer age;
}

event SequenceEvent {
   sequence <DataHolder> complex;
}

An example constructed SequenceEvent event is show below:

SequenceEvent([DataHolder("kap", 1), DataHolder("gbs", 2)])

The equivalent event definitions for the above in Java are defined below:

import com.apama.jmon.Event;

public class DataHolder extends Event {
   /** Event fields */
   public String name;
   public long age;

   /** No argument constructor
   */
   public DataHolder () {
      this("", 0);
   }
   /** Construct a DataHolder object and set the instance variables
   */
   public DataHolder (String n, long a) {
      name = n;
      age = a;
   }
}

import com.apama.jmon.Event;

public class SequenceEvent extends Event {

   /** Event field */
   public DataHolder[] people;

   /** No argument constructor
   */
   public SequenceEvent() {
      this( new DataHolder[]{} );
   }

   /** Construct a SequenceEvent object and set the instance variable
   */
   public SequenceEvent(DataHolder[] p) {
      this.people = p;
   }
}

Sample Java code to create and emit a SequenceEvent event is shown below:

  s = new SequenceEvent(new DataHolder[] {new DataHolder("kap", 1),
   new DataHolder("gbs", 2)} );
  s.emit();

Events can also include Map types, which are equivalent to EPL dictionary types. When you use Map types, Apama recommends that you use generic maps whenever you can. For example, in EPL the following event is a dictionary of dictionaries and each internal dictionary is a sequence of SimpleEvent types:

event ComplexEvent {
  dictionary <string,
    dictionary <string, sequence<SimpleEvent>>> complex;
}

You can implement this in Java as follows:

import java.util.Map;
import java.util.HashMap;
import com.apama.jmon.Event;
import com.apama.jmon.annotation.EventType;

@EventType(description = "Event that contains a field with a complex structure")
public class ComplexEvent extends Event {

   /** Event field */
   public Map<String, Map<String, SimpleEvent[]>> complex;
   /**
   * No argument constructor
   */
   public ComplexEvent() {
      this(new HashMap<String, Map<String, SimpleEvent[]>>());
   }

   /**
   * Construct a ComplexEvent object, set the instance variable complex
   *
   * @param complex The dictionary/Map to use as the field value
   */
   public ComplexEvent(
      Map<String, Map<String, SimpleEvent[]>> complex) {
        this.complex = complex;
      }
}

This example is provided in its complete form as a sample. It is distributed in the folder samples/java_monitor/complex_event/.

Non-null values for non-primitive event field types

When the correlator creates an event to pass to the JMon code, it ensures that all fields of a non-primitive type have a non-null value. Note that this is different from the Java default, which is to allow null values for non-primitive types.

The com.apama.jmon.Event default constructor uses reflection to initialize non-primitive null fields with the following values:

  • sequence — an empty array of the specified type.
  • dictionary — an empty java.util.HashMap object.
  • string — an emptyjava.lang.String object.
  • event — a default construction of the event, with recursive initialization for any of its non-primitive fields that have null values.

In your application, if you explicitly assign a null value to a non-primitive event field, and your application tries to emit, enqueue, or route that event, the correlator logs an error and terminates your application.

About monitors

Monitor classes configure the activity of the correlator. This is analogous to how an Enterprise JavaBean effectively defines the activity of an application server.

All monitor classes must implement the com.apama.jmon.Monitor interface and define an onLoad method. When a monitor class is loaded into the correlator, it is instantiated as an object and its onLoad method is executed. In Java parlance, this would be equivalent to the static void main (args[]) method.

Most Java code (with certain limitations) can be executed within the onLoad method, although its primary purpose is probably to configure one or more asynchronous listeners for specific events or event sequences.

A monitor class must define a “no argument” constructor. The Java code within the correlator uses this when the class definition is loaded.

Below is a minimal monitor:

import com.apama.jmon.*;

public class Simple implements Monitor {
   /**
    * No argument constructor used by the jmon framework on
    * application loading
    */
   public Simple() {}

   /**
    * Implementation of the Monitor interface onLoad method.
    * Does nothing.
    */
   public void onLoad() {
   }
}

The above monitor class does nothing and is shown here as a template for how to define a monitor class.

EPL. Although there are similarities, the concept of a monitor in EPL and in JMon is not the same. The EPL monitor is a very powerful custom programming structure, whereas in JMon a monitor class is primarily a standard Java class with an entry method that gets automatically executed upon loading (as described in the topics below).

About event listeners and match listeners

For a monitor class to leverage the intrinsic features of the correlator, it must set up one or more listeners.

A listener is a conceptual entity whose function is to sift through all incoming event streams looking for a particular event or sequence of events. The event or sequence of events of interest is represented as an event expression.

The simplest way of setting up a listener is by creating an instance of an EventExpression and then specifying a MatchListener object that gets triggered when the expression becomes true, that is, when a suitable event or event sequence is detected. A more efficient alternative is to use a prepared event expression, which is described in Optimizing event types.

A match listener is a Java object that implements the com.apama.jmon.MatchListener interface and implements the match method. This method is called by the correlator when the event expression it is registered with is detected.

Example of a MatchListener

The following example illustrates this functionality:

import com.apama.jmon.*;
public class Simple implements Monitor, MatchListener {

   /**
    * No argument constructor used by the jmon framework on
    * application loading
    */
   public Simple() {}
   /**
    * Implementation of the Monitor interface onLoad method. Sets up
    * a single event expression looking for all Tick events
    * with a trade price of greater than 10.0. This class instance
    * is added as a match listener to the event expression.
    */
   public void onLoad() {
      EventExpression eventExpr = new EventExpression("Tick(*, >10.0)");
      eventExpr.addMatchListener(this);
   }

   /**
    * Implementation of the MatchListener interface match method.
    * Prints out
    * a message when the listener triggers
    */
   public void match(MatchEvent event) {
      System.out.println("Pattern detected");
   }
}

This example illustrates several new concepts.

Consider the onLoad method. Firstly it creates an event expression object variable. This object, of type com.apama.jmon.EventExpression, represents an event, or sequence of events, to look for. The constructor of an EventExpression is passed a string that defines the actual event expression.

As the syntax of an event expression will be illustrated in the next section it is enough to say that this event expression is specifying “the first Tick event whose price parameter is greater than the value 10.0”.

Then, a match listener is registered with the newly created event expression object. A match listener can be any object that implements the com.apama.jmon.MatchListener interface and defines the match(MatchEvent event) method. For the sake of simplicity, the Simple monitor class has here been written to also implement the MatchListener interface, and therefore the statement,

eventExpr.addMatchListener(this);

is passing this as the reference to a suitable MatchListener.

Once a match listener has been registered with an event expression the correlator creates a listener entity to start looking for the specified event expression.

Listeners are asynchronous. Hence the match method may be invoked at any time subsequent to the activation of the listener, but always after all Java code in the current method finishes executing. Therefore in this case all Java statements in the onLoad method would finish being executed before match is called after a match.

Defining multiple listeners

A monitor can define any number of event expressions, and create any number of listeners. The following code,

public void onLoad() {
   EventExpression eventExpr1 = new EventExpression("Tick(*, >10.0)");
   EventExpression eventExpr2 =
      new EventExpression("NewsItem(\"ACME\", *)");

   eventExpr1.addMatchListener(this);
   eventExpr2.addMatchListener(this);
}

is creating two event expressions, eventExpr1 and eventExpr2. Then each is assigned a match listener, thus activating two distinct listeners. The fact that both are being assigned the same match listener object, i.e. this same object this, is inconsequential. It just means that the same method, the match method of this object, will be called when the correlator detects either of the event expressions.

As already described, creating a listener is an asynchronous operation that returns immediately. In the above code, in practice both listeners are created concurrently. It is not possible for the eventExpr1 listener to trigger before the eventExpr2 listener is created. However, once the enclosing method’s code has completed execution, the listeners can trigger at any time, and independently of each other.

Removing listeners

A MatchListener instance that is no longer connected to an event expression, and to which there are no references, is garbage collected in the usual way. In some situations, you might want to be notified when the correlator removes its reference to the MatchListener (when it can no longer fire). For example, you might need this notification if the MatchListener has unmanaged resources (for example, open files) that need to be explicitly cleaned up when it is no longer needed, or your application has other references to the MatchListener that need to be removed when the listener can no longer fire so that it can be garbage collected. In those situations, you can define your listener so that it implements the com.apama.jmon.RemoveListener interface. There is no requirement to implement this interface. It is up to you to determine whether you need it.

The RemoveListener interface extends the MatchListener interface by providing one additional method: removed(). If you implement the RemoveListener interface, the correlator calls your implementation of the removed() method in the following situations:

  • The application removes your listener from the event expression it is attached to.
  • The event expression your listener is attached to is in a state that will never match. For example, on A() within (10.0) after 10 seconds have elapsed without an A().

In the following example, the removed() method is called because the event expression dies after 10 seconds.

import java.util.HashMap;
import com.apama.jmon.*;

public class Test implements Monitor {
   public Test() {}
   public void onLoad() {
      EventExpression e = new EventExpression("TestEvent() within(10.0)");

      e.addMatchListener(new RemoveListener() {
         public void match(MatchEvent event) {
            System.out.println(Correlator.getCurrentTime() +
               ": Received match");
         }
      public void removed(EventExpression e) {
         System.out.println(Correlator.getCurrentTime() +
            ": Received removed");
      }
      });
   }
}

Description of the flow of execution in JMon applications

The flow of execution of JMon applications through the correlator at any given time is single threaded. All the listeners of JMon applications are fired in a single-threaded manner. However, during the lifetime of a JMon application, its execution may be moved among a number of threads by the correlator. This is particularly important since thread-local variables will not behave in the same way as you would expect them to in a conventional Java application.

When a number of monitor classes are loaded into the JVM within the correlator their onLoad methods are executed in turn, in the same order as the injected classes, and any listeners created are set up and activated.

Control then reverts to the correlator, which takes in one event from its input queue. This event is examined by each of the active listeners in turn (the order is undefined), and each one that triggers immediately calls the match() method in its registered MatchListener object.

Once all the listeners have processed the event (and hence all match methods terminated), control reverts to the correlator to process the next input event. Note that since events can also match listeners in EPL monitors, these would also be processed before control reverts.

However, JMon applications can create other Java threads. In such multi-threaded JMon applications, the correlator has no control of these additional Java threads. Consequently, you should never route or emit an event from a Java thread that was not the thread in which the correlator invoked the JMon application. Doing this results in unpredictable behavior. To communicate from your JMon application to other parts of the correlator, use the enqueue() method or preferably, the enqueueTo() method.

Parallel processing in JMon applications

By default, the correlator operates in a serial manner. If you want, you can implement contexts for parallel processing. You can create contexts only with EPL but you can then use those contexts from your Apama JMon code. This section provides information about how to use contexts in Apama JMon applications.

For general information about contexts and instructions for creating contexts, see Implementing parallel processing.

Overview of contexts in JMon applications

The Apama JMon API provides the com.apama.jmon.Context type. This class corresponds to the EPL context type, but with a more limited set of features:

  • A JMon event definition can contain a Context type field. This lets you transfer a reference to a context to and from an Apama JMon application. You cannot pass context references between the correlator and your Apama JMon application on their own.

  • You can enqueue events to

    • Particular contexts:Event.enqueueTo(Context c)

    • A list or array of contexts:

      Event.enqueueTo(java.util.List<Context> ctxList)
      Event.enqueueTo(Context[] ctxList)
      

      See Emitting, routing, and enqueuing events.

  • You can call Context.getCurrent() to obtain a reference to the context that a piece of code is running in. See Obtaining context references.

  • The Context class provides accessor methods for context properties such as context name and context ID.

Using contexts in JMon applications

To use EPL contexts in JMon applications

  1. In EPL code, create a context that you want to use in your JMon application.

  2. In your JMon application, define an event type that contains a Context field.

  3. Use this event type to obtain a reference to the context you created in EPL.

  4. Use the context reference to enqueue events to that context.

Using the Context class default constructor

The com.apama.jmon.Context class default constructor, public Context(), creates a dummy context that provides the same functionality as an uninitialized context variable in EPL. A JMon dummy context does not correspond to an actual correlator context. The JMon dummy context corresponds to the implicit context that is created in EPL for uninitialized context variables. The default constructor is provided for convenience. Use it when you want to enqueue an event to another context from a JMon application and the event happens to have a context field that contains an irrelevant value. As with other JMon types, this value cannot be null. Following is an example, beginning with the event definition:

import com.apama.jmon.*;

public class ContextEvent extends Event {
   public long id;
   public boolean req;
   public Context c;
   public ContextEvent(long id) {
      this.id = id;
      this.req = true;
      this.c = new Context();
   }
}

Here is the JMon application:

public class SampleJMonApp implements Monitor {
   ...
   public void onLoad() {
   ...
   ContextEvent req = new ContextEvent(service_id);
   ...
   // send requests here
   req.route();
   ...
   EventExpression cexpr =
      new EventExpression("all ContextEvent(*,false,*):ackEvt");
         cexpr.addMatchListener(new MatchListener() {
            public void match(MatchEvent event){
               ContextEvent ackEvt =
               (ContextEvent)event.getMatchingEvents().get("ackEvt");
               // extract the context here
               Context serviceContext = ackEvt.evt;
               ...
            }
         });
   }
   ...
}

Here is the EPL application:

monitor ContextFactory
{
   ...
   action onload() {
   ...
      on all ContextEvent(*, true, *) as req {
         integer svcid;
         ...
         context serviceContext := context("svc");
         ContextEvent ack :=
            ContextEvent(svcid, false, serviceContext);
         route ack;
         ...
      }
   }
   ...
}

Descriptions of methods on the Context class

You can call the following methods on a Context object. For more information, see the description of the context type in the API reference for EPL (ApamaDoc).

  • public long getId()

    Returns the unique identifier for the context. For a Context instance that would return the following toString() result: "context(2,"context_name",false)", the getId() method returns the value 2. This method returns 0 for a Context instance created with the default constructor.

  • public String getName()

    Returns the name of the context. For example, suppose you create a context with the following EPL code:

    context c := context("test");

    If you transfer a reference to this context into your JMon application, a call to the getName() method on this context instance returns "test".

    This method returns an empty string for a Context instance created with the default constructor.

  • public String toString()

    Returns a string representation of the context instance. This method produces a string that is identical to the string that EPL produces. For example: "context(2,"context_name",false)". The first item in the string, 2 in this example, is the context’s unique identifier. The second item in the string, "context_name", is the name of the context. The third item in the string is the value of the receivesInput boolean flag, which indicates whether the context is public or private.

    This method returns "context(0,"",false)" for a Context instance created with the default constructor.

    For details about public and private contexts, see Implementing parallel processing and Creating contexts.

  • public static Context getCurrent()

    Returns a Context instance that corresponds to the current correlator context. This is the context that contains the code that you are calling. Apama executes single-threaded JMon applications in the main correlator context. Consequently, this method always returns a Context instance that references the main correlator context.

    During execution, JMon applications can create new Java threads. Do not confuse new threads with correlator contexts. The Context.getCurrent() method returns null when you call it inside newly created Java threads.

Identifying external events

In some situations, you might want to determine whether an event originated outside the correlator. To do this, call the Event.isExternal() method:

public boolean isExternal()

This method returns true if the event was sent to the correlator by some external process and that event was then passed into your JMon application.

Optimizing event types

About event types introduced event type classes.

The correlator creates several indexing data structures for every event type. The complexity and efficiency of these data structures depends on the number of parameters an event has, and therefore “smaller” (with less parameters) events are processed more rapidly.

Therefore, if possible, when designing an application it is preferable to control it using a number of “smaller” event types rather than through a single event type with a large number of parameters.

Wildcarding parameters in event types

Alternatively, if large event types are unavoidable, you can optimize performance by reviewing the usage of these event types in JMon, specifically within event templates in event expressions.

If a parameter of an event is never matched against directly within any event expressions, that is only * (or wildcard) ever appears against it in event templates, then the event type’s definition can be amended to indicate this. This tells the correlator to ignore this parameter in its internal indexing.

Consider the event type definition presented in About event types.

/*
 * Tick.java
 *
 * Class to abstract an Apama stock tick event. A stock tick event
 * describes the trading of a stock, as described by the symbol
 * of the stock being traded, and the price at which the stock was
 * traded
 *
 */
import com.apama.jmon.Event;

public class Tick extends Event {
   /** The stock tick symbol */
   public String name;

   /** The traded price of the stock tick */
   public double price;

   /**
    * No argument constructor
    */
   public Tick() {
      this("", 0);
   }

   /**
    * Construct a tick object and set the name and price
    * instance variables
    *
    * @param name  The stock symbol of the traded stock
    * @param price The price at which the stock was traded
    */
   public Tick(String name, double price){
      this.name = name;
      this.price = price;
   }
}

If all references to this event type in event expressions look similar to this,

Tick("ACME", *)

that is, where the second parameter price is always specified as a *, then this parameter could be wildcarded in the event type definition.

This can be done by annotating the field in the event type class, as shown here

/** The traded price of the stock tick */
@com.apama.jmon.annotation.Wildcard
public double price;

This definition in the Tick class will override the default behavior, and it lets the correlator know that it can optimize its indexing by ignoring the price parameter.

As many parameters as desired can be wildcarded in this way. For example, if both price and name were to be wildcarded in Tick, they should be defined as follows,

/** The stock tick symbol */
@com.apama.jmon.annotation.Wildcard
public String name;

/**The traded price of the stock tick */
@com.apama.jmon.annotation.Wildcard
public double price;

Of course, if you were to do this, then

Tick(*, *)

would be the only valid event template that can be expressed in JMon. Any other expression would cause a Java runtime error.

Logging in JMon applications

The logging facilities in JMon are provided by Log4j, a publicly available logging library for Java. These logging facilities are included in com.apama.util.Logger. See the API reference for Java (Javadoc).

Info
Full documentation for Log4j 2 can be found at https://logging.apache.org/log4j/2.x/.

It is recommended that you do not use the FATAL or CRIT log levels provided by the Logger class, which are present only for historical reasons. It is better to use ERROR for all error conditions regardless of how fatal they are, and INFO for informational messages. By default, the JMon classes log at WARN level. See Setting correlator and plug-in log files and log levels in a YAML configuration file for information about configuring log levels in the correlator.

To ensure that the correlator can serialize logging behavior, specify that instances of Logger are static.

Using EPL keywords as identifiers in JMon applications

If you use EPL keywords as event name or field identifiers, then in the following situations you must escape such identifiers by preceding them with hash (#) symbols:

  • You refer to the JMon identifier in EPL code: You must escape the identifier in the EPL code that contains the reference.
  • You refer to the JMon identifier in a JMon event expression: You must escape the identifier in that JMon event expression.

For example, consider the following Java code:

class test extends Event {
   int id;
   float price;
   int integer;
}

Now suppose you want to write the following EPL code:

on all test(id=7) as f {
   print f.toString();
   emit f;
}

No escaping is necessary. However, suppose you want to write this EPL code:

print f.integer.toString();

In this case, you must escape integer as follows:

print f.#integer.toString();

Likewise, you must escape integer in the following JMon event expression:

new EventExpression("all test(#integer > 5)");

See also Keywords.