MongoEMF Update

I have a couple of updates for you on the MongoEMF project.  First off, I have released version 0.6.0.  This version brings a significant refactoring to the structure of the project to make way for a new query engine.  More on this in a bit.  I changed all OSGi services to use declarative services (DS), so you will now need to include the appropriate DS bundle for your favorite OSGi container.  I also removed lazy bundle activation (Neil will be proud) so you must make sure the org.eclipselabs.mongo and org.eclipselabs.mongo.emf.query.simple bundles get started.  Finally, I added the ability for a query to return a cursor instead of materializing all of the objects.  Please see the Release Notes for all the details.

The current query engine in MongoEMF has several limitations that need to be overcome.  As I mentioned in a previous post, I have proposed a Google Summer of Code project to re-write the query engine using Xtext.  Tiger Gui has submitted a student proposal to Google for this project.  He has already done some prototyping and the results look very promising.  If you are interested in seeing Eclipse accept this project for GSoC, please show your support on the soc-dev mailing list.  If you have any feedback on the design of the new query engine, please post to the MongoEMF community forum.

Right now, I’m taking a serious look at the OSGi services in MongoEMF.  I’m planning on refactoring them in the next release to include the ability to configure Mongo instances through the OSGi ConfigAdmin.  If you have any interest in this area, you feedback is welcome.

Finally, I’m considering proposing MongoEMF as an Eclipse project.  I don’t expect to begin the process until we get close to the 1.0 release.  Would you, the community, support this project proposal and the move to an Eclipse project?

MongoEMF 0.5.1 Released

I have released MongoEMF version 0.5.1.  MongoEMF is a bridge between MongoDB and the Eclipse Modeling Framework making it very easy to store and retrieve instances of EMF objects in MongoDB.  This version is a maintenance release with bug fixes and minor enhancements.  For a complete list of new features, please see the Release Notes.  A Google group is now available for community discussions of MongoEMF.

MongoEMF 0.5.0 Released

I have released version 0.5.0 of MongoEMF.  MongoEMF is a bridge between MongoDB and the Eclipse Modeling Framework making it very easy to store and retrieve instances of EMF objects in MongoDB.  This version includes the ability to provide custom data type converters for storing non-native attribute values as a native type in MongoDB.  For example, you can now store a Calendar as a long.  The code was also refactored into a builder pattern, giving you the ability to completely customize how objects are serialized and deserialized in the database.  For a complete list of new features, please see the Release Notes.  I have also made some progress on a User Guide.  If you have any interest in contributing to this project, please contact me.

Google Summer of Code 2012 with Xtext, EMF, and MongoDB

The Eclipse Google Summer of Code for 2012 will start coming to life soon, and I have an idea for a project involving Xtext, EMF, and MongoDB.  Ed Merks and I have created a project called MongoEMF that allows you to persist EMF objects to MongoDB.  MongoEMF has the ability to query objects based on attribute and reference values, but is lacking some functionality and robustness.  We think a re-write of the query engine using Xtext and EMF would make for a great Google Summer of Code project.  This project has a very well defined scope, is easily unit tested, and involves some pretty cool technology.

The project will consist of two major parts.  The first will be to define a query grammar (possibly re-using an existing grammar) using Xtext.  The result will be an EMF query model that can be serialized and de-serialized to a string.  The string will be used as the query portion of a URI, and must be human readable.  For example:  mongo://host/db/collection/?(tag == ‘java’ || tag == ‘JSON’) && (category == ‘Eclipse’).  Clients will be able to specify the query as string or EMF model.  The second part of the project will be to create a processing engine that builds a MongoDB query from the EMF query model.  The result will be a DBObject that can be sent to MongoDB as a query.

An example use-case is as follows:  A client constructs an EMF query model.  The query model is then serialized to a string and included in a URI.  The URI is sent to a server in a HTTP GET call.  The server extracts the query string from the URI and re-builds the EMF query model.  The query model is passed to the query engine and a DBObject is returned containing a MongoDB specific query.  The DBObject is sent to MongoDB resulting in some number of DBObjects returned.  The resulting DBObjects are converted into EMF objects and returned to the client.

The student is expected to develop extensive unit tests for his / her code as well as end-user documentation.  Documentation will be contributed to the UserGuide on the MongoEMF wiki.  We also anticipate that the student will become a committer on MongoEMF, and will continue to provide bug fixes and enhancements after the project is complete.

We consider this to be an advanced Eclipse project.  The student should already be comfortable coding in Java and developing OSGi bundles with Eclipse.  A student with working knowledge of EMF will be preferred, but you are not required to already know Xtext or MongoDB.  If you are interested in this project, I would recommend forking the MongoEMF project on GitHub and experimenting with the latest code in the master branch.  Instructions for setting up your environment can be found on the Development wiki page.  If you have any questions, please comment on this post.

This project idea will be included on the Eclipse Google Summer of Code wiki soon.

eTrack EMF Tutorial

I’ve made a little more progress with eTrack and I now have two complete EMF tutorials available.  Creating the Entity Domain Model walks you through creating an EMF ecore model for the Entity domain, the corresponding genmodel, and how to use the generated editor.  Refactoring the Entity Domain Model shows you how to refactor an EMF model into two separate models.  These are the first tutorials available in a series that will cover the building of an entire application.  If you would like to contribute to the project, please let me know or open an issue.

Restlet Extensions for OSGi Environments 0.5.0 Released

I have released Restlet Extension for OSGi Environments version 0.5.0.  This project provides a framework for building RESTful OSGi web services using dynamic applications, routers, filters, and resources.  The project has been renamed from Restlet integration with OSGi & Equinox, and has also been refactored to be a Restlet extension.  This build is temporary until the extension is officially released as part of Restlet.  This release requires Restlet 2.1M7 or later.

MongoEMF 0.4.0 Released

I have released MongoEMF 0.4.0.  Some of the notable changes include:

  • Reading objects from a query Result has been significantly improved
  • Write performance for bulk stores has improved
  • Added MongoResourceImpl for improved load performance when using URI mappings
  • Added OPTION_USE_ID_ATTRIBUTE_AS_PRIMARY_KEY to store objects using the ID attribute value as the MongoDB primary key

For a complete list of the changes, see the Release Notes.

OSGi at REST

Introduction

I’ve been working on a project to make building RESTful OSGi web applications as simple as creating a basic OSGi service, and I think I have a solution that comes pretty close to this goal. The project is currently called restlet-integration-with-equinox as hosted on EclipseLabs. I am in the process of moving the project to GitHub, and it will be renamed to Restlet Extension for OSGi Environments.  This framework integrates the Restlet RESTful web framework with OSGi allowing you to dynamically register resources, filters, routers, and applications as part of a RESTful web application.

The project originally started out supporting the registration of applications and resources as OSGi services or with an Equinox extension point.  This all worked fine until I started adding the ability to register routers and filters.  The code became complicated and ugly, so I branched the repository and started over.  As the second iteration progressed, it too became complicated, and it occurred to me that the core of the problem (delayed dynamic binding) was identical to the problem that OSGi declarative services has to solve.  That’s when I had that AH-HA moment where the problem becomes clear, and you get to delete all of that ugly, complicated, code.  The solution is to use OSGi declarative services and its dynamic binding capabilities to stitch together the resources, filters, routers, and applications.  And, since you are using OSGi services, you can add and remove resources at runtime and it all just works.

Framework

The Restlet Extension for OSGi Enironments framework is organized as a set of service components and interfaces for you to register as declarative services to form your RESTful web application.  Using these service components, it’s possible to implement a simple application with a router and some resources, or a very complex graph of filters, routers, and resources as demonstrated below.

Application

Here is the API specification for the service interfaces:

Service Interfaces

Here is the API specification for the service components (I have omitted the service interfaces that each provider implements):

Service Components

FilterProvider and ResourceProvider are abstract and must be extended as described below.  RouterProvider and ApplicationProvider can be used without extending them.  The remainder of this post will walk you through examples of creating RESTful web applications using this technology.

Setup

Before you begin development of your application, the target platform needs to be crated with the following frameworks:

If you would like to minimize your target platform, the following bundles are the minimum required:

  • javax.servlet
  • org.eclilpse.equinox.common
  • org.eclipse.equinox.ds
  • org.eclispe.equinox.http.jetty
  • org.eclipse.equinox.http.servlet
  • org.eclipse.equinox.util
  • org.eclipse.osgi
  • org.eclipse.osgi.services
  • org.mortbay.jetty.server
  • org.mortbay.jetty.util
  • org.restlet
  • org.restlet.ext.servlet
  • org.eclipselabs.restlet
  • org.eclipselabs.restlet.servlet

If you are not familiar with setting up your target platform, here are the detailed steps:

  1. Download Restlet JEE 2.0.8 and Restlet Extensions for OSGi Environments 0.3.0.  You do not need to download Equinox – we’ll get that from a p2 repository.
  2. Uncompress the downloads into a targets directory.
  3. Launch Eclipse (I’m using Indigo) and select Preferences -> Plug-in Development -> Target Platform.
  4. Click Add…
  5. Choose Nothing: Start with an empty target definition.
  6. Click Next
  7. Name the target platform.
  8. Click Add…
  9. Choose Directory and click Next.
  10. Add <target directory>/restlet-jee-2.0.8/lib
  11. Click Finish.
  12. Click Add…
  13. Choose Directory and click Next.
  14. Add <target directory>/restlet-ext-osgi
  15. Click Finish.
  16. Click Add…
  17. Choose Software Site.
  18. Work with: http://download.eclipse.org/releases/indigo.
  19. Expand EclipseRT Target Platform Components.
  20. Check Equinox Target Components.
  21. Click Finish.
  22. Click Finish.
  23. Check the target definition you just created to make it Active.
  24. Click OK.

Edit Target Definition 1

Let’s test the target definition.  Create an OSGi launch configuration with the following bundles:

  • javax.servlet
  • org.eclipse.equinox.http.jetty
  • org.eclipse.equinox.http.servlet
  • org.eclipse.osgi
  • org.eclipse.osgi.services
  • org.mortbay.jetty.server
  • org.mortbay.jetty.util

Set Default Auto-Start: true (not ideal, but it gets you up and running quickly) and add the following VM argument: -Dorg.osgi.service.http.port=8080.

Run Configurations 3

Run the application and point your web browser to http://localhost:8080/.  You should get a 404 error.  This lets you know that jetty is responding to your request, but there are currently no resources to handle the request.  For more information on setting up OSGi as a web server, see my blog post: OSGi as a Web Application Server.

Hello RESTful World

For this tutorial we are going to create a single resource at the URI http://localhost:8080/hello with a plain text representation.  We need to create and wire together three objects: Application, Router, and ServerResource.  Start by creating a new Plug-in Project called org.eclipselabs.restlet.examples.app.  You do not need a bundle activator.

Open the MANIFEST.MF and add the following imported packages:

  • org.eclipselabs.restlet
  • org.restlet
  • org.restlet.resource

Create a new package: org.eclipselabs.restlet.examples.app and add the following HelloResource:

package org.eclipselabs.restlet.examples.app;

import org.restlet.resource.Get;
import org.restlet.resource.ServerResource;

public class HelloResource extends ServerResource
{
  @Get("txt")
  public String sayHello()
  {
    return "Hello RESTful World";
  }
}

In that same package, add the following HelloResourceProvider:

import org.eclipselabs.restlet.ResourceProvider;
import org.restlet.Context;
import org.restlet.resource.Finder;

public class HelloResourceProvider extends ResourceProvider
{
  @Override
  protected Finder createFinder(Context context)
  {
    return new Finder(context, HelloResource.class);
  }
}

At the root of the project create an OSGI-INF folder to hold our service declarations.  In the OSGi-INF folder, create the following declarative service as application.xml:

<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" immediate="true" name="org.eclipselabs.restlet.examples.app">
   <implementation class="org.eclipselabs.restlet.ApplicationProvider"/>
   <service>
      <provide interface="org.eclipselabs.restlet.IApplicationProvider"/>
   </service>
   <property name="alias" type="String" value="/"/>
   <reference bind="bindRouterProvider" cardinality="1..1" interface="org.eclipselabs.restlet.IRouterProvider" name="IRouterProvider" policy="static" unbind="unbindRouterProvider"/>
</scr:component>

Create the following declarative service as router.xml:

<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" immediate="true" name="org.eclipselabs.restlet.examples.app.router">
   <implementation class="org.eclipselabs.restlet.RouterProvider"/>
   <service>
      <provide interface="org.eclipselabs.restlet.IRouterProvider"/>
   </service>
   <reference bind="bindResourceProvider" cardinality="1..n" interface="org.eclipselabs.restlet.IResourceProvider" name="IResourceProvider" policy="dynamic" unbind="unbindResourceProvider"/>
</scr:component>

Create the following declarative service as hello.xml:

<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" immediate="true" name="org.eclipselabs.restlet.examples.app.hello">
   <implementation class="org.eclipselabs.restlet.examples.app.HelloResourceProvider"/>
   <service>
      <provide interface="org.eclipselabs.restlet.IResourceProvider"/>
   </service>
   <property name="paths" type="String">
     /hello
   </property>
</scr:component>

If you are not using the component definition editor to create your declarative services, be sure to add the following to the MANIFEST.MF:

Service-Component: OSGI-INF/application.xml, OSGI-INF/router.xml, OSGI-INF/hello.xml

You are now ready to run and test your web application.  Add the following bundles to the launch configuration you created in the Setup step:

  • org.eclipselabs.restlet.examples.app
  • org.eclipse.equinox.common
  • org.eclipse.equinox.ds
  • org.eclipse.equinox.util
  • org.eclipselabs.restlet
  • org.eclipselabs.restlet.servlet
  • org.restlet
  • org.restlet.ext.servlet

Run the application and point your browser to http://localhost:8080/hello.  You should see “Hello RESTful World”.

Run Configurations 2

One of the neat features of Restlet is that you can specify more than one representation in a resource.  Let’s add an HTML representation to our hello resource:

package org.eclipselabs.restlet.examples.app;

import org.restlet.resource.Get;
import org.restlet.resource.ServerResource;

public class HelloResource extends ServerResource
{
  @Get("txt")
  public String sayHello()
  {
    return "Hello RESTful World";
  }

  @Get("html")
  public String getDocument()
  {
    StringBuilder html = new StringBuilder();
    html.append("<html>\n");
    html.append("  <body>\n");
    html.append("    <h2>Hello RESTful World</h2>\n");
    html.append("   </body>\n");
    html.append("</html>\n");
    return html.toString();
  }
}

Now, when you reload http://localhost:8080/hello in your browser, you should see “Hello RESTful World” in a Heading 2 style.  The complete solution for this example application can be downloaded from the Restlet Extensions for OSGi Environments downloads page.

Applications

Your OSGi web application will consist of one or more Restlet Application instances.  An application is created by declaring an OSGi service component of type ApplicationProvider which provides the service IApplicationProvider, and has an “alias” property that specifies the root path of the application.  The alias of each Restlet application in your OSGi application must be unique, start with “/” and not end with “/” with the exception of “/” itself.  It should not be necessary to extend ApplicationProvider, but you must declare the service in your own bundle.  The ApplicationProvider has a dependency on the IRouterProvider service.  This dependency should be declared as static with a cardinality of 1..1 and bind functions (un)bindRouterProvider().

Suppose you wanted to create more than one Application.  Each Application needs its own instance of a Router.  How does OSGi declarative services know which IRouterProvider to bind to which ApplicationProvider?  When you declare the dependency from ApplicationProvider to IRouterProvider, there is a target parameter you can set to specify the exact IRouterProvider to bind against.  Here is an example of declaring two applications each binding to a unique router using the component.name property given to the service instance.

<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" immediate="true" name="org.eclipselabs.restlet.examples.app1">
   <implementation class="org.eclipselabs.restlet.ApplicationProvider"/>
   <service>
      <provide interface="org.eclipselabs.restlet.IApplicationProvider"/>
   </service>
   <property name="alias" type="String" value="/app1"/>
   <reference bind="bindRouterProvider" cardinality="1..1" interface="org.eclipselabs.restlet.IRouterProvider" name="IRouterProvider" policy="static" target="(component.name=org.eclipselabs.restlet.examples.app.router1)" unbind="unbindRouterProvider"/>
</scr:component>
<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" immediate="true" name="org.eclipselabs.restlet.examples.app2">
   <implementation class="org.eclipselabs.restlet.ApplicationProvider"/>
   <service>
      <provide interface="org.eclipselabs.restlet.IApplicationProvider"/>
   </service>
   <property name="alias" type="String" value="/app2"/>
   <reference bind="bindRouterProvider" cardinality="1..1" interface="org.eclipselabs.restlet.IRouterProvider" name="IRouterProvider" policy="static" target="(component.name=org.eclipselabs.restlet.examples.app.router2)" unbind="unbindRouterProvider"/>
</scr:component>

Routers

Every Restlet Application instance needs at least one Router instance.  Technically speaking, this isn’t entirely true, but for all practical purposes, you are going to want a Router.  A router is created by declaring an OSGi service component of type RouterProvider which provides the service IRouterProvider.  The RouterProvider has a dependency on IResourceProvider and IRouterProvider services.  The dependency on IResourceProvider should be declared as dynamic with a cardinality of 1..n and bind functions (un)bindResourceProvider().  This allows more than one resource to bind to a router and allows the resources to come and go without taking down the application.  The dependency on IRouterProvider is optional and if declared should be dynamic with a cardinality of 0..1 and bind functions (un)bindDefaultRouterProvider().  The default router is asked to handle the URI routing when none of the resources attached to the router can handle the URI.  The default router will make more sense when I discuss filters below.

When an application contains multiple routers, a target filter must be applied to the IResourceProvider services so that the resources are bound to the correct router.  Since there can be many resources attached to a router, and each resource has a unique component.name, it’s not practical to use the component.name as a filter.  I recommend giving each resource a property with a common value that is unique to a router.  For example, if a resource has the property: type = public, then the router provider can bind to resources with the target (type = public).  For the case of multiple applications, you may want to create a property that identifies the application such as: app = app1.  The binding target is an LDAP filter, so you can combine both the app and type properties: (&(app = app1)(type = public)).  Here is an example of declaring two routers for two different applications:

<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" immediate="true" name="org.eclipselabs.restlet.examples.app.router1">
   <implementation class="org.eclipselabs.restlet.RouterProvider"/>
   <service>
      <provide interface="org.eclipselabs.restlet.IRouterProvider"/>
   </service>
   <reference bind="bindResourceProvider" cardinality="1..n" interface="org.eclipselabs.restlet.IResourceProvider" name="IResourceProvider" policy="dynamic" target="(app=app1)" unbind="unbindResourceProvider"/>
</scr:component>
<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" immediate="true" name="org.eclipselabs.restlet.examples.app.router2">
   <implementation class="org.eclipselabs.restlet.RouterProvider"/>
   <service>
      <provide interface="org.eclipselabs.restlet.IRouterProvider"/>
   </service>
   <reference bind="bindResourceProvider" cardinality="1..n" interface="org.eclipselabs.restlet.IResourceProvider" name="IResourceProvider" policy="dynamic" target="(app=app2)" unbind="unbindResourceProvider"/>
</scr:component>

Resources

Resources are where you define exactly how an external client interacts with your application by responding to HTTP GET, PUT, POST, and DELETE requests.  You must create two classes for every logical resource your application provides: the resource class itself extending ServerResource from the Restlet framework, and a resource provider extending ResourceProvider from the Restlet Extension for OSGi Environments framework.  A resource is created by declaring an OSGi service component of the type you extended from ResourceProvider which provides the service IResourceProvider.  The ResourceProvider does not require dependencies on any other services, but does require a property named paths which is a string array of paths relative to the application alias.  The resource is registered with the router for each path declared in the paths property.  Note that the PDE component definition editor does not support array properties, so you will have to switch to the Source tab to create the paths property.  It is necessary to extend ResourceProvider to provide the classloading “glue” between Restlet and OSGi.  Your resource provider should override Finder createFinder(Context context) and return an instance of a new Finder passing in the Context and the class of your resource.

Here is an example of two resources that respond to http://localhost:8080/hello and http://localhost:8080/example:

package org.eclipselabs.restlet.examples.app;

import org.restlet.resource.Get;
import org.restlet.resource.ServerResource;

public class HelloResource extends ServerResource
{
  @Get("txt")
  public String sayHello()
  {
    return "Hello RESTful World";
  }
}
import org.eclipselabs.restlet.ResourceProvider;
import org.restlet.Context;
import org.restlet.resource.Finder;

public class HelloResourceProvider extends ResourceProvider
{
  @Override
  protected Finder createFinder(Context context)
  {
    return new Finder(context, HelloResource.class);
  }
}
<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" immediate="true" name="org.eclipselabs.restlet.examples.app.hello">
   <implementation class="org.eclipselabs.restlet.examples.app.HelloResourceProvider"/>
   <service>
      <provide interface="org.eclipselabs.restlet.IResourceProvider"/>
   </service>
   <property name="paths" type="String">
     /hello
   </property>
</scr:component>
package org.eclipselabs.restlet.examples.resource;

import org.restlet.resource.Get;
import org.restlet.resource.ServerResource;

public class ExampleResource extends ServerResource
{
  @Get
  @Override
  public String toString()
  {
    return "Example";
  }
}
package org.eclipselabs.restlet.examples.resource;

import org.eclipselabs.restlet.ResourceProvider;
import org.restlet.Context;
import org.restlet.resource.Finder;

public class ExampleResourceProvider extends ResourceProvider
{
  @Override
  protected Finder createFinder(Context context)
  {
    return new Finder(context, ExampleResource.class);
  }
}
<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" immediate="true" name="org.eclipselabs.restlet.examples.resource">
   <implementation class="org.eclipselabs.restlet.examples.resource.ExampleResourceProvider"/>
   <service>
      <provide interface="org.eclipselabs.restlet.IResourceProvider"/>
   </service>
   <property name="paths" type="String">
   	/example
   </property>
</scr:component>

Filters

Filters, just as the name implies, provide a mechanism for filtering a request as it is routed to the resource.  The typical use-case for a filter is to protect resources from unauthorized access.  Filters are created similar to resources by extending both Filter and FilterProvider.  A filter is created by declaring an OSGi service component of the type you extended from FilterProvider which provides the service IFilterProvider.   The FilterProvider does not require dependencies on any other services.  Your filter provider should override Filter createFilter(Context context) and return an instance of a new Filter passing in the Context.

Filters can be wired to routers, resources, and other filters.  The wiring is done by placing a service dependency on IFilterProvider in the component being filtered.  Notice that RouterProvider, ResourceProvider and FilterProvider all extend from RestletProvider which has a bindFilterProvider() function.  When declaring filters, you will probably want to use the component.name property as a target.  Here is an example of an authentication and authorization filter:

package org.eclipselabs.restlet.examples.security;

import org.restlet.Context;
import org.restlet.Request;
import org.restlet.Response;
import org.restlet.data.Cookie;
import org.restlet.security.Authenticator;
import org.restlet.security.User;

public class SessionAuthenticator extends Authenticator
{
  public SessionAuthenticator(Context context)
  {
    super(context, false, new SessionEnroller());
  }

  @Override
  public boolean authenticate(Request request, Response response)
  {
    Cookie sessionCookie = request.getCookies().getFirst("session");
    Account account = AccountManager.getInstance().getAccount(sessionCookie.getSecond());

    if(account != null)
    {
      User user = new User(account.getCredential().getId(), account.getID());
      request.getClientInfo().setUser(user);
      return true;
    }

    return false;
  }
}
package org.eclipselabs.restlet.examples.security.providers;

import org.eclipselabs.restlet.components.FilterProvider;
import org.restlet.Context;
import org.restlet.routing.Filter;

import org.eclipselabs.restlet.examples.security.SessionAuthenticator;

public class SessionAuthenticationFilterProvider extends FilterProvider
{
  @Override
  protected Filter createFilter(Context context)
  {
    return new SessionAuthenticator(context);
  }
}
<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" immediate="true" name="org.eclipselabs.restlet.examples.authentication">
   <implementation class="org.eclipselabs.restlet.examples.security.SessionAuthenticationFilterProvider"/>
   <service>
      <provide interface="org.eclipselabs.restlet.providers.IFilterProvider"/>
   </service>
</scr:component>
package org.eclipselabs.restlet.examples.security;

import org.restlet.Request;
import org.restlet.Response;
import org.restlet.security.Authorizer;
import org.restlet.security.Role;

public class SessionAuthorizer extends Authorizer
{
  @Override
  protected boolean authorize(Request request, Response response)
  {
    String accountID = request.getOriginalRef().getSegments().get(2);
    return accountID != null && accountID.equals(new String(request.getClientInfo().getUser().getSecret()));
  }
}
package org.eclipselabs.restlet.examples.security.providers;

import org.eclipselabs.restlet.components.FilterProvider;
import org.restlet.Context;
import org.restlet.routing.Filter;

import org.eclipselabs.restlet.examples.security.SessionAuthorizer;

public class SessionAuthorizerFilterProvider extends FilterProvider
{
  @Override
  protected Filter createFilter(Context context)
  {
    return new SessionAuthorizer();
  }
}
<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="org.eclipselabs.restlet.examples.authorization">
   <implementation class="org.eclipselabs.restlet.examples.security.providers.SessionAuthorizerFilterProvider"/>
   <reference bind="bindFilterProvider" cardinality="1..1" interface="org.eclipselabs.restlet.providers.IFilterProvider" name="IFilterProvider" policy="static" target="(component.name=org.eclipselabs.restlet.examples.authentication)" unbind="unbindFilterProvider"/>
   <service>
      <provide interface="org.eclipselabs.restlet.providers.IFilterProvider"/>
   </service>
</scr:component>

Service Dependency Injection

The Restlet Extensions for OSGi Environments framework provides support for dependency injection into your resources.  If your resource extends InjectedServerResource and your resource provider creates an instance of InjectedFinder, you may then use @Inject in your resource to obtain references to other services such as the OSGi LogService.  Here is an example of creating a resource that uses dependency injection with the OSGi LogService.

package org.eclipselabs.restlet.examples.resources;

import javax.inject.Inject;

import org.eclipselabs.restlet.di.eclipse.InjectedServerResource;
import org.osgi.service.log.LogService;

public class MyServerResource extends InjectedServerResource
{
  protected void log(int level, String message)
  {
    log(level, message, null);
  }

  protected void log(int level, String message, Throwable exception)
  {
    LogService logService = this.logService;

    if (logService != null)
      logService.log(level, message, exception);
  }

  @Inject
  private LogService logService;
}

References

  1. Restlet – RESTful web framework
  2. Restlet Extension for OSGi Environments – Restlet integration with OSGi
  3. Restlet in Action – Book on Restlet
  4. OSGi as a Web Application Server – Blog post on setting up OSGi as a web application server

Update Sept 28, 2011: Changed the project name to Restlet Extension for OSGi Environments and updated link to GitHub.

MongoEMF 0.3.2 Released

I have released MongoEMF 0.3.2.  This build adds support for storing OSGi log entries to MongoDB, and includes bug fixes for queries against dates and defaults values.

OSGi Logging in MongoDB

I’ve added a new bundle, org.eclispelabe.mongo.emf.log, that will convert an OSGi LogEntry into an EMF object and store it into MongoDB.  Storing your OSGi log entries into MongoDB is a simple matter of configuring the ILogService (declarative service) with the OSGI ConfigurationAdmin service.  I have created a LogServiceConfigurator helper class if you’d rather not deal with ConfigurationAdmin.  The log service requires two properties:

  • baseURI
  • logLevel

The baseURI must be a valid MongoEMF collection URI of the form mongo://host/database/collection/ – for example: mongo://localhost/data/logs/.  The logLevel is set to one of the logging levels defined in the OSGi LogService: LOG_ERROR, LOG_WARNING, LOG_INFO, and LOG_DEBUG.

Here is an example configuration using the LogServiceConfigurator for logging errors and warnings:

 
LogServiceConfigurator.configureLogService(URI.createURI("mongo://localhost/junit/logs/"), LogService.LOG_WARNING);

Querying Default Values

The standard EMF serializations: XML, XMI, and Binary do not store default values for attributes.  The Mongo EMF binding was written this way as well to maintain consistency, but has the side effect of not being able to query objects based on attributes set to their default value.  To solve this problem, we’ve added the option:

MongoDBURIHandlerImpl.OPTION_SERIALIZE_DEFAULT_ATTRIBUTE_VALUES

Setting this option to Boolean.TRUE when saving your object to MongoDB will force attributes with default values to be persisted to MongoDB.  Here is a simple example:

Resource resource = resourceSet.createResource(uri);
resource.getContents().add(object);
HashMap<String, Object> options = new HashMap<String, Object>(1);
options.put(MongoDBURIHandlerImpl.OPTION_SERIALIZE_DEFAULT_ATTRIBUTE_VALUES, Boolean.TRUE);

try
{
  resource.save(options);
}
catch(IOException w)
{
  e.printStackTrace();
}