The PMP Bundle contains the implementation of the ProSyst Message Protocol (PMP). It forwards remote requests to the framework system and to active bundles as well as issues such requests.
Contents:
The JAR file of the PMP Bundle is pmp.jar, and is located in the bundles folder.
|
The com.prosyst.mbs.services.pmp package, which contains the PMP
Service.
PMP is a point-to-point protocol, which provides an efficient way for remote method invocation of services in a framework from another framework. The current implementation relies on the OSGi IO Connector service. It has a comprehensive API, and uses no stubs and skeletons which lightens its performance.
For more details about the operations supported by PMP, refer to the PMP Protocol Specification.
By using PMP you can:
Figure 1 shows a diagram of the stages and procedure calls involved in the PMP communication.
This chapter contains a brief description of the services registered by the PMP Bundle.
The PMP Service implements the point-to-point communication mechanism of PMP (see PMP Protocol Specification for more information). The API of the PMP Service hides all complex operations on part of the service users and provides a usage model similar to the Java Remote Method Invocation (RMI).
The PMP Service receives requests from bundles found on another framework, processes and passes them to the services in service registry. It also creates connections, sends and receives events.
The service interface of the PMP Service is com.prosyst.mbs.services.pmp.PMPService.
You can get instance of the PMP Service using the techniques defined in the OSGi Framework Specification. For example:
import org.osgi.framework.BundleActivator; public class PMPTester implements BundleActivator {
public void stop(BundleContext bc) throws Exception {
if (refPMPService != null) {
bc.ungetService(refPMPService);
} |
The PMP Service implements an Event Collector, which allows other bundles to send custom events to interested remote listeners.
The PMP Bundle enables other bundles to configure its communication properties
through the methods of the OSGi Configuration Admin service (see Config
Bundle). It registers an org.osgi.service.cm.ManagedServiceFactory
service with service PID mbs.pmpservice.pid.
The PMP Bundle registers the Managed Service Factory service in the framework
if the mbs.pmp.createFactoryConfig system property is true.
The Remote Parser Generator service implements the com.prosyst.mbs.services.remconsole.RemoteConsoleGenerator
interface and can be used remotely to execute pluggable commands, supported
in the framework, over PMP. In particular, this functionality is integrated
in the com.prosyst.mbs.services.RemoteConsoleService interface
whose instance can be obtained from RemoteConsoleGenerator.
The Remote Parser Generator is mainly used by the mConsole.
PMP users cannot get all services registered in a distant framework. To make
a service PMP-accessible, you should additionally implement the com.prosyst.util.io.Remote
interface in the service class. In the remoteInterfaces method
you should specify the classes and interfaces whose methods remote PMP users
can invoke.
You can also specify the users that are authorized to access your service (they
should be registered in the OSGi User
Admin Service). At service registration, define authorized roles as a service
property with key Remote.AUTHORIZED_ROLES and with value a string
array containing the names of authorized roles (see the User
Admin Bundle document for details about user roles). If such roles are not
specified, only users from the administration group can access the service.
Listing 2.1 shows a service interface, called TestService. The
TestServiceImpl class in Listing 2.2 implements TestService
and enables access to the service interface methods by implementing
as well. Listing 2.3 registers RemoteTestService specifying an imaginary
user "guest" as authorized role.
public interface TestService { |
import com.prosyst.util.io.Remote; |
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.ServiceRegistration;
import java.util.Properties;
import com.prosyst.util.io.Remote;
public class TestServiceActivator implements BundleActivator {
ServiceRegistration sReg = null;
|
This chapter discusses the ways to get a PMP connection.
If a framework wants to connect to another framework, it must open an individual connection for referring to services on and receiving events from the remote framework.
To bind to the target framework (in particular to an mBS), invoke
the method of the PMP Service.
On success, you receive a connect
object representing this connection. PMPConnection
The connect method takes two parameters:
String uri - The URI to log in, which must be defined according
to the URI syntax defined in IO Connector Service specification, part of the
OSGi Service Platform
Service Compendium Release 4.
Note that you must have an org.osgi.service.io.ConnectionFactory
implementer running in both of communicating frameworks.
Specifically for the COMM or the UDP communication schemes: If no timeout is specified, 10 seconds is set by default.
Dictionary login - A dictionary containing login information
according to the requirements of the Simple
Login service (com.prosyst.mbs.services.useradmin.SimpleLogin):
As dictionary keys use the USERNAME and PASSWORD
fields of SimpleLogin and as values - valid username and password,
respectively.
import com.prosyst.mbs.services.pmp.PMPConnection; |
You can register a connection listener for newly open connections by a remote
PMP Service. The listener interface to implement is com.prosyst.mbs.pmp.PMPConnListener.
You register it in the PMP Service by calling service's addPMPConnListener
method.
You process connection events in the clientConnected and clientDisconnected
methods. In both methods the PMP Service sends you a PMPConnection
object representing the new connection. Hence, you may examine the properties
of the established communication session and use the connection for a callback
to the remote framework.
public class MyConnListener implements PMPConnListener {
public void clientConnected(PMPConnection connection) {
System.out.println("Framework Connected" + connection.getURI());
}
public void clientDisconnected(PMPConnection connection) {
connection.disconnect("URI " + connection.getURI() + " disconnected!");
} |
It is possible to access some attributes of the remote PMP Service, which
calls the methods of your service. You can do this with the methods of com.prosyst.mbs.services.pmp.PMPContext.
When a service method is invoked by remote PMP Service, the local PMP Service
creates a new job, implementing Runnable and PMPContext,
and attaches it to a thread, taken from the Thread Pool Manager. Therefore,
to get the PMPContext instance of the current communication session:
com.prosyst.util.threadpool.ThreadContext
instance (see the description
of the Thread Pool Manager). ThreadContext by invoking its getRunnable
method and cast the result to PMPContext (for clarification,
see Listing 3.3). Then, you can use the following PMPContext methods:
getConnection method - You get a PMPConnection
for callback to a remote PMP Service. getAuthorization method - You get the com.prosyst.mbs.services.useradmin.Authorization
of the user that connected from the remote framework. Then, you can check
the access rights of the user by using the features of the User
Admin and User Admin Extension
bundles. public String testMethod(String message) {
|
Considering the message sequence chart of PMP, the algorithm to invoke a service method on a remote (executing) framework is:
The procedure above is realized by using three objects, located in the com.prosyst.mbs.services.pmp
package:
PMPConnection - standing for the communication session to
the remote framework.RemoteObject - representation of a service.RemoteMethod - symbolizing a service method. If you want to contact the interface of a service, you should use one of
the two getReference methods of PMPConnection.
Both return a RemoteObject to represent a single service.
Listing 4.1 calls the imaginary service in Listings 2.1 - 2.3, which is registered on a remote framework.
import com.prosyst.mbs.services.pmp.RemoteObject; |
Warning: If a service method returns
objects that belong to a certain interface, they must be assigned in the
appropriate Remote.remoteInterfaces() method implementation
to access remotely their methods. Otherwise, the caller receives the requested
object as a RemoteObject reference, and only by value.
If you requested a service with getReference, use the returned
RemoteObject object to access a method in the service interface.
There are two possible cases:
getMethods
method of RemoteObject.getMethod
of RemoteObject.Object methods are represented as RemoteMethod objects.
Tip: If you are not sure what exactly
the attributes of a methods are, use getMethods.
Listing 4.2 refers to the testMethod of the TestService,
shown in Listing 2.1 and Listing 2.2.
import com.prosyst.mbs.services.pmp.RemoteMethod; |
To execute a service method, use a RemoteMethod's invoke
method. A java.lang.Object instance represents the operation
result, and developers should explicitly cast it to the expected object
type.
You can assign a separate class loader to load the object returned on
invoking a remote service method by using the invoke(Object[], boolean,
Class) method.
Listing 4.3 invokes the testMethod method of the TestService,
and prints the result.
if(method != null) { |
You can map the result from a method invocation
to an object that implements java.io.Serializable or com.prosyst.util.io.Externalizable
by invoking changeReturnType of RemoteMethod.
This object should read and optionally write data coming from a bundle that
is running on the remote framework.
The PMP Bundle supports invoking methods passing as parameters remote object
references (RemoteObject objects). This allows you to:
java.io.Serializable
or com.prosyst.util.io.Externalizable). To a great degree this
prevents from problems, which may emerge when communicating objects.Figure 2.1 shows the operation sequence used for the first type of remote references in method invocations.

Figure 2.1: First scenario for using remote references
as method parameters.
The first scenario requires that there are two methods - one (method A), which
takes as an argument a specific object type, for example SomeObject,
and one (method B), which returns an object of this specific type. The method
with return type SomeObject may be in the service that holds the
method requiring it as an argument or in another service.
Note: The specific object to be used as remote
reference must implement com.prosyst.util.io.Remote.
By using the PMP Service a bundle on framework B invokes method B to obtain
the object, necessary to invoke method A of service A - this is SomeObject.
The serialization flag of the RemoteObject.invoke() method must
be false.
Next, the request is redirected to the opposite PMP Service, which calls method
B. method B returns the real SomeObject object to the local PMP
Service, which associates it with a RemoteObject. The RemoteObject
is then sent back to framework B.
The bundle on framework B invokes method A through the PMP Service using the
RemoteObject as an argument. On framework A, the PMP Service locates
the associated SomeObject reference and invokes method A on it.
In the example below framework B calls the getService method of
a TestService on framework A and then uses the returned RemoteObject
to call the setService method of the same service. Finally, it
prints the result to the system output.
On framework A:
public interface TestService {
public TestService getService();
public String setService(TestService service);
} |
public class TestServiceImpl implements TestService, public String setService(TestService service) {
if(service != null) {
return "Hello! Object received!";
}
return null;
}
public Class[] remoteInterfaces() {
return new Class[] {TestService.class};
}
|
On framework B:
. . . |
Figure 2.2 illustrates this second mechanism - using remote references as method parameters.

Figure 2.2: Second scenario for using remote references
as method parameters.
The second scenario defines how to make a callback. A callback is performed
in a service method, which has a com.prosyst.mbs.services.pmp.RemoteObject
input argument.
When framework B invokes method A of service A through the PMP Service, it
passes a real object, for example a SomeObject, instead of a RemoteObject.
The local PMP Service associates the received SomeObject reference
to a RemoteObject and sends this RemoteObject to the
opposite PMP Service, which invokes method A.
In the body of method A, service A makes a callback. Knowing SomeObject's
type and methods, service A uses the RemoteObject to invoke a method
of the real SomeObject object - this is method B. On framework
B, the PMP Service receives the method invocation request, locates the SomeObject
reference and invokes method B.
Note: The resources consumed to make a callback must be released after the session is closed by the side of the framework to which the callback is directed. See Releasing Resources for a Closed Session.
The example below shows a simple callback between a service called TestService
and a TestObject object. An entity invokes the callBack
method of TestService over PMP passing a TestObject
object as a parameter. On the target framework (framework A on Figure 2.2),
the callMe method of TestObject is then called in
the body of the callBack method. The result from the callMe
method is printed to the system output.
On framework A:
import com.prosyst.mbs.services.pmp.RemoteObject; public interface TestService {
public void callBack(RemoteObject remObj);
} |
import com.prosyst.mbs.services.pmp.RemoteObject;
import com.prosyst.mbs.services.pmp.RemoteMethod;
import com.prosyst.mbs.services.pmp.PMPException;
public class TestServiceImpl implements TestService, Remote {
public void callBack(RemoteObject remObj) {
try {
String[] remArgTypes = new String[0];
RemoteMethod remMethod = remObj.getMethod("callMe", remArgTypes);
String result = (String)remMethod.invoke(null , true);
System.out.println("The result from the callback is: \n\t" + result);
} catch (PMPException exc) {exc.printStackTrace();}
}
public Class[] remoteInterfaces() {
return new Class[] {TestService.class};
}
} |
On framework B:
public class TestObject {
public String callMe() {
String msg = "This is a callback!";
return msg;
}
} |
. . . |
It is recommended (even required when making callbacks) to release the resources associated with a certain session after the initiator is no longer connected and thus optimize the performance of bundles. Following is a short guidance of how to do this:
getSessionID
method of the PMPContext instance (see Obtaining
a Connection through PMP Context) and keep it.PMPConnectionListener to receive notification when
a remote PMP Service disconnects (see Obtaining
a Connection through a Listener). In such case, the clientDisconnected
method of the listener is called, in which the PMP Service passes the corresponding
connection. You can get the session ID from that connection and compare it
to the one retrieved at method invocation. If there is a match, then allocated
resources for this session can be released.This chapter discusses the possible ways to post custom events to remote frameworks.
To successfully use such type of eventing, you should provide an event source that belongs to a definite type. An interested remote PMP Services can subscribe to this type of event.
You register a new event source by calling the addEventSource
method of the Event Collector of the PMP Service.
Note: Posting events over PMP as objects
requires these objects to be java.io.Serializable or com.prosyst.util.io.Externalizable.
Listing 6.1 registers an event source of type myEvent with the Event Collector of the PMP Service.
. . . |
To fire an event from the local framework to a remote framework, call the event
method of EventCollector.
Listing 6.2 calls the event method to post a custom event defined
in Listing 6.1.
String message = "Hello!"; |
Through the com.prosyst.mbs.services.pmp.PMPContext interface
you can post events to a particular connected entity which invoked some of the
methods of your service. For example, if there is a failure in executing the
method.
You receive an instance of PMPContext as the Runnable
job, attached to the current thread (see Obtaining a Connection
through PMP Context). Then, you call the postEvent method passing
as arguments the message type, message content and the ID of the bundle holding
the event source object.
Listing 5.3 posts an event to the entity that called the fireEvent
method of an imaginary service.
public String fireEvent() { |
Often, it is very important to load the execution of a program in the right situation. Posting events from one framework to another appears to be a very efficient notification mechanism when specific situations arise. This chapter discusses the programming concepts to register listeners for events to a remote framework.
The PMP Service supports the following event types:
The com.prosyst.util.event.BasicEvent combines the above event
types.
To receive successfully events over PMP, developers should execute the following sequence of operations:
To contact another framework, call the connect method of the PMP
Service. On success, you receive a PMPConnection object, which
contains the functionality of an events manager (com.prosyst.util.event.EventsManager)
for registering event listeners.
Event managers handle events to clients by transforming them into a format
that is suitable for further processing. In PMP the event manager is represented
by com.prosyst.util.event.EventsManager interface that has methods
for subscribing listeners for the runtime events on the connected framework.
Currently, the PMPConnection extends EventsManager
and you can use it for listening to events from the remote framework of interest.
A developer who desires to register a listener for a certain event type should
get and use the EventsManager interface as described above. Through
it, you are able to register a listener for all PMP-supported events. Then you
can filter and cast them to the desired type.
The listener interface to implement is com.prosyst.util.EventListener.
You register such listener in EventsManager through the addEventListener
method passing a listener implementation object and a string array of the events
to be notified about. The events are static fields of EventListener
which reflect supported event types.
You process events, which are instances of com.prosyst.util.event.BasicEvent,
in the event method of EventListener. If you subscribed
for more than one event type, then you can distinguish the event type by comparing:
type string argument of the event method to
the fields in EventListener; BasicEvent.The table below shows supported events and their field equavalents.
|
|||||||||||||||||||||||||||||||||||||||||||||||||||
Listing 7.1 implements an event listener, and Listing 7.2 registers it using
PMPConnection.
import com.prosyst.util.event.EventListener; |
String subscribedTypes = {EventListener.SERVICE_EVENT + "=myEvent"}; |
The PMP Bundle uses VM system properties and a property editor in the mConsole.
The Managed Service Factory service, whose factory PID is mbs.pmpservice.pid,
generates configuration dictionaries, each containing the configuration properties
reflected by the fields of the com.prosyst.mbs.services.pmp.PMPService
interface.
|
The factory configuration mechanism is used to create connections on different transports and on different ports. For example, if the PMP Service has two separate configurations - one for TCP/IP and one for UDP, remote frameworks can connect to the service by using either TCP/IP or UDP. It is recommended that a PMP Service has several different configurations in case a remote framework does not support a particular transport or port, etc.
You use the OSGi Configuration Admin Service (see Configuration Admin Service Specification from the OSGi Service Platform Service Compendium) to modify a configuration dictionary and/or create new ones.
You can easily view and edit configuration dictionaries from the PMP Bundle property editor in the mConsole.
Visual administration over the PMP Bundle is provided by the the mConsole application. With the general property editor you can modify the main communication parameters of a separate configuration.
Figure 3: PMP communication properties.
The configuration of the PMP Bundle is based on its ManagedServiceFactory
service. The mConsole shows the dictionaries of the PMP Bundle
configuration factory in a general property editor. See "Working with
the General Property Editor" chapter in the mConsole
document.
To validate the changes you made on the PMP Bundle, click . The Refresh button updates the configuration in case another framework administrator has made some changes too.
The PMP Bundle uses the following system properties:
|
Tip: To learn more about using system properties in the mBS framework, refer to "System Properties" from Getting Started.
The PMP Demo illustrates the usage of the PMP Service.
To pass objects over PMP, these objects should be java.io.Serializable
or com.prosyst.util.io.Externalizable.