Sunday, July 23, 2017

Reactor: Reactive Programming Java 8

One of the more interesting features in the upcoming release of Java 9 is the support for Reactive Programming in Java. At a high-level Reactive programming deals with asynchronous data streams. Reactive streams provides a standard for asynchronous stream processing. Java 9 supports Reactive programming implementing the Reactive Streams specification through the Flow API. But before the release of Java 9, there are ways to implement Reactive programming in Java 8. Reactor and RxJava are a couple of APIs to implement Reactive streams in Java 8. Reactor is used internally by the Spring Framework to it's own Reactive support in version 5. In this post, we will look into Reactor library.

Monday, July 10, 2017

Mybatis Spring Integration

This post will give a quick introduction into integrating MyBatis and Spring with a very basic application. I will describe only the integration using XML based configuration. As always with MyBatis, this starts with setting up SqlSessionFactory from Spring. Instead of configuring the datasource and mapping in mybatis-config.xml, all configuration will be setup in Spring configuration. The only additional configuration will be the Mapper.xml file.

Sunday, July 09, 2017

Spring Standalone Application Setup with Gradle

This post is a continuation of the Spring Standalone Application post. In this post I will go over the application setup and the Gradle build file used for building the project. The assumption here is that Gradle is already installed on the machine and ready to use. For instructions on how to install Gradle please go the Gradle installation page.

Continue to full post ...

Application Setup

Following is the directory structure I had for this project. In case of the Annotation based approach, you don't need the resources folder.

+---SpringStandalone
    |   build.gradle
    |               
    \---src
        +---main
        |   \---java
        |       +---main
        |       |       SpringStandaloneTest.java
        |       |       
        |       \---service
        |               TestService.java
        |   \---resources
        |           applicationContext.xml
        |               
        \---test
            \---java

Gradle Build File: Gradle Application Plugin

The Gradle Application plugin is very useful for creating Standalone applications that can be run using gradle run. By default, the Gradle Application plugin applies the java plugin and Distribution plugin. You can configure the main class and any JVM arguments that you may want to pass to the application. To pass the main class name, you can use the mainClassName parameter like below

mainClassName = "main.SpringStandaloneTest"
And to pass any JVM arguments to the application, you can use applicationDefaultJvmArgs as shown below
applicationDefaultJvmArgs = ["-Dprop=val"]
And here is the full build.gradle file I used for the spring standalone application
apply plugin:'application'
mainClassName = "main.SpringStandaloneTest"
applicationName = 'SpringStandalone'

repositories {
    jcenter()
}

dependencies {
  compile group: 'org.springframework', name: 'spring-core', version: '4.3.9.RELEASE'
 compile group: 'org.springframework', name: 'spring-context', version: '4.3.9.RELEASE'
 compile group: 'org.springframework', name: 'spring-beans', version: '4.3.9.RELEASE'
 compile group: 'org.springframework', name: 'spring-tx', version: '4.3.9.RELEASE'
 compile group: 'org.springframework', name: 'spring-orm', version: '4.3.9.RELEASE'

    // Use JUnit test framework
    compile 'junit:junit:4.12'
}


applicationDefaultJvmArgs = ["-Dprop=val"]

Standalone Spring Application

Having a basic spring standalone application ready always helps when you want to do a quick POC or test of new libraries or tools you plan to use. This post shows a couple of ways in which you can setup a basic Spring standalone application.

  • Spring Standalone application with ApplicationContext XML Configuration file.
  • Spring Standalone application with Annotations

Continue to full post...

For this application I will use a simple service class TestService that has a single method echo(), which returns the Upper case version of any string passed as a parameter. The TestService class will be used a component to be injected into the main application class.

Spring Standalone application with ApplicationContext XML Configuration file

In this model we have 4 files

  1. SpringStandaloneTest.java
  2. TestService.java
  3. applicationContext.xml
  4. build.gradle (will go over the gradle build in the next post)
Following are the files used for this application

SpringStandaloneTest.java
package main;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import service.TestService;

public class SpringStandaloneTest {

 public static void main(String[] args) {
  ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
  SpringStandaloneTest test = ctx.getBean("springStandalone", SpringStandaloneTest.class);
  test.callService();

 }

 private TestService testService = null;

 private void callService() {
  System.out.println(testService.echo("Hello"));

 }

 public TestService getTestService() {
  return testService;
 }

 public void setTestService(TestService testService) {
  this.testService = testService;
 }

}
TestService.java
package service;

public class TestService {
 
 public String echo(String str) {
  return str.toUpperCase();
 }

}
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

 <bean name="testService" class="service.TestService" />
 <bean name="springStandalone" class="main.SpringStandaloneTest">
  <property name="testService" ref="testService"></property>
 </bean>

</beans>

Spring Standalone application with Annotations

In this model, we will setup the standalone application with annotations instead of the applicationContext.xml file. The annotation @Component is used to define a class as a Spring component, so that Spring can detect it as a Spring bean. The @ComponentScan is used to direct Spring where to look for Components. It is similar to the directive when using Spring XML configuration. The following is the code used to implement the Standalone Spring application using annotations.

SpringStandaloneTest.java
package main;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;

import service.TestService;

@ComponentScan(basePackages= {"main", "service"})
public class SpringStandaloneTest {

 public static void main(String[] args) {
  ApplicationContext context = new AnnotationConfigApplicationContext(SpringStandaloneTest.class);

  SpringStandaloneTest test = context.getBean(SpringStandaloneTest.class);
  test.callService();
  
 }

 @Autowired
 private TestService service = null;

 private void callService() {
  System.out.println(service .echo("Hello"));

  
 }

}
TestService.java
package service;

import org.springframework.stereotype.Component;

@Component
public class TestService {
 
 public String echo(String str) {
  return str.toUpperCase();
 }

}
In the next post I will describe the Gradle build setup used for this standalone application.

Saturday, July 08, 2017

AsynchronousFileChannel

Java 7 AsynchronousFileChannel is an asynchronous channel for reading and writing to files asynchronously. In this post, we will look into a few operations on AsynchronousFileChannel.

  • Read from a file using Future
  • Read from File using CompletionHandler
  • Write to File using Future
  • Write to file using CompletionHandler
One thing common to all the operations will be the position within the file. Since we are working asynchronously, there is no current position, and the position where you want to read or write has to be sent with each call.

Continue to full post...

An AsynchronousFileChannel can be created using the open method. This static method takes the Path and the type of operations (READ, WRITE etc.) as paramters

Reading Data with Future

Following is the read() method that returns a Future.

Future operation = fileChannel.read(buffer, 0);
The data from the file is read into the ByteBuffer parameter starting at the beginning of the file. Since this is an asynchronous call, the read() method will return immediately, even if the read is not completed. To check if the read wheter the read operation completed, you can call the isDone() on the returned Future object.
In the following program, we try to read from a file and wait till the read is complete. Although this is not an ideal use case, it will demonstrate how to use the "Read with Future" feature.
package nio;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousFileChannel;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

public class AsyncFileChannelTest {
    public static void main(String[] args) {
        Path path = Paths.get("C:/test/data.csv");
        AsynchronousFileChannel fileChannel = null;
        try {
            fileChannel = AsynchronousFileChannel.open(path, StandardOpenOption.READ);
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            long position = 0;

            StringBuffer fileData = new StringBuffer();

            Future operation = fileChannel.read(buffer, position);
            // Future returns -1 if End of File is reached.
            while (operation.get() > 0) {
                while (!operation.isDone())
                    ;
                // Switch ByteBuffer from read to write mode
                buffer.flip();

                byte[] data = new byte[buffer.limit()];
                buffer.get(data);

                fileData.append(new String(data));

                buffer.clear();
                // Update to new read position.
                position = position + operation.get();
                operation = fileChannel.read(buffer, position);
            }
            System.out.println(fileData);
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

}


Reading with CompletionHandler

This version of the read() operation takes a CompletionHandler as a parameter.

package nio;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousFileChannel;
import java.nio.channels.CompletionHandler;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;

public class AsyncFileChannelTest {
    public static class MyCompletionHandler 
            implements CompletionHandler {
        @Override
        public void failed(Throwable exc, ByteBuffer attachment) {
            // TODO Auto-generated method stub

        }

        @Override
        public void completed(Integer result, ByteBuffer buffer) {
            System.out.println("result = " + result);
            bytesRead = result.intValue();
            if (bytesRead < 0)
                return;
            // Switch ByteBuffer from read to write mode
            buffer.flip();

            byte[] data = new byte[buffer.limit()];
            buffer.get(data);

            fileData.append(new String(data));

            buffer.clear();
            position = position + bytesRead;
            fileChannel.read(buffer, position, buffer, this);

        }

    }

    private static int bytesRead = 0;
    private static StringBuffer fileData = new StringBuffer();
    private static long position = 0;
    private static AsynchronousFileChannel fileChannel = null;

    public static void main(String[] args) {
        Path path = Paths.get("C:/test/data.csv");

        try {
            fileChannel = AsynchronousFileChannel.open(path, StandardOpenOption.READ);
            ByteBuffer buffer = ByteBuffer.allocate(1024);

            MyCompletionHandler myCompletionHandler = new MyCompletionHandler();
            fileChannel.read(buffer, position, buffer, myCompletionHandler);
            // read() returns -1 if End of File is reached.
            while (bytesRead > 0) {

                // Update to new read position.
                position = position + bytesRead;
                fileChannel.read(buffer, position, buffer, myCompletionHandler);
            }

            // Main thread waits till the asynchronous operations are complete
            try {
                Thread.currentThread().sleep(10000);
            } catch (InterruptedException e) {

                e.printStackTrace();
            }
            System.out.println(fileData);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

}
Once the read is finished the completed() method of CompletionHandler is called with the number of Bytes read as a paramter. The second parameter can be any object, and in our case, I passed the same ByteBuffer object as a parameter to help read the entire file. The failed() method is called if the read operation fails.

Writing Data using Future

Writing to a file with Future follows the same model as read. The differnces are that you open the channel in "WRITE" mode instead of "READ" and call the write() method. When the write is done, the number bytes written to the file will be set in the Future. As with read() we wait till the read is complete by calling isDone() method.

package nio;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousFileChannel;
import java.nio.channels.CompletionHandler;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

public class AsyncFileChannelTest {

    public static void main(String[] args) {
        Path path = Paths.get("C:/test/data.csv");
        AsynchronousFileChannel fileChannel = null;

        try {
            fileChannel = AsynchronousFileChannel.open(path, StandardOpenOption.WRITE);
            ByteBuffer buffer = ByteBuffer.allocate(100);

            buffer.put("Hello World".getBytes());
            buffer.flip();

            Future operation = fileChannel.write(buffer, 0);
            buffer.clear();

            while(!operation.isDone());

            System.out.println("Number of Bytes Written : " + operation.get());

            
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

       
    }

}

Writing with CompletionHandler

Writing to a file with CompletionHandler follows the same model as a read. The differnces are that you open the channel in "WRITE" mode instead of "READ" and call the write() method.

package nio;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousFileChannel;
import java.nio.channels.CompletionHandler;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;

public class AsyncFileChannelTest {
    public static class MyCompletionHandler implements CompletionHandler {

        @Override
        public void completed(Integer result, ByteBuffer attachment) {
            System.out.println("Number of bytes written : " + result);

        }

        @Override
        public void failed(Throwable exc, ByteBuffer attachment) {
            // TODO Auto-generated method stub

        }

    }

    public static void main(String[] args) {
        Path path = Paths.get("C:/test/data.csv");
        AsynchronousFileChannel fileChannel = null;

        try {
            fileChannel = AsynchronousFileChannel.open(path, StandardOpenOption.WRITE);
            ByteBuffer buffer = ByteBuffer.allocate(100);

            MyCompletionHandler myCompletionHandler = new MyCompletionHandler();

            buffer.put("Hello World".getBytes());
            buffer.flip();
            fileChannel.write(buffer, 0, buffer, myCompletionHandler);
        } catch (IOException e) {
            e.printStackTrace();
        }

        // Main thread waits till the asynchronous operations are complete
        try {
            Thread.currentThread().sleep(10000);
        } catch (InterruptedException e) {

            e.printStackTrace();
        }

    }

}

Tuesday, July 03, 2012

Integrate Jersey and Spring

This post describes a way to integrate spring with Jersey resource classes. It expands on the earlier sample Restful Web Services With Jersey API. The code here has been implemented on following configuration
  • Tomcat 7
  • Java 7
  • Spring 3.1.1
  • Jersey 1.12
To show the use of Spring, I added MyService class which will be injected into RestWS class. For this example, we start out with the sample code in Restful Web Services With Jersey API and make the following changes...
  1. Web.xml: In the Web Deployment Descriptor, the Jersey Servlet has to be modified to use com.sun.jersey.spi.spring.container.servlet.SpringServlet instead of com.sun.jersey.spi.container.servlet.ServletContainer
    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
        id="WebApp_ID" version="3.0">
        <display-name>JerseyRest</display-name>
        <welcome-file-list>
            <welcome-file>index.html</welcome-file>
        </welcome-file-list>
        <context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/applicationContext.xml</param-value>
        </context-param>
        <listener>
            <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
        </listener>
    
        <servlet>
            <servlet-name>Jersey Web Application</servlet-name>
            <servlet-class>com.sun.jersey.spi.spring.container.servlet.SpringServlet</servlet-class>
            <init-param>
                <param-name>com.sun.jersey.config.property.packages</param-name>
                <param-value>com.blogspot.aoj.restws</param-value>
            </init-param>
    
            <load-on-startup>1</load-on-startup>
        </servlet>
        <servlet-mapping>
            <servlet-name>Jersey Web Application</servlet-name>
            <url-pattern>/rest/*</url-pattern>
        </servlet-mapping>
    </web-app>
  2. RestWS: There is not much change in the RestWS.java file, other than adding the field MyService which will be injected by spring. The following sample code shows @Autowire, which works with @Component annotation for spring to inject dependencies. However, you can implement the same example without Autowiring by simply creating a bean in spring context file.
    /**
     * @author Abhi Vuyyuru
     */
    
    package com.blogspot.aoj.restws;
    
    import javax.ws.rs.GET;
    import javax.ws.rs.Path;
    import javax.ws.rs.PathParam;
    import javax.ws.rs.Produces;
    import javax.ws.rs.core.MediaType;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    import com.blogspot.aoj.service.MyService;
    
    @Path("/restws")
    @Component
    public class RestWS {
        
        @Autowired
        private MyService myService;
    
        @GET
        @Path("concat/i/{i}/j/{j}")
        @Produces(MediaType.TEXT_HTML)
        public String concat(@PathParam("i") String i, @PathParam("j") String j) {
            return myService.concat(i, j);
        }
    
        public MyService getMyService() {
            return myService;
        }
    
        public void setMyService(MyService myService) {
            this.myService = myService;
        }
    
    }
  3. /WEB-INF/applicationContext.xml: The following code shows code for Autowire and otherwise. Simply comment the unused version
    <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"     xmlns:context="http://www.springframework.org/schema/context"     xsi:schemaLocation="             http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd             http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">         <bean id="myService" class="com.blogspot.aoj.service.MyService" />     <bean id="restWS" class="com.blogspot.aoj.restws.RestWS">         <property name="myService" ref="myService"></property>     </bean>     <!-- <context:component-scan base-package="com.blogspot.aoj.restws" /> --> </beans>
  4. Client will be the same as used in the previous code sample Restful Web Services With Jersey API
  5. The Jersey Spring Servlet is part of the jersey-spring.jar file which can be downloaded from the Jersey download site
  6. Finally, the following is the ant build file that I used.
    <project name="jerseyRest" default="compile" basedir=".">
        <property file="build.properties" />
        <property file="${user.home}/build.properties" />
        <property name="app.name" value="jerseyRest" />
        <property name="app.path" value="/${app.name}" />
        <property name="app.version" value="0.1-dev" />
        <property name="build.home" value="${basedir}/build" />
        <property name="catalina.home" value="c:/tomcat7" />
        <property name="dist.home" value="${basedir}/dist" />
        <property name="docs.home" value="${basedir}/docs" />
        <property name="manager.url" value="http://localhost:8080/manager/text" />
        <property name="manager.username" value="tomcat" />
        <property name="manager.password" value="tomcat" />
        <property name="src.home" value="${basedir}/src" />
        <property name="web.home" value="${basedir}/WebContent" />
        <path id="compile.classpath">
            <fileset dir="${catalina.home}/bin">
                <include name="*.jar" />
            </fileset>
            <pathelement location="${catalina.home}/lib" />
            <fileset dir="${catalina.home}/lib">
                <include name="*.jar" />
            </fileset>
            <fileset dir="${web.home}/WEB-INF/lib">
                <include name="*.jar" />
            </fileset>
    
        </path>
        <taskdef resource="org/apache/catalina/ant/catalina.tasks" classpathref="compile.classpath" />
        <taskdef name="deploy" classname="org.apache.catalina.ant.DeployTask" classpathref="compile.classpath" />
        <taskdef name="list" classname="org.apache.catalina.ant.ListTask" classpathref="compile.classpath" />
        <taskdef name="reload" classname="org.apache.catalina.ant.ReloadTask" classpathref="compile.classpath" />
        <taskdef name="findleaks" classname="org.apache.catalina.ant.FindLeaksTask" classpathref="compile.classpath" />
        <taskdef name="resources" classname="org.apache.catalina.ant.ResourcesTask" classpathref="compile.classpath" />
        <taskdef name="start" classname="org.apache.catalina.ant.StartTask" classpathref="compile.classpath" />
        <taskdef name="stop" classname="org.apache.catalina.ant.StopTask" classpathref="compile.classpath" />
        <taskdef name="undeploy" classname="org.apache.catalina.ant.UndeployTask" classpathref="compile.classpath" />
    
        <property name="compile.debug" value="true" />
        <property name="compile.deprecation" value="false" />
        <property name="compile.optimize" value="true" />
    
    
        <target name="all" depends="clean,compile" description="Clean build and dist directories, then compile" />
    
        <target name="clean" description="Delete old build and dist directories">
            <delete dir="${build.home}" />
            <delete dir="${dist.home}" />
        </target>
    
    
        <target name="compile" depends="prepare" description="Compile Java sources">
            <mkdir dir="${build.home}/WEB-INF/classes" />
            <javac srcdir="${src.home}" destdir="${build.home}/WEB-INF/classes" debug="${compile.debug}" deprecation="${compile.deprecation}" optimize="${compile.optimize}">
                <classpath refid="compile.classpath" />
            </javac>
            <copy todir="${build.home}/WEB-INF/classes">
                <fileset dir="${src.home}" excludes="**/*.java" />
            </copy>
        </target>
    
        <target name="dist" depends="compile,javadoc" description="Create binary distribution">
            <mkdir dir="${dist.home}/docs" />
            <copy todir="${dist.home}/docs">
                <fileset dir="${docs.home}" />
            </copy>
            <jar jarfile="${dist.home}/${app.name}-${app.version}.war" basedir="${build.home}" />
        </target>
    
    
        <target name="install" depends="compile" description="Install application to servlet container">
            <deploy url="${manager.url}" username="${manager.username}" password="${manager.password}" path="${app.path}" localWar="file://${build.home}" />
        </target>
    
    
        <target name="javadoc" depends="compile" description="Create Javadoc API documentation">
            <mkdir dir="${dist.home}/docs/api" />
            <javadoc sourcepath="${src.home}" destdir="${dist.home}/docs/api" packagenames="*">
                <classpath refid="compile.classpath" />
            </javadoc>
        </target>
    
    
    
        <target name="list" description="List installed applications on servlet container">
            <list url="${manager.url}" username="${manager.username}" password="${manager.password}" />
        </target>
    
    
        <target name="prepare">
            <mkdir dir="${build.home}" />
            <mkdir dir="${build.home}/WEB-INF" />
            <mkdir dir="${build.home}/WEB-INF/classes" />
            <copy todir="${build.home}">
                <fileset dir="${web.home}" />
            </copy>
            <mkdir dir="${build.home}/WEB-INF/lib" />
        </target>
    
        <target name="reload" depends="compile" description="Reload application on servlet container">
            <reload url="${manager.url}" username="${manager.username}" password="${manager.password}" path="${app.path}" />
        </target>
        <target name="remove" description="Remove application on servlet container">
            <undeploy url="${manager.url}" username="${manager.username}" password="${manager.password}" path="${app.path}" />
        </target>
    </project>

Monday, March 28, 2011

Resful Web Services With Jersey API

This post describes how to use Jersey API to create RESTful Web Services. To keep it simple, I'm not going describe how REST works or should be implemented. Rather, it is simple example on how to use the API to implement some of the more common features of a REST service. The post describes how to
  • Create a RESTful Web Service using Jersey
  • Create GET, POST, PUT and DELETE handlers in the service
  • Create a Jersey Client to invoke the various methods on the Service
The example here has been tested on Tomcat7, with Java SE 6. The following steps explain how to use the API
More ...............
  1. Download Jersey from http://jersey.java.net/
  2. Create a Dynamic Web Project(JerseyRest) in Eclipse
  3. Add the Jersey Jar files to the classpath. The following files were used:http://www.blogger.com/img/blank.gif
    Server:
    • asm-3.1.jar
    • jersey-core-1.4.jar
    • jersey-server-1.4.jar
    Client:
    • jersey-client-1.4.jar
    • jersey-core-1.4.jar
  4. Add the Jersey Servlet to Web.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
    <display-name>JerseyRest</display-name>
    <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
    </welcome-file-list>

    <servlet>
    <servlet-name>Jersey Web Application</servlet-name>
    <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
    <init-param>
    <param-name>com.sun.jersey.config.property.packages</param-name>
    <param-value>com.blogspot.aoj.restws</param-value>
    </init-param>

    <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
    <servlet-name>Jersey Web Application</servlet-name>
    <url-pattern>/*</url-pattern>
    </servlet-mapping>
    </web-app>
    Note:
    • The Jersey Servlet maps to all requests under /rest
    • The package where your service class resides is provided in the package-name init param.
    Create the Service Class
    /**
    * @author Abhi Vuyyuru
    */

    package com.blogspot.aoj.restws;

    import javax.ws.rs.Consumes;
    import javax.ws.rs.DELETE;
    import javax.ws.rs.FormParam;
    import javax.ws.rs.GET;
    import javax.ws.rs.POST;
    import javax.ws.rs.PUT;
    import javax.ws.rs.Path;
    import javax.ws.rs.PathParam;
    import javax.ws.rs.Produces;
    import javax.ws.rs.core.MediaType;

    @Path("/restws")
    public class RestWS {
    @GET
    @Produces("text/plain")
    @Path("hello")
    public String sayHello() {
    return "Hello World";
    }

    @GET
    @Path("concat/i/{i}/j/{j}")
    @Produces("text/plain")
    public String concat(@PathParam("i") String i, @PathParam("j") String j) {
    System.out.println("GET Input : " + i + j);
    return (i + j);
    }

    @POST
    @Path("posts")
    @Produces(MediaType.TEXT_HTML)
    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
    public String consumeReq(@FormParam("i") String i, @FormParam("j") String j) {
    System.out.println("POST Input : " + i + j);
    return i + j;
    }

    @PUT
    @Path("puts")
    @Produces(MediaType.TEXT_HTML)
    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
    public void putReq(@FormParam("i") String i, @FormParam("j") String j) {
    System.out.println("PUT Input : " + i + j);
    return;
    }

    @DELETE
    @Path("dels/i/{i}/j/{j}")
    public void deleteReq(@PathParam("i") String i, @PathParam("j") String j) {
    System.out.println("DELETE Input : " + i + j);
    return;
    }

    }
  5. Create the Client
    /**
    * @author Abhi Vuyyuru
    */
    package com.blogspot.aoj.clients;

    import java.io.IOException;

    import javax.ws.rs.core.MultivaluedMap;

    import com.sun.jersey.api.client.Client;
    import com.sun.jersey.api.client.WebResource;
    import com.sun.jersey.core.util.MultivaluedMapImpl;

    public class RestWSClient {

    public static void main(String[] args) throws IOException {
    Client client = Client.create();
    WebResource wsClient = client.resource("http://localhost:8080/JerseyRest/restws/");

    String helloResp = wsClient.path("hello").get(String.class);
    System.out.println(helloResp);

    MultivaluedMap queryParams = new MultivaluedMapImpl();
    queryParams.add("i", "val1");
    queryParams.add("j", "val2");
    String postResp = wsClient.path("posts").post(String.class, queryParams);
    System.out.println(postResp);

    String getResp = wsClient.path("concat").path("i/" + "val1").path("j/" + "val2").get(String.class);
    System.out.println(getResp);

    wsClient.path("puts").put(queryParams);

    wsClient.path("dels").path("i/" + "val1").path("j/" + "val2").delete();

    }
    }

Popular Posts