Developing Components:
The EBI Wrapper Mechanism

The EBI Wrapper Mechanism

Programming an event-based component is somewhat different from programming a reusable Java object. Event-based components communicate by using asynchronous events. Therefore, it is not possible or desirable to obtain a pointer (Java reference) to an object in another component and make calls on that object. This can complicate component development somewhat. Procedure calls (or method calls in OOP parlance) are a natural and effective way of programming for most OO developers. To bridge this gap, c2.fw provides tools that can seamlessly integrate event-based programming with procedure call based programming. They work by providing a way to translate procedure calls into events and back again. This mechanism is called the EBI (for Event-Based Integration) wrapper mechanism.

When using this mechanism, component developers can obtain a "stub" object that implements a given interface. Calls to this object get translated into events, which are then sent via c2.fw's standard event distribution mechanisms to other components. Presumably, one of these components implements the stubbed interface. On the target component, the events are translated back into a procedure call by means of a skeleton. The response is returned to the calling component in much the same way.

The EBI wrapper mechanism includes functions that will create these stubs and skeletons automatically. xArchADT is a good example of a component that uses this mechanism to provide a service.

Important Note! Previous releases of ArchStudio 3 included an earlier version of the EBI Wrapper mechanism that involved creating two separate Java classes for each component, as was documented in previous versions of this tutorial. These components are fully compatible with "new" style EBI components as documented in this tutorial. However, the new style components are approximately three times faster and require much less maintenance. We recommended that you refactor old style components into the new style. For assistance with this, contact Eric Dashofy.

To take advantage of this mechanism, your component must be a DelegateBrick. This allows the EBI wrapper classes to plug in "delegate" message handlers where necessary to process procedure calls and responses. All the functions needed to allow your component to call an EBI service on another component, or to provide such a service, are in the c2.pcwrap.EBIWrapperUtils class. There are two methods that you will be most interested in.


Using a service provided by another component:

The addExternalService method allows you to create a local stub to make calls on an EBI service provided by another component. Its Javadoc is shown here:

addExternalService

public static Object addExternalService(DelegateBrick b,
                                        Interface iface,
                                        Class serviceClass)
Create a local proxy within a given DelegateBrick that can make calls, via events, to a stub in another component. So, if another component has called EBIWrapperUtils.deployService to deploy a service, this routine can be called in a given component to create a proxy to that service. For example, let's assume that another component has exposed an interface called XArchFlatInterface. The call to this method would be:

XArchFlatInterface flat = (XArchFlatInterface)EBIWrapperUtils.addExternalService(thisBrick, MY_INTERFACE, XArchFlatInterface.class);.

Parameters:
b - Brick within which to create the proxy, usually this.
iface - Interface on Brick b on which the outgoing calls will be made.
serviceClass - Class of the remote interface to proxy.
Returns:
An object implementing the class specified in the serviceClass parameter.

This function is usually called from the constructor of a component that wants to use an external service. In the example given in the Javadoc, a stub is being created for the XArchFlatInterface Java interface, a service provided by the xArchADT component. For "legacy" C2 components, replace MY_INTERFACE above with topIface, since requests usually go out the top interface of a component.


Providing a service to other components:

The deployService method allows you to deploy a service that can be used by other components. Its Javadoc is shown here:

deployService

public static void deployService(DelegateBrick b,
                                 Interface callIface,
                                 Interface stateChangeIface,
                                 Object api,
                                 Class[] interfaces,
                                 Class[] stateChangeInterfaces)
Deploy an EPC service that can be called by other components. A "service" is one or more Java interfaces implemented by an object. In addition to responding to calls on these interfaces, this function can automatically create"listeners" to watch the object for state changes and emit state change events when one of the listeners is called. The object providing the service must implement the following "listener" pattern methods:

public void addFooListener(FooListener l);
public void removeFooListener(FooListener l);

In this case, you can pass FooListener.class as one of the array elements in the stateChangeInterfaces parameter of this call, and Foo events will be emitted on the stateChangeIface.

Parameters:
b - Brick deploying the EPC service.
callIface - Interface on brick b on which calls will arrive and call responses will be sent.
stateChangeIface - Interface on brick b on which state change notifications will be sent (may be the same as callIface).
api - The object actually implementing the service (may be b).
interfaces - Java interface(s) that are implemented by api that are deployed as part of the service.
stateChangeInterfaces - "Listener" interface(s) to monitor and emit state change messages for. Zero length arrays are acceptable here.

This function is usually called from the constructor of a component that wants to provide a service. For "legacy" C2 components, both the callIface and stateChangeIface parameters are usually bottomIface, since requests arrive at the bottom interface of a component, and state change notifications are emitted through that interface.


That's It!

That's all there is to deploying and using EPC services. To see examples of components that deploy and use services, see the code for xArchADT (which provides the XArchFlatInterface service) and the Hello World Component (which uses that service).