Notice: This Wiki is now read only and edits are no longer possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.
OSGi Remote Management Tool
Contents
Project Title
OSGi Remote Management Tool
Synopsis
I will introduce idea of remote monitoring and controlling of external application based on OSGi platform. Its implementation will be a modified Plugin Registry view. At first I will try to present the meaning of OSGi in Eclipse environment and opportunities to use this view. Additionally, I will present the concept of project’s implementation.
Project Idea
The main aim of this project is to provide remote management of application based on OSGi platform. I am going to show meaning and main application of it and then I will present importance of this project.
Firstly, we should know what is exactly OSGi. So it is a platform which provides an opportunity to us to create modular applications. In this case, module (in OSGi called bundle) is an independent single unit, which is a logical whole entirety and can be installed and uninstalled separately. The main feature of modules is that they should not be concerned with the internal implementation of other modules that it interacts with. It allows us to change the implementation of one module with no need to update all other modules that use it. The standard unit of deployment in Java is the JAR file but OSGi’s bundle has some advantages above it. Mainly, bundles allow us to define explicit dependencies between them. Also we can exactly define in manifest file which version of each library our bundle needs, so more than one version of each library can residence in the same application. Additionally OSGi default makes packages inside one bundle private for others because we only describe in manifest which packages can be imported by others. The crucial thing in OSGi is that it is a dynamic module system for Java. It allows us to install, uninstall and update all modules without restarting or even stopping application for these operations. At once we can think that OSGi is an ideal platform for each application server but it can find implementation in other environments (e.g., handheld devices, IT managed environments). In Eclipse community OSGi is very important because whole Eclipse platform is based on it. It causes that creating new plug - ins and development of all environment are so simple.
In this case we can notice requirement of application which allows monitoring modules within OSGi application. In an Eclipse environment we can use Plugin Registry view. Unfortunately it only allows monitoring modules in Eclipse instance in which it is working. However, it seems an ideal basis for the project. Generally project will realize communication between an application based on one of the OSGi implementations and monitoring plugin on an Eclipse instance. It will be based on client – server architecture. In this communication external application will be a server and our view in eclipse will be a client. A server provides information about bundles and services which is interpreted by our application (Plug-in Registry view). Additionally it should make available operations on individual bundles, such as starting and stopping them, installing new bundles and uninstalling old ones. This application allows for example remote supervision of servers based on OSGi implementation so we can react immediately on any problem on the server side when it occurs.
Components of design and functionality
All functionality will be provided by modified Plugin Registry view. Method of presentation will be slightly changed. Bundles and services of each application will be grouped by its name. It should by enough clear and transparent for a user.
Most of the functionality should be realized by additional operation in Plugin Registry view (starting, stopping modules, installing, uninstalling). Of course not all of OSGi implementations provide all of these operations so server application must provide information about OSGi implementation to a client. For example remote installation of bundles on Equinox can by impossible. On the basis of this information it should provide only permitted functionality. View with connected external applications should allow to add new ones, removing and insight into the basic information about them. Whole project will be part of Eclipse SDK, so will seamlessly integrate with it, but will also keep minimum dependencies on it to be possibly bundled as a separate Eclipse RCP application.
Proposed implementation
The first step of implementation should be the choice of the first protocol which will be used to communication with external OSGi applications. It must be enough simply for this phase. The basic method of connecting is a standard socket interface. This solution is partly implemented in bug number 243439. In my opinion this solution should be considered before we decide for other protocol. If we accept this, further development should be focused on its completion. It is very important to choose good format of data which will be send by a socket. We can choose objects serialization and in this case is important to implement good validation of objects because it is crucial. We can also think about some kind of encryption. The Java Cryptography Extension (JCE) provides support for encryption of serialized objects. If we use a XML format, we must choose another way to do this.
After that we have to adapt Plugin Registry view to handling remote connection (e.g. making and breaking it). After connection with external application our agent should download information about all bundles and services installed on this one. Supervision should be in real – time (any change of bundle’s state must be seen immediately in monitoring application). In such case, server must send information about changes to client application. More efficient is to send only description of the change (e.g. which bundle change its state and what is a new state). Another way is to send whole object. In the second solution update of model in a client is easier. We have to think which solution will be better.
On this phase we achieve functionality of Plugin Registry view but with remote monitoring. At this point, another task would be to add further functionality: remote operation on bundles and even installing new bundles in external application. After this phase we should start implementation of the second universal protocol. Unfortunately on this stage of designing we cannot clearly choose the best one. There are several possibilities. One of them is JMX (e.g. org.eclipse.equinox.monitoring). Another possible solution would be to use the Eclipse Communication Framework (ECF). For example we can choose remote services API which is very similar to classic OSGi services API. After additional protocol/protocols will be added, we will add mechanism of expansibility for new protocols (e.g. from other plugins).
In conclusion our client should offer following functionality:
- connect with external OSGi application
- present all basic information about bundles and services working on it
- allow to start and stop installed bundles
- allow to uninstall each installed bundle
- allow to install new bundles
Plugin Registry View architecture
Plugin consists of four basic classes:
- RegistryBrowser – a main class of the plugin; it creates all main parts of the plugin and allows to manage bundles, services and extension points in current Eclipse instance
- LocalRegistryBackend – it is responsible for communication between the plugin and the OSGi application instance (current Eclipse instance)
- BackendChangeListener – it is a backend listener; it changes model and informs its other listeners about backend changes
- RegistryBrowserModelChangeListener – it is a model listener; it updates view when model is changed
Model Initialization in Plugin Registry View
When the Plugin Registry is started it creates an object of RegistryModel class. This is done through static method of the model factory:
model = RegistryModelFactory.getRegistryModel(new URI(“local://”));
Depending on the URI a RegistryModel object is created with a proper backend (currently only LocalRegistryBackend can be created). In the next step a RegistryBrowserModelChangeListener is added to model listeners:
model.addModelChangeListener(listener);
The last step of model initialization is:
model.connect(monitor, true);
This method call backend’s connect(IProgressMonitor). In this method backend is added as listener for bundles, extension points and services changes. When the second argument in a model.connect(IProgressMonitor, Boolean)
is true then backend initialization starts. The backend gets current information about all bundles, extension points and services in the Eclipse instance. For each of them backend calls a proper method in a BackendChangeListener object. For instance during bundles initialization for each bundle the method listener.addBundle(Bundle)
is called. Then BackendChangeListener instance adds each of them to proper container in the model and calls fireModelChangeEvent(ModelChangeDelta)
method for update a view (in this method for each listener added to a model list a modelChanged()
method is called). There is an example diagram of bundles initialization:
After initialization of the initial state the backend has a role of listener of changes in the application. Whenever any change occurs one of the methods from the list below is called:
public void bundleChanged(BundleEvent event)
public void serviceChanged(ServiceEvent event)
public void added(IExtension[] extensions)
public void removed(IExtension[] extensions)
public void added(IExtensionPoint[] extensionPoints)
public void removed(IExtensionPoint[] extensionPoints)
First two methods are connected with service and bundles listeners. The last four are implementation of IRegistryListener interface. The diagram below show information flow when new service is registered:
Possible protocol implementations
Below we list possible implementations of data sources from where PDE Plug-in registry could pull the information about running OSGi framework.
Custom text protocol based on Socket connection
Pros:
- No additional dependencies for org.eclipse.pde.runtime (PDE SDK)
- ...
Cons:
- Requires target to include org.eclipse.pde.runtime plug-in
- Requires reimplement of connection handling, develop custom protocol. Lot of work, partially done in bug 243439 [1].
- ...
Java Management eXtensions (JMX)
Equinox monitoring server provides almost all required information to correct work of plugin registry:
- bundles – all information except exported packages and runtime libraries
- extension points – all required information
- services – there is information about plugins which registered it but has problem with multiple registers (when service is registered by more than one plugin we can get information only about one of them)
It also delivers main operation on plugins:
- start
- stop
- uninstall
There are no operations allow to install plugin from target location.
Pros:
- Available impl in Equinox Monitoring incubator
- it delivers all required inforamtion
Cons:
- Requires Java 1.5
- additional operation (e.g. bundles installing) required modification in Equinox Monitoring server implementation
- Possibly effort required to adjust equinox.monitoring to our needs (shouldn't this be an advantage?)
Custom text protocol based on ECF connection layer abstraction
Pros:
- Robust connection handling.
- A number of existing protocols already supported with common abstraction (e.g. XMPP, socket-based comm, r-osgi, etc).
Cons:
- Requires develop custom protocol. slewis comment: This is not correct. You can/could use
one (or several) existing impls: XMPP, ECF generic (socket), others. Plus you can/could use existing code for a new impl.
- Dependency for target to include ECF connection layer and our custom protocol-based server. slewis comment: not sure what this means.
Remote OSGi / ECF RFC 119
Pros:
- Little effort required, once RFC 119 is complete.
Cons:
- Additional dependency for target to include RFC 119 impl
- Will ECF ROSGi work with Equinox from Eclipse 3.2, or 3.3? Answer: No, but this is not unique to ECF, as *no* ROSGi impl will work on Equinox < 3.5 (since it depends upon the service registry hooks in OSGi 4.2/Equinox 3.5).
- Will ECF ROSGi work with non-Equinox? Answer: Yes. But is this really a requirement?
Custom
Here we will describe how to implement your own data source for plug-in registry
Socket protocol implementation
This is a basic implementation of the communication between a client application (Plugin Registry View) and a server (other instatance of an Eclipse). It consists new package org.eclipse.pde.internal.runtime.registry.remote
with tree classes:
- ConnectionClient – implementaion of a client side of the application; it sends requests to the server
- ConnectionServer – implementation of a server side of the application; it sends responses to the client whenever he sends any request; it is bundle and service listener so he also can send inforation about updates to the client without request
- RemoteRegistryBackend – new backend implementation
ConnectionServer is created during start method of a PDERuntimePlugin:
ConnectionServer s = new ConnectionServer();
s.startListening(12000);
In this example, the server will listen for request on the port 12000. RegistryModelFactory allows to create different models depending on an argument of RegistryModelFactory.getRegistryModel(URI)
. At this stage we can only replace LocalRegistryBackend for RemoteRegsitryBackend:
model = RegistryModelFactory.getRegistryModel(new URI("remote://localhost:12000"));
The different between them is that LocalRegsistryBackend is the service, bundle and extension points listener. RemoteRegistryBackend only calls client method to communicate with the server.
Below diagram shows example of communication on the client side during bundles initialization:
When registryModel calls initializeBundles method of remoteRegistryBackend it uses connectionClient instatnce to get inforamtion about bundles form the server. For each response new readerThread is created and it calls client’s receiveEvent method. The rest steps are the same as in the local bundles initialization.
Next diagram shows bundle initialization on the server side:
Server has LocalRegistryBackend insatnce to get information about local bundles. New implementation of the RegistryBackendListener does not update local model and view but only calls send() method of the ConnectionClient class.
slewis comment about socket server impl as described above: this a potentially very large security hole in PDE and Eclipse
ECF Remote Services API implementation
- client - Eclipse instance which connects with remote application
- server - OSGi application which you want to monitoring
For both you will need:
- project set File:Plugin registry remote.psf
- for self-hosting you need patch for [2]
- "patch to ch.ethz.iks.r_osgi.impl.CodeAnalyzer" from bug 274982[3]
You must add these plugins to your application.
Client's plugin registry view connects with local instatnce of Eclipse. To establish connection with other Eclipse instance (server app):
- choose "Connect" on the toolbar
- enter r-osgi://ip_address:port in the connection dialog, where port is r-OSGi instance port on the server side (you can change it by setting ch.ethz.r-osgi.port property in server application, default is 9278 or higher - if 9278 is already in use, you will get proper warning and next free port will be addressed)
After that in plugin registry view you should see model from server application.
How it works:
R-osgi plugin adds new implementation of RegistryBackend - RosgiRegistryBackend. When rosgi plugin starts it register RosgiRegistryHost remote service. RosgiRegistryBackend connects with server's RosgiRegistryHost remote service. After that RosgiRegistryBackend register its own remote service which is a RegistryModel's BackendChangeListener. On the server side RosgiRegistryHost creates instance of LocalRegistryBackend and connects with remote service registered by RosgiRegistryBackend. Next, RosgiRegistryHost sets that remote service as listener for LocalRegistryBackend. Now every operation on RegsitryBackend is delegated by RosgiRegistryBackend to RosgiRegistryHost remote service. Then it calls methods from LocalRegsitryBackend which calls methods from its listener (BackendChangeListener remote service).