Deploying Servlets on Smart Cards: Portable Web Servers with Java Card 3.0

By Bruce Hopkins, January 2010

No, that's not a typo. No, I'm not talking about technology that will be available 10 years from now. Java Card 3.0 technology is available today that allows application developers to create and deploy servlet applications on smart card devices. This article shows developers how to get started with developing servlets with the Java Card Connected Development Kit 3.0.2.

Background

In previous versions of the Java Card specification, Java developers were significantly limited in the breadth and depth of the applications that could be created for Java Card 2 devices, such as:

  • A very strict subset of Java APIs, with only JDK 1.0 features
  • No support for java.lang.String objects
  • No threads
  • No garbage collection
  • No support for networking
  • No native support for .class files
  • No dynamic class loading
  • 1-D Arrays
  • 8-bit CPUs
  • 8kB of RAM

Despite these limitations, Java Card technology became the most widely deployed Java platform in the world with over 3.5 billion deployments. Java Card 3.0 technology has several significant enhancements over the Java Card 2 platform, as explained in the following sections.

Comparing JavaCard 2 to JavaCard 3

As you can see from the sequence diagrams in Figures 1 and 2 located below, creating a complete application that involved using Java Card 2 technology could be tedious.

Figure 1. A Sequence Diagram Depicting the Interactions Between a Desktop Application and a Java Card 2 Application

Figure 1. A Sequence Diagram Depicting the Interactions Between a Desktop Application and a Java Card 2 Application

Figure 2. A Sequence Diagram Depicting the Interactions Between a Mobile Application and a Java Card 2 Application

Figure 2. A Sequence Diagram Depicting the Interactions Between a Mobile Application and a Java Card 2 Application

As you can see from the preceding figures, both the desktop and mobile applications need to eventually use the APDU (application protocol data unit) protocol to communicate with applications (also known as applets) located on the Java Card 2 smart card. In some cases, however, the API restrictions -- combined with having to use byte arrays for all interaction with the smart card -- were major deterrents to attracting enterprise Java developers to the Java Card platform.

However, the Java Card 3 platform provides significant improvements to its predecessor, and those changes should appeal not only to enterprise and desktop developers, but to mobile developers as well. The Java Card 3 platform includes support for the following features:

  • An API based upon a CLDC subset, with Java 6 features
  • Annotations
  • byte, short, int, long, char and java.lang.String
  • Threads
  • Servlets
  • Garbage collection of objects
  • TCP/IP networking
  • HTTP and HTTPS
  • .class files
  • .war deployment files
  • Dynamic class loading
  • 2-D Arrays
  • 32-bit CPUs
  • 24kB of RAM

Figure 3, shown below is a sequence diagram showing the steps and actions involved in creating a complete application using the Java Card 3 platform.

Figure 3. A Sequence Diagram Depicting the Interactions Between a Mobile or Desktop Application and a Java Card 3 Application

Figure 3. A Sequence Diagram Depicting the Interactions Between a Mobile or Desktop Application and a Java Card 3 Application

With Java Card 3 technology, smart card application development has instantly become a lot easier, and has now taken a significant leap-ahead in capability so that the following scenarios are possible:

  • Developers no longer need to create individual client applications to access the data and resources on the smart card. The only client interface needed is an ordinary web browser.
  • Smart Card applications are now fully functioning TCP-based servers. These server applications are Java servlets, and they have a full HTTP stack to allow them to process GET requests, POST requests, headers, cookies, sessions, and so on.
  • You can secure the data between the client (the browser) and the server (the smart card) by using the industry-standard SSL (secure sockets layer).

Getting Started the Java Card Connected Development Kit and the Persistence Example

Did you know that Java Card applications have access to two heap spaces? One of them is volatile, which means that it acts like RAM, so all information stored in that heap location is lost after the system is reset (that is, when the card is removed and inserted). The other heap area is non-volatile, so data stored in that location is truly persistent, even after a system reset.

To get clear understanding of how to store data on the card in the volatile heap allocation, let's take a look at the Persistence example from the Java Card Connected Development Kit 3.0.2. Table 1, shown below, provides a detailed breakdown of the files contained within the %folder_root%\JCDK3.0.2_ConnectedEdition\samples\web\Persistence folder.

Table 1. Description of Files and Folders Within the Persistence Example

Folder/File Name Description
/build.xml This is the primary ant build xml file. The project name, base directory, and import file are specified in this file.
/build/ This is the parent folder that contains the build arifacts that will be automatically created by ant. These artifacts include the intermediary /WEB-INF/classes folder, which will be packaged into the final .war file
/config/ This is the parent folder that contains the configuration files.
/config/build-impl.xml This is an autogenerated ant build file that is imported from the primary build.xml file. It is not recommended for developers to modify this file.
/config/genfiles.properties This is an autogenerated file used by NetBeans. It is not recommended for developers to modify this file.
/config/project.properties This is the main property file that sets several configurable properties such as the main servlet, the main URL, as well as the web context path.
/config/project.xml This the NetBeans project XML file.
/dist This is the parent folder containing the redistributable items / artifacts after the build process is complete.
/dist/Presistence.signature This is a binary file that contains a digital signature.
/dist/Presistence.war This is the deployable .war file that will be loaded on the Java Card.
/html/ This is the parent folder containing the index.html as well as the accompanying images.
/html/index.html This is a simple placeholder html page that redirects to the "index" path of the JavaCard WAR application.
/html/images/ This is the folder that contains the images referenced by the JavaCard servlet.
/META-INF/ This is the parent folder containing manifest files.
/META-INF/javacard.xml This is the JavaCard application descriptor file.
/META-INF/MANIFEST.MF This is a simpe manifest file that's common for JAR and WAR files.
/src This is the parent folder for all Java source code.
src/.../PresistanceServlet.java This is a servlet that shows the contents of the database, adds new items to the database, and deletes existing items.
src/.../IndexServlet.java This is a servlet that has been mapped to the "index" path of the Java Card WAR application. This servlet presents an HTML form, which invokes the HelloWorldServlet card application.
src/.../Database.java JavaCard 3 applications have two heap spaces (volatile and non-volatile). This is a simple class that store data in volatile heap.
/WEB-INF This is the parent folder that contains the assests used by the servlets.
/WEB-INF/footer.i This is a part of an HTML file.
/WEB-INF/header.i This is a part of an HTML file.
/WEB-INF/index.i This is a part of an HTML file.
/WEB-INF/web.xml This is a typical web.xml that defines and maps the servlets with URLs.

Listing 1 is the code for Database.java, a class that allows multiple users in different browser sessions to store and retrieve data objects from the volatile heap space of a Java Card application.

Listing 1. Database.java




package com.sun.jchowto.persistence;

import java.util.Vector;

/**
 * 
 */
public class Database {
    private static Vector<String> items = new Vector<String>();

    /**
     * @param item
     */
    public static void addItem(String item) {
        if (!items.contains(item)) {
            items.addElement(item);
        }
    }

    /**
     * @return
     */
    public static Vector<String> getItems() {
        return items;
    }

    /**
     * @param item
     * @return
     */
    public static boolean delete(String item) {
        return items.removeElement(item);
    }
}


As you can see, the code for the database is pretty simple as it is primarily a wrapper class that allows users to store, retrieve, and delete objects from a String-typed Vector. It demonstrates the capabilities of the Java Card 3 platform well, since it shows that you can use generics, first introduced in the Java SE 5.0.

Listing 2 is the code for the Java Card 3 servlet that accesses the database.

Listing 2. PersistenceServlet.java





package com.sun.jchowto.persistence;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * A Simple Persistence Servlet.
 */
public class PresistanceServlet extends HttpServlet {   
 /* (non-Javadoc)
     * @see javax.servlet.http.HttpServlet#doPost(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
     */

    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException 
    {

        String op = request.getParameter("op");
        String item = request.getParameter("item");

        if (op != null) {
            if (op.equals("Add")) {
                if (item != null) {
                    Database.addItem(item);
                }
            } else if (op.equals("Delete")) {
                if (item != null) {
                    Database.delete(item);
                }
            }
        }

        response.setContentType("text/html");
        PrintWriter out = response.getWriter();
        RequestDispatcher dispatcher = null;

        dispatcher = request.getRequestDispatcher("/WEB-INF/header.i");
        dispatcher.include(request, response);

        out.println("<tr>");
        out.println("<td bgcolor=\"#FFFFFF\" align=\"center\" valign=\"middle\">");
        out.println("<table bgcolor=\"#000000\" border=\"0\" width=\"100%\" cellspacing=\"1\" cellpadding=\"15\">");
        out.println("<tr>");
        out.println("<td align=\"center\" bgcolor=\"#FFFFFF\">");

        out.println("</b><big><big>Simple Database</big></big></b>");
        out.println("<form method=\"get\" action=\"database\">");
        out.println("<table border = 0>");
        out.println("<tr>");
        out.println("<td>Item : </td><td colspan=2><input type=\"text\" name=\"item\"></input></td>");
        out.println("</tr>");
        out.println("<tr>");
        out.println("<td> </td>");
        out.println("<td><input type=\"submit\" name=\"op\" value=\"Add\"></td>");
        out.println("<td><input type=\"submit\" name=\"op\" value=\"Delete\"></td>");
        out.println("</tr>");
        out.println("<tr>");
        out.println("<td colspan=3><hr></td>");
        out.println("</tr>");
        out.println("<tr>");
        out.println("<td colspan=3><b>Items in Database</b></td>");
        out.println("</tr>");
        out.println("<tr>");
        out.println("<td colspan=3><textarea readonly rows=\"5\" cols=\"20\">");
        if(Database.getItems().size() <= 0) {
            out.print(" \n \nDatabase is Empty;\n \n ");
        } else {
        for (String str : Database.getItems()) {
            out.println(str);
        }
        }
        out.println("</textarea></td>");
        out.println("</tr>");
        out.println("</table>");
        out.println("</form>");

        out.println("</td>");
        out.println("</tr>");
        out.println("</table>");
        out.println("</td>");
        out.println("</tr>");

        dispatcher = request.getRequestDispatcher("/WEB-INF/footer.i");
        dispatcher.include(request, response);

    }
}


As you can see from the preceding code listing, PersistenceServlet.java works like any other subclass of HTTPServlet. All you need to do is override the HTTP methods that you want, and replace them with your own code. In this case, we're only supporting HTTP GET requests. If the HTTP parameter "op" is set to "Add", then we'll add a new item to the database. If, however, "op" is set to "Delete", then the specified item will be removed from the database.

In either case, the servlet completes its work by showing the final list of contents in the database. The Java Card 3 platform doesn't support JSP files, so you should notice in Listing 2 that much of the application is dedicated to creating the HTML response. Figure 4 is the PersistenceServlet in action.

Figure 4. Adding My Favorite Stock Symbols to the PersistenceServlet.java

Figure 4. Adding My Favorite Stock Symbols to the PersistenceServlet.java

Conclusion

The Java Card 3 platform is lightyears ahead of its predecessor. It includes several new features that allow developers to create extremely sophisticated applications using Java servlet technology. Are you ready for a new generation of servlet applications that execute on a smart card?