Pages

Wednesday, December 11, 2019

Hibernate for multi column IN clause

Data-sets sometimes do not make sense on their own and make sense only when they are viewed as pairs rather than individually. Composite keys that we use in the relational databases are such examples where although both of the values do make sense on their own but for a specific set of data the individual value is not enough and you need a pair or a set of keys to identify a record or to make sense of a record.

For example in the Forex market only a currency pair makes sense when you are looking for some prices. This is because the price of a unit of currency makes sense only in terms of the units of another currency. For example as of today GBP 1.0 gives you USD 1.3, however without the GBP the 1.3 USD does not make any sense.

I such scenarios when we want to look up for a list of values in the SQL IN clause, we need to be able to provide a pair rather than a single value, i.e., running the IN clause over two columns. Something like follows.

    SELECT DISTINCT notional_currency, other_notional_currency
    FROM instrument_descriptor 
    WHERE (notional_currency, other_notional_currency) 
    IN (('AUD', 'EUR'), ('EUR', ‘GBP’), ('AUD', 'USD''))
    EORDER BY notional_currency, other_notional_currency

However, when it comes to implement that in Hibernate. To achieve that we have to create a separate component that contains these two columns and then use that component to populate the IN clause.


    @Embeddable
    public class InstrumentDescriptorCurrencyPair {

 private String notionalCurrency;
 private String otherNotionalCurrency;
 
 // No argument constructor required by Hibernate
 public InstrumentDescriptorCurrencyPair() {
 }
 
 // Getters and Setters .. 
 public String getNotionalCurrency() {
  return notionalCurrency;
 }
 ......
    }

Note that the column names has to be the same as defined in the original entity.

Then we need to "embed" the component in the original entity.


    // Entity class .. 
    public class InstrumentDescriptor extends PersistentObject {

        private static final long serialVersionUID = 2946565846321427118L;
        private static final int BASE_HASH = InstrumentDescriptor.class.getName().hashCode();

        // Non related fields omitted for brevity .. 
        private String notionalCurrency;
        private String otherNotionalCurrency;
        
        // Embed the component .. 
        @Embedded
        private InstrumentDescriptorCurrencyPair currencyPair;
        
        // Component getters and setters .. 
        public InstrumentDescriptorCurrencyPair getCurrencyPair() {
            return currencyPair;
        }
        public void setCurrencyPair(InstrumentDescriptorCurrencyPair currencyPair) {
            this.currencyPair = currencyPair;
        }

        ......

    }

Now we can use the Hibernate to run the SQL with multiple columns in the IN clause.



    @SuppressWarnings("unchecked")
    public IterableScrollableResults listInstruments2(List quotePairs, Date startDate, Date endDate) {
     
     InstrumentDescriptorCurrencyPair columns;
     List currencyPairs = new ArrayList<>();
     
     // Create a list of pairs using the Component
     for (QuotePair quotePair : quotePairs) {
      columns = new InstrumentDescriptorCurrencyPair(quotePair.getBaseCurrency(), quotePair.getTermCurrency());
      currencyPairs.add(columns);
 }

     // Notice that we are using the name of the component as defined in the Entity class
                   String sql = "FROM InstrumentDescriptor AS instrument "
          + “WHERE instrument.currencyPair IN (:currencyPair) "
          + "ORDER BY instrument.notionalCurrency, instrument. otherNotionalCurrency";
        
            ScrollableResults results = (ScrollableResults) template.execute((Session session) ->{
         
            Query query = session.createQuery(sql);
            query.setParameterList("currencyPair", currencyPairs);
            return query.scroll();
        });

        return results;
    }

For those of you how are using the configurations instead of the annotations, we can do that in the .hbm.xml files as well.

Just update the .hbm.xml files for the entity and add the new component's configuration.


    <component name="currencyPair" class="net.worldflow.dvega.common.model.InstrumentDescriptorCurrencyPair">
     <property name="notionalCurrency" access="field" length="3" insert="false" update="false" />
     <property name="otherNotionalCurrency" access="field" length="3" insert="false" update="false" />
    </component>

Notice that the properties are added as read-only in the Component configuration.

Friday, November 14, 2014

Create and Invoke a JSR-352 Batchlet Using EJB Timer

Batch Processing is referred to processing a series of jobs without manual intervention. These are in contrast with OLTP processes that require some input from the users to initiate a process. All input parameters are predefined through scripts, job control language control files, etc. These tasks (jobs) often process large amounts of data from a range of sources.

Java EE Batch Processing Framework (JSR-352) provides the batch execution infrastructure common to all batch applications. This enables us, the developers, to concentrate on the business logic of these batch processes. The batch framework consists of a job specific XML based language, as set of batch annotations and some interfaces to implement the business logic, a batch container that manages the bath jobs and a set of APIs to interact with the batch container.

In this first JSR-352 post, I will concentrate on the Batchlet. I have chosen this because this is the simplest way of getting up and running with the JSR-352 Batch Processing Framework. We will use a Timer to trigger the Batchlet and a RESTful Web Service to create the Timer that will trigger the Batchlet. Let's start with the Service first.

This is how my the service looks like:

package com.mybatchproject;


import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

import javax.ejb.EJB;
import javax.ejb.Timer;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

/**
 * http://localhost:8080/BatchJobServer/resource/test/timerservice
 * 
 * @author Raza Abidi
 *
 */
@Path("test")
public class BatchJobService {
 
 @EJB
 MyEJBTimer timerEJB;
 
 
 @GET
 @Path("/timerservice")
 @Produces(MediaType.TEXT_XML)
 public TimerInfo generateTimeStamp() {
  
  Date schedule;
  
  try {
   // Add a delay of one minute
   Calendar cl = new GregorianCalendar();
   cl.add(Calendar.MINUTE, 1);
   schedule = cl.getTime();
  } catch (Exception e) {
   e.printStackTrace();
   return null;
  }
  
  TimerInfo to = new TimerInfo();
  to.setJobName("my-test-batch-job"); // same as the xml name
  to.setJobSchedule(schedule);
  to.setJobMessage("Job scheduled sucessfully");
  
  Timer timer;
  try{
   timer = timerEJB.createNewTimer(schedule, to);
  }catch(Exception e){
   to.setJobMessage("Failed to create timer");
   e.printStackTrace();
   return to;
  }
  
  to = (TimerInfo) timer.getInfo();
  
  System.out.println("Timer created successfully: " + to);
  
  return to;
 }
}

All we are doing here is preparing a simple POJO TimerInfo and populating it with some data. We are then creating a simple Timer using the MyEJBTimer helper EJB and saving the POJO in the Timer. This is to illustrate that a Timer can contain data that can be used when the Timer expires. It will make more sense later on.

This is what the POJO TimerInfo looks like:


package com.mybatchproject;

import java.io.Serializable;
import java.util.Date;

import javax.xml.bind.annotation.XmlRootElement;

/**
 * @author Raza Abidi
 * @date 13 Nov 2014 15:45:22
 */
@XmlRootElement(name="TimerInfo")
public class TimerInfo implements Serializable{
 
 private static final long serialVersionUID = -6478588792874137803L;
 
 private String jobName;
 private Date jobSchedule;
 private String jobMessage;
 
 @Override
 public String toString() {
  
  StringBuilder sb = new StringBuilder();
  sb.append("\n").append("Name: ").append(jobName);
  sb.append("\n").append("Schedule: ").append(jobSchedule);
  sb.append("\n").append("Message: ").append(jobMessage).append("\n");
  
  return sb.toString();
  
 }
 
 public String getJobName() {
  return jobName;
 }

 public void setJobName(String jobName) {
  this.jobName = jobName;
 }

 public Date getJobSchedule() {
  return jobSchedule;
 }

 public void setJobSchedule(Date jobSchedule) {
  this.jobSchedule = jobSchedule;
 }

 public String getJobMessage() {
  return jobMessage;
 }

 public void setJobMessage(String jobMessage) {
  this.jobMessage = jobMessage;
 }

}

Once the POJO is populated with data then we use the timerEJB.createNewTimer(schedule, to); method of our helper EJB to create a timer. The method takes two parameters, schedule and info. The schedule is a date object representing the date/time when the timer is scheduled to expire and the info is an instance of TimerInfo class that contains some necessary data that we can retrieve from the timer when it gets expired. Note that we are already creating the Scheduled Object with a delay of 1 minute. This timer will expire one minute after it is created.

Let’s see what the MyEJBTimer helper class looks like:

package com.mybatchproject;

import java.util.Date;

import javax.annotation.Resource;
import javax.ejb.Singleton;
import javax.ejb.Timeout;
import javax.ejb.Timer;
import javax.ejb.TimerService;


/**
 * @author Raza Abidi
 * @date 13 Nov 2014 15:36:58
 */
@Singleton
public class MyEJBTimer {

 @Resource 
 private TimerService ts;

 public Timer createNewTimer(Date date, TimerInfo timerInfo) {
  
  Timer timer = ts.createTimer(date, timerInfo);
  return timer;
  
 }
 
 @Timeout
 public void timerExpired(Timer timer){
  
  System.out.println("Timer Expired @ :" + new Date());
  
  TimerInfo to = (TimerInfo) timer.getInfo();
  
  to.setJobMessage("Timer Executed Successfully");
  
  System.out.println("Timer Info: " + to);
  
  BatchJobHandler jobHandler = new BatchJobHandler();
  
  jobHandler.startJob(to);
  
 } 
}

This is a simple EJB providing the implementation of what needs to be done when a Timer gets expired. The TimerService is injected as a Resource in this EJB and used by the two methods to create and use Timers created using the resource.

The first method createNewTimer(Date date, TimerInfo timerInfo) is the one called by the RESTFul service to create a Timer. This takes two parameters and uses the TimerService resource to create the Timer in the system. Upons successful creation of a Timer it will return the Timer object to the caller.

The second method timerExpired(Timer timer) annotated with the @Timeout annotation is the one that gets triggered when a timer gets expired. This is where we have implemented the logic to trigger the Batchlet using the BatchJobHandler helper class. Let’s see that that class looks like.

package com.mybatchproject;

import java.util.Properties;

import javax.batch.operations.JobOperator;
import javax.batch.runtime.BatchRuntime;

/**
 * @author Raza Abidi
 * @date 13 Nov 2014 15:40:11
 */
public class BatchJobHandler {

 public void startJob(TimerInfo to) {
  
  String jobName = to.getJobName();
  
  JobOperator jobOperator = BatchRuntime.getJobOperator();
  
  Properties jp = new Properties();
  
  long executionId = jobOperator.start(jobName, jp);
  
  System.out.println("Job Started: " + jobName + "  Execution ID:" + executionId);
 }
}

Here we are getting a reference to the JobOperator from the BatchRuntime and then using the jobOperator.start(jobName, jp); method to invoke the Batch Process. The method returns an Execution ID which is the ID of that Job and can be used later to pause, stop, restart the job using the methods provided by the Batch API.

Note that we used the TimerInfo object to get the name of the job that we want to start.

Now we need to create the actual Batch Job. All Batch Jobs are defined in XML and they must be located inside the META-INF/batch-jobs folder of your application server. I created an XML document to describe my Batch Job at:

 META-INF/batch-jobs/my-test-batch-job.xml

Notice the name of the file, it is exactly the same as what we passed to the to.setJobName("my-test-batch-job");. The Batch Runtime uses the name of the XML file to identify whcih jobs it needs to start when you invoke the jobOperator.start(jobName, jp); method.

This is what the my-test-batch-job.xml file contains:


<?xml version="1.0" encoding="UTF-8"?>
<job id="my-test-batch-job" xmlns="http://xmlns.jcp.org/xml/ns/javaee" version="1.0">
 
 <step id="my-test-batch-step">
  <batchlet ref="MyBatchJobBatchlet"/>
 </step>
 
</job>

Now we need to create a class that represents the Batch Job. This class must implement the Batchlet Interface and provide the implementation of at least the process() method. This how my class looks like:


package com.mybatchproject;

import javax.batch.api.Batchlet;
import javax.enterprise.context.Dependent;
import javax.inject.Named;

/**
 * @author Raza Abidi
 * @date 13 Nov 2014 15:50:56
 */
@Dependent
@Named("MyBatchJobBatchlet")
public class MyBatchJobBatchlet implements Batchlet {

 @Override
 public String process() throws Exception {
  
  System.out.println("Starting the Batch Job");
  
  for (int i = 0; i < 5; i++) {
   
   
   try{
    Thread.sleep(1000);
   }catch(Exception e){
    e.printStackTrace();
   }
   
   System.out.println("Processing the Batch Job : " + i);
   
  }
  
  System.out.println("Finished the Batch Job");
  
  
  return null;
 }

 @Override
 public void stop() throws Exception {
 }
}


Notice the @Named annotation and the batchlet tag in the XML file. Both of these are referring to the same name, i.e., MyBatchJobBatchlet to bind the job definition with the job.

This Batchlet is not doing anything useful really; it is simply printing a message and then waiting for one second before printing the next message in a loop that will iterate 5 times. This is only to illustrate that the jobs will be ruining for a long period of time without any manual intervention.

When you type in the URL for this service ina browser, you will get teh following response:

<?xml version="1.0" encoding="UTF-8" standalone="true"?>
<TimerInfo>
 <jobMessage>Job scheduled sucessfully</jobMessage>
 <jobName>my-test-batch-job</jobName>
 <jobSchedule>2014-11-13T17:52:16.475Z</jobSchedule>
</TimerInfo>

And this is what you should see on the console output of your Application Server.

INFO: Initiating Jersey application, version Jersey: 2.0 2013-05-14 20:07:34...
INFO: Timer created successfully: 
Name: my-test-batch-job
Schedule: Thu Nov 13 17:22:24 GMT 2014
Message: Job scheduled sucessfully
INFO: Timer Expired @ :Thu Nov 13 17:22:24 GMT 2014
INFO: Timer Info: 
Name: my-test-batch-job
Schedule: Thu Nov 13 17:22:24 GMT 2014
Message: Timer Executed Successfully
INFO: Job Started: my-test-batch-job  Execution ID:48
INFO: Starting the Batch Job
INFO: Processing the Batch Job : 0
INFO: Processing the Batch Job : 1
INFO: Processing the Batch Job : 2
INFO: Processing the Batch Job : 3
INFO: Processing the Batch Job : 4
INFO: Finished the Batch Job

As you can see, the service created a Timer and sent a response back to the browser streight away. After 1 minute, the timer expired and started the Batch Job.

Last but not least, if you are using Maven to build your project then you need to add the Maven dependency for JSR-352 to our Java EE project.

<dependency>
 <groupId>javax.batch</groupId>
 <artifactId>javax.batch-api</artifactId>
 <version>1.0</version>
 <scope>provided</scope>
</dependency>

If you are using Glassfish as your application server then you can use the admin console to view the Bath Jobs executing in the server. You can view them under the "Monitoring Data" area and then the "Batch" tab on the Monitoring Data screen. At the moment you can only view the status of teh jobs running in the system, btu hopefully in later versions there will be options to interact with the jobs.

You can also use the methods ptovided by the Batch Runtime API to interact with the batch runtime and provide your own implementation of the admin interface to interact with the Bath Jobs if you need to. It is not as diffcult as it sounds really. If I manage to find some time, I may write another post on how to create a management interface for the Batch Runtime. :)

Monday, November 3, 2014

Configuring Glassfish 4.1 as a Windows Service

Previously I did publish a post on how to install Glassfish V2 as a Windows service a few years ago. Things have moved on quite a bit since then and now the latest version of the server comes with a built in command to configure the domain as a windows service.

There are a few short comings though. The command does not fully leverage the windows services and you still have to configure a few things after creating the service. Well, without further ado, let’s start installing the service and you will soon find out what I meant by “shortcomings”.

First thing first, we need to make sure the Glassfish is working properly even before we think about starting to configure that as a service. Use the asadmin prompt to verify that you can start-stop the sample domain and that everything is working fine.

NOTE: You need admin privileges to install the windows service.

Now open a new command prompt as administrator and type in the following command.

asadmin create-service domain1
The Windows Service was created successfully.  It is ready to be started.  Here are the details:
ID of the service: domain1
Display Name of the service:domain1 GlassFish Server
Server Directory: C:\glassfish4\glassfish\domains\domain1
Configuration file for Windows Services Wrapper: C:\glassfish4\glassfish\domains\domain1\bin\domain1Service.xml
The service can be controlled using the Windows Services Manager 
or you can use the Windows Services Wrapper instead:
Start Command:  C:\glassfish4\glassfish\domains\domain1\bin\domain1Service.exe  start
Stop Command:   C:\glassfish4\glassfish\domains\domain1\bin\domain1Service.exe  stop
Restart Command:  C:\glassfish4\glassfish\domains\domain1\bin\domain1Service.exe  restart
Uninstall Command:  C:\glassfish4\glassfish\domains\domain1\bin\domain1Service.exe  uninstall
Install Command:  C:\glassfish4\glassfish\domains\domain1\bin\domain1Service.exe  install
Status Command: C:\glassfish4\glassfish\domains\domain1\bin\domain1Service.exe status
You can also verify that the service is installed (or not) with sc query state= all
windows.services.uninstall.good=Found the Windows Service and successfully uninstalled it.
For your convenience this message has also been saved to this file: C:\glassfish4\glassfish\domains\domain1\PlatformServices.log
Command create-service executed successfully.

This command will create a service like a breeze. However, the description of the service created using this command is not very descriptive. Problem here is that if you have more than a few services installed on the system, especially if you are looking to install multiple domains in one server then these descriptions are really not good enough.

Fortunately the command created a few exe files and a configuration file that we can use to install, uninstall the service at will. These files are located in the bin folder of the domain. The configurations of the service are stored in domain1Service.xml which looks like below for me.


<service>
  <id>domain1</id>
  <name>domain1 GlassFish Server</name>
  <description>GlassFish Server</description>
  <executable>C:/glassfish4/glassfish/lib/nadmin.bat</executable>
  <logpath>C:\\glassfish4\\glassfish\\domains/domain1/bin</logpath>
  <logmode>reset</logmode>
  <depend>tcpip</depend>
  <startargument>start-domain</startargument>
  <startargument>--watchdog</startargument>
  <startargument>--domaindir</startargument>
  <startargument>C:\\glassfish4\\glassfish\\domains</startargument>
  <startargument>domain1</startargument>
  <stopargument>stop-domain</stopargument>
  <stopargument>--domaindir</stopargument>
  <stopargument>C:\\glassfish4\\glassfish\\domains</stopargument>
  <stopargument>domain1</stopargument>
</service>

We are only interested in the following tags as they are the ones displayed in the Windows Services Manager

<service>
  <name>domain1 GlassFish Server</name>
  <description>GlassFish Server</description>
</service>

We simply need to update these two parameters and give our domain a more descriptive display name and description. I updated the values as follows and save the file.

<service>
  <name>GF Domain1</name>
  <description>Windows service for the GlassFish Domain1 domain</description>
</service>

After saving the file, you now need to uninstall the existing service and then install the service again using the domain1Service.exe file that got created in the previous step. Open a command prompt, go to the bin directory, and run the following commands:

C:\> cd \glassfish4\glassfish\domains\domain1\bin
C:\glassfish4\glassfish\domains\domain1\bin> domain1Service.exe uninstall
C:\glassfish4\glassfish\domains\domain1\bin> domain1Service.exe install
C:\glassfish4\glassfish\domains\domain1\bin> 

You now have your Glassfish 4.1 domain configured as a Windows service with a name and description of your choice.

Thursday, April 17, 2014

Securing RESTful APIs with HTTP Basic Authentication

HTTP Basic Authentication is the simplest way for a HTTP User Agent to provide a username and password to the web server to enforce access control of the resources. The Basic Authentication method provides no confidentiality and the credentials are transmitted as merely Base64 encoded string. Therefore, this method of authentication is typically used over HTTPS for added security.

The user credentials are sent using the Authorization header. The header is constructed as follows:

  • Combine username and password into a string “username:password”
  • Encode the resulting string in a Base64 variant
  • Prefix the encoded string with “Basic ” ; notice the space here
These encoded credentials are then sent over to the server. On the server side you can then extract these credentials and use them to authenticate the user.

In this example, I shall create a very simple RESTful web service and a very simple java client that will call this restful web service with an HTTP Authorization header. Let's start with creating a RESTful web resource that extracts the authentication data from the HTTP Header and returns the decoded credentials as simple text back to the client.


package com.test.service;

import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;

import sun.misc.BASE64Decoder;

@Path("auth")
public class TestHTTPAuthService {
 
 @Context
 private HttpServletRequest request;
 
 @GET
 @Path("basic")
 @Produces(MediaType.TEXT_PLAIN)
 public String authenticateHTTPHeader(){
  
  String decoded;
  try{
   // Get the Authorisation Header from Request
   String header = request.getHeader("authorization");
   
   // Header is in the format "Basic 3nc0dedDat4"
   // We need to extract data before decoding it back to original string
   String data = header.substring(header.indexOf(" ") +1 );
   
   // Decode the data back to original string
   byte[] bytes = new BASE64Decoder().decodeBuffer(data);
   decoded = new String(bytes);
   
   System.out.println(decoded);
   
  }catch(Exception e){
   e.printStackTrace();
   decoded = "No/Invalid authentication information provided";
  }
  
  return decoded;
 }
}

We know the format of data in the authorization header and thus we can extract the encoded part of the data and then decode it to get the credentials. This service is simply returning the decoded credentials back to the caller.

Now let’s create a simple java class that will call this service. We will send the username and password in the HTTP Header and printout the result from the service.


package servlet;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;

import sun.misc.BASE64Encoder;

public class BasicHTTPAuthentication {

 public static void main(String[] args) {

  try {
   
   String webPage = "http://localhost:8080/TESTService/resource/auth/basic";
   String name = "Aladdin";
   String password = "Open Sesame";

   String authString = name + ":" + password;
   System.out.println("Auth string: " + authString);
   
   String authStringEnc = new BASE64Encoder().encode(authString.getBytes());
   System.out.println("Base64 encoded auth string: " + authStringEnc);

   URL url = new URL(webPage);
   URLConnection urlConnection = url.openConnection();
   urlConnection.setRequestProperty("Authorization", "Basic " + authStringEnc);
   InputStream is = urlConnection.getInputStream();
   InputStreamReader isr = new InputStreamReader(is);

   int numCharsRead;
   char[] charArray = new char[1024];
   StringBuffer sb = new StringBuffer();
   while ((numCharsRead = isr.read(charArray)) > 0) {
    sb.append(charArray, 0, numCharsRead);
   }
   String result = sb.toString();

   System.out.println("---------------------------------------------");
   System.out.println("Response from the server: " + result);
   
  } catch (MalformedURLException e) {
   e.printStackTrace();
  } catch (IOException e) {
   e.printStackTrace();
  }
 }
}

Here we are simply converting and encoding the credentials according to the HTTP guidelines. After that we are using the setRequestProperty() to add these values to an authorization header. Once the header is set, we then send this request to the service which can extract the credentials form the request and sends them bac as a response.

Below is the console output when we run this code:


Auth string: Aladdin:Open Sesame
Base64 encoded auth string: QWxhZGRpbjpPcGVuIFNlc2FtZQ==
---------------------------------------------
Response from the server: Aladdin:Open Sesame

The service side of the code is simply extracting the credentials from the HTTP Header and writing them in the log file before generating a response, which is also nothing more than the decoded credentials.

Below is an extract from the log files showing the entry logged by this service:

[glassfish 4.0] [INFO] [tid: _ThreadID=22 _ThreadName=Thread-3] [[Aladdin:Open Sesame]]

This is a very simple example to show the HTTP Basic Authentication using the HTTP Authorization headers. This is not a recommended approach by any means. You can clearly see more than a few flaws in this approach, not to mention how easy it is to decode the credentials.

However, simply adding the added security of HTTPS over TLS, you significantly improve the level of security of this simple authentication mechanism.

Another improvement would be to use Servlet Filters instead of authentication credentials in every service/resource. You can intercept the request to a resource and authenticate the user even before it reaches anywhere near the resource. Feel free to browse my previous post on Using Servlet Filters for a demonstration on how the servlet filters can be used to intercept request and responses.

Thursday, April 10, 2014

Using ServletFilter to authenticate a user's Session

Servlet Filters are interceptors for requests and responses to transform or use the information in the request or response. Filters normally do not create a response themselves, instead, they provide global functions that can be attached to any web resources.

Filters are very important for a number of reasons. First of all, they provide a modular way to create units of functionality that can be reused, and secondly they can be used to transform the data in request or response.

Filters can perform manay different types of functions, including but not limited to :

  • Authenticating the requests
  • Logging and auditing
  • Data Transformation
  • Data Compression
  • Localization
In this example I am going to try to explain Filters by developing a simple filter that verifies that the user still has a valid session. If the session is expired then the Filter will block the request from going any further and redirect the user to the login page.

Let’s base our Filter on the following assumptions

  • We have a session bean called UserBean
  • The bean is stored in the session as user
  • The login page authenticates the user
  • The login page creates and stores a UserBean in session
  • We will always have a user variable in session
Based on the following assumptions, all we need to do is to make sure that we have an instance of UserBean in the session variable user with some valid user credentials.

This is what my Servlet Filter looked like when I first created it. All we need to do is to implement the Filter interface and override the doFilter() method. Whatever we want to do with that filter would be provided in this method.


public class SessionFilter implements Filter {

 @Override
 public void doFilter(ServletRequest req, ServletResponse res,
   FilterChain chain) throws IOException, ServletException {

  String sessionExpired = "/mywebproject/sessionExpired.html";

  try {

   HttpServletRequest request = (HttpServletRequest) req;
   HttpServletResponse response = (HttpServletResponse) res;

   HttpSession session = request.getSession(false);
   if(null == session){
   
    request.getRequestDispatcher("/sessionExpired.html").forward(request, response);
    
   }else{
   
    UserBean ub = (UserBean)session.getAttribute("user");
    if(null == ub){
    
     response.sendRedirect(sessionExpired);
     
    }else if (ub.getUserID() == null){
    
     response.sendRedirect(sessionExpired);
    }
   }

  } catch (Exception f) {
   f.printStackTrace();
  }
  chain.doFilter(req, res);
 }
}

Here we are simply checking for the session if we have a valid UserBean object in the session. If we have an object in the session then we validate the object if it contains a user id. If everything is fine then we continue the process and pass the process flow to the next filter in the chain. If not then redirect the control to the session expired page to let the users know that the session is no longer valid and they have to login to the system again.

Ignored Resources:
There is one problem though; this filter was not working because it was redirecting even the login page to the session expired page. This is because the filter is invoked every time we send a request to the server and a request to the login page will never have a user object in the session on our first request. As a result the system becomes un-usable.

There are a few ways to deal with this issue; the easiest would be to get the context path from the request and avoid any session checks if the context path contains the name of your login page.

The clean way however is to provide a list of ignored resources in the web.xml configuration file. This is what the configuration file looks like when we provide ignored resources:


 <filter>
     <filter-name>SessionFilter</filter-name>
     <filter-class>com.mywebproject.common.filter.SessionFilter</filter-class>
     <init-param>
         <param-name>avoid-urls</param-name>
         <param-value>login</param-value>
     </init-param>     
 </filter>
 <filter-mapping>
     <filter-name>SessionFilter</filter-name>
     <url-pattern>/pages/*</url-pattern>
 </filter-mapping>
 

The avoid-urls parameter tag initializes the Filter with this list of URLs that the filter will avoid. Unfortunately this is simply an indicator here and you still need to provide an implementation for the filter to avoid the URLs provided in this list.

Note: You can provide more than one comma separated URLs in the param-value parameter.

Now we need to provide an implementation to avoid these URLs in our Filter. This is how the updated SessionFilter looked like after adding the functionality to load and then avoid the URLs provided in the web.xml configuration file.


package com.mywebproject.common.filter;

import java.io.IOException;
import java.util.ArrayList;
import java.util.StringTokenizer;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import com.mywebproject.user.bean.UserBean;

public class SessionFilter implements Filter {
 
 private ArrayList<String> urlList;

 @Override
 public void init(FilterConfig config) throws ServletException {

  urlList = new ArrayList<String>();
  String urls = config.getInitParameter("avoid-urls");
  StringTokenizer token = new StringTokenizer(urls, ",");
  
  while (token.hasMoreTokens()) {
   urlList.add(token.nextToken());

  } 
 }
 
 @Override
 public void doFilter(ServletRequest req, ServletResponse res,
   FilterChain chain) throws IOException, ServletException {

  String sessionExpired = "/mywebproject/sessionExpired.html";

  try {

   HttpServletRequest request = (HttpServletRequest) req;
   HttpServletResponse response = (HttpServletResponse) res;
   
   String url = request.getServletPath();
   boolean allowedRequest = false;
   for (String allowed: urlList) {
    
    if(url.contains(allowed)){
     allowedRequest = true;
     break;
    }
   }

   if(!allowedRequest){

    HttpSession session = request.getSession(false);
    if(null == session){
    
     request.getRequestDispatcher("/sessionExpired.html").forward(request, response);
     
    }else{
    
     UserBean ub = (UserBean)session.getAttribute("user");
     if(null == ub){
     
      response.sendRedirect(sessionExpired);
      
     }else if (ub.getUserID() == null){
     
      response.sendRedirect(sessionExpired);
     }
    }

   }

  } catch (Exception f) {
   f.printStackTrace();
  }
  chain.doFilter(req, res);
 }
}

This Filter will now avoid checking for a valid session for any requests for the login page. Other than that page, it will always look for a valid session and a valid logged in user. If the session is expired or if there is no valid UserBean in the session then the Filter will not allow the request to go ahead and will redirect the user to the login page.

It is just one example of how the filters can be used. As mentioned in the beginning of this post, the filters can be used for all sorts of tasks that you want to perform on all or probably most of requests coming to your server.

Thursday, January 9, 2014

Compressed ZIP IO Streams using java

Java provides the java.util.zip package for data compression in a zip-compatible format. Classes in this package allow you to manipulate zip files and create zip archives. Java uses specialized input/output streams to read/write compressed data. These streams can be used to send data to any destination in a compressed format.

The java.util.zip package provides a ZipInputStream for reading the compressed data, i.e., zip files and a ZipOutputStream for writing data in a compressed format. Both of these IO Streams are implementations of Filter Input/Output streams and in terns extend the java.io.InputStream and java.io.OutputStream in the hierarchy.

This interesting inheritance hierarchy makes it every easy for us to use both of these Zip IO Streams as wrappers to any IO Streams. For example, it would be very easy to write a custom RMI Socket to transfer compressed data over the network. For example, here is the code to read data from a file, compress it and send it over to another server using a socket:

 // Create an input stream for reading file data
 InputStream in = new FileInputStream(file);
 
 // Create a socket on a remote server
 Socket socket = new Socket(hostName, portNumber);
 
 // Acquire the remote socket to write data to
 OutputStream out = socket.getOutputStream();
 
 // Create a ZIP output stream to compress data
 ZipOutputStream zos = new ZipOutputStream(out);
 
 //  Open and start reading from the file
 int len;
    while ((len = in.read(buffer)) > 0) {
  // Send data using ZIP output stream (compressed)
     zos.write(buffer, 0, len);
    }

Similarly on the server side, you need to wrap the input stream in a ZipInputStream to read the compressed data. This approach will significantly reduce the network traffic if there is a requirement to send large amount of data over remote systems.

For the purpose of illustrating the end to end working, I used the file IO Streams to demonstrate how the ZIP package is used. There is no reason however, why you cannot replace the java.io.FileInputStream and the java.io.FileOutputStream with any type of IO Streams you may need to use for your project.

For the purpose of this post, I created a utility class ZipUtil, that has three methods:

  • public void createArchive: This method is used to create a new ZIP file containing all files in a given folder.
  • public void extractArchive: This method is used to extract all the files from a given ZIP archive.
  • private List<String> listFiles: This is a private method to generate a list of all files that can be compressed. This method is used internally by createArchive() method.
Let's look at all of these methods in detail:

Creating ZIP Archive

First we shall see how we can create ZIP Archives using the classes provided in the java.util.zip package.

 public void createArchive(File sourceDir, File zipFile)throws Exception{
 
  String root = sourceDir.getAbsolutePath();
  
  // Needed for listFiles method
  int rootLen = root.length() + 1;
  List<String> files = listFiles(rootLen, root, zipFile.getName());
  
  ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipFile));
  
  for (String file : files) {
   // Create a new zip entry and add it to the file 
   zos.putNextEntry(new ZipEntry(file));
   
   // Open a read the file data to compress in zip format
   InputStream in = new FileInputStream(root + File.separator + file);
   int len;
   while ((len = in.read(buffer)) > 0) {
    zos.write(buffer, 0, len);
   }
   in.close();
  }
  zos.close();
 }

As you can see, it is a very simple method that reads a folder and creates a zip entry for every file in the given folder. The only tricky bit in the code is actually getting the list of all the files that are to be archived in the new zip file. I shall explain that later. Other then that, all we are doing here is reading data from each file in the folder and writing that to the ZipOutputStream, which will compress that data for you before storing it to the disk in the given zip file.

Now let's see the listFiles method:

 private List<String> listFiles(int rootLen, String path, String zipFile) {

  List<String> files = new ArrayList<String>();
  
  File root = new File( path );
  File[] list = root.listFiles();

  // see if the directory is empty
  if (list == null) 
   return files;
  
  // traverse through each file in the directory
  for ( File f : list ) {
   if ( f.isDirectory() ) {
    
    // In case it is a directory then call recursively to 
    // get a list of all the files in the sub directory
    files.addAll(listFiles(rootLen, f.getAbsolutePath(), zipFile));
   }
   else {
    
    // Skip the zip file if it already exists anywhere in the directory tree
    // otherwise that can result in a deadlock
    if(f.getName().equals(zipFile))
     continue;
    
    // We need the relative pats in the archive, remove the parent directories. 
    files.add(f.getAbsolutePath().substring(rootLen));
   }
  }
  return files;
 }

It is a very simple method to get the list of all the files in the given directory recursively. For that, simply get the list of all files in a directory, go through the list of all the files one by one, if the file is a file then add it in the list to return, if the file is a directory then call the same method recursively with the subdirectory. That way, we will get the list of all the files in the full directory tree.

There are, however, a few minor details that we need to consider. Notice the two extra parameters to this method, rootLen and zipFile. Both of them are there for a special reason. The root length is the length of the root path of the parent folder provided to the createArchive() method. The class java.io.File only provides either the full path of a file or just the file name, both of these are not usable for the archive because we have to maintain the folder hierarchy within the zip archive, relative to the root folder path.

The workaround is to get the full path of each file and then remove the root path from the absolute path of the file, this way we will end up with the path of the files in sub folders, relative to the root path of the parent folder. Simply because String manipulation is comparatively expensive, we pass the length of the root path in rootLen parameter and remove that number of characters from the absolute path of each file, leaving only the relative paths with the names.

Another important consideration is that if the zip file already exists (anywhere in the given directory tree) it can create a deadlock. We have already created an OutputStream for the file and we will end up trying to open an InputStream on the same file, which can result in a deadlock. To avoid that problem we pass the name of the zip file in zipFile parameter and remove the zip file from the returned list if it already exists.

Extracting a ZIP Archive

We just saw how easy it is to create a ZIP Archive using the utility classes provided by the java.util.zip package. Now let's see how to extract files from a ZIP Archive to a folder.

 public void extractArchive(File archive, File outputDir) throws Exception{
 
  // Open the ZIP file
  ZipInputStream zis = new ZipInputStream(new FileInputStream(archive));
  
  // Start traversing the Archive
  ZipEntry ze;
  while ((ze = zis.getNextEntry()) != null){
   
   // Create a new file for each zip entry
   File f = new File(outputDir, ze.getName());
   
   // Create all folder needed to store in correct relative path.
   f.getParentFile().mkdirs();
   
   OutputStream os = new FileOutputStream(f);
   int len;
   while ((len = zis.read(buffer)) > 0) {
    os.write(buffer, 0, len);
   }
   os.close();
  }
  zis.close();
 }

This is the other way around in comparison to the createArchive() method we saw earlier. The compressed ZIP files must be opened using the ZipInputStream and the data read using this stream can be written back to any type of stream.

The only tricky bit here is the f.getParentFile().mkdirs(); part, this is because we must create subdirectories if there are any in the zip archive. Remember, a ZIP file may contain a full directory tree.

Testing the Example

To demonstrate the working of these utility methods, I created a test class and a folder with some test data. We shall first create a zip file using that test data and then extract the zip file in a given folder.

Here is the test class:

package zip;

import java.io.File;

public class MyZipTest {

 private static final String ZIP_FILE = "C:/temp/zipTest/testFiles/test.zip";
 private static final String SOURCE_FOLDER = "C:/temp/zipTest/testFiles";
 private static final String OUTPUT_FOLDER = "C:/temp/zipTest/unzip";

 public static void main(String arg[]){

  File archive = new File(ZIP_FILE);
  File srcDir = new File(SOURCE_FOLDER);
  File destDir = new File(OUTPUT_FOLDER);

  ZipUtil tst = new ZipUtil();
  try{
   // To create a zip archive
   tst.createArchive(srcDir, archive);
   
   // To extract the zip archive
   tst.extractArchive(archive, destDir);
  }catch(Exception e){
   e.printStackTrace();
  }
 }
}

Here is the utility class:

package zip;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

public class ZipUtil {

 byte[] buffer;
 
 public ZipUtil(){
  buffer = new byte[1024];
 }
 
 /**
  * Utility method to create a zip archive of all the files in a given folder. 
  * The method takes the full qualified name of the folder and the name 
  * of the zip file
  * 
  * @param sourceDir -- Directory to archive
  * @param zipFile -- Archive name
  * @throws Exception
  */
 public void createArchive(File sourceDir, File zipFile)throws Exception{

  String root = sourceDir.getAbsolutePath();
  
  if(!sourceDir.exists())
   throw new IOException("Source Directory " + root + " does not Exists");
  
  if(!sourceDir.isDirectory())
   throw new IllegalArgumentException(root + " is not a valid directory");
  
  // Needed for listFiles method
  int rootLen = root.length() + 1;
  List<String> files = listFiles(rootLen, root, zipFile.getName());
  
  if (files.size()<=0)
   throw new IllegalArgumentException(root + " is not empty");

  ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipFile));
  
  System.out.println("Archiving: " + root);
  
  for (String file : files) {
   
   System.out.println("Ading: " + file);
   
   // Create a new zip entry and add it to the file 
         zos.putNextEntry(new ZipEntry(file));
   
         // Open a read the file data to compress in zip format
   InputStream in = new FileInputStream(root + File.separator + file);
   int len;
         while ((len = in.read(buffer)) > 0) {
          zos.write(buffer, 0, len);
         }
         in.close();
  }
  zos.close();
  System.out.println("Created: " + zipFile);
 }
 
 /**
  * This private method is used by the <code> public void createArchive(File sourceDir, File zipFile) </code> <br /> 
  * This method will generate the list of all the files in a given directory tree, with relative paths 
  * of the files in the sub directories if there are any. <br />
  * The third parameter is the name of the file that this method will ignore while generating the list. 
  * @param rootLen -- Length of the root directory path
  * @param path -- Directory to traverse
  * @param zipFile -- Name of the file to avoid 
  * @return
  */
 private List<String> listFiles(int rootLen, String path, String zipFile) {

  List<String> files = new ArrayList<String>();
  
  File root = new File( path );
  File[] list = root.listFiles();

  // see if the directory is empty
  if (list == null) 
   return files;
  
  // traverse through each file in the directory
  for ( File f : list ) {
   if ( f.isDirectory() ) {
    
    // In case it is a directory then call recursively to 
    // get a list of all the files in the sub directory
    files.addAll(listFiles(rootLen, f.getAbsolutePath(), zipFile));
   }
   else {
    
    // Skip the zip file if it already exists anywhere in the directory tree
    // otherwise that can result in a deadlock
    if(f.getName().equals(zipFile))
     continue;
    
    // We need the relative pats in the archive, remove the parent directories. 
    files.add(f.getAbsolutePath().substring(rootLen));
   }
  }
  return files;
 }
 
 /**
  * Utility method to extract all the files in a ZIP Archive to the given directory. 
  * If the ZIP file contains a complete directory tree, the method will take care of 
  * creating sub directories and placing files in appropriate locations within the 
  * sub directories. 
  * @param archive -- Zip Archive
  * @param outputDir -- Output directory for extracted files 
  * @throws Exception
  */
 public void extractArchive(File archive, File outputDir) throws Exception{
  
  String root = outputDir.getAbsolutePath();
  
  if(!outputDir.exists()){
   outputDir.mkdir();
  }
  
  if(!outputDir.isDirectory())
   throw new IllegalArgumentException(root + " is not a valid directory");

  System.out.println("Processing: " + archive.getAbsolutePath());
  System.out.println("Extracting files to: " + root);
  
  // Open the ZIP file
  ZipInputStream zis = new ZipInputStream(new FileInputStream(archive));
  
  // Start traversing the Archive
  ZipEntry ze;
  while ((ze = zis.getNextEntry()) != null){
   
   System.out.println("Extracting: " + ze);
   
   // Create a new file for each zip entry
   File f = new File(outputDir, ze.getName());
   // Create all folder needed to store in correct relative path.
            f.getParentFile().mkdirs();
   
            OutputStream os = new FileOutputStream(f);
            
   int len;
         while ((len = zis.read(buffer)) > 0) {
          os.write(buffer, 0, len);
         }
   os.close();
  }
  
  zis.close();
  
  System.out.println("Successfully Extracted: " + archive.getAbsolutePath());
 }
}

And this is the output when you run the test class to create a zip archive.

Archiving: C:\temp\zipTest\testFiles
Ading: first\TestText-1.txt
Ading: first\TestText-2.txt
Ading: first\TestText-3.txt
Ading: second\TestText-4.txt
Ading: second\TestText-5.txt
Ading: second\TestText-6.txt
Ading: second\TestText-7.txt
Ading: TestText-10.txt
Ading: TestText-8.txt
Ading: TestText-9.txt
Created: C:\temp\zipTest\testFiles\test.zip

And this is the output when you run the test class to extract a zip archive.

Processing: C:\temp\zipTest\testFiles\test.zip
Extracting files to: C:\temp\zipTest\unzip
Extracting: first\TestText-1.txt
Extracting: first\TestText-2.txt
Extracting: first\TestText-3.txt
Extracting: second\TestText-4.txt
Extracting: second\TestText-5.txt
Extracting: second\TestText-6.txt
Extracting: second\TestText-7.txt
Extracting: TestText-10.txt
Extracting: TestText-8.txt
Extracting: TestText-9.txt
Successfully Extracted: C:\temp\zipTest\testFiles\test.zip

As you can see, the technique can be used to compress any type of data streams. This may significantly reduce the bandwidth requirements of your system and also can dramatically improve the performance.

However, there are a few pitfalls there. You are adding some extra processing before sending data over any stream, and also you have to process data on the other end before you can use it. This extra processing time may not be justifiable in most of the cases, and you may even end up slowing down your system rather then gaining any performance benefits.

As every powerful tool, this must be approached with caution. This approach is desired only when you are transferring large amounts of data on a single request, and a data compression would make a difference. If you are sending small data chunks then it may not give you any benefits, or worse, may even introduce more problems.

Monday, June 17, 2013

HTTPS Client using X.509 Certificate

Hypertext Transfer Protocol Secure (HTTPS) is a communication protocol for secure communication. HTTPS is widely used on the internet to secure the communication on public websites. Technically it is not a protocol itself; rather, it is the result of layering the HTTP over SSL/TSL protocol to add the security capabilities of SSL/TSL to the standard HTTP protocol. More formally it is HTTP Over TLS according to RFC 2818 on IETF.

All the communication between the client and the server is encrypted using public key certificates. On connection request from the client, HTTPS server presents a certificate to the browser with its public key and the subsequent communication between the server and the client is encrypted using the public key in the certificate.

Public-key infrastructure (PKI) is especially suitable for web because it still provides some protection even if only one side of the communication link is authenticated. As long as the server is authenticated, any client can download the public key certificate from the server and use the public key to encrypt the data before sending it over to the server. That however means it is the responsibility of the client to examine the public key certificate and make sure that the certificate is valid for that server, i.e., the server is actually who it says he is.

Normally every certificate is signed by some authority to mark that the certificate is trusted and can be used for secure communication. Most websites use well know certificate authorities (e.g. VeriSign/Microsoft/etc.) to sign the certificate for them. Most of the browsers have a list of well know certificate authorities. When a server presents a certificate signed by one of the certificate authorities in the browser’s list, the browser use them to establish a secure connection with the server. However, when the signatory is not in the list of browser then they present a message to the user that the certificate is not signed by a trusted authority and let the users decide whether they want to trust the server or not.

Most of the browsers come equipped with this functionality. When you connect to a website using HTTPS URLs the browsers take care of the details for the users. If the certificate presented by the server is signed by one of the well-known Certificate Authority then the browsers simply use that certificate and in case of a self-signed certificate the browsers ask users to validate and accept the certificate before establishing the data communication.

The bottom line is that the certificate must be marked as trusted before it can be used to establish a connection with the server.

  • Using Certificate to open HTTPS Connection

Java uses the keystore to achieve this functionality. Any certificate that exists in the keystore is considered trusted and can be used to establish a connection with the server. To create a HTTPS connection programmatically, we first need to add the certificate to the keystore. A very simple way to get the certificate is to point your browser to the https:// url and ask to view the certificate and then download it.

I used FireFox to get the certificate.

  • Go to the https url, because it is self-signed, FireFox will display the warning that the connection is untrusted.
  • Go to I Understand the Risk and click Add Exception.
  • That will open the Add Exception dialog, click on the View button to see the certificate details.
  • This will open the certificate details for you. Click on the Details Tab to see the details of the certificate.
  • On this tab you have an option to Export the certificate.

When you click Export, it will open the save file dialogue. Save the certificate to an appropriate location on your disk. The certificate will be saved with either .crt or .perm extension.

Once you have the certificate then the next step will be to add that in your keystore. You can do it by using the keytool command in java as follows.

keytool -import -keystore yourKyeStore.jks -file YourCert.crt
This command will create a keystore for you and import the certificate to your keystore. If the keystore does not exist then it will create a keystore for you. For an existing keystore, it will ask for the password of your keystore, and for a new keystore it will ask for a password for the keystore and then ask again to confirm the password and on confirmation create a new keystore with the provided password.

At this point it will show you the detials of the certificate and ask you if you trust the certificate.


C:\temp\certs>keytool -import -keystore store.jsk -file cert.crt
Enter keystore password:
Re-enter new password:

Owner: CN=www.certificateserverurl.com, OU=Sun GlassFish Enterprise Server, 
 O=Sun Microsystems, L=Santa Clara, ST=California, C=US
Issuer: CN=www.certificateserverurl.com, OU=Sun GlassFish Enterprise Server, 
 O=Sun Microsystems, L=Santa Clara, ST=California, C=US
Serial number: 5013bd9b
Valid from: Sat Jul 28 11:23:23 BST 2012 until: Tue Jul 26 11:23:23 BST 2022
Certificate fingerprints:
         MD5:  90:03:8C:BA:32:1F:AD:96:40:CE:49:1D:A3:A3:F6:72
         SHA1: 8D:AE:25:8F:9C:3A:70:81:55:03:5E:B7:92:D2:0A:E6:CB:99:A3:59
         Signature algorithm name: SHA1withRSA
         Version: 3

Extensions:

#1: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: F9 A7 36 D2 9B 4D 10 68   0F 22 2F 31 16 39 59 1A  ..6..M.h."/1.9Y.
0010: 65 70 F6 56                                        ep.V
]
]

Trust this certificate? [no]:  y
Certificate was added to keystore

C:\temp\certs>

Enter "y" on this prompt to add the certificate to your keystore.

Once you have the certificate added to the JVM Truststore, all you need to do is to tell your Java Program to use the truststore before opening a HTTPS connection. This is how you do it:


 System.setProperty("javax.net.ssl.trustStore", keystore);
 System.setProperty("javax.net.ssl.keyStorePassword", "changeit");
 
 //con = openHttpsConnection(queryString);
 URL url = new URL(queryString);
 con = (HttpsURLConnection)url.openConnection(); 
 
Java adds all the trusted certificates in a keystore. Here you are specifying the keystore and the password for the keystore to enable java to search for an appropriate certificate from this store. When a connection request is made the server will present the certificate to the java client. The java client will look into this keystore to see if we already have this certificate added as a trusted certificate in the keystore. If the certificate is found then a HTTPS connection can be established.

Supposing you have a user search service running on a HTTPS server. Below is the code you will use to call that secure service to search for registered users in your server.


package user;

import java.net.URL;

import javax.net.ssl.HttpsURLConnection;

import user.xml.UserXMLHandler;
import user.xml.generated.Users;

public class TestUserServlet {
 
 private static final String strUrl = "https://www.yourserver.co.uk/users/";
 private static final String keystore = "C:\\temp\\certs\\store.jks";
 
 private static final String find = "profile?";
 
 private static final String FNAM = "firstName";
 private static final String LNAM = "lastName";
 
 public static void main(String s[]) throws Exception{
  
  Users users = null;
  
  System.out.println(strUrl);
  
  TestUserServlet test = new TestUserServlet();
  
  users = test.doFindUser("raza", "abidi");
  System.out.println(users.toString());
  
 }
 
 private Users doFindUser(String firstName, String lastName) throws Exception{
  
  String queryString = strUrl + find + FNAM + "=" + firstName + "&" + LNAM + "=" + lastName;
  
  HttpsURLConnection con = null;
  
  try{
   
   // Set the keystore to use
   System.setProperty("javax.net.ssl.trustStore", keystore);
   System.setProperty("javax.net.ssl.keyStorePassword", "changeit");
   
   URL url = new URL(queryString);
   con = (HttpsURLConnection)url.openConnection();
  }catch(Exception e){
   e.printStackTrace();
   if(con!=null)
    con.disconnect();
   
   throw e;
  }
  
  if(con==null){
   throw new Exception ("Failed to open HTTPS Conenction");
  }
  
  Users users = null;
  try{
   users = new UserXMLHandler().getUsersXML(con.getInputStream());
  }finally{
   con.disconnect();
  }
  return users;
 }
}
All we are doing here is telling java which keystore to use to find a certificate before trying to open a connection to the secure server. Java will look into the keystore and will use the most appropriate certificate from the list of certificates in the keystore. The certificate already has information about the issuing server and java will use that information to find out which certificate to use to establish a secure connection with the server.

  • HTTPS Connection without Certificate

I would strongly advise against using this approach when connecting to a secure server. Getting a certificate from the secure server and installing it in the JVM keystore is a pretty trivial task and there is no need to bypass that process otherwise what is the point of implementing a secure server connection. However, sometimes, most probably in your test environments, you may need to connect to the HTTPS server without using the certificate. On these occasions the workaround is to provide your own implementation of the TrustManager and override the security methods to trust any given certificate.

Even in this scenario, all the communication between server and client will still be encrypted, the only problem is that you blindly trust every certificate as it is and that opens the system vulnerable to security breaches. That is the reason why you should avoid bypassing the keystore approach. However, for odd occasions when it is needed, here is how you do it.


package user;

import java.net.URL;
import java.security.cert.CertificateException;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import user.xml.UserXMLHandler;
import user.xml.generated.Users;

public class TestUserServlet {

 private static final String strUrl = "https://www.yourserver.co.uk/users/";

 private static final String find = "profile?";

 private static final String FNAM = "firstName";
 private static final String LNAM = "lastName";


 public static void main(String s[]) throws Exception{

  Users users = null;

  System.out.println(strUrl);

  TestUserServlet test = new TestUserServlet();

  users = test.doFindUser("raza", "abidi");
  System.out.println(users.toString());

 }

 private Users doFindUser(String firstName, String lastName) throws Exception{

  String queryString = strUrl + find + FNAM + "=" + firstName + "&" + LNAM + "=" + lastName;

  HttpsURLConnection con = null;

  try{
   con = openHttpsConnection(queryString);
  }catch(Exception e){
   e.printStackTrace();
   if(con!=null)
    con.disconnect();

   throw e;
  }

  if(con==null){
   throw new Exception ("Failed to open HTTPS Conenction");
  }

  Users users = null;
  try{
   users = new UserXMLHandler().getUsersXML(con.getInputStream());
  }finally{
   con.disconnect();
  }
  return users;
 }

 // Creating our own implementation of an all trusting trust manager
 private HttpsURLConnection openHttpsConnection(String queryString) throws Exception{

  // Create a trust manager that does not validate certificate chains
  TrustManager[] trustAllCerts = new TrustManager[] { 
    new X509TrustManager() {

     @Override
     public void checkClientTrusted(java.security.cert.X509Certificate[] arg0,
       String arg1) throws CertificateException {
      // TODO Auto-generated method stub

     }

     @Override
     public void checkServerTrusted(java.security.cert.X509Certificate[] arg0,
       String arg1) throws CertificateException {
      // TODO Auto-generated method stub

     }

     @Override
     public java.security.cert.X509Certificate[] getAcceptedIssuers() {
      // TODO Auto-generated method stub
      return null;
     }

    } 
  };

  // Install the all-trusting trust manager
  final SSLContext sc = SSLContext.getInstance("SSL");
  sc.init(null, trustAllCerts, new java.security.SecureRandom());
  HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());

  // Create all-trusting host name verifier
  HostnameVerifier allHostsValid = new HostnameVerifier() {
   public boolean verify(String hostname, SSLSession session) {
    return true;
   }
  };

  // Install the all-trusting host verifier
  HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);

  URL url = new URL(queryString);
  HttpsURLConnection con = (HttpsURLConnection)url.openConnection();

  return con;
 }
}

Here we are providing our own implementation of the TrustManager instead of using the trusted certificates from our keystore. All the magic is happening in the openHttpsConnection() method where we are passing the URL to connect to and the method is returning a HTTPS connection.

Notice the lines where we are calling the static methods setDefaultSSLSocketFactory and setDefaultHostnameVerifier of HttpsURLConnection class. Here we are setting our own HostnameVerifier and SSLSocketFactory implementation.

Notice the verify() method of the HostnameVerifier class. This method is simply returning true for every host and thus any host becomes valid for the HTTPS connection.

Also notice how the SSLContext is initialised. Here we are passing the customer implementation of X509TrustManager interface where we are simply overriding all the security methods with empty implementations; essentially doing nothing to prevent a security breach.

That means that any certificate from the HTTPS server is accepted as trusted and used for encrypting communication between the client and the server. This allows you to connect to a HTTPS server without installing the certificate in the JVM before making any connections.

Thursday, May 16, 2013

Implementing Observer Pattern

The Observer Pattern is a design pattern in which an object (called subject) is designed in such a way that other objects can be added as observers of the Subject, and any change in the state of the Subject can be notified to the Observers. This is very useful when you want to implement some event driven logic such as implementing a threshold of stock and notifying the purchasing application if stock goes below the set threshold.

In this way we completely separate the concerns of different areas of the application and can implement functions that are fired up based on the events happening in your application. This programming model is called Even Driven Programming where you implement the logic based on the events happeing in the application. Without going into the details of Event Drive programming; let’s see how this is implemented in Java.

Java provides a class Observable and an interface Observer in the java.util package to implement the Observable paradigm. This is what you do:

  • To Create Observable (the Subject), extend the Observable class
  • To create Observers, implement Observer interface and override update(Object obj) method
After that all you need to do is to addObserver() instances in your Observable class. Let’s see how it is done; we start by creating our Subject.

package observertest;

import java.util.Observable;

public class MyObservable extends Observable {
 
 public int sum(int a, int b){
  
  // If not set then observers will think nothing is changed
  // hence no action required. 
  setChanged();
  
  // Perform the business logic
  int c = a+b;
  
  System.out.println("Notifying Observers");
  // A call to notifyObservers() also clears the changed flag
  notifyObservers(new Integer(c)); 
  
  return c;
 }

}

This is a very simple Observable with only one business method sum(int a, int b) . Things to note here are calls to setChanged() and notifyObservers(). The setChanged method is a marker that means something is changed in your Observable object. If the marker is not set then a call to notify will have no effect. This is where you control whether to notify the observers or not.

The other interesting bit is the notifyObservers() method. A call to this methid will fire a notification to ALL the observers observing this object. Note that it takes an Object as a parameter so we have to convert any primitive types to their object wrappers. This is Java’s mechanism to pass parameters to the Observers if we want. The same parameter will be passed to all the observers listening to any changes to this object.

Now let’s see the Observer. To make the point clear, I created two observers on the same Subject.

package observertest;

import java.util.Observable;
import java.util.Observer;

public class MySecondObserver implements Observer {

 @Override
 public void update(Observable o, Object arg) {
  
  System.out.println("Second Observer Notified:" + o + "  :  " + arg);

 }

}

And the second Observer for our example

package observertest;

import java.util.Observable;
import java.util.Observer;

public class MySecondObserver implements Observer {

 @Override
 public void update(Observable o, Object arg) {
  
  System.out.println("Second Observer Notified:" + o + "  :  " + arg);

 }

}

As you can see, all we are doing here is implementing the Observer interface and overriding the update() method. A call to the notifyObservers() from the Observable will result in a call to the update() method eventually. The first parameter is the Object under observation and second parameter is the value you passed to the notifyObservers() method from your Observable.

Let’s see this in action. I am creating a main class where I will create instance of the Observable and will add these Observers to the Observable. Here we go….

package observertest;

public class MainClass {

 public static void main(String[] args) {
  
  int a = 3;
  int b = 4;
  
  System.out.println("Starting");
  MyObservable ob = new MyObservable();
  
  // Add observers
  System.out.println("Adding observers");
  ob.addObserver(new MyFirstObserver());
  ob.addObserver(new MySecondObserver());
  
  System.out.println("Executing Sum :  " + a + " + " + b);
  ob.sum(a, b);
  System.out.println("Finished");
  
 }
}

Here we are simply creating an instance of the Observable class and adding the two Observers to our class. After that we call our business method and this is where the Observers are notified. The Observable does not know nor does it care how many Observers are listening to changes to its state, all it does is notify everyone that something is changed and send some information about the changes.

Similarly, the Observers are completely independent of the Observable. They are interested only in the Subject for a change of state and what action they want to perform if they are notified of that change is completely up to the Observers.

This is the output when we run the MainClass

Starting
Adding observers
Executing Sum :  3 + 4
Notifying Observers
Second Observer Notified:observertest.MyObservable@1b499616  :  7
First Observer Notified: observertest.MyObservable@1b499616  :  7
Finished

Note that your output may be different as we have no control over which observer will be notified first. However, all of the Observers are going to receive the same data, the Subject, and some details passed by the Subject, an Integer in our case.

For more details look at the JavaDocs for Observer and Observable. Some study of Event Driven Programming paradigm would also give you better insight into the pros and cons of this programming model.

Monday, May 13, 2013

SSH - SFTP Communication

FTP is the most popular protocol to transfer files over the network. The protocol has been around since the very early days of computer networks and is still widely used. FTP protocol provides functions to upload, download and delete files, create and delete directories, read the contents of a directory.

There are several libraries for almost every programming language that provide set of APIs that can be used to work with the FTP commands programmatically. In Java there are several open source libraries that can be used. The most popular is Apache Commons Net library that provides easy to use APIs to work with FTP file transfer. You can go to Commons NET link for more details including several working sample applications that you can use.

SFTP however is a completely different story. To begin with, it has nothing to do with the FTP protocol and unlike the common perception, architecturally they are completely different. SFTP abbreviation is often mistaken as Secure FTP which is not entirely correct. Another perception is that SFTP is some kind of FTP over SSL or SSH. In fact SFTP is abbreviation of "SSH File Transfer Protocol". This is not FTP over SSL and not FTP over SSH. SFTP is an extension of the Secure Shell (SSH) protocol which provides the file transfer capabilities. See this SFTP Wiki page for more details.

SFTP works over a secure channel, i.e. SSH. First you connect to the secure channel, as soon as the connection is established; the server presents a public key to the client, any subsequent communication between the server and the client will be encrypted using the public key presented by the server. After establishing the connection, you then need to authenticate the communication using any supported authentication mechanism, i.e. Public Key or Username-Password. Successfully authentication creates a secure channel on which you create the SFTP connection for secure file transfer to and from the SFTP server.

That all sounds very nice and interesting, but the story starts getting muddy after that. Unfortunately there are not many complete open source implementations of SFTP in Java. What I could find so far are these two implementations of SFTP in the open source world, one is JSch and the other one is SSHTools All other implementations are either a fork of one of these two or they are in a very initial stage.

I will be using SSHTools for this example. I found that comparatively easy to use and it does what it says on the tin. You however, are welcome to try both and see which one you like the most. Both of these libraries provide very similar interfaces and are not very difficult to use. To use the SSHTools libraries, all you need to do is to download the j2ssh-core-0.2.9.jar from SSHTools website and place it on your classpath. For this example I will be creating a SFTP Client class to connect to an SFTP server using the UserName-Password authentication.

Any SFTP communication starts by creating the secure channel. First thing is to create an SSH connection using SshClient to the SFTP server and then authenticate your credentials using an instance of PasswordAuthenticationClient with your credentials and then pass it to the SshClient for authentication.


 // Create SSH Connection. 
 SshClient ssh = new SshClient();
 ssh.connect("sftp_server", new ConsoleKnownHostsKeyVerification());
 
 // Authenticate the user
 PasswordAuthenticationClient passwordAuthenticationClient = new PasswordAuthenticationClient();
 passwordAuthenticationClient.setUsername("user_name");
 passwordAuthenticationClient.setPassword("password");
 try{
  int result = ssh.authenticate(passwordAuthenticationClient);
  if(result != AuthenticationProtocolState.COMPLETE){
   throw new Exception("Login failed !");
  }
 }catch(Exception e){
  throw new Exception("Authentication Failure: " + e.getMessage()); 
 }
 
 //Open the SFTP channel
 try{
  sftp = ssh.openSftpClient();
 }catch(Exception e){
  throw new Exception("Failed to open SFTP channel: " + e.getMessage());
 }
 

Interesting bits to observe in this piece of code are connection and authentication related lines. First of all the ConsoleKnownHostsKeyVerification class that we pass as parameter to the connect() method. This is because when you connect to any SSH server, it supplies the public key to client and the client will use this public key for any further communication with the server. That means the login and password that we are passing to the SSH server for authentication is encrypted using this public key before it is sent over to the server for authentication.

When we pass only the host name to the connect method, it will by default try to find the known_hosts file in $HOME/.ssh/known_hosts and failing to find this file or the host in this file will prompt the user to verify the server public key signature and the following prompt will come up.

The host your.sftp.server is currently unknown to the system
The host key fingerprint is: 1028: 69 54 9c 49 e5 92 59 40 5 66 c5 2e 9d 86 af ed
Do you want to allow this host key? [Yes|No|Always]:

From this prompt, you have to manually enter one of these options to continue

  • Yes will use this host for the current session
  • No will not continue with the communication
  • Always will add this host to the known host file in your system
If you select the Always option then the host will be added to the known_hosts file and any subsequent communication will not ask for verification of the public key signature.

When using the ConsoleKnownHostsKeyVerification class in the connect method, the SshClient uses the instance of this class to negotiate the protocol and exchange the key with the SSH Server on your behalf, when it returns the connection becomes ready for communication. Thus avoiding any need of user interaction to verify the server signature and manually negotiate the SSH connection. Now the credentials can be encrypted using the Public Key of the server and sent over to the server for authentication.

When your login is authenticated, then you can open an SftpClient over this SSHConnection. This is the hard work done; once you have the SftpClient then you have all the standard FTP operations at your disposal. When you finish with your FTP operations, get, put, ls, mkdir, etc. then make sure you disconnect from both the SFTP channel and the SSH connection.


 public void disconnect() throws Exception{
  
  if(sftp == null)
   throw new Exception("SFTP channel is not initialized.");
  
  if(ssh == null)
   throw new Exception("SSH session is not initialized.");
  
  try{
   sftp.quit();
  }catch(Exception e){
   throw new Exception("Failed to disconnect from the server: " + e.getMessage());
  }
  
  try{
   ssh.disconnect();
  }catch(Exception e){
   throw new Exception("Failed to disconnect from the server: " + e.getMessage());
  }
 }
 

There are a few lines of code that will be repeated for every SFTP operation, i.e. connection and authentication code and disconnect. Let’s create a wrapper for our SFTP communication and then we can use this wrapper in our application to do our SFTP operations. Encapsulating these methods in a few easy to use interfaces will make our life a lot easier.


package ftp;

import com.sshtools.j2ssh.SftpClient;
import com.sshtools.j2ssh.SshClient;
import com.sshtools.j2ssh.authentication.AuthenticationProtocolState;
import com.sshtools.j2ssh.authentication.PasswordAuthenticationClient;
import com.sshtools.j2ssh.transport.ConsoleKnownHostsKeyVerification;

public class SFtp {
 
 private String host;            // Remote SFTP hostname

 private SshClient ssh;
 private SftpClient sftp;
 
 public SFtp(String host) {
  
  this.host = host;
  this.ssh = null;
  this.sftp = null;
 }
 
 public void connect(String user, String password) throws Exception{
  
  // Connect to SSH. 
  ssh = new SshClient();
  try{
   ssh.connect("sftp_server", new ConsoleKnownHostsKeyVerification());
  }catch(Exception e){
   throw new Exception("SSH connection failure: " + e.getMessage());
  }
  
  // Authenticate the user
  PasswordAuthenticationClient passwordAuthenticationClient = new PasswordAuthenticationClient();
  passwordAuthenticationClient.setUsername(user);
  passwordAuthenticationClient.setPassword(password);
  try{
   int result = ssh.authenticate(passwordAuthenticationClient);
   if(result != AuthenticationProtocolState.COMPLETE){
    throw new Exception("Login failed !");
   }
  }catch(Exception e){
   throw new Exception("Authenticvation Failure: " + e.getMessage()); 
  }
  
  //Open the SFTP channel
  try{
   sftp = ssh.openSftpClient();
  }catch(Exception e){
   throw new Exception("Failed to open SFTP channel: " + e.getMessage());
  }
 }
 
 public void cd(String remoteDir) throws Exception{
  
  if(sftp == null)
   throw new Exception("SFTP channel is not initialized.");
  
  if(remoteDir==null || remoteDir.trim().length()==0)
   throw new Exception("Remote directory name is not provided.");
  
  try{
   sftp.cd(remoteDir);
  }catch(Exception e){
   throw new Exception("Failed to change remote directory: " + e.getMessage());
  }
 }
 
 public void put(String fileName) throws Exception{
  
  if(sftp == null)
   throw new Exception("SFTP channel is not initialized.");
  
  if(fileName==null || fileName.trim().length()==0)
   throw new Exception("File name is not provided.");
  
  //Send the file
  try{
   sftp.put(fileName);
  }catch(Exception e){
   throw new Exception("Failed to upload file: " + e.getMessage());
  }
 }
 
 public void disconnect()throws Exception{
  
  if(sftp == null)
   throw new Exception("SFTP channel is not initialized.");
  
  if(ssh == null)
   throw new Exception("SSH session is not initialized.");
  
  try{
   sftp.quit();
  }catch(Exception e){
   throw new Exception("Failed to disconnect from the server: " + e.getMessage());
  }
  
  try{
   ssh.disconnect();
  }catch(Exception e){
   throw new Exception("Failed to disconnect from the server: " + e.getMessage());
  }
 }
 
}

Since we are not using the SSH connection ever in our application directly, there is no need to provide any details of that in our wrapper. All we are interested in is the SFTP connection. That’s why the connect method takes the user and password as the parameters and does all the work of authenticating the users on the SSH channel and creating the SFTP connection.

In other implemented methods, cd, put, and disconnect, I am checking for a valid SFTP connection before any operation. The interesting bit here is the disconnect() method where we are making sure that both SFTP and SSH are disconnected.

And here is a sample client application that is using our wrapper to upload a file to an SFTP server.


package ftp;

public class SFTPTester {

 // Set these variables for your testing environment:
 private static String host = "your.sftp.server";  // Remote SFTP hostname
 private static String userName = "your_user";     // Remote system login name
 private static String password = "your_pswd";     // Remote system password
 private static String remoteDir = "remote_dir";   // Directory on SFTP Server
 
 public static void main(String argv[]) throws Exception {
 
  SFtp sftp = new SFtp(host, port);
  sftp.connect(userName, password);
  sftp.cd(remoteDir);
  sftp.put(filePath);
  sftp.disconnect();
  
 }
}

As you can see, creating a wrapper does encapsulates most of the code from your application and you end up with easy to use very simple interface to connect to your SFTP Server to upload files from your local directory. This is a very simple wrapper implementing only a few SFTP methods. Now you can add your own implementation of other FTP methods that you require.

Thursday, May 9, 2013

Queue Map Hybrid -- Creating Data Structures in Java

Recently I came across a problem where I was looking for a Queue implementation that can store Key-Value pairs. The benefits I was looking for were two folds, first of all, it must behave in a FIFO fashion, and secondly, I should be able to lookup an item by the Key without removing it from the structure. An Ideal implementation for me would be a hybrid of Queue and Map data structure implementations already available in the Collection Framework.

Like any modern programmer :-) my first attempt was to search for the available implementations and to my surprise I could not find anything that could fit to my criteria. I am surprized that no one ever considered such data structure or is it something that is so specialized that no one ever bothered to publish that, whatever is the reason; I did not find any clean implementation that I could use for my requirements.

That gave me a motivation to create my own and publish it for the community, maybe there is someone else looking for a similar solution and can benefit from the work I have already done. However, instead of simply posting my solution here, I am also taking this as an opportunity to provide some guidelines for students and junior programmes on how to design a new data structure. In this post I will try to explain what are the data structures and how we design the data structures.

Data Structures

Data structures are a special way of storing and organizing data in computer’s memory. In addition to storing the data, they also provide some functionality to manipulate the data stored in the structure. What functionality is provided depends on the data structure. Typical functionality is to Add, Remove, Find, First, Last, etc. Different kind of data structures are suited for different applications, some are very basic, like arrays, and some are highly specialized like B+ Tree. Bottom line is, you store some related data in-memory and provide appropriate operations on that data.

Functional Requirements

The first step on defining a data structure is to gather the requirements, what exactly are you looking to store in your structure and what behaviour is expected from that structure. For the purpose of this exercise, I have created this list of requirements that I am looking to achieve. The new structure must be able to

  • Store Key-Value pairs
  • Have a fixed size of structure
  • Remove last entry when adding a new pair
  • Find a Value by Key
  • Store any Object as Key or Value
  • Update Value of a Key
  • Remove any item using Key
Now that we have our requirements laid down, we can start looking at the existing solutions and how much of the given functionality they provide. I had in mind the Queue and the Map from Java Collection Framework, combining these two will give me all of the above functions.

Designing the Interface

An Interface is a set of functions that will be available for the users of that structure. In our case, all the public methods of the Data Structure are going to be the interface for that data structure. Now that we have the functional requirements, we can define the public methods of the new structure that we are going to create. This is what I came up with:

 public synchronized void addItem(K key, V value);
 public synchronized V getItem(K key);
 public synchronized void remove(K key);
 public int size();
 public void clear();

These methods will cover the functional requirements that we set out in our Gathering Functional Requirements phase. Now we can worry about the actual implementation of these methods.

Before we start implementing these methods, we must first look at the underlying structures that we are going to use. Remember, we have two basic requirements we set out in the beginning, it must behave like a Queue, and it must be able to store Key-Value pairs; for that we already have two very nice interfaces in Java Collection Framework; Queue and Map. Both of these interfaces provide functions to add, get, and remove elements from the structures. However, they are interfaces, and we need to choose the correct implementations of these interfaces in our new structure, we don’t want to re-invent the wheel, do we?

For the purpose of this exercise we are going to use the LinkedList implementation of Queue and HashMap implementation of Map; simply because they are the most basic ones. Now let’s start implementing the Structure. We begin by declaring the class and instance variables.


public class QueuedMap<K, V> {

 private static final int MAX_SIZE=1024;

 private int size;
 private Map<K, V> values;
 private Queue<K> keys;

 public QueuedMap() {
  this(64);
 }

 public QueuedMap(int size) throws IllegalArgumentException{

  if(size<=0){
   throw new IllegalArgumentException("Size can only be a +ive Integer");
  }

  if(size > QueuedMap.MAX_SIZE)
   throw new IllegalArgumentException("Size cannot be more than " + QueuedMap.MAX_SIZE);

  this.size = size;
  this.values = new HashMap<K, V>(this.size);
  this.keys = new LinkedList<K>();
 }

}

Here are a few interesting things to note, First of all the use of Generics. (If you are new to Generics the follow this nice Oracle Tutorial or this Wikipedia Page for more information) This class declaration covers our "Store Key-Value pairs" requirement by using the Map and also the "Store any Object as Key or Value" requirement by allowing creating the class instance of any Type. There is also an element of Type Safety by introducing the Generics, refer to the links above for details of how Generics achieve that.

The other important bit is the constructor of the structure. The default constructor initializes the structure with a default size of 64 but the overriding constructor takes the size as a parameter and initializes the structure with the given size. This fulfils the "Have a fixed size of structure" requirement. The Structure can have virtually any size, but once initialized, it cannot be changed. The MAX_SIZE constant that restricts the size of our Structure is there only for a reference to let you define a maximum size of your structure if you want to impose that restriction, Also notice the Map and Queue initialized as HashMap and LinkedList in the constructor.

Now let’s look at the implemented methods of our DataStructure. I will start from the easiest ones first, namely size() and clear() methods. These are the standard methods that should be implemented by any Data Structure.


 public int size(){
  return this.keys.size();
 }

 public void clear(){
  this.values.clear();
  this.keys.clear();
 }
 

As you can see, we are simply encapsulating the methods provided by our underlying Data Structures and providing a wrapper on these methods. In the size() method, we are simply returning the size of our Queue and in the clear() method we are simply calling the clear() method of both our Queue and our Map. Since we already have methods available for these functions in our underlying data structures, we don’t have to reinvent the wheel here and simple encapsulation is more than adequate.

Now let's look at the other methods in our Data Structure. Notice the synchronized keyword on all of our operations; this is because both the underlying Data Structures that we are planning to use are not synchronized, and we have to provide our own thread safety mechanisms.


 public synchronized void addItem(K key, V value){

  if(key == null || value == null)
   throw new NullPointerException("Cannot insert a null for either key or value");

  // First see if we already have this key in our queue
  if(this.keys.contains(key)){
   // Key found. 
   // Simply replace the value in Map
   this.values.put(key, value);
  }else{
   // Key not found
   // Add value to both Queue and Map
   this.enqueue(key, value);
  }
 } 
 

This is a very simple method exploiting the actual implementation from the underlying structures. The first thing to check before we add this Key-Value pair is that the Key and Value must not be null. If we have a value for both objects then we check if we already have this Key in our structure. In that case, simply replace the Value in our Map with the new Object received. If not then add this Key-Value pair to our Data Structure. This is how we are tackling our "Store any Object as Key or Value" and the "Update Value of a Key" requirements. The actual work of storing a Key-Value pair is rather involved and we use a private method enqueue(K, V) for that which is not visible to the users of this Structure.


 private void enqueue(K key, V value){

  if(this.keys.size() < this.size){
   // We still have space in the queue
   // Add they entry in both queue and the Map
   if(this.keys.add(key)){
    this.values.put(key, value);
   }
  }else{
   // Queue is full. Need to remove the Head 
   // before we can add a new item.
   K old = this.keys.poll();
   if(old!=null)
    this.values.remove(old);

   // Now add the new item to both queue and the map
   this.keys.add(key);
   this.values.put(key, value);
  }
 }

Here in the enqueue(K, V) method, first thing we are checking is if we still have space in the Structure. For that we use the instance variable size that we initialized in the constructor and we are not allowing the Structure to grow any larger than this size. If the size or our structure is still less than the maximum size with which the Structure is initialized then simply add the Key to the Queue and the Key-Value pair in the Map. If we have already reached the maximum size defined for this Structure then first remove the oldest Key from the Queue, then remove the pair with this Key from the Map before adding the new entries in both Queue and Map.

This is where you can see the Queue and Map in action. Adding Keys in the Queue ensures that when it comes to add a new element in the Structure, the oldest one is removed, and then we can use the Key to manipulate the data stored in the Map. This takes care of our "Remove last entry when adding a new pair" requirement.

The remaining two methods, getItem(K key) and remove(K key) are also fairly simple. All we are doing here is wrapping the functionality already provided by the underlying Queue and Map to control the behaviour.


 public synchronized V getItem(K key){

  if(key==null)
   return null;

  V val = this.values.get(key);
  return val;
 }

 public synchronized void remove(K key){

  if(key == null)
   throw new NullPointerException("Cannot remove a null key");

  this.keys.remove(key);
  this.values.remove(key);
 }

Here in the getItem(K key) we are simply returning the Value for that Key from our Map if the Key is not null. This fulfils our "Find a Value by Key" requirement.

The remove(K key) is slightly involved, here we are taking the Key and removing the Key from both the Queue and the Map. This takes care of the "Remove any item using Key" requirement we set out for the Structure.

That completes our Data Structure with all of the Functional Requirements we set out at the beginning of this post. Below is the full source for you to give you the full picture of how this all fits together.


package com.raza.collection;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Queue;

/**
 * <p>
 * QueuedMap is a specialised implementation of the Queue which can 
 * store Key Value pairs instead of just the Objects. This flexibility 
 * comes handy when you want to retrieve a specific Object from the Queue 
 * then instead of trying to find the object by iterating the whole 
 * Queue you can simply get the Object using the Key.
 * </P><p>
 * In order for the structure to work properly, it is vital to override 
 * the hashCode() and equals(Object obj) methods in your Key class. These are 
 * the methods that the underlying Map will use to compare the Keys 
 * to retrieve/remove the correct Object from the QueuedStore.
 * </P><p>
 * The structure will always have a fixed size. If the structure is not 
 * initialised with a given value then it will use default value of 64 
 * to initialise. Once the Structure is initialised then the size cannot 
 * be amended. Once the overall structure reaches the maximum size then 
 * any new Key Value pairs added to the structure will result in removing 
 * the oldest entry from the structure.
 * </P><p>
 * There is virtually no size limit to the size of the structure. The structure 
 * can be initialised with any arbitrary value, however, at the time of initialisation 
 * one should always consider keeping up with the best practices used to initialise 
 * Map data structures as the underlying implementation uses the HashMap to store 
 * the Key Value pairs.
 * </P>
 * 
 * @author Baqir Raza Abidi
 * @date 26 Mar 2013 16:03:08
 */
public class QueuedMap<K, V> {

 /**
  * Final variable indicates the Maximum size of this 
  * structure. 
  */
 private static final int MAX_SIZE=1024;

 private int size;
 private Map<K, V> values;
 private Queue<K> keys;

 /**
  * Default constructor for the class. Creates a class with the default 
  * structure size of {@code 64}. Once the structure is created then the 
  * size of the structure will remain the same.   
  */
 public QueuedMap() {
  this(64);
 }

 /**
  * <p>
  * Creates the structure with the given size. The constructor throws Exception if
  * the size given is less then 1. The structure cannot be created with a 0 or -ive 
  * size. 
  * </p><p>
  * The maximum size of the structure is also limited to the {@code QueuedStore.MAX_SIZE}
  * </p>
  *  
  * @param size Size of the Structure. 
  * @throws IllegalArgumentException If an invalid size is provided. 
  */
 public QueuedMap(int size) throws IllegalArgumentException{

  if(size<=0){
   throw new IllegalArgumentException("Size can only be a +ive Integer");
  }

  if(size > QueuedMap.MAX_SIZE)
   throw new IllegalArgumentException("Size cannot be more than " + QueuedMap.MAX_SIZE);

  this.size = size;
  this.values = new HashMap<K, V>(this.size);
  this.keys = new LinkedList<K>();
 }

 /**
  * <p>
  * Add a new {@code (Key, Value)} pair to the structure. Both the Key and Value can 
  * be any {@code Objects}. The method throws a {@code NullPointerException} in case any of
  * the Key and Value are {@code null}. 
  * </p><p>
  * If both the Key and Value are non null objects then it will try to store the
  * pair to the structure. If the key already exists in the Store then it will
  * simply replace the Value of that Key in the Store with the new Value. If the 
  * Key is a new one then it will try to store a new entry in the Structure. 
  * </p><p>
  * When storing a new entry in the structure, it first checks the size of the 
  * Structure and if it is still less than the size with which it was initialised then 
  * it will add the Key Value pair to the Structure. In case the size is now reached 
  * the limit then the method will first remove the oldest entry from the Structure 
  * and then will add the new Key Value pair to the Store. 
  * </p>
  * 
  * @param key  Object represents the Key.
  * @param value Object represents the Value. 
  * @throws Exception 
  */
 public synchronized void addItem(K key, V value){

  if(key == null || value == null)
   throw new NullPointerException("Cannot insert a null for either key or value");

  // First see if we already have this key in our queue
  if(this.keys.contains(key)){
   // Key found. 
   // Simply replace the value in Map
   this.values.put(key, value);
  }else{
   // Key not found
   // Add value to both Queue and Map
   this.enqueue(key, value);
  }
 }

 /**
  * Returns the value to which the specified key is associated,
  * or {@code null} if this Structure contains no association for the key.
  * <p>
  * More formally, if this map contains a mapping from a key
  * {@code k} to a value {@code v} such that {@code (key==null ? k==null :
  * key.equals(k))}, then this method returns {@code v}; otherwise
  * it returns {@code null}.  (There can be at most one such mapping.)
  * </p>
  *
  * @param key the key whose associated value is to be returned
  * @return the value to which the specified key is mapped, or
  *         {@code null} if this map contains no mapping for the key
  */
 public synchronized V getItem(K key){

  if(key==null)
   return null;

  V val = this.values.get(key);
  return val;
 }

 /**
  * Removes the mapping for a key from this Structure if it is present
  * (optional operation).   More formally, if this Structure contains a 
  * mapping from key <tt>k</tt> to value <tt>v</tt> such that
  * <code>(key==null ?  k==null : key.equals(k))</code>, that mapping
  * is removed.
  *
  * @param key key whose mapping is to be removed from the map
  */
 public synchronized void remove(K key){

  if(key == null)
   throw new NullPointerException("Cannot remove a null key");

  this.keys.remove(key);
  this.values.remove(key);
 }

 /**
  * Returns the number of elements in this collection.  
  * @return size of the structure.
  */
 public int size(){
  return this.keys.size();
 }

 /**
  * Removes all of the elements from this collection (optional operation). 
  * The collection will be empty after this method returns.
  */
 public void clear(){
  this.values.clear();
  this.keys.clear();
 }

 /*
  * Method implementing the actual logic to add 
  * the Key Value pair to the structure. 
  */
 private void enqueue(K key, V value){

  if(this.keys.size() < this.size){
   // We still have space in the queue
   // Add they entry in both queue and the Map
   if(this.keys.add(key)){
    this.values.put(key, value);
   }
  }else{
   // Queue is full. Need to remove the Head 
   // before we can add a new item.
   K old = this.keys.poll();
   if(old!=null)
    this.values.remove(old);

   // Now add the new item to both queue and the map
   this.keys.add(key);
   this.values.put(key, value);
  }
 }
}

Note here that the QueuedMap Data Structure that we created is using HashMap and LinkedList as the building blocks. Both of these DataStructures from Java Collection Framework allow null values to be stored, this is something that we have to handle ourselves. Also both of these DataStructures are not synchronized, i.e., they are not suitable for multi-threaded applications. Hence all the operational methods in this QueuedMap are marked as synchronized explicitly for thread safety.

I tried to provide some Guidelines of how we can create a new Data Structures by combining the existing functionality already provided by the Collection Framework. These are the same principles that are applied to any software development, wherever possible; reuse the existing functions, classes, methods. However, you still need to consider the pros and cons of the underlying building blocks. For example, since HashMap and LinkedList are not synchronized, we have to take care of that ourselves or alternatively use some other implementations of Queue and Map that provide thread safety.

This gives you basic building blocks to come up with your own ideas and create more complex data structures according to your requirements. One good change to this Data Structure may be to implement this as a Priority Queue where instead of removing the oldest entry, you remove the least accessed entry. The possibilities are endless.