Writing REST API Web Service application in Java EE 6 is now trivial with JAX-RS API and Jersey (the reference implementation of JAX-RS, bundled with GlassFish v3). I'll show you how, with raw real code. ;-)
Create a new Dynamic Web project in Eclipse. You'll need to choose a Java EE container runtime, it will download the libraries ("Java EE 6 SDK") as well.
Create a new JAX-RS resource class. What makes it a resource class is you sprinkle it with javax.ws.rs.Path annotation. I use JBoss Tools and GlassFish server plugin for Eclipse so either or both of them adds the Java EE libraries to my build path, including the most important here is jsr311-api.jar. If you use Maven you can depend on javax.ws.rs:jsr311-api:1.1.1 artifact.
A sample resource class is like below. Note that I split my resource class to interface and implementation class. package com.abispulsa.bisnis.service; import javax.ws.rs.FormParam;
import javax.ws.rs.POST;
import javax.ws.rs.Path; import org.eclipse.emf.ecore.EObject; /**
* <!-- begin-user-doc -->
* A representation of the model object '<em><b>Refiller</b></em>'.
* <!-- end-user-doc -->
*
* <!-- begin-model-doc -->
* Refill the target mobile number by some amount.
*
* This is the public facing REST API.
* <!-- end-model-doc -->
*
* <p>
* The following features are supported:
* <ul>
* <li>{@link com.abispulsa.bisnis.service.Refiller#getSession <em>Session</em>}</li>
* </ul>
* </p>
*
* @see com.abispulsa.bisnis.service.ServicePackage#getRefiller()
* @model
* @generated
*/
public interface Refiller extends EObject { /**
* <!-- begin-user-doc -->
* This actually only queues it. The real work is done in the queue processor job.
* <!-- end-user-doc -->
* @model
* @generated
*/
@Path("refill")
@POST
String refill(@FormParam("mobileNumber") String mobileNumber, @FormParam("voucherCode") String voucherCode); } // Refiller You may notice I'm using the mighty EMF to design the resource class. Yes, that's right! ;-)
(ok, so that's the excuse for me for posting this article to EclipseDriven, I'm hoping people will be curious "what's EMF? sounds cool!" hahahaha) Ok so here's the actual resource class : package com.abispulsa.bisnis.service.impl; import javax.ws.rs.Path; import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.InternalEObject;
import org.eclipse.emf.ecore.impl.ENotificationImpl;
import org.eclipse.emf.ecore.impl.EObjectImpl; import com.abispulsa.bisnis.service.Refiller;
import com.abispulsa.bisnis.service.ServicePackage;
import com.abispulsa.bisnis.service.Session; /**
* <!-- begin-user-doc -->
* An implementation of the model object '<em><b>Refiller</b></em>'.
* <!-- end-user-doc -->
* <p>
* The following features are implemented:
* <ul>
* <li>{@link com.abispulsa.bisnis.service.impl.RefillerImpl#getSession <em>Session</em>}</li>
* </ul>
* </p>
*
* @generated
*/
@Path("/")
public class RefillerImpl extends EObjectImpl implements Refiller { /**
* <!-- begin-user-doc -->
* Make it public constructor for used in JAX-RS.
* We should wrap it inside application and use CDI though.
* <!-- end-user-doc -->
* @generated NOT
*/
public RefillerImpl() {
super();
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated NOT
*/
public String refill(String mobileNumber, String voucherCode) {
return String.format("MobileNumber=%s voucherCode=%s", mobileNumber, voucherCode);
...
} private void checkAuthentication() {
// TODO Auto-generated method stub
} ... } //RefillerImpl There are several things to notice here:
The last thing is you need to configure the Jersey servlet in your web.xml : <?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<servlet>
<servlet-name>ServletAdaptor</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.abispulsa.bisnis.service.impl</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet> <servlet-mapping>
<servlet-name>ServletAdaptor</servlet-name>
<url-pattern>/api/v1/*</url-pattern>
</servlet-mapping> <session-config>
<session-timeout>30</session-timeout>
</session-config> </web-app> The web.xml above tells the Java EE 6 Container (i.e. GlassFish v3) to:
Deploying the app into GlassFish v3 outputs the following log: INFO: Scanning for root resource and provider classes in the packages:
com.abispulsa.bisnis.service.impl
INFO: Root resource classes found:
class com.abispulsa.bisnis.service.impl.RefillerImpl
INFO: No provider classes found. INFO: GlobalStatsProvider registered
INFO: Initiating Jersey application, version 'Jersey: 1.1.5 01/20/2010 04:04 PM'
INFO: Adding the following classes declared in META-INF/services/jersey-server-components to the resource configuration:
class com.sun.jersey.multipart.impl.FormDataMultiPartDispatchProvider
class com.sun.jersey.multipart.impl.MultiPartConfigProvider
class com.sun.jersey.multipart.impl.MultiPartReader
class com.sun.jersey.multipart.impl.MultiPartWriter INFO: Loading application com.abispulsa.bisnis.server.rest at /apbrest
INFO: Instantiated an instance of org.hibernate.validator.engine.resolver.JPATraversableResolver. INFO: com.abispulsa.bisnis.server.rest was successfully deployed in 8.179 milliseconds.
* Trying ::1... connected
* Connected to localhost (::1) port 8080 (#0)
> POST /apbrest/api/v1/refill HTTP/1.1
> User-Agent: curl/7.21.0 (i686-pc-linux-gnu) libcurl/7.21.0 OpenSSL/0.9.8o zlib/1.2.3.4 libidn/1.18
> Host: localhost:8080
> Accept: */*
> Content-Length: 36
> Content-Type: application/x-www-form-urlencoded
>
< HTTP/1.1 200 OK
< X-Powered-By: Servlet/3.0
< Server: GlassFish Server Open Source Edition 3.0.1
< Content-Type: text/plain
< Transfer-Encoding: chunked
< Date: Thu, 23 Dec 2010 09:34:31 GMT
<
* Connection #0 to host localhost left intact
* Closing connection #0
MobileNumber=08123456 voucherCode=A5 Alright! So I guess my application works! ;-) Pretty straightforward, huh?
As mentioned before, Jersey will create your resource classes. If you want to control instantiation of your classes, you can create class that implements javax.ws.rs.core.Application. After that you configure it in your web.xml like this: <web-app> <servlet> <servlet-name>Jersey Web Application</servlet-name> <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class> <init-param> <param-name>javax.ws.rs.Application</param-name> <param-value>MyApplication</param-value> </init-param> </servlet> ....
I haven't tried it yet, but I think one probable use case is if you want to use Dependency Injection (CDI) in your resource classes.......... ALTHOUGH GlassFish already does this for you (you can use JAX-RS and CDI at the same time), so you probably only use Application for this purpose if the container doesn't support integration between these specs.
Another, more valid use case and I guess more common if you want to be "pure Java EE 6" is to leave out web.xml altogether:
Requirements
- Eclipse IDE, pick the Java EE edition. Latest version is 3.6 SR1 (Helios)
- JBoss Tools plugin for Eclipse IDE (probably optional)
- A Java EE 6 Server like GlassFish v3 or JBoss AS 6 (not GA yet)
Create the Web (WAR) Project
Create a new Dynamic Web project in Eclipse. You'll need to choose a Java EE container runtime, it will download the libraries ("Java EE 6 SDK") as well.
Implement the Resource Class
Create a new JAX-RS resource class. What makes it a resource class is you sprinkle it with javax.ws.rs.Path annotation. I use JBoss Tools and GlassFish server plugin for Eclipse so either or both of them adds the Java EE libraries to my build path, including the most important here is jsr311-api.jar. If you use Maven you can depend on javax.ws.rs:jsr311-api:1.1.1 artifact.
A sample resource class is like below. Note that I split my resource class to interface and implementation class. package com.abispulsa.bisnis.service; import javax.ws.rs.FormParam;
import javax.ws.rs.POST;
import javax.ws.rs.Path; import org.eclipse.emf.ecore.EObject; /**
* <!-- begin-user-doc -->
* A representation of the model object '<em><b>Refiller</b></em>'.
* <!-- end-user-doc -->
*
* <!-- begin-model-doc -->
* Refill the target mobile number by some amount.
*
* This is the public facing REST API.
* <!-- end-model-doc -->
*
* <p>
* The following features are supported:
* <ul>
* <li>{@link com.abispulsa.bisnis.service.Refiller#getSession <em>Session</em>}</li>
* </ul>
* </p>
*
* @see com.abispulsa.bisnis.service.ServicePackage#getRefiller()
* @model
* @generated
*/
public interface Refiller extends EObject { /**
* <!-- begin-user-doc -->
* This actually only queues it. The real work is done in the queue processor job.
* <!-- end-user-doc -->
* @model
* @generated
*/
@Path("refill")
@POST
String refill(@FormParam("mobileNumber") String mobileNumber, @FormParam("voucherCode") String voucherCode); } // Refiller You may notice I'm using the mighty EMF to design the resource class. Yes, that's right! ;-)
(ok, so that's the excuse for me for posting this article to EclipseDriven, I'm hoping people will be curious "what's EMF? sounds cool!" hahahaha) Ok so here's the actual resource class : package com.abispulsa.bisnis.service.impl; import javax.ws.rs.Path; import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.InternalEObject;
import org.eclipse.emf.ecore.impl.ENotificationImpl;
import org.eclipse.emf.ecore.impl.EObjectImpl; import com.abispulsa.bisnis.service.Refiller;
import com.abispulsa.bisnis.service.ServicePackage;
import com.abispulsa.bisnis.service.Session; /**
* <!-- begin-user-doc -->
* An implementation of the model object '<em><b>Refiller</b></em>'.
* <!-- end-user-doc -->
* <p>
* The following features are implemented:
* <ul>
* <li>{@link com.abispulsa.bisnis.service.impl.RefillerImpl#getSession <em>Session</em>}</li>
* </ul>
* </p>
*
* @generated
*/
@Path("/")
public class RefillerImpl extends EObjectImpl implements Refiller { /**
* <!-- begin-user-doc -->
* Make it public constructor for used in JAX-RS.
* We should wrap it inside application and use CDI though.
* <!-- end-user-doc -->
* @generated NOT
*/
public RefillerImpl() {
super();
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated NOT
*/
public String refill(String mobileNumber, String voucherCode) {
return String.format("MobileNumber=%s voucherCode=%s", mobileNumber, voucherCode);
...
} private void checkAuthentication() {
// TODO Auto-generated method stub
} ... } //RefillerImpl There are several things to notice here:
- The implementation resource class is @Path annotated. Of course, since you can't instantiate an interface!
- It's possible to "split" JAX-RS annotations between interface, class, interface methods and class method. In my example, the interface defines the the REST API and specific structure of the service. However, the implementation can decide where to put the service itself using @Path. The implementation do not override any of the JAX-RS annotations (REST API structure) defined by the interface.
- A public constructor is needed (EMF generated default constructor is protected, there is a reason why), because Jersey will instantiate the resource class directly. It's possible to implement javax.ws.rs.Application so you can instantiate your resource classes yourself and configure Jersey for that. More on this later.
Configuring web.xml for Jersey
The last thing is you need to configure the Jersey servlet in your web.xml : <?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<servlet>
<servlet-name>ServletAdaptor</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.abispulsa.bisnis.service.impl</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet> <servlet-mapping>
<servlet-name>ServletAdaptor</servlet-name>
<url-pattern>/api/v1/*</url-pattern>
</servlet-mapping> <session-config>
<session-timeout>30</session-timeout>
</session-config> </web-app> The web.xml above tells the Java EE 6 Container (i.e. GlassFish v3) to:
- Create a Jersey servlet at URL path: /api/v1
- Load JAX-RS resource classes from my package:
Deploy the Web Project
Deploying the app into GlassFish v3 outputs the following log: INFO: Scanning for root resource and provider classes in the packages:
com.abispulsa.bisnis.service.impl
INFO: Root resource classes found:
class com.abispulsa.bisnis.service.impl.RefillerImpl
INFO: No provider classes found. INFO: GlobalStatsProvider registered
INFO: Initiating Jersey application, version 'Jersey: 1.1.5 01/20/2010 04:04 PM'
INFO: Adding the following classes declared in META-INF/services/jersey-server-components to the resource configuration:
class com.sun.jersey.multipart.impl.FormDataMultiPartDispatchProvider
class com.sun.jersey.multipart.impl.MultiPartConfigProvider
class com.sun.jersey.multipart.impl.MultiPartReader
class com.sun.jersey.multipart.impl.MultiPartWriter INFO: Loading application com.abispulsa.bisnis.server.rest at /apbrest
INFO: Instantiated an instance of org.hibernate.validator.engine.resolver.JPATraversableResolver. INFO: com.abispulsa.bisnis.server.rest was successfully deployed in 8.179 milliseconds.
Testing the JAX-RS REST API Server with curl
Ok so now l want to test it, using curl is my favorite (in Ubuntu/Debian you can just sudo apt-get install curl), but you can use any tool that understands HTTP requests. ceefour@annafi:~/project/AbisPulsa/workspace/com.abispulsa.bisnis.service$ curl -v --data-urlencode mobileNumber=08123456 --data-urlencode voucherCode=A5 'http://localhost:8080/apbrest/api/v1/refill' * About to connect() to localhost port 8080 (#0)* Trying ::1... connected
* Connected to localhost (::1) port 8080 (#0)
> POST /apbrest/api/v1/refill HTTP/1.1
> User-Agent: curl/7.21.0 (i686-pc-linux-gnu) libcurl/7.21.0 OpenSSL/0.9.8o zlib/1.2.3.4 libidn/1.18
> Host: localhost:8080
> Accept: */*
> Content-Length: 36
> Content-Type: application/x-www-form-urlencoded
>
< HTTP/1.1 200 OK
< X-Powered-By: Servlet/3.0
< Server: GlassFish Server Open Source Edition 3.0.1
< Content-Type: text/plain
< Transfer-Encoding: chunked
< Date: Thu, 23 Dec 2010 09:34:31 GMT
<
* Connection #0 to host localhost left intact
* Closing connection #0
MobileNumber=08123456 voucherCode=A5 Alright! So I guess my application works! ;-) Pretty straightforward, huh?
Using your Own javax.ws.rs.core.Application Implementation
As mentioned before, Jersey will create your resource classes. If you want to control instantiation of your classes, you can create class that implements javax.ws.rs.core.Application. After that you configure it in your web.xml like this: <web-app> <servlet> <servlet-name>Jersey Web Application</servlet-name> <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class> <init-param> <param-name>javax.ws.rs.Application</param-name> <param-value>MyApplication</param-value> </init-param> </servlet> ....
I haven't tried it yet, but I think one probable use case is if you want to use Dependency Injection (CDI) in your resource classes.......... ALTHOUGH GlassFish already does this for you (you can use JAX-RS and CDI at the same time), so you probably only use Application for this purpose if the container doesn't support integration between these specs.
Say Goodbye to web.xml
Another, more valid use case and I guess more common if you want to be "pure Java EE 6" is to leave out web.xml altogether:
JAX-RS 1.1 offers a @ApplicationPath annotation applicable to javax.ws.rs.core.Application which let you specify the webcontext and remove the need for any web.xml
References
- http://docs.sun.com/app/docs/doc/820-4867/ggnxs?a=view
- http://forums.java.net/node/700437
- http://download.oracle.com/javaee/6/api/javax/ws/rs/package-tree.html
- http://download.oracle.com/javaee/6/api/javax/ws/rs/core/Application.html
- http://www.kentlai.name/2009/03/digging-into-jersey-jax-rs.html
- http://jersey.576304.n2.nabble.com/web-xml-for-multiple-resource-classes-td3621400.html
- http://www.vogella.de/articles/REST/article.html
Nice to see EMF used in this example. Thanks for this post.
ReplyDeleteIts like you read my mind! You seem to know so much about this, like you wrote the book in it or something.
Delete@Lars Thank you Lars! Although it does feel like EMF is only a decorator here.
ReplyDeleteAt least it proves that EMF is not intrusive to application. And it's a very nice way to keep documentation for Java classes and JAX-RS services.
The satchel bag is not a new idea but it's been given a whole new style and class with this selection from My cambridge satchel us Bag! It's a great choice to have if you want to have a decent size bag that's easy to carry. They all have a simple carry handle on top as well as shoulder straps for wearing cambridge satchel across your body. If you need to a new handbag then this is what you should be getting this season. They're all beautifully designed and made from the finest quality materials. The designers have put a lot of thought into what women want from a bag and there are various pockets for different hermes handbags outlet things.
ReplyDeleteAt least this Buy RS Goldestablishes that will EMF is just not intrusive in order to program. And it's really an incredibly good method to preserve records Sell Rs Goldwith regard to Espresso courses as well as JAX-RS companies.
ReplyDeletethanks for your sharing
ReplyDeleteNonetheless, it absolutely was not right up windows 7 professional product key until Invoice Gates named Steve Ballmer CEO in 2000 that Microsoft's genuine push to woo firms to Home windows commenced, and it is been a love affair ever considering that.
ReplyDeleteIf you need to a new handbag then this is what you should be getting this season. They're all beautifully designed and made from the finest quality materials.
ReplyDeletexiaomi redmi note 2 review
meizu mx5 review
meizu review