8-Dec-05 (Created: 8-Dec-05) | More in '00.05-Articles'

Servlet Based Reosurce Readers in J2EE applications

Problem

In a j2ee web app one needs to read config files, test data files, or xml files or xslt files at run time. If you read them from a file directory, the directories may not be valid at run time inside the web app container. One can use the class loader instead to load these files. But I prefer to read them using the servlet context of an init servlet. The approach will also work for containers that only work with war files (WebSphere is an example).

How to use a resource reader to read files


String relativeFilename = "/somedir/somfile.xml";
InputStream is = ResourceReader.readResourceUsingRelativeURL(relativeFilename);
//work with is
is.close();

ResourceReader is a static class in which all the methods are static. The method here will read a file called "/somedir/somefile.xml" from the root of the web app.

Source code of the ResourceReader


public class ResourceReader  
{
   private static ServletContext m_ctx;

   //Called from any int servlet's init method
   public static void init(ServletContext ctx)
   {
      if (m_ctx == null)
      {
         m_ctx = ctx;
      }
   }
   
   //if needed. Usually not required.
   public static ServletContext getServletContext()
   {
      return m_ctx;
   }
   
   /**
    * Given a relative url return an input stream for that url
    * @param relativeUrl
    * @return
    */
   public static InputStream readResourceUsingRelativeURL(String relativeUrl)
   {
      return m_ctx.getResourceAsStream(relativeUrl);
   }
   
   /**
    * Given an input stream return the contents of the stream as a string
    * @param iStream
    * @return
    */
   public static String getContentsAsAString(String relativeUrl)
   {
      return readContents(
               new BufferedReader(
                  new InputStreamReader(
                     readResourceUsingRelativeURL(relativeUrl))));
   }
   
   private static String readContents(BufferedReader input)
   {
      try
      {
         StringBuffer contents = new StringBuffer();
         String line = null; //not declared within while loop
          while ( (line = input.readLine()) != null) 
          {
            contents.append(line);
            contents.append(System.getProperty("line.separator"));
          }
          return contents.toString();
      }
       catch (IOException ex) 
       {
        throw new RuntimeException("Could not read the input buffered reader",ex);
       }
       finally 
       {
          //I am not sure why we are closing it, if we are not the owner
          //of this resource
          try 
          {
            if (input != null) 
            {
             //flush and close both "input" and its underlying Reader
             input.close();
            }
          }
          catch (IOException ex) 
          {
            ex.printStackTrace();
          }
       }
   }
}//eof-class

You can improve upon the code a little bit. Closing the input stream is a bit sneaky in the above code. The closing of a stream should preferably be done by the owner of the stream.

Initializing the resourcereader


public class InitServlet extends HttpServlet
{
    public void init(ServletConfig config) throws ServletException
    {
       //set servlet context
      ResourceReader.init(config.getServletContext());
    }
}//eof-class