Nyota:Documentation
From Eclipse.compeople.de
Nyota > Documentation
Contents |
[edit] The Idea
Equinox and OSGi have already an established simple way for registered java components as OSGi services. These services maintain their own lifecycle. They can be looked up in the central OSGi service registry. Afterwards a method on the service can be invoked as on any other java instance.
Nyota makes OSGi services available outside the current JVM by publishing them as web service endpoint. This is as simple as adding new properties when registering the OSGi service.
On the client that wants to remotely access such a service a proxy is registered as an OSGi service on the client JVM. So the component on the client that wants to use a remote OSGi service, calls the OSGi service in the local (client) JVM and the proxy transports the request and response between client and server. These client OSGi services with the embedded proxy are either created through an API (RemoteServiceFactory), through Declarative Service (RemoteServiceBuilder) or through Discovery. With Discovery a background task on the client connects to the server and automatically creates OSGi services on the client for each web service endpoint on the server.
[edit] Publishing an OSGi Service as Web Service
This example of a bundle activator shows how an OSGi service becomes a Web Service in Nyota:
public class Activator implements BundleActivator {
private ServiceRegistration pingPongReg;
public void start(BundleContext context) throws Exception {
PingPong pingPong = new PingPong();
Hashtable<String, String> properties = new Hashtable<String, String>(3);
properties.put("nyota.remote", "true");
properties.put("nyota.remote.protocol", "hessian");
properties.put("nyota.remote.path", "/PingPongWS");
pingPongReg = context.registerService(IPingPong.ID, pingPong, properties);
}
public void stop(BundleContext context) throws Exception {
pingPongReg.unregister();
pingPongReg = null;
}
}
Nyota tracks all services as they are published (and unpublished). If it finds a property "nyota.remote=true", then it tries to publish this OSGi service as web service.
In this case the PingPongService is made available under the URL "http://localhost/hessian/PingPongWS". If, for some reason, the Activators stop method is called and the service is unregistered, then also the web service endpoint is unpublished and therefore no longer available.
Here is a picture that illustrates the process:
Note: The protocol property "hessian" is only indirectly translated into the path segment "/hessian". What really happens is that the Nyota Publisher asks the Nyota Hessian Publisher to publish the OSGi service. The Hessian Publisher chooses to add a path segment called /hessian before the actual Web Service Url. So its not mandatory that the two values are the same. This behaviour makes Urls more unique, since it avoids conflicts between publishers.
[edit] Accessing the remote OSGi Service
To access an OSGi Service that runs on the server from the client we have to create the corresponding web service proxy on the client and register it as OSGi Service. The code for that looks like this.
public class Activator implements BundleActivator {
private IRemoteServiceRegistration pingPongReg;
public void start(BundleContext context) throws Exception {
RemoteServiceFactory rsf = new RemoteServiceFactory();
String url = "http://localhost/hessian/PingPongWS";
String protocol = "hessian";
pingPongReg = rsf.createAndRegisterProxy(IPingPong.class, url, protocol);
}
public void stop(BundleContext context) throws Exception {
if (pingPongReg != null) {
pingPongReg.unregister();
pingPongReg = null;
}
}
}
A fixed URL is bound to a protocol and an interface. RemoteServiceFactory creates the proxy and registers the OSGi Service.
So once you have done that calling is as simple as calling a local OSGi Service:
public class Activator implements BundleActivator {
public void start(BundleContext context) throws Exception {
ServiceReference pingPongRef = context.getServiceReference(IPingPong.ID);
if (pingPongRef == null) {
return;
}
IPingPong pingPong = (IPingPong) context.getService(pingPongRef);
if (pingPong == null) {
return;
}
Ping ping = new Ping();
ping.setText("I ping you and you pong me");
try {
Pong pong = pingPong.ping(ping);
System.out.println("PingPong::Client:: " + pong);
} finally {
context.ungetService(pingPongRef);
}
}
public void stop(BundleContext context) throws Exception {
}
}
Here is a picture that illustrates what happens inside:
Note: IPingPong.ID is in this sample equivalent to IPingPong.class.getName().
[edit] Starting / Stoping OSGi Services
[edit] Starting
Nyota publishes an OSGi Service as Web Service Endpoint as soon as the bundle that contains the services is started. Say you use the sample as decribed in the Nyota:Setup the status of the started bundles look like this:
id State Bundle 0 ACTIVE org.eclipse.osgi_3.3.0.v20070530 1 ACTIVE de.compeople.nyota.publisher.hessian_0.4.0 2 ACTIVE org.eclipse.equinox.http.registry_1.0.0.v20070608 3 ACTIVE org.eclipse.equinox.http.servlet_1.0.0.v20070606 4 ACTIVE org.eclipse.equinox.http.jetty_1.0.0.v20070607 5 ACTIVE org.codehaus.xfire_1.2.6 6 ACTIVE org.eclipse.osgi.services_3.1.200.v20070605 7 ACTIVE de.compeople.nyota.publisher_0.4.0 8 ACTIVE de.compeople.nyota.core_0.4.0 9 ACTIVE org.eclipse.core.jobs_3.3.0.v20070423 10 ACTIVE de.compeople.nyota.console_0.4.0 11 ACTIVE org.eclipse.equinox.registry_3.3.0.v20070522 12 ACTIVE de.compeople.nyota.publisher.xfire_0.4.0 13 ACTIVE com.caucho.hessian_1.0.0 14 ACTIVE org.eclipse.equinox.common_3.3.0.v20070426 15 ACTIVE org.mortbay.jetty_5.1.11.v200705231735 16 ACTIVE org.apache.commons.logging_1.0.4.v200705231731 17 ACTIVE de.compeople.nyota.sample.pingpong.server_0.4.0 18 ACTIVE de.compeople.nyota.sample.pingpong.common_0.4.0 19 ACTIVE javax.servlet_2.4.0.v200705291052
While starting one of the OSGi Services that was published triggered this debug message in the console:
Nyota::ServicePublishEventDispatcher:: DEBUG: service endpoints count: 2 Nyota::HessianRemoteServicePublisher:: DEBUG: published web service. protocol=hessian, url=http://localhost/hessian/PingPongWS, interface=de.compeople.nyota.sample.pingpong.common.IPingPong Nyota::HessianRemoteServicePublisher:: DEBUG: web service count: 2
So clicking on this link [http://localhost/hessian/PingPongWS] will open a page in the browser that says something like this:
calls protocol=hessian, url=http://localhost/hessian/PingPongWS, interface=de.compeople.nyota.sample.pingpong.common.IPingPong
which is the default message if a Web Service Endpoint (hessian) is opened in the browser.
[edit] Stoping
Say you stop the bundle that started the OSGi Service for this Web Service Endpoint
> stop 17 stops the OSGi service and Nyota unpublished the Web Service Endpoint
Nyota::HessianRemoteServicePublisher:: DEBUG: unpublished web service. protocol=hessian, url=http://localhost/hessian/PingPongWS, interface=de.compeople.nyota.sample.pingpong.common.IPingPong
> ss
... 17 RESOLVED de.compeople.nyota.sample.pingpong.server_0.4.0 ...
Clicking on this link [http://localhost/hessian/PingPongWS] again shows:
calls null
No Web Service Endpoint for this url.
[edit] The Remoteconsole
The Remote Console is an optional feature of Nyota. It is helpful while you develop the code but not recommended for productive environment. The package "de.compeople.nyota.console" can be include on client and on server and gives you a status of the active services that are published (on the server) or proxied (on the client) using Nyota.
The work very simular as "ss" for the status of the bundles, or status for the status of the OSGi Services. To use it make sure you add "-console" (without quotes) as program argument to enable the basic console feature in eclipse runtime.
Once you started the process, you can type into the console window. The only command available currently is "remotestatus" (again without quotes). On the server it displays the following:
osgi> remotestatus Nyota:: no OSGi services to publish Nyota:: published end point=(protocol=hessian, url=http://localhost/hessian/ServicePublisherWS, interface=de.compeople.nyota.core.publisher.IServicePublishEventDispatcher) Nyota:: published end point=(protocol=hessian, url=http://localhost/hessian/PingPongWS, interface=de.compeople.nyota.sample.pingpong.common.IPingPong) Nyota:: no OSGi services registered
On the client it displays:
osgi> remotestatus Nyota:: registered remoteServiceRef=(hostId= de.compeople.nyota.core.factory.RemoteServiceFactory, end point=(protocol=hessian, url=http://localhost/hessian/PingPongWS, interface=de.compeople.nyota.sample.pingpong.common.IPingPong))
[edit] Declarative Services
OSGi services can be published as Web Service Endpoint by Declarative Services too. The Service declaration only requires the Nyota specifically properties.
<?xml version="1.0" encoding="UTF-8"?> <component name="foo.myservice.AService"> <implementation class="foo.myapp.server.internal.ServiceImpl"/> <property name="nyota.remote">true</property> <property name="nyota.remote.protocol">hessian</property> <property name="nyota.remote.path">/ServiceWS</property> <service> <provide interface= "foo.myapp.commons.IService"/> </service> </component>
To declare a Web Service Endpoint as OSGi service you can do it with the RemoteServiceBuilder. The RemoteServiceBuilder creates a service proxy for the given Web Service Enpoint properties and registers this as OSGi Service.
<?xml version="1.0" encoding="UTF-8"?>
<component name="foo.myservice.AService" immediate="true">
<implementation class="de.compeople.nyota.core.factory.RemoteServiceBuilder"/>
<property name="nyota.interface" value="foo.myapp.commons.IService"/>
<property name="nyota.remote.path" value="http://localhost/hessian/ServiceWS"/>
<property name="nyota.remote.protocol" value="hessian"/>
</component>
[edit] Discovery
When a OSGi Service is registered on the server, Nyota already knows all the metadata to publish it as a Web Service Endpoint from the properties supplied with the OSGi Service Registration. This is the same metadata that is required on the client to create a Proxy there and register it as a Web Service Proxy in the OSGi Service Registry.
The Discovery Component from Nyota, which is an optional component runs on the client. It accesses the Service Publisher on the server (using Nyota) to access the metadata of all published Web Service Endpoints. For each Service Discovery then creates a Web Service Proxy and registers it as OSGi Service on the client.
This picture illustrates the process:
Discovery currently polls the Service Publisher in a regular intervall. In futures versions this could either events "pushed" to the server or Discovery is only run once at client start.
Discovery also stops Web Service Proxies on the client when it detects that the OSGi Service on the server was stopped.
