Tuesday, June 19, 2012

First Impression on Riak vs mongoDB vs Cassandra/HBase

As part of the building out the next generation technology platform, we would like to explore NoSQL solutions to compliment our existing platform, which is built on RDBMS, primarily Oracle.

I have used mongoDB, Cassandra and HBase in the past life and I am eager to learn what Riak could offer as an alternative NoSQL solution.

In the next few weeks, I will be publishing our findings, lessons learned along the way. In this post, I will give my first un-biased impression on Riak vs other NoSQL technologies.

First Impression on Riak

Riak is an open source, distributed database solution, written in Erlang and supported by Basho. From first glimpse, it offers the following nice features,
  • Objects are stored by buckets and keys
  • Really nice HTTP API (for developing/debugging purpose)
  • Horizontal and linear scalability
  • Masterless replication with tunable read/write consistency level
  • Consist Key Hashing and even load distribution
  • Automatically rebalancing when new nodes are introduced or removed
  • Support Linkage between objects, a nature way to build hierarchy object model
  • Complex query support including secondary index, free text search, and MapReduce support
  • Excellent client library support
  • Thousands of name branded customers
From the first glance, Riak is very much like Cassandra with automatic cluster management, nicer API, and much less complexity in terms of cluster management and learning curve (no more Thrift API).

On the other other hand, Riak is a strict name/value pair model and does not offer column family or super column family support, as supported in Cassandra/HBase. I guess we can simulate column family support by turning bucket into row key, and keys into column family columns.

Overall, Riak looks like a good candidate for our prototyping and I will share our experience in the next  few blogs.

Performance Tuning Hibernate Transaction Flush Mode

I have been using Hibernate on and off for the post ten years and here are some tips and tools that I have used to help me identify, tune, and improve Hibernate performance.

Tip 1 Use a good JDBC Profiler

My personal favorite is Elvyx, which is easy to install, configure, and use. While Hibernate SQL log is useful, it is not easy to read and it won't show the actual parameters sent to the database. Elvyx, on the other hand, has a UI that will show both unbound (similar to Hibernate) and bound SQL, which shows the actual parameters in the SQL. Elvyx UI also allows us to do the following,
  • Sort the queries
  • Total time eclipsed summary graph
  • Drill down to a single query and how execution status
  • Export data into Excel and other formats

A JDBC profiler should be used as part of the development, QA process to catch potential performance issues and in production to help trouble shoot live performance issues.

In Development and QA

In development, JDBC profiler should be used to profile every Web Services call or every single page-turn for web applications, to identify the following potential performance issues,
  • Hibernate is generating the correct SQL (from HQL)
  • Hibernate is loading just right amount of data (use lazy loading whenever possible)
  • Hibernate is generating the correct amount of SQL calls. An abnormal amount of SQL calls per web service call or per web page turn indicates poor design and potential performance issue
  • Look for SQL that is taking long time to execute. Examine the explain plan and make sure the plan makes sense. If the generated sql does not meet requirement, consider rewriting the query or using native SQL or a function or a stored procedure for better performance

In Production

Since Elvyx is not intrusive and does not recompiling application or any other type of special treatment, it is ideal to trouble shoot live production performance issue. Simple deploy, configure, restart, and start troubleshooting.

Tip 2 Understand Transaction Flush Mode

Most people don't understand Hibernate Transaction Flush Mode and what is the most appropriate Flush mode to use. Wrong Transaction Flush mode will lead to huge performance issues.

What is Transaction Flush Mode

Hibernate does not flush every add or update transaction to the database. Rather Hibernate collects them and waits for the right time to flush them all t the database. And the right time is defined by the Transaction Flush mode. There are four Flush mode,

  • Always, the session is flushed every query
  • Commit, the session is flushed when transaction is committed
  • Manuel, the session is flushed manually, i.e., Hibernate will NOT flush session to the database during query or commit time
  • Auto, default Flush mode and yet the most confusion one. The session is flushed before a query is executed or transaction is committed

Why we need transaction Flush mode?

Database transaction is expensive and does not perform well so Hibernate turns auto commit off. Hibernate defers database transaction until the end when all necessary database updates have been made.

For example, in a transaction, we can do the following,
  1. Begin transaction
  2. Create employee A
  3. Create employee B
  4. Associate A with its manager C
  5. Associate B with its manager D
  6. Commit transaction
Instead of 4 separate transactions, we only need a single transaction. Very efficient.

Now, if we change the follow a little,
  1. Begin transaction
  2. Create employee A
  3. Create employee B
  4. Associate A with its manager C
  5. Look up all employees reporting to C
  6. Associate B with its manager D
  7. Look up all employees reporting to D
  8. Commit transaction
If we don't' call transaction flush before step 5 and step 7, we will get incorrect results, because the query results won't include the newly created employee A and B. If we want to include newly created results in the query results before committing them to the database, we must flush the pending transactions (creation of employee A and B) to the database before they can be included in a later query.

Hibernate default Flush mode, AUTO, is designed to be overly cautious and does a database flush every time before executing a query. It is designed to protect novice user but it does come with a hefty performance penalty.

What is the Performance Penalty associated with Database Transaction Flushing

Hibernate does not keep track of which object has been modified in session object. In order to do a proper transaction flush, it must first determine which object has changed in the session by going through ALL the objects in the session and comparing the current object with what's in the database one object at a one. This process is extremely CPU intensive and only gets worse if one has a lot of objects loaded in the session, which is typical in a bulk load/update type of transactions.

Default Flush Mode introduces Performance Problem during Bulk Operations

We had a page that creates a new campaign based on an existing campaign template via a deep copying . A campaign object could contain possibly hundreds of other objects. A typical flow is like the following,

  • Begin Transaction
  • Retrieve the template campaign
  • Shallow copy and save the top level campaign objects
  • For each top level campaign object 
    • Retrieve next level campaign objects
    • Shallow copy and save the secondary level campaign objects
  • Iterate through all nested objects
  • Commit Transaction
A typical copy operation takes 30 minutes. This clearly indicates a performance issue. After further investigation, we traced the problem back to hefty performance cost introduced by database transaction flush.

For each select statement like retrieving the next level campaign objects, Hibernate does a database flush and as the number of objects loaded in the session increases, the time to determine the "dirty" objects increases dramatically. And there is absolute NO need to do database flush, since we are NOT making any changes to existing objects, only creating new ones.

The solution is to switch the default flush mode to COMMIT. This cuts the execution time from 30 minutes to 3 seconds.

So next time if an operation takes abnormal long time to execute and it is not being held up by the database itself, check Hibernate transaction flush mode carefully. Typically I use either MANUEL or COMMIT for any type of bulk operations or read-only operations.

Tip 3 Use Batch Operations

As we have shown before, Hibernate carries huge performance penalty if we execute one query at a time, because of the overhead related to database transaction management. However, we can reduce this cost dramatically if we can batch a set of operations together and carry them out in a single transaction or a single query.
We had a page displaying a grid, which can be sorted or filtered by a set of criteria. The original implementation performs poorly because it is implemented like the following,
  • Select a set of user ids based on the selection criteria
  • Get each user for each returned user id
A must better performant implementation is like,
  • Select a set of user ids based on selection criteria
  • For every 300 user id
    • Select users where user id in (the set of 300 users)
The second implementation is typically 10 to 20 times faster than the first one.

Friday, June 15, 2012

How to Update Facebook Status on user's behalf

In the previous blog entry, "how to tweet on user's behalf", we talked about how to tweet on user's behalf through Twitter application. In this blog, we will discuss similar function on Facebook, i.e., how to update status on user's behalf. And necessary steps are very similar,

  1. Create a Facebook campaign specific application
  2. Obtain an access token for a particular Facebook account. This process does require user to log into his/her Facebook account and explicitly grant permission to the Facebook app, which will post on user's behalf. Once the access token is retrieved, we can post on the user's behalf through the app. Unlike Twitter, the access token currently does expire in 60 days, upon which we must go through the same process of obtaining a new access token. Not very user friendly in our opinion.

Setting up a Facebook Application

Step1. Go to https://developers.facebook.com/
Step2. Fill in necessary information,
App ID/App Key and App Secret will be used in obtaining access token.

Obtaining Access Token

Obtain an access token for a particular Facebook account. This process does require user to log into his/her Facebook account and explicitly grant permission to the Facebook app, which will post on user's behalf. Once the access token is retrieved, we can post on the user's behalf through the app. Unlike Twitter, the access token currently does expire in 60 days, upon which we must go through the same process of obtaining a new access token. Not very user friendly in our opinion.

Here is the high level flow for obtaining a Facebook access token,

Here is the detailed sequence diagrams on obtaining access token,
Once an access token is granted, we can start updating user's status as the following,

HTTP POST "https://graph.facebook.com/" + facebookUser + "/feed?access_token=" + token + "&message=" + URLEncoder.encode(message, "utf-8");

How to Tweet on user's behalf

As part of multichannel campaign, we would like to tweet on customer's behalf. In order to accomplish that, we need the following,

  • Create a Twitter application, which will tweet on customer's behalf. The application should also contain the appropriate campaign information and URL
  • Obtain an access token for a particular Twitter handle or handles. This process does require user to log into his/her Twitter accounts and explicitly grant permission to the Twitter app, which will tweet on user's behalf. Once the access token is retrieved, we can tweet on the user's behalf through the app. The access token currently does not expire, except for in the situation where user changes his password or revokes the access permission explicitly
In the blog, we walk through the necessary steps on how to obtain an access token.

Setting up a Twitter Application

Step1: Log into https://dev.twitter.com/apps/new
Step2: Filling the necessary information for the App, including the appropriate information for the Campaign,
Consumer Key, Consumer secret, and Callback URL will be used in obtaining access token.

Obtaining Twitter Access Token

Obtaining Twitter access token does require user to log into his/her Twitter accounts and explicitly grant permission to the Twitter app, which will tweet on user's behalf. Once the access token is retrieved, we can tweet on the user's behalf through the app. The access token currently does not expire, except for in the situation where user changes his password or revokes the access permission explicitly.

Here is a high level interaction diagram on this process,

Here is the corresponding sequence diagram,

Once an access token and associated token secret are obtained, we can store them in a persistent storage
and tweet on behalf of the user.
Twitter native Web Services API is very hard to use and we highly recommend going with Twitter4j.

Wednesday, June 6, 2012

How to use Apache HttpClient 4 library securely connect to RESTful Web Service

In this blog, we will show to how to securely connect to RESTful web services, using Apache HttpClient 4 and HTTPS and basic authentication through username and password

Self-signed Certificate Support

Apache HttpClient 4 has changed quite a bit from version 3 and has much better self-signed certificate support. In order to support self-signed certificates, we need to create a new class that implements TrustStrategy called TrustSelfSignedStrategy and our TrustSelfSignedStrategy will trust any certificates and just return true. This class is just for illustration purpose and shouldn't be used in production.

   protected static class TrustSelfSignedStrategy implements TrustStrategy  
   {  
     @Override  
     public boolean isTrusted(X509Certificate[] arg0, String arg1) throws CertificateException  
     {  
       return true;  
     }  
   }  

The following code shows how to create a ClientConnectionManager object using the above TrustSelfSignedStrategy.
   protected ClientConnectionManager enableSelfSignedCerts() throws Exception  
   {  
     TrustStrategy trustStrategy = new TrustSelfSignedStrategy();  
     X509HostnameVerifier hostnameVerifier = new AllowAllHostnameVerifier();  
     SSLSocketFactory sslSf = new SSLSocketFactory(trustStrategy, hostnameVerifier);  
     Scheme https = new Scheme("https", 443, sslSf);  
     SchemeRegistry schemeRegistry = new SchemeRegistry();  
     schemeRegistry.register(https);  
     ClientConnectionManager connection = new PoolingClientConnectionManager(schemeRegistry);  
     return connection;  
   }  

Preemptive Basic Authentication with Username and Password

Next we will show how to use preemptive basic authentication using username and password. In web services world we must use preemptive basic authentication, since there is no web client to ask back to and prompt user for authentication credentials.

       String urlString = PING_IDENTITY_SERVER_URL + TOKEN_AUTH + URLEncoder.encode(TEST_TOKEN, "UTF-8");  
       URL url = new URL(urlString);  
       // support self-signed certificates  
       DefaultHttpClient httpClient = new DefaultHttpClient(enableSelfSignedCerts());  
       // add username/password for BASIC authentication  
       httpClient.getCredentialsProvider().setCredentials(new AuthScope(url.getHost(), url.getPort()),  
           new UsernamePasswordCredentials("user", "secret"));  
       // Create AuthCache instance  
       // Add AuthCache to the execution context  
       AuthCache authCache = new BasicAuthCache();  
       BasicScheme basicAuth = new BasicScheme();  
       authCache.put(new HttpHost(url.getHost(), url.getPort(), url.getProtocol()), basicAuth);  
       BasicHttpContext localcontext = new BasicHttpContext();  
       localcontext.setAttribute(ClientContext.AUTH_CACHE, authCache);  
       //  
       HttpGet getRequest = new HttpGet(urlString);  
       getRequest.setHeader("Content-Type", "application/json");  
       // call HTTP GET with authentication information  
       HttpResponse response = httpClient.execute(getRequest, localcontext);  
       if (response.getStatusLine().getStatusCode() != 200)  
       {  
         throw new RuntimeException("Failed : HTTP error code : " + response.getStatusLine().getStatusCode());  
       }  
       BufferedReader br = new BufferedReader(new InputStreamReader((response.getEntity().getContent()))); 

Troubleshooting Tips

If getting a 401 error, make sure that preemptive authentication is used and username and password is correct.

Saturday, June 2, 2012

Secure Jersey with OAuth2, Open Authentication Framework

Overview

Our platform must be secure. After some initial investigation, we decided to go with OAuth2, the next generation of OAuth protocol. The OAuth protocol enables websites or applications (Consumers) to access Protected Resources from a web service (Service Provider) via an API, without requiring Users to disclose their Service Provider credentials to the Consumers. More generally, OAuth creates a freely-implementable and generic methodology for API authentication.


Securing Jersey with OAuth2

We looked at implementing OAuth2 support as Tomcat security realm, servlet filter, or Tomcat valve. In the end, we decided to go with Tomcat valve for the following reasons,
  • Since we are implementing web services and not web applications, there is no standard way of caching Tomcat session between requests. This makes session based security realm irrelevant.
  • Servlet filer can do almost exactly the same thing as a Tomcat Valve, except for a servlet filter is deployed at web application level. This means we have to deploy this servlet for every web application we deploy. Not as convenient as a Tomcat valve
  • On the other hand, Tomcat valve is Tomcat specific. If we want a portable solution, we will have to stick with Servlet filter. Luckily we are sticking with Tomcat for now and there is very little effort if we need to switch to a Servlet filter based implementation

OAuth Tomcat Valve Class

Here is the example Valve class,
 package jersey.oauth;  
 import java.io.IOException;  
 import javax.servlet.ServletException;  
 import javax.servlet.http.HttpServletResponse;  
 import org.apache.catalina.connector.Request;  
 import org.apache.catalina.connector.Response;  
 import org.apache.catalina.valves.ValveBase;  
 import com.sun.security.auth.UserPrincipal;  
 public class OAuthValve extends ValveBase  
 {  
     protected String identityServerURL;  
     public String getIdentityServerURL() {  
         return identityServerURL;  
     }  
     public void setIdentityServerURL(String identityServerURL) {  
         this.identityServerURL = identityServerURL;  
     }  
     @Override  
     public void invoke(Request request, Response response) throws IOException,  
             ServletException {  
         if (request.getMethod().equals("OPTIONS"))  
             getNext().invoke(request, response);  
         else  
         {  
 //            response.sendError(HttpServletResponse.SC_FORBIDDEN);  
             String authentication = request.getHeader("authentication");  
             if (authentication == null)  
             {  
                 authentication = request.getParameter("access_token");  
             }  
             else  
             {  
                     String[] tokens = authentication.split(" ");  
                 if (tokens.length >= 2 && tokens[0].equalsIgnoreCase("Bearer"))  
                 {  
                     authentication = tokens[1];  
                 }  
                 else  
                 {  
                     authentication = null;  
                 }  
             }  
             if (authentication == null)  
                 response.sendError(HttpServletResponse.SC_UNAUTHORIZED);  
             else  
             {  
                 // TODO call identity server, passing on the access token
                 // Set return principal 
                 request.setUserPrincipal(new UserPrincipal("name"));  
                 getNext().invoke(request, response);  
             }  
         }  
     }  
 }  


Here is the sample Host block of Tomcat server.xml file,
 <Host appBase="webapps" autoDeploy="true" name="localhost" unpackWARs="true" xmlNamespaceAware="false" xmlValidation="false">  
     <!-- SingleSignOn valve, share authentication between web applications  
        Documentation at: /docs/config/valve.html -->  
     <!--  
     <Valve className="org.apache.catalina.authenticator.SingleSignOn" />  
     -->  
     <!-- Access log processes all example.  
        Documentation at: /docs/config/valve.html -->  
     <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" pattern="common" prefix="localhost_access_log." resolveHosts="false" suffix=".txt"/>  
         <Valve className="jersey.oauth.OAuthValve" identityServerURL="localhost"/>  
    <Context docBase="JerseyCors" path="/jersey" reloadable="true" source="org.eclipse.jst.jee.server:JerseyCors"/></Host>  
Deploy, start Tomcat and test.

Friday, June 1, 2012

Enable Cross Origin Resource Sharing for Jersey

Overview

In this blog, we will talk about how to enable and configure CORS support for Jersey, and more importantly, how to trouble shoot if CORS is not working properly.

As mentioned in the previous blog, we were disappointed to find out Apache CXF CORS support did not work and were pleasantly surprised on how easy CORS filter has been to setup and configure. We have tested CORS filter against Jersey, RESTeasy, and Apache CXF and it worked for every single one of them.

Enable CORS Support

CORS filter is implemented as a Servlet that must be enabled and configured at the web app's level, inside web.xml file.
Here is a sample web.xml file,
<?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_2_5.xsd" id="WebApp_ID" version="2.5">
  <servlet>
    <servlet-name>Jersey Root REST Service</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>jersey.cors</param-value>
    </init-param>
 <init-param>
  <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
  <param-value>true</param-value>
 </init-param>
 <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>Jersey Root REST Service</servlet-name>
    <url-pattern>/*</url-pattern>
  </servlet-mapping>
  <filter>
  <filter-name>CORS</filter-name>
  <filter-class>com.thetransactioncompany.cors.CORSFilter</filter-class>
  
  <!-- Note: All parameters are options, if ommitted CORS Filter
       will fall back to the respective default values.
    -->
  <init-param>
   <param-name>cors.allowGenericHttpRequests</param-name>
   <param-value>true</param-value>
  </init-param>
  
  <init-param>
   <param-name>cors.allowOrigin</param-name>
   <param-value>*</param-value>
  </init-param>
  
  <init-param>
   <param-name>cors.supportedMethods</param-name>
   <param-value>GET, HEAD, POST, OPTIONS, PUT, DELETE</param-value>
  </init-param>
  
  <init-param>
   <param-name>cors.supportedHeaders</param-name>
   <param-value>Content-Type, X-Requested-With, Accept, Authentication</param-value>
  </init-param>
  
  <init-param>
   <param-name>cors.exposedHeaders</param-name>
   <param-value>X-Test-1, X-Test-2</param-value>
  </init-param>
  
  <init-param>
   <param-name>cors.supportsCredentials</param-name>
   <param-value>true</param-value>
  </init-param>
  
  <init-param>
   <param-name>cors.maxAge</param-name>
   <param-value>3600</param-value>
  </init-param>

 </filter>

 <filter-mapping>
  <!-- CORS Filter mapping -->
  <filter-name>CORS</filter-name>
  <url-pattern>/*</url-pattern>
 </filter-mapping>
  
</web-app>

Configuring CORS Filter

The default configuration values are good for everything except for the following two fields, 
  • cors.supportedMethods
  • cors.supportedHeaders
These two fields must be checked if CORS filter is not working as one expected.

cors.supportedMethods specifies a list of supported methods and the default value is GET, HEAD, and POST only. We recommend listing all HTTP methods as supported methods.

cors.supportedHeaders lists the set of supported header fields. This set must be expanded if more headers are passed in unexpected.  We recommend listing as many headers as possible.

Testing and Troubleshooting

CORS support can be tested through javascript and here is an example,
<html> 
<head> 
<title>Cors Example</title> 
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script type="text/javascript" src="log4javascript.js"></script>
<script> 
var hello = JSON.stringify({"greeting":"Hello","name":"jersey"});
//alert(hello);
$(document).ready(function() {

 //alert('before ajax call');
 $.ajax({
  headers: {
   Authentication : 'Bearer access_token'
  },
  
  //this is the php file that processes the data and send mail
  //url: "http://localhost:8080/cxf-hello-cors/rest/annotatedGet/hello", 
  //url: "http://localhost:8080/cxf-hello-cors/service1/time", 
  // url: "http://localhost:8080/resteasy/tutorial/helloworld",
  url: "http://localhost:8080/jersey/hello",
  
  contentType: "application/json",

  //GET method is used
  type: 'DELETE',
  
  //pass the data         
  dataType: 'json',   
   
  //data: JSON.stringify(hello), 
  data: hello,
  
  //Do not cache the page
  cache: false,
   
  //success
  success: function (html) {  
   //alert(html); 
   document.getElementById("cors").innerHTML = "Echo: " + html.greeting + "," + html.name; 
           
  } ,
  error:function (data, status) {
   alert(data);
   alert(status);
     }      
 });
     
 });
</script>
</head> 
<body> 

<h1>This is the CORS test page</h1>

<p>Hello, <div id="cors"/>

</body> 
</html>

Troubleshooting CORS

We use a combination of Tomcat access log, Firefox Firebug, and Jersey client to troubleshoot CORS support.
CORS relies on header to relay cross origin  resource sharing information back to the browser and CORS-supported browser will enforce CORS based on these header fields. When CORS is not working as expected, the majority of the errors happen when Web Services do not pass back the appropriate headers due to permission related issues, like supported headers or supported methods. The best place to look for this type of information is in Tomcat's access log.
Here are some sample entries from the access log,

127.0.0.1 - - [31/May/2012:15:40:42 -0400] "GET /jersey/hello HTTP/1.1" 401 -
127.0.0.1 - name [31/May/2012:15:42:27 -0400] "GET /jersey/hello HTTP/1.1" 200 36
127.0.0.1 - - [31/May/2012:15:42:39 -0400] "GET /jersey/hello HTTP/1.1" 401 -
127.0.0.1 - - [31/May/2012:15:44:18 -0400] "GET /jersey/hello HTTP/1.1" 401 -
127.0.0.1 - - [31/May/2012:15:45:45 -0400] "GET /jersey/hello HTTP/1.1" 401 -
127.0.0.1 - - [31/May/2012:15:46:38 -0400] "GET / HTTP/1.1" 401 -
127.0.0.1 - - [31/May/2012:15:46:52 -0400] "GET /jersey/hello HTTP/1.1" 401 -
0:0:0:0:0:0:0:1%0 - - [31/May/2012:15:47:02 -0400] "OPTIONS /jersey/hello HTTP/1.1" 403 94
127.0.0.1 - - [31/May/2012:15:48:06 -0400] "GET / HTTP/1.1" 401 -
0:0:0:0:0:0:0:1%0 - - [31/May/2012:15:51:23 -0400] "OPTIONS /jersey/hello HTTP/1.1" 200 -
0:0:0:0:0:0:0:1%0 - name [31/May/2012:15:51:23 -0400] "DELETE /jersey/hello HTTP/1.1" 200 36
127.0.0.1 - name [31/May/2012:16:01:12 -0400] "GET /jersey/hello HTTP/1.1" 200 36 
Each entry represents an access from the client. The last three entries represent the following, request URI, HTTP status code, return content length. If CORS is not working as expected, check the following,
  • Make sure there is an entry in the access log that corresponds to the request
  • Make sure HTTP status code is correct. If HTTP status code is 403, check CORS filter's
    supported methods and supported headers to make sure that both settings are configured
    properly
If HTTP code is 200 but CORS is still not working, turn Firebug on and examine the request
pay special attention to response headers,
Debugging CORS response with Firebug


Make sure the set of Access-Control-* headers present in response.

Implement RESTful Web Services using Jersey

Jersey Overview

Jersey is the open source, production quality, JAX-RS (JSR 311) Reference Implementation for building RESTful Web services. Jersey is very lightweight and can be deployed in Web application containers like Tomcat, Jetty, Glassfish.

In this blog, we will provide a comprehensive tutorial on how to create a RESTful web services using Jersey, including,
  • Support for HTTP method, GET, PUT, POST, and DELETE
  • Support for various content types including TEXT, XML, and HTML
  • JSON support

Develop RESTful Web Services using Eclipse

We will demonstrate how to develop web services in Jersey using Eclipse. in the following steps,
  1. Create a new Dynamic Web Project in Eclipse
  2. Import Jersey related libraries
  3. Configure web.xml to support Jersey
  4. Create a Java class that implements Web Services
  5. Deploy web project in Tomcat
  6. Start Tomcat and test

Configure Tomcat to enable access log logging

We need to enable Tomcat to log accesses for easy debugging. Uncomment the following block in Tomcat's server.xml file,
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" pattern="common" prefix="localhost_access_log." resolveHosts="false" suffix=".txt"/>

Configure web.xml to support Jersey

Here is a sample web.xml file, which includes JSON support and auto scanning of Java package jersey.cors. Replace package name "jersey.cors" with one's own package.

<?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_2_5.xsd" id="WebApp_ID" version="2.5">
  <servlet>
    <servlet-name>Jersey Root REST Service</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>jersey.cors</param-value>
    </init-param>
 <init-param>
  <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
  <param-value>true</param-value>
 </init-param>
 <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>Jersey Root REST Service</servlet-name>
    <url-pattern>/*</url-pattern>
  </servlet-mapping>
</web-app>

Create a Java Class that Implements Web Services


package jersey.cors;

import javax.ws.rs.DELETE;
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;

// POJO, no interface no extends

// The class registers its methods for the HTTP GET request using the @GET annotation. 
// Using the @Produces annotation, it defines that it can deliver several MIME types,
// text, XML and HTML. 

// The browser requests per default the HTML MIME type.

//Sets the path to base URL + /hello
@Path("/hello")
public class HelloWorldRest {

 @GET
 @Path("/{param}/")
 public String getMsg(@PathParam("param") String msg) {
 
  String output = "Jersey say : " + msg;
 
  return output;
 
 }
 @GET
 @Path("/world")
 public String getFixedMsg(String msg) {
 
  String output = "Jersey say : fixed path" + msg;
 
  return output;
 
 }
 // This method is called if TEXT_PLAIN is request
 @GET
 //@Path("helloworld")
 @Produces(MediaType.TEXT_PLAIN)
 public String sayPlainTextHello() {
  System.out.println("sayPlain");
  return "Hello Jersey";
 }

 // This method is called if XML is request
 @GET
 //@Path("helloworld")
 @Produces(MediaType.TEXT_XML)
 public String sayXMLHello() {
  System.out.println("sayXML");
  return "" + " Hello Jersey" + "";
 }

 // This method is called if HTML is request
 @GET
 //@Path("helloworld")
 @Produces(MediaType.TEXT_HTML)
 public String sayHtmlHello() {
  System.out.println("sayHTML");
  return "<html> " + "<title>" + "Hello Jersey" + "</title>"
    + "<body><h1>" + "Hello Jersey" + "</body></h1>" + "</html> ";
 }
 
 // This method is called if JSON is request
 @GET
 //@Path("helloworld")
 @Produces(MediaType.APPLICATION_JSON)
 public Hello sayJsonHello() {
  return new Hello("Hello", "Jersey");
 }
        @PUT
 @Produces(MediaType.APPLICATION_JSON)
 public Hello updateHello(Hello hello)
 {
  System.out.println("put");
  return hello;
 }
 @POST
 @Produces(MediaType.APPLICATION_JSON)
 public Hello createHello(Hello hello)
 {
  System.out.println("post");
  return hello;
 }
 @DELETE
 @Produces(MediaType.APPLICATION_JSON)
 public Hello deleteHello(Hello hello)
 {
  System.out.println("post");
  return hello;
 } 
 @DELETE
 @Produces(MediaType.TEXT_PLAIN)
 public String deleteHello(String hello)
 {
  System.out.println("post");
  return hello;
 } 
}
Here is the Hello class, which serves as JSON transport object.
package jersey.cors;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class Hello {
 String greeting;
 String name;
 public Hello()
 {
  
 }
 public Hello(String greeting, String name)
 {
  this.greeting = greeting;
  this.name = name;
 }
 public String getGreeting() {
  return greeting;
 }
 public void setGreeting(String greeting) {
  this.greeting = greeting;
 }
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
 
} 

Testing Web Services

After web service project is deployed in Tomcat, we should be able to start Tomcat with no error.
Generally, Web Services can be tested in the following manner,
  • HTTP GET method can be tested directly through a browser
  • HTTP GET, PUT, DELETE, and POST can be tested through Java script
  • HTTP GET and POST can be tested through Jersey client. (Due the limitation in Java URLConnection class, it can be challenging to test HTTP PUT and DELETE using Jersey client). 

Javascript Example

 Here is an Javascript HTTP DELETE example, with JSON support,
<html> 
<head> 
<title>Cors Example</title> 
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script type="text/javascript" src="log4javascript.js"></script>
<script> 
var hello = JSON.stringify({"greeting":"Hello","name":"jersey"});
//alert(hello);
$(document).ready(function() {

 //alert('before ajax call');
 $.ajax({
  headers: {
   Authentication : 'Bearer access_token'
  },
  
  //this is the php file that processes the data and send mail
  //url: "http://localhost:8080/cxf-hello-cors/rest/annotatedGet/hello", 
  //url: "http://localhost:8080/cxf-hello-cors/service1/time", 
  // url: "http://localhost:8080/resteasy/tutorial/helloworld",
  url: "http://localhost:8080/jersey/hello",
  
  contentType: "application/json",

  //GET method is used
  type: 'DELETE',
  
  //pass the data         
  dataType: 'json',   
   
  //data: JSON.stringify(hello), 
  data: hello,
  
  //Do not cache the page
  cache: false,
   
  //success
  success: function (html) {  
   //alert(html); 
   document.getElementById("cors").innerHTML = "Echo: " + html.greeting + "," + html.name; 
           
  } ,
  error:function (data, status) {
   alert(data);
   alert(status);
     }      
 });
     
 });
</script>
</head> 
<body> 

<h1>This is the CORS test page</h1>

<p>Hello, <div id="cors"/>

</body> 
</html>

Jersey Client Example 

Here is a HTTP GET Jersey client example,
package jersey.cors.client;

import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
 
public class JerseyClient {
 
  public static void main(String[] args) {
 try {
 
  Client client = Client.create();
 
  WebResource webResource = client
     .resource("http://localhost:8080/jersey/hello");
  
  ClientResponse response = webResource.accept("application/json")
                   .get(ClientResponse.class);
 
  if (response.getStatus() != 200) {
     throw new RuntimeException("Failed : HTTP error code : "
   + response.getStatus());
  }
 
  String output = response.getEntity(String.class);
 
  System.out.println("Output from Server .... \n");
  System.out.println(output);
 
   } catch (Exception e) {
 
  e.printStackTrace();
 
   }
 
 }
}