вівторок, 3 вересня 2013 р.

RESTful web-services in OSGi container: meet Karaf and CXF

Hi all! Today we going to talk about OSGi, namely Apache Felix implementation, and creating JAX-RS web-services using Apache CXF implementation. I am not a fan of heavyweight solutions, but learning these technologies is a job necessity, so I decided to write this small tut just to save my sandbox experiments.

Note: you can find this tut sources on GitHub

[Tools]


For this tut you will need the following tools installed
  • Java SDK of version 1.6
  • Apache Maven
  • Apache Karaf

[Installing Karaf]


Download and unpack Apache Karaf distribution. Run Karaf console by invoking {KARAF_DIR}/bin/karaf (or {KARAF_DIR}\bin\karaf.bat for Windows). Issue the following command:
karaf@root> features:install webconsole
This command will install Karaf web-console, which is a convinient web-interface for managing karaf server. You can visit http://localhost:8181/system/console/bundles to access it (default creds are karaf/karaf). Now issue the two following commands:
        karaf@root> features:chooseurl cxf-dosgi 1.4.0
        karaf@root> features:install cxf-dosgi-discovery-distributed
    
These commands will install CXF feature (all necessary CXF bundles will be installed). Now, if you didn't get any errors during execution of the commands above, then your Karaf is ready for the tut.

[Exploring Maven Pax Plugin]


OSGI development tools are scarce at the present moment and IDEs lack adequate integration. Too bad. Well, at least we have several pretty decent Maven plugins, which can be a lot of help, namely: Pax Plugin, Bundle Plugin and Karaf Plugin. In this tutorial we will use Pax plugin to create our project structure and to create our test bundle.

Lets start by issuing the following command:
        mvn org.ops4j:maven-pax-plugin:create-project \
        -DgroupId=ogsicxf \
        -DartifactId=osgicxf \
        -Dversion=1.0-SNAPSHOT
    
For those, who have used Maven before, it should be self explanatory: this command uses pax plugin from maven repo to create an OSGi project with group ID "osgicxf" and artifact ID "osgicxf" of version 1.0-SNAPSHOT.

OK, now let's cd into directory of our newly created OSGi project where root pom.xml file is situated and issue the following command
        mvn pax:create-bundle \
        -Dpackage=osgicxf \
        -DbundleName=osgicxf-bundle \
        -Dversion=1.0-SNAPSHOT
    
This command will create OSGi bundle with BundleActivator and sample OSGi service.

[Writing RESTful web-service]


Let's now write a sample "Hello World" web-service using JAX-RS spec. First, let's add mentioned spec as maven dependency in our bundle's pom.xml:
        
            javax.ws.rs
            javax.ws.rs-api
            2.0-m10
        
    
This will add a jar file containing JAX-RS annotations to our classpath. Now we can write our service interface:
        @WebService
        @Produces(MediaType.TEXT_PLAIN)
        public interface IHelloWorldService {
            @GET
            @Path("/")
            String sayHello();
        }
    
The implementation of this interface will be brain-dead simple:
        public class HelloWorldService implements IHelloWorldService {

            public HelloWorldService() {
                System.out.println(HelloWorldService.class.getName()+" is up and running");
            }

            @Override
            public String sayHello() {
                return "Hello World from "+HelloWorldService.class.getSimpleName();
            }

        }
    

[Bringing to life]


One of the convinient ways to bring our service to life (read, instantiate it, connect it to CXF servlet which in turn will be mapped in Karaf's Jetty server) is to create blueprint XML context file, which will be parsed by Apache Aries services in Karaf. Now, blueprint -- is an OSGi alliance spec, that describes dependecy injection framework in OSGi container and Apache Aries is a blueprint implementation. The good thing is that blueprint xml config can contain JAX-RS and CXF specific namespaces, which will greatly simplify configuring web services. This is how our blueprint.xml will look like:
        

            
                
                    
                
            

            
                
                    
                
            

            

        
    
That's pretty much it.

[Deploying into Karaf]


Deployment now should be extremely easy: just issue mvn clean install on bundle's pom.xml and copy jar file to {KARAF_DIR}/deploy. You can now navigate to Karaf web-console and see you bundle installed.
Now head to http://localhost:8181/cxf/hello to call the only method of our web service.

So this concludes our simple tut. Hope you will put this information to good use.

середа, 7 серпня 2013 р.

Lightweight Java web-app skeleton: meet Jetty, Jersey, Guice and Gradle

[Introduction]


This tutorial is about creating extremely lightweight web application using a list of technologies, described below. Application uses embedded Jetty web server and servlet container, which does not need to be downloaded separately - it's downloaded from maven repo. The application can be easily run with main method of a Main java class or simply by invoking "gradle run".

Jetty [link] - a lightweight java servlet container. Easily embedded, has a number of artifacts in central maven repository, can be started directly from main method of a Java class.

Jersey [link] - a JAX-RS (Java API for RESTful web-services) implementation. It has neat annotation-based configuration that is somewhat similar to Spring MVC controllers configuration.

Guice [link] - a lightweight dependency-injection framework created by guys from Google. Configuration is done in pure Java without any XML.

Gradle [link] - a modern build automation tool. Can do everything that Maven does and way more. Uses Groovy as a build scripting language (instead of XML, used in maven pom files).

Apart from those big and imposing guys described above, I will use some of not-so-big-and-imposing-but-really-important dudes, but more on that later.

[Code]


Code for this tutorial is hosted on Github and can be accessed here [link].

I strongly recommend to check any questioned files straight by this link, as I want to keep this tutorial as simple as possible and don't want to quote every single file.

[Tools]


You will need JDK or version 5 or above installed, of course.

You will need gradle installed ( [link] ).

You can easily follow the steps described further with any IDE of your choice (or even without one), but I recommend using Intellij IDEA (CE will do) or Eclipse with Gradle plug-in to simplify the process.

You will also need Git installed if you wish to clone project sources from Github.

[Build script]


Let's start by creating the standard maven-like directory structure with our java sources situated in ${projectFolder}/src/main/java. Putting java sources in this folder is a convention for gradle projects and you obligated to specify your sources path in your build file if you decide not to follow this convention.

The first file we will create is our gradle build file ${projectFolder}/buid.gradle. The full build gradle can be viewed from GitHub build.gradle. The first lines of the build file are:

apply plugin: 'java'
apply plugin: 'application'

mainClassName = "graguijer.Main"

Their meaning is simple: we are using java plugin to compile our java sources and application plugin to add a set of specific tasks to our gradle build script specific for standalone java application. We are telling gradle, that our main application class is graguijer.Main, so when we try to invoke "gradle run" from command line, the main method of this class will be executed.

repositories {
    mavenCentral()
}

test {
    useTestNG()
}

The first closure from the snippet above is instructing gradle to use central maven repo to download dependencies from. The second closure is telling gradle that we will use TestNG for our unit tests instead of JUnit (there will be no unit tests actually, but this part of gradle configuration is provided for reference purposes).

The rest of our build script is a list of dependencies, used in our project. Dependencies are separated into groups using line breaks. The main groups are, respectively:
  • language utilities
  • logging utilities
  • jetty artifacts
  • guice artifacts
  • jersey artifacts
  • freemarker dependency for view processing
  • testing artifacts

[Starting jetty web server]


As it was said earlier, you do not need to deploy this application to an external web-server. Gradle downloads jetty artifacts and our Main class runs Jetty server programmatically from its main method:
public static void main(String[] args) throws Exception {

        WebAppContext webAppContext = new WebAppContext("web", "/");
        webAppContext.setResourceBase("web");

        Server server = new Server(8080);
        server.setHandler(webAppContext);
        server.start();
        server.join();

}
Here we create a new Jetty server using "web" folder as our resource root. Then we starting Jetty and joining its thread with our main thread. Simple as that.

[Guicy stuff]


Ok, now we have a web application with managed dependencies, which can be easily started. Let's extend our application skeleton by adding dependency injection mechanics to it. All dependency injections will be done by Guice IoC. In order to use Guice in a web application, you need to add the following to your web.xml:

    <listener>
        <listener-class>graguijer.GuiceServletConfigListener</listener-class>
    </listener>

    <filter>
        <filter-name>guiceFilter</filter-name>
        <filter-class>com.google.inject.servlet.GuiceFilter</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>guiceFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

Here we declare GuiceServletConfigListener, which is a ServletContexListener. It configures our Injector using ServletModule, so all request that pass though guiceFilter are managed by Guice. Let's take a look inside GuiceServletConfigListener:
public class GuiceServletConfigListener extends GuiceServletContextListener {
   @Override
    protected Injector getInjector() {
        return Guice.createInjector(new ServletModule() {
            @Override
            protected void configureServlets() {
                bind(FreemarkerProvider.class);
                bind(MainController.class);
                serveRegex("/(js|css)/.*")
                .with(StaticContentForwardingServlet.class);
                serve("/*").with(GuiceContainer.class);
            }
        });
    }
}

We explicitly binding FreemarkerProvider and MainController inside our listener. They are not injected anywhere, but Guice expects them to be bound to process our views and serve our URL. All our static content forwarded to default container servlet using StaticContentForwardingServlet. Also, as you can see, all our non-static content processed by GuiceContainer, which is Jersey container managed by Guice. The cool thing about this container is that uses guice bound beans with @Path annotations to serve URLs specified using Jersey. That's why our MainController must be bound. Let's take a look inside MainController:
@Path("/")
@Singleton
public class MainController {
    @GET
    @Produces(MediaType.TEXT_HTML)
    public Viewable index() {
        Map<String, Object> model = Maps.newHashMap();
        model.put("string1", "Hello");
        model.put("string2", "World");
        return new Viewable("index", model);
    }
}
As  you can see, our Jersey bean serves the root web app path and returns index view with model, containing two strings. Guice expects a ViewProvider to be bound to process views. Luckily, we have FreemarkerProvider (describing its implementation is beyond of the scope of this tutorial - I will leave it to the reader), which will process our ftl templates, namely index.ftl:
<html>
    <head>
        <title>GraGuiJer</title>
        <link rel="stylesheet" href="/css/style.css">
    </head>
    <body>
        <div id="helloworld">${string1} ${string2}</div>
    </body>
</html>
If you will run this example using main method of the main class and go to http://127.0.0.1:8080/ you will see "Hello World" string in dark red. It means that our web app serves both static (by loading css) and dynamic (by processing our view) content.

Hope you will put this information to good use.