4

I spent quite a few days now trying to figure out how to add a website in OSGi.

I hava Restlet web service running with Jetty extension to use Jetty as a connector. This feature provides different resources under multiple URLs.

But I would also like to have a small website running on the system that can be accessed by the user. I wanted to use some HTML,Javascript,CSS and provide the current data status with some graphs and pictures.

I assume since Jetty is running in the background I would be able to deploy this website on Jetty and maybe call the server resources provided by Restlet in Javascript.

Apparently nothing worked except the restlet services.

My question would be is it possible to add a WAB bundle and expect it to work(Since Jetty is running in background)? Or is there any better way to add a website in OSGi? Or The only option I have now is, since it is possible to return an HTML form as a representation, add all my javascript code inside the HTML form and send it as a response to GET request(Which I believe is a mess).

Everything will run in Raspberry pi so I can only have a very small footprint. I am using Equinox, Restlet 2.3.0 and Jetty 9.2.6.

I would really appreciate if someone knows a link where i could get info on getting at least a sample page running in OSGi. I have tried many with no luck.

Excite
  • 484
  • 1
  • 5
  • 19

3 Answers3

2

I recommend you to have a look at how it is done in Apache Karaf (https://github.com/apache/karaf). More on Apache Karaf and WebContainers here: http://karaf.apache.org/manual/latest/users-guide/webcontainer.html

Jorge Martinez
  • 1,221
  • 8
  • 16
0

In fact, Jetty is internally used by Restlet under the hood through its connector feature. This way, it's not convenient (and not the correct approach) to register dynamically applications.

That said, Restlet is really flexible and dynamic. This means that you can dynamically handle bundles that contain Restlet applications in a similar way than WAB bundles, i.e. attach them to virtual hosts of a component.

Here is the way to implement this:

  • Create a bundle that makes available the Restlet component into the OSGi container. You should leverage the FrameworkListener listener to be able that all connectors, converters, and so on... are registered into the Restlet engine:

    private Component component;
    
    public void start(BundleContext bundleContext) throws Exception {
        bundleContext.addFrameworkListener(new FrameworkListener() {
            component = new Component();
            (...)
            component.start();
        });
    }
    
    public void stop(BundleContext bundleContext) throws Exception {
        component.stop();
    }
    
  • When the component is started, you can look for bundles that are present in the container and contained Restlet applications. For each bundle of this kind, you can register a dedicated OSGi service that make available the internal Restlet application you want to register against the component.

    ServiceReference[] restletAppRefs = bundleContext.getServiceReferences(
         "restletApplication",
                    null);
    
    if (restletAppsRefs != null) {
        for (ServiceReference restletAppRef : restletAppsRefs) {
            RestletApplicationService descriptor
                 = (RestletApplicationService) bundleContext
                   .getService(serviceReference);
            String path = descriptor.getPath();
            Application restletApplication = descriptor.getApplication();
    
            // Register the application against the component
            (...)
        }
    }
    

    Registering applications against the component is

    try {
        VirtualHost virtualHost = getExistingVirtualHost(
                       component, hostDomain, hostPort);
        if (virtualHost == null) {
            virtualHost = new VirtualHost();
            virtualHost.setHostDomain(hostDomain);
            virtualHost.setHostPort(hostPort);
    
            component.getHosts().add(virtualHost);
        }
    
        Context context = component.getContext().createChildContext();
        virtualHost.setContext(context);
    
        virtualHost.attachDefault(application);
    
        component.updateHosts();
    
        application.start();
    } catch(Exception ex) {
        (...)
    }
    
  • You also need to take into account the dynamics of OSGi. I mean bundles can come and go after the start of the OSGi container itself. You can leverage

    bundleContext.addServiceListener(new ServiceListener() {
        public void serviceChanged(ServiceEvent event) {
            if (isServiceClass(event, RestletApplicationService)) {
                int type = event.getType();
    
                if (type == ServiceEvent.REGISTERED) {
                    // Register the Restlet application against the component
                } else if (type == ServiceEvent.UNREGISTERING) {
                    // Unregister the Restlet application
                }
            }
        }
    });
    

Hope it helps you, Thierry

Thierry Templier
  • 198,364
  • 44
  • 396
  • 360
  • thanks a lot for your response. But I already have a full Restlet based service running. I have created the component, registered my application and add a route to my different resource classes with their corresponding url. The problem is on providing a website with a nice user interface that summarises and presents the status(by accessing the different resource url and adding some javascript,css...). I currently used FreeMarker and I return the website as html form representation by FreeMarker. But it goes against the concept of html form. I wanted to make the website HTML directly accessibl – Excite Dec 15 '15 at 17:17
0

There are many options available to you - OSGi doesn't really impose many restrictions on what you can do. If you want to use OSGi's capabilities then here's a couple of ideas:

  • One option would be to deploy a WAB. You'll need to ensure that your framework has the necessary OSGi Services running though. Just because some bundle is using Jetty internally it doesn't follow that the necessary OSGi services are running.

The bundle org.apache.felix.http.jetty does provide the necessary services to deploy a WAB. Version 2.2.2 is 1.3MB on disk, and embeds its own copy of Jetty. Other implementations are available (e.g. Pax-Web, as used in Karaf - which also embeds Jetty)

  • Another option would be to use the OSGi Http service directly (again you'd need to include a bundle which implements this service (like the Felix one mentioned). A call to org.osgi.service.http.HttpService.registerResources() will serve up static content from within your bundle.

If the this additional footprint is a real concern then you might want to look at how you can get Restlet to use the OSGi http service, rather than providing it's own via embedded Jetty.

Yet another option would be to take a Jetty centric view of things. Restlet's embedded Jetty is probably not configured to serve arbitrary content from disk. You could look at either re-configuring the embedded Jetty to do this, or consider deploying Restlet to a 'standard' Jetty install. Personally, I'd try the latter.

Paul M
  • 357
  • 1
  • 8
  • As you said in the first option to deploy WAB I need to have the necessary bundles and that was one of my problems. Identifying and fulfilling the dependancies was a headache given no clear guide for equinox under J2SE option. I will try org.apache.felix.http.jetty over the weekend but I think that again comes with a whole other dependancies on other felix bundles. As for the second one even Jetty recommend embedding Jetty in OSGi than deploying the application on Jetty. – Excite Dec 16 '15 at 10:52