Vaadin OSGi ICEPush Services

1. Introduction

About 4 years ago i started working with OSGi, but this is the first project i am using declarative OSGi services. The concept of OSGI allows to build very extendable and loose coupled software environments. In particular the use of OSGI-services is very important to create some kind of plugin architecture which allows to provide functionality on a very flexible way.

OSGi and vaadin

So far web applications did not support these concepts very well. Some time ago Chris Brind, Neil Bartlett and Peter Kriens have written different vaadin OSGi integrations which make it possible to run vaadin inside an OSGi container. (See blog from Chris Brind: Comparing approaches to vaadin and OSGi)

Vaadin is a framework to build web applications based on java code. It uses GWT (google web toolkit) to render the UI elements and offers serversided counterparts to the client UI widgets. A really amazing framework to build high level web UIs.

Kai Tödters vaadin demo app

The vaadin OSGi implementation from Chris Brind was used by Kai Toedter to write his amazing vaadin application based on OSGI-services. Using the “whiteboard pattern”, OSGi-services that are used to provide UI elements like Actions and Components are injected into the com.vaadin.Application. With this approach Kai could build a very loose coupled application environment. The UI elements “contributed” to the application depend on the installed and started OSGi-bundles.

Basically Kai’s vaadin application can be divided into two different parts:

  1. The main bundle with its main application that requires OSGi-services to build the UI.
  2. Contributor bundles providing services required by the main application.

The main bundle defines the layout of the main application but there is no knowledge about the exact content of the application involved. The content is provided by “contributor bundles” and may contain Actions, Buttons or Views as some kind of vaadin.Component.

This image displays Kai’s demo application. All shown bundles contain OSGi-services that are used to access the UI-elements. As an example the red arrows are pointing to the provided UI elements.

The next image gives you a summary about the bundle dependencies. To keep things simple, we only consider the IViewContribution service. IActionContribution works nearly the same way.

The main bundle requires IViewContribution services which offer access to the UI elements that should be added to the user interface. The interface IViewContribution will be implemented by classes located in different bundles. The OSGi-service-component-runtime observes starting and stopping bundles and injects the upcomming services into the bound MainApplication. Bindings are defined in the service component definition.

Service component definition:
com.siemens.ct.osgi.vaadin.pm.main/META-INF/vaadinMain.xml

Contribution to Kai’s demo application

At the end of this blog i am going to tell you, how applications can be push enabled automagically. All you have to do is to install and start a couple of bundles and all vaadin applications have the capability to become pushed.

Therefore we have to enhance Kai’s application by a provided interface called IApplicationProvider.

public interface IApplicationProvider {

/**
* Returns the provided application.
*
* @return
*/
Application getApplication();

}

That interface returns an instance of the application associated with this applicationProvider.

Additionally we let Kai’s application implement that interface and return “this” as the reference.

public class MainApplication extends Application implements
IApplicationProvider {

@Override
public Application getApplication() {
return this;
}

No we are going to provide the MainApplication.class as an OSGi-service for the interface IApplicationProvider.

Each time a new application was created by the component factory, then service components which reference this interface will be called.

2. Services come and services go

Before i start writing about the vaadin osgi push service, i’d like to talk about the flexibility of OSGi-services.

People already using OSGi know that bundles have a lifecycle. They can become installed, started, stopped,… into a running OSGi container without the requirement of restarting the container. A very flexible way of providing functionality.

Of course, if a bundle contains OSGI-services and the bundle was started a new service is offered by the framework. If the bundle becomes stopped, the service will be deregistered from the OSGi-runtime. It would be good practice to handle this flexibility inside your applications if you are using OSGi-services. Of course you can assume that services are static, but if you don’t so, then your application should be designed to handle the lifecycle of bundles.

Referring to Kai’s application this would imply that stopping a service bundle (a yellow one from image above) will remove all UI contributions like actions, menu bar actions and views associated with this bundle from the UI. You can use Kai’s “bundle view” to demo this issue.

Stopping or starting a bundle like “com.siemens.ct.osgi.vaadin.pm.printaction” will remove a service from the main application which reflects the changes immediatly and updates the UI. The menu bar action and the button “print” will be removed.

OSGi management console

Kai used the client UI of his application to control the lifecycle of bundles, but OSGi offers another way. You can use the OSGi management console. The commands “start bundleNumber” and “stop bundlenumber” will start and stop these bundles.

But if you are using the management console with Kai’s application, a starting or stopping bundle will not update the UI immediately since the server cannot notify the UI about this change! So you have to wait for the next UI refresh until the client UI has reflected the stopped bundle.

This image displays the problem using the management console to control the lifecycle of bundles. If a bundle becomes stopped, the serversided components get a dirtyState, which cannot be pushed to the client!

The changes will be transfered to the client at the next client UI refresh. Since vaadin clients are not pushable without using any addons, the server cannot inform the client about changes.

But vaadin offers an addon called ICEPush. ICEPush allows the client UI to be notified by the server on changes. A really helpful addon which perfectly matches the requirements described above.

3. Details about the implementation

This chapter of my post gives you an introduction how i have implemented ICEPush using the vaadin OSGi integration from Chris Brind.

Main goal was to provide bundles which enable the ICEPush addon and the “vaadin OSGi ” addon at the same time. And to push changes from the server the client UI in OSGi environments.

Main issue

ICEPush and vaadin-OSGi both provide their own servlet.

  • ICEPushServlet is responsible to serve the ICEPush javascript code and to handle requests ending with “.icepush”
  • VaadinOSGiServlet is responsible to create a new instance of com.vaadin.Application based on an OSGi-ComponentFactory

Servlet

Since exactly one servlet is required for my issue i decided to merge the contents of both servlets and to create a new one called ICEPushVaadinOSGiServlet. Luckily both implementations are based on the “Apache License 2.0” license and so it was legal to combine them.

The ICEPushVaadinOSGiServlet offers a compound functionality as ICEPushServlet and VaadinOSGIServlet do.

This code displays a stub of the new servlet class. At the beginning of the method stub you can see where is it original from.

/**
* Merges org.vaadin.osgi.VaadinOSGiServlet (vaadins osgi addon) and
* {@link org.vaadin.artur.icepush.ICEPushServlet} (vaadins icePush addon).
*/
public class ICEPushVaadinOSGiServlet extends AbstractApplicationServlet {

// from org.vaadin.osgi.VaadinOSGiServlet
@Override
protected Class<? extends Application> getApplicationClass()
throws ClassNotFoundException {
return Application.class;
}

// from org.vaadin.osgi.VaadinOSGiServlet
@Override
protected Application getNewApplication(HttpServletRequest request)
throws ServletException {
// ...
}

@Override
// from org.vaadin.artur.icepush.ICEPushServlet
public void init(ServletConfig servletConfig) throws ServletException {
// ...
}

@Override
// from org.vaadin.artur.icepush.ICEPushServlet
protected void service(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
// ...
}

/**
* Sends the ICEPush javascript code to the client.<br>
* from org.vaadin.artur.icepush.ICEPushServlet
*
* @param request
* @param response
* @throws IOException
*/
private void serveIcePushCode(HttpServletRequest request,
HttpServletResponse response) throws IOException {
// ...
}

/**
* Track the component instance and session. If this is disposed the entire
* associated http session is also disposed.<br>
*
* from org.vaadin.osgi.VaadinOSGiServlet
*/
class VaadinSession {
// ...
}
}

VaadinOSGiApplicationManager

The VaadinOSGiApplicationManager is the main class of the vaadin OSGi integration. It runs as an OSGi component and is responsible to create and register a servlet at the http service. In the org.vaadin implementation the VaadinOSGiServlet is used.

I  enhanced this manager and added a required OSGi-service (interface == IServletFactory ) which provides a HttpServlet. With this approach the used servlet is very loose coupled and can be provided by OSGi-services. The service has to provide an implementation of the IServletFactory which creates new instances from a http servlet.

/**
* A factory provided by OSGI-Services to contribute servlets.
*/
public interface IServletFactory {

/**
* Returns a servlet to be used by the {@link VaadinOSGiApplicationManager}.
*
* @param factory
*            which has create the {@link Application}
* @param servletpath
*            which is used to register the servlet
* @param initialProperties
*            Properties registered against the component factory.
* @return
*/
HttpServlet createServlet(ComponentFactory factory, String servletpath,
Map<String, Object> initialProperties);

}

4. Vaadin OSGi Push Addon bundles

The original VaadinOSGiApplicationManager was copied since i did not want to change the “none pushing osgi vaadin” implementation from Chris Brind and have created a new bundle called org.vaadin.pushosgi.

This bundle is replacing the org.vaadin.osgi bundle and contains the VaadinOSGiApplicationManager including the extended IServletFactory functionality.

As you can see, no servlets are contained in the bundle. Since the servlets are provided by OSGi-services, they are defined in different bundles.

The next image displays two servlet contributor bundles which offer OSGi-services.

With this approach you only have to decide which servlet should be used and to install the prefered bundle into the target platform. No further steps are required. The dependencies between the OSGi bundles and services will be resolved by the OSGi framework and the installed servlet will be used automatically.

That image displays a summary about the bundles involved.

ICEPush implementation

If you are using the ICEPush addon by Artur Signell you have to install the ICEPush addon. It is divided into a server side and a client UI part.

Serverside

All required java code for the server side is contained in the bundle “org.redvoodo.vaadin.addon.icepush“. No changes have been made to the sourcecode. Just an OSGi-bundle has been created from the ICEPush-jar-files.

Client UI

Using vaadin all client side addons have to be compiled at once. The resulting widgetset has to be provided as described in redvoodo.org. The example from this post uses the widgetset from bundle-fragment “org.redvoodo.extension.ct.osgi.widgetset.fragment“.

The widgetset has been speficied in the launch configuration:

-Dorg.redvoodo.addon.osgi.push.servlet.widgetset=
org.redvoodo.extension.ct.osgi.pushosgi.widgetset.PushosgiWidgetset

Minimal bundle requirement

If you want to use the vaadin OSGi ICEPush, you have to install a minimal set of bundles:

  • org.vaadin.pushosgi – the main bundle which contains VaadinOSGiApplicationManager
  • org.redvoodo.addon.osgi.push.servlet – provides the ICEPushVaadinOSGiServlet
  • org.redvoodo.vaadin.addon.icepush – server side java classes from ICEPush
  • some fragment bundle like org.redvoodo.extension.ct.osgi.widgetset.fragment containing the compiled widgetset

Thats all you have to add to your OSGi launch configuration to have a properly configured “vaadin OSGi pushable application”.

But there is no further support. You have to handle the ICEPush yourself.

pusher = new ICEPush();
application.getMainWindow().addComponent(pusher);

// doing the push
pusher.push();

Demo

This movie demos what i was writing about so far:

5. redVoodo Push Services

So far you can use ICEPush in vaadin OSGi applications. But there is no further support for some kind of “OSGi push services”.

Therefore i have prepared a set of very flexible and loose coupled bundles which offer “OSGi push services” and help you to manage your pushing applications.

Bundles:

  • org.redvoodo.addon.osgi.push.services – The service interface definition
  • org.redvoodo.addon.osgi.push.services.impl.service – Provides default implementation for IPushService
  • org.redvoodo.addon.osgi.push.services.impl.manager – Provides default implementation for IPushServiceManager
  • org.redvoodo.addon.osgi.push.services.impl.managed.pusher – Provides default implementation for IManagedPusher
  • org.redvoodo.addon.osgi.push.services.application.bridge – The queen of this addon. Bridges IApplicationProvider and IManagedPusher

org.redvoodo.addon.osgi.push.services

Lets start with the service interfaces:

The main interfaces of these services are IPusher and IPushService:

public interface IPusher {

/**
* Forces a push to the client. If the pusher is not active, a call to
* this method must not result in an error.
*
* @return true if the push was successful. False otherwise. If the pusher
*         was not active, false will be returned.
*/
boolean push();

/**
* Returns the application the pusher is prepared for. Or <code>null</code>
* if the pusher is a compound pusher which pushes several applications.
*
* @return
*/
Application getApplication();

}

The IPusher is responsible to push changes to the client. Each pusher is associated with exactly one Application.

/**
* A push service is used to notify the client, that it should refresh its
* state.
*/
public interface IPushService {

/**
* Activates the push functionality for the given application and ensures,
* that the pusher for this application can be accessed by this service.<br>
* The acitvated pusher will be stored in this service until deactivate
* pusher is called.
*
* @param application
* @return
*/
IPusher activatePusher(Application application);

/**
* Deactivates the push functionality for the given application. Further
* calls to a pusher associated with this application will result in an
* error.
*
* @param application
* @return
*/
void deactivatePusher(Application application);

/**
* Deactivates the push functionality for the application associated with
* the given pusher. Further calls to pusher associated with this
* application will result in an error.
*
* @param application
* @return
*/
void deactivatePusher(IPusher pusher);

/**
* Returns a pusher which pushes all applications that are registered within
* this pushService.
*
* @return
*/
IPusher getGlobalPusher();

/**
* Returns a pusher for the given application.
*
* @param application
* @return
*/
IPusher getPusher(Application application);

/**
* Returns a compound pusher based on the scope. The scope allows to collect
* pushers which are registered within this pushService.
*
* @param scope
* @return
*/
IPusher getPusher(IScope scope);

/**
* Scope is used to create a compound pusher based on other pushers.
*/
public static interface IScope {

/**
* Returns a compound pusher which delegates the push call to the
* contained pusher.
*
* @param pushers
* @return
*/
IPusher getPusher(Map<Application, IPusher> pushers);

}
}

The IPushService is responsible to activate and deactivate pusher for their associated Application and to access them.

Since IPushService is an OSGi-service, you have to handle the lifecycle of that service. See chapter “services come and services go”.

org.redvoodo.addon.osgi.push.services.application

ATTENTION: Bundle was removed with 0.7.2. Was not an OSGi like approach.

org.redvoodo.addon.osgi.push.services.impl.service

ATTENTION: In Version 0.7.1 this bundle was named

org.redvoodo.addon.osgi.push.services.impl

This image is a summary about the service and its default implementation.

The bundle org.redvoodo.addon.osgi.push.services.impl.service can be used as a default implementation of the push service. But you can write your own implementation and provide it as a service.

org.redvoodo.addon.osgi.push.services.impl.manager

Was added with 0.7.2

The image shows a summary and the default implementation of the IPushServiceManager. The PushServiceManager is responsible to manage IPushServices. It allows clients to register listener and to observe the services and their lifecycle.

The bundle org.redvoodo.addon.osgi.push.services.impl.manager can be used as a default implementation of the IPushServiceManager. But you can write your own implementation and provide it as a service.

org.redvoodo.addon.osgi.push.services.impl.managed.pusher

Was added with 0.7.2

To hide the lifecycle of IPushService and IPushServiceManager, i have prepared an interface which describes some kind of a helper class.

IManagedPusher.class

It internally uses the IPushServiceManager and IPushService, but hides the lifecycle handling from the developer. If services come and services go, the ManagedPusher does not have to be refreshed externally. All the refreshing stuff is handled internally.

A very useful class to minimize the amount of effort required to use the redVoodo push services.

The component factory can be required as any OSGi-service. But you have to specify the target of the requirement.

(component.factory=org.redvoodo.addon.osgi.push.services.managed.pusher)

Code samples how to use the service:

/**
* Called by the OSGi framework
*/
public void bindManagedPusherFactory(ComponentFactory pusherFactory,
Map<String, Object> properties) {
      this.pusherFactory = pusherFactory;
}

/**
* Called by the OSGi framework
*/
public void unbindManagedPusherFactory(ComponentFactory factory,
Map<String, Object> properties) {
      this.pusherFactory = null;
}

// to create a new pusher
IManagedPusher pusher = (IManagedPusher) pusherFactory.
newInstance(null).getInstance();
pusher.setup(application);
pusher.pushToClient();

// to dispose the pusher
pusher.dispose();

For details how to use see class

org.redvoodo.addon.osgi.push.services.application.bridge.ApplicationPusherBridge

org.redvoodo.addon.osgi.push.services.application.bridge

This bundle is a really important bundle for the vaadin OSGi push services addon. It bridges the IApplicationProvider and the IManagedPusher. Installing this bundle into the target platform will automatically enable push for all applications provided by IApplicationProvider.

The org.redvoodo.addon.osgi.push.services.application.bridge bundle requires the IApplicationProvider OSGi-Service. Each time a new application was created by the component factory, the service component will be notified about the new application and uses the ComponentFactory to create an instance of IManagedPusher. The managed pusher itself handles the registration at the IPushService. If the application is destroyed the service component will also be notified and the pusher for the destroyed application will be removed.

Additionally this class requires the componentFactory-service. If a new ComponentFactory for IManagedPusher became available, the class will handle this notification. If no factory was installed yet, nor of the applications are push enabled. But an upcoming component factory service causes the bridge to create new instances of IManagedPusher for each application. And so all applications become push enabled.

Referring to Kai’s demo application, only one change had to be made to his application. The IApplicationProvider was added to the vaadin.xml compontent definition as a provided service. But his application does not have any dependency to the redVoodo push services. Immediately after the instantiation of an application by a component factory, the application becomes push enabled automatically.

The push to Kai’s application is triggered by the bundle “org.redvoodo.extension.ct.osgi.observer” (All org.redvoodo.extension.ct.osgi bundles are extensions of Kai’s application). Since this bundle requires the IPushServiceManager service, it has access to all registered push enabled applications and can use that service to push all applications. (Remember: The applications have been registered at the pushService by the ManagedPusher above).

String symbolicName = event.getBundle().getSymbolicName();
if ((symbolicName.startsWith("com.siemens.ct.osgi.vaadin.pm")
|| symbolicName.startsWith("com.siemens.ct.pm.model."))
&& !((symbolicName.contains("main")
|| symbolicName.contains("theme")
|| symbolicName.contains("bundleview")
|| symbolicName.contains("logback")))) {
       // push all registered clients
       serviceManager.getPushService().getGlobalPusher().push();
}

If a bundle becomes started or stopped, the bundleChanged event will be called. For specified bundles the AppPusherPlugin#pushAll() method will be called, which pushed all dirty states to the client.

How to use push services

There are several ways how redVoodo push services can be used.

Require a service

Require a service like IPushServiceManger, IPushService or IManagedPusher. Depends what the service will be used for.

Use the default implementations

Provided by bundles:

  • org.redvoodo.addon.osgi.push.services.impl.managed.pusher
  • org.redvoodo.addon.osgi.push.services.impl.manager
  • org.redvoodo.addon.osgi.push.services.impl.service

Write your own services

Feel free to write your own services and to provide them as a service.

Conclusion

I hope this blog post could give you an introduction about the redVoodo OSGi ICEPush services. If you have any suggestions it would be really nice if you may write a comment.

Thanks a lot to Kai Tödter, Chris Brind, Neil Bartlett and Peter Kriens for the really great available code and blog posts how vaadin OSGi integration can be implemented.

Further informations

In bed with vaadin and OSGi by Chris Brind

Dynamic modular Web Applications with Vaadin and OSGi by Kai Tödter

OSGi vaadin integration by Peter Kriens

blog by Neil Bartlett

blog by Ekkehard Gentz

redVoodo.org

how to use vaadin and OSGi from redVoodo

how to use vaadin addons from redVoodo

how to push to browser from redVoodo

Comparing approaches by Chris Brind

Advertisements

Tags: , ,

9 Responses to “Vaadin OSGi ICEPush Services”

  1. Push Services –> mobile and enterprise (Vaadin + OSGI) « ekkes-corner: eclipse | osgi | mdsd | erp | mobile Says:

    […] Florian did some work on Push Services: there’s already a Vaadin Add-on ICEpush providing this feature to Vaadin […]

  2. Kai Tödter Says:

    Great Post, Flo! Thanx

  3. Josh Prismon Says:

    Got a question, Upload doesn’t seem to work correctly with this. Has anyone else tried? I tried using the standard examples – but the automatic and the select file upload version, and neither work both fail with:
    .vaadin.terminal.gwt.server.UploadException: Upload failed
    at com.vaadin.terminal.gwt.server.AbstractCommunicationManager.streamToReceiver(AbstractCommunicationManager.java:614)
    at com.vaadin.terminal.gwt.server.AbstractCommunicationManager.doHandleSimpleMultipartFileUpload(AbstractCommunicationManager.java:467)
    at com.vaadin.terminal.gwt.server.CommunicationManager.handleFileUpload(CommunicationManager.java:257)
    at com.vaadin.terminal.gwt.server.AbstractApplicationServlet.service(AbstractApplicationServlet.java:495)
    at org.redvaadin.addon.osgi.push.servlet.ICEPushVaadinOSGiServlet.service(ICEPushVaadinOSGiServlet.java:173)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
    at org.eclipse.equinox.http.servlet.internal.ServletRegistration.service(ServletRegistration.java:61)
    at org.eclipse.equinox.http.servlet.internal.ProxyServlet.processAlias(ProxyServlet.java:126)
    at org.eclipse.equinox.http.servlet.internal.ProxyServlet.service(ProxyServlet.java:68)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
    at org.eclipse.equinox.http.jetty.internal.HttpServerManager$InternalHttpServiceServlet.service(HttpServerManager.java:318)
    at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:511)
    at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:390)
    at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)
    at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765)
    at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
    at org.mortbay.jetty.Server.handle(Server.java:326)
    at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542)
    at org.mortbay.jetty.HttpConnection$RequestHandler.content(HttpConnection.java:939)
    at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:756)
    at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:218)
    at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)
    at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:409)
    at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582)
    Caused by: java.lang.NullPointerException
    at com.vaadin.ui.Upload$1.getOutputStream(Upload.java:1007)
    at com.vaadin.terminal.gwt.server.AbstractCommunicationManager.streamToReceiver(AbstractCommunicationManager.java:553)
    … 23 more

    • Florian Pirchner Says:

      Hi John,

      I tried all 3 types of uploads from the vaadin sampler. Everything work really fine without any error.

      Can you provide me with some code of your upload?

      at com.vaadin.ui.Upload$1.getOutputStream(Upload.java:1007)
      Would be really interesting why the exception is thrown at this statement.

      Thanks, Florian

  4. Josh Prismon Says:

    Got past the exception, it was due to the Receiver not working correctly. No I seem to have another generic error where none of the associated listeners – The StartedListener or SuceddedListener don’t seem to be fired. Learning Vaadin right now, so I love the solution, but it’s still a learning curve.

  5. http://tinyurl.com/nwscgrace32937 Says:

    “Vaadin OSGi ICEPush Services Flos Blog” was in fact a great blog.
    If it owned more pix this should be perhaps even more beneficial.

    Cya ,Leanne

  6. http://tinyurl.com/tennmaloy30312 Says:

    “Vaadin OSGi ICEPush Services Flos Blog” was in
    fact a remarkable read and I was in fact very
    pleased to come across the blog. Thanks a lot-Marie

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s


%d bloggers like this: