Monday, July 21, 2014

Creating a Java @WebService using @Interceptors

This post will explain how to set up a maven webservice which uses an interceptor class. To do this just create a maven project using maven-archetype-webapp as archetype - e.g., per command line:

mvn archetype:create -DgroupId=package.name -DartifactId=project_name -Dpackage=package.name.project_name -Dversion=1.0-SNAPSHOT -DarchetypeArtifactId=maven-archetype-webapp

As I am using glassfish v 3.1.1 as application server and java 1.6 following pom file is used:
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.sjd.simple</groupId>
    <artifactId>SoapService</artifactId>
    <packaging>war</packaging>
    <version>1.0.0</version>

    <licenses>
        <license>
            <name>Apache License, Version 2.0</name>
            <distribution>repo</distribution>
            <url>http://www.apache.org/licenses/LICENSE-2.0.html</url>
        </license>
    </licenses>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <jaxws.plugin.version>2.1</jaxws.plugin.version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>org.glassfish.extras</groupId>
            <artifactId>glassfish-embedded-all</artifactId>
            <version>3.2-b06</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>javax</groupId>
            <artifactId>javaee-api</artifactId>
            <version>6.0</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.10</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <!-- Set the name of the war, used as the context root when the app is 
            deployed -->
        <finalName>SoapService</finalName>

        <plugins>
            <plugin>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.1.1</version>
                <configuration>
                    <!-- Java EE 6 doesn't require web.xml, Maven needs to catch up! -->
                    <failOnMissingWebXml>false</failOnMissingWebXml>
                </configuration>
            </plugin>

            <!-- Compiler plugin enforces Java 1.6 compatibility and activates annotation 
                processors -->
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.3.1</version>
                <configuration>
                    <source>1.6</source>
                    <target>1.6</target>
                </configuration>
            </plugin>

        </plugins>
    </build>

</project> 
Using annotations, the actual implementation of the WebService is very straight forward. Just add an @WebService annotation to your class. If you want to implement an interceptor you just have to use the annotations @Interceptor and specify the class which should be used. Also we will have to annotate our class as java bean.
@Stateless marks this bean as a Stateless Session Bean, and @WebService causes the application server to make all public methods of this bean accessible as web service calls.
Here the interceptor is used for every method insiede our WebService class (You may also use this annotation for individual methods).
package com.sjd.simple;

import javax.ejb.Stateless;
import javax.interceptor.Interceptors;
import javax.jws.WebMethod;
import javax.jws.WebService;

@Stateless
@WebService
@Interceptors( { AuthenticationInterceptor.class } )
public class HelloWorld implements IHelloWorld {

  public HelloWorld() {
    // nothing to do
  }

  @Override
  @WebMethod
  public String sayHello(String bla) {
     return "Hello !";
  }
}

For the interceptor you will have to write a normal POJO class, but add the annotation @AroundInvoke to a method. This annotation may be applied to any non-final, non-static method with a single parameter of type InvocationContext and return type Object of the target class/superclass or of any interceptor class. The annotated method will be called before each method that uses this class as interceptor.
package com.sjd.simple;

import javax.interceptor.AroundInvoke;
import javax.interceptor.InvocationContext;

public class AuthenticationInterceptor {

  @AroundInvoke
  public Object invoke(final InvocationContext ctx) throws Exception {
    if (ctx != null) {
      System.out.println("test");
      return ctx.proceed();
    } else {
      return null;
    }
  }

}


As you can see, implementing a @WebService using an interceptor is fairly easy - but be careful since the interceptor will only work if following requirements are met:

javax.interceptor.Interceptors may be bound to a simple Web Bean, enterprise Web Bean or EJB 3 style session, singleton or message driven bean using the javax.interceptor.Interceptors annotation, or by using a Web Beans interceptor binding. - docs.jBoss

In this case we are using beans as @WebServices, it seems that the URL used to access it changes from:
http://localhost:8080/<application_name>/<class_name>Service?wsdl to
http://localhost:8080/<class_name>Service/<class_name>?wsdl
example:
http://localhost:8080/SoapService/HelloWorldService?wsdl    [without @Stateless]
http://localhost:8080/HelloWorldService/HelloWorld?wsdl       [with @Stateless]
I only figured that one out because of this report: @WebService and @Stateless not showing endpoint in GlassFish 4.0 admin console

Of course you may change this default URL by the serviceName and name attribute of the @WebService annotation: e.g., @WebService(serviceName="soap", name="testservice"), which would result in following URL to access our webservice: 
http://localhost:8080/soap/testservice?wsdl 
 
I hope I could provide some help on how to implement a webservice, while using interceptors. Also here is another link to a nice much more detailed tutorial on WebServices in general.



No comments:

Post a Comment