CheckEvent

This page has been updated on the 21 July 2010.
Information validated on 2.4.0 framework.

Objective

The purpose of muiKeyboards example is to show how to provide interfaces and events and the checkEvent example will teach you how to manage events systems.
This will be done in several step :

  • STEP 1 : Architecture of provided interfaces
  • STEP 2 : Architecture of provided events
  • STEP 3 : Manage event systems
  • STEP 4 : Change provided events

Preliminary step

  • Download the project muiKeyboards : Download
  • Unzip and import the muiKeyboards project in your workspace.

muiKeyboards is a user interface component which shows a possible use of different types of keyboard.

  • Launch this component in the simulator and test it.

You will see that the button Valid doesn’t work on the simulator. Let’s check out the associated “onClick” function on the MDU. The code looks like:

  Component.getInstance().evt_DataKeyboardEvent_set();


  Component.getInstance().evt_DataKeyboardEvent_set();


This code is inside all the valid buttons in the keyboards. In fact these methods allow to send an event.

  • Open the JCPN file, and you can see some fields we have not seen before: there are entries in provided/interfaces and provided/events.

First, we will look at the provided interfaces.

Step 1 : Architecture of provided interfaces

In the JCPN file you can see in provided/interfaces that we have an entry called “Keyboards”.
In this entry, one method is defined : boolean getEntry(String).
Please note that you can click on it, change the return type, change the parameter and make a comment. You also have the possibility to add new methods using this interface.

Open the generated folder and package and the generated file for this interface: “Keyboard.java”. You can see that you have an abstract class “Keyboard” with a boolean abstract method called getEntry(BuffRef data).

As this “Keyboard” class is abstract, we need to implement this class. That is why we have in the src folder a file named “Keyboard_impl.java” with Keyboard_impl class which implements the Keyboard class and therefore the method boolean getEntry(BuffRef data).

So each time another component calls a method of the interface, it is actually the method on implemented class which is called.

Step 2 : Architecture of provided events

In the JCPN file you can see in provided/events that we have an entry called “DataKeyboardEvent”.
In this entry called “Keyboard”, there is no attribute inside, so there is no data linked with the event. In fact, this event is just a flag that indicates that we clicked on the accept button.

This event generates two files called “DataKeyboardEvent.java” and “DataKeyboardEventData.java”. There is also a method “evt_DataKeyboardEvent_set()”, generated in “Component.java”, used to launch the event.

Step 3 : Manage event systems

Theory

The Morpheus event system is pretty similar to the java event system. It uses a dispatcher and listener design patterns to manage events.

First we need to create a table with the events we want to manage and an EventDispatcher to catch those events. After that we need to implement EventListener; each listener can handle all or part of the events caught by EventDispatcher. You can have as many EventListener as you want. Making specific listeners that listen only one event is a good practice. All listeners must be registered to an EventDispatcher, once all EventListener are registered, the event dispatching is possible.

Example

We know that muiKeyboards sends an event when we click on the accept button, we will see now how to manage it in a new project.

  1. create a non graphical component called checkEvent with package name : com.training.checkEvent
  2. open the JCPN, and add the following component :
    • required/interfaces :
      • Debug (to print in log file)
      • Keyboard (provided interface of muiKeyboards)
    • required/events :
      • ShutdownEvent (to catch the shutdown signal of the device)
      • MessageReceptionEvent (to catch arrival of new messages on MessageGate)
      • ButtonEvent (to catch button clicks on top of the Dreevo)
      • IgnitionEvent (to catch changes in state of ignition in C4)
      • DataKeyboardsEvent (provided events of muiKeyboards)
  3. add a new initial class and create it.
    In this class we will make a method initDispatcher()
  public void start() 
  {
    _cpn = Component.getInstance();
    _dbg = _cpn.getDebug();

    _dbg.init(0);

    initDispatcher();
  }
	
  private void initDispatcher()
  {
  }

In the initDispatcher we need to retrieve each event and check for validity of each one, like this :

  private void initDispatcher()
  {
    ShutdownEvent         she = _cpn.getShutdownEvent();
    MessageReceptionEvent mre = _cpn.getMessageReceptionEvent();
    ButtonEvent           be  = _cpn.getButtonEvent();
    IgnitionEvent         ie  = _cpn.getIgnitionEvent();
    DataKeyboardEvent     dke = _cpn.getDataKeyboardEvent();
		
    ArrayList events = new ArrayList();
		
    if (she != null) 	events.add(she);
    if (mre != null) 	events.add(mre);
    if (be  != null) 	events.add(be);
    if (ie  != null) 	events.add(ie);
    if (dke != null) 	events.add(dke);

This way, we are sure that all the events in the list are available.

But we can also have another problem.

  • Open up the JCPN file, and find IgnitionEvent and ButtonEvent.
    • IgnitionEvent is available on C4 and H4 but not on DREEVO.
    • ButtonEvent is available on DREEVO but not on C4 and H4.
  • Click on these events you can see a field called ‘modifier’ which is set to: “Exactly one ()”. That means that your component needs this other component in order to run. The problem is that by default, your application will never run because we cannot be on C4/H4 and DREEVO at the same time. That is why ‘modifier’ can’t take another value. If we want to introduce the fact that the component can be available or not, we must choose: “Zero or one (?)”. This ‘modifier’ determines the dependencies of the component, if you don’t want to have hard dependencies, please always set it to “Zero or one (?)”.

Beware: by default we use singletons for instances of components by using the method getXXXXX(). The fact that we have a singleton is linked with the modifiers “Exactly one ()” and “Zero or one (?)”. But in some cases like management of several MessageGate channels or change of several parameters in different components simultaneously, it can be interesting to have different classes. So if you choose the “One or more” or “Zero or more” modifier, you will create a new instance each time and the method to get it will be: createXXXX(). And you have the same requirements to tell if you absolutely need this component or if it can be there or not.

Once ‘modifiers’ are handled we can continue to manage events. To be sure that our components and events are valid, we need to create the event table.

    [...]
    if (dke != null) 	events.add(dke);

    Event[] tab = new Event[events.size()];
    events.toArray(tab);

    EventDispatcher edis = new EventDispatcher(tab);
    [...]

And now the EventListener. For this, we are going to make our Initial and EventListener classes.

public class Initial implements com.mdi.tools.cpn.Initial, EventListener{

And because we implement EventListener we need to implement following method :

  public void dispatchEvent(EventData arg0) 
  {
  }

Now that we have an EventListener we can register it to our recorder and then start the dispatching process.

    [...]
    EventDispatcher edis = new EventDispatcher(tab);
    edis.registerListener(this, tab);
    edis.startProcess();
    [...]

Once started, each time an event is launched, the EventDispatcher will automatically call the dispatchEvent() method of the Listener with the Event as generic event. So in our dispatchEvent() method, we need to check this event type, in order to retrieve the value inside.
Here is an example with ShutdownEvent :

  public void dispatchEvent(EventData arg0) 
  {
    if (arg0 instanceof ShutdownEventData) 
    {
      ShutdownEventData ev = (ShutdownEventData) arg0;
      _dbg.print("ShutdownEvent : shdreason="+ev.shdReason.value+" - level="+ev.level.value);
      if (ev.level.value == 10)
        this.shutdown();
    }
  }

Because the generic type is EventData, we check if this EventData is an instance of ShutdownEventData. If true, we cast the EventData in ShutdownEventData, so we can now access directly the value inside: shReason (why the device shutdown) and the level (from 10 to 0). In this example we catch the level 10 (first level of shutdown) and call the shutdown method of our component. Within this shutdown method you can stop your loop, save your data, send last information, stop connections, etc…

And each event has its own data inside (see java MDI framework javadoc)

    [...]
    else if (arg0 instanceof IgnitionEventData) 
    {
      IgnitionEventData ev = (IgnitionEventData) arg0;
      _dbg.debug("IgnitionEvent : new state = "+ev.state.value);
    }
    else if (arg0 instanceof ButtonEventData) 
    {
      ButtonEventData ev = (ButtonEventData) arg0;
      _dbg.print("ButtonEvent : nbclick="+ev.nbClick.value);
    }
    else if (arg0 instanceof IButtonEventData) 
    {
      IButtonEventData ev = (IButtonEventData) arg0;
      _dbg.print("IButtonEvent : key="+ev.key.value+" - status="+ev.status.value);
    }
    else if (arg0 instanceof MessageReceptionEventData) 
    {
      MessageReceptionEventData ev = (MessageReceptionEventData) arg0;
      _dbg.print("MessageReceptionEvent : new message on channel "+ev.key.value);
      // if (ev.key.value == myChannel)
      //   messageGate.getMessage(buffref, intref);
    }
  }

Now we will manage the DataKeyboardEvent, which is provided by muiKeyboards. Even if it was given by the user component, we manage it the same way as other events.

    [...]
    else if (arg0 instanceof DataKeyboardEventData) 
    {
      _dbg.print("DataKeyboardEvent : receive");
    }
  }

The data Keyboard is just a flag that indicates that we validated what is on the screen; there is no data inside so you cannot retrieve data by typing “ev.”. So to retrieve the content of the keyboard, we can use the provided interface Keyboard with its method getEntry().

    [...]
    else if (arg0 instanceof DataKeyboardEventData) 
    {
      BuffRef buf = new BuffRef(1024);
      Component.getInstance().getKeyboards().getEntry(buf);
      _dbg.print("Keyboards.getEntry : "+ buf);
    }
  }

After that you can run a simulation with muiKeyboards, and checkEvent launched together with MuiKeyboards as the main package.

If it all went well, you will see in the console an entry if you go in keyboards, type some text and click ‘OK’.

  [...]
  2010-XX-XX XX:XX:XX  L[j$com/training/checkEvent$0] Keyboards.getEntry : TESTCHECKEVENT
  [...]

What we are actually doing here is an inter-component communication using events and interfaces.
Keep this in mind if you build a project with different components that work together.

In this case, we can use it in a more optimized way.

Step 4 : Change provided event

We have seen that we can send data inside of the Event. But for the moment we launch empty events and use interfaces to retrieve data. We are going to directly send the data with the Event and not use the provided interface anymore.

For this we need to modify the muiKeyboards JCPN file:

  1. In the JCPN you can click on “DataKeyboardEvent” in provided/events.
  2. In “Keyboards”, there is a section called attribute; in this section click on add, then on “String newAttribute”.
  3. Scroll down and change the name of this attribute to “data” on keep the type as String.
  4. Save the file.

When you save this file, you will see that there are 4 errors that appear in the generated code.

Because we add a new parameter on the Event, we need to give this parameter when we launch the event.

Open the MDU file, and in the “onClick” section of each “valider” button you need to change the line to this :

  Component.getInstance().evtDataKeyboardEvent_set(Keyboards_impl.getInstance().returnEntryString());

This way, we send data with the event and on the other side, we can retrieve the data more easily.
In the event management of your Initial class of chechEvent, you can change it to:

    [...]
    else if (arg0 instanceof DataKeyboardEventData) 
    {
      DataKeyboardEventData ev = (DataKeyboardEventData) arg0;
      _dbg.print("DataKeyboardEvent : data="+ev.data);
    }
  }