Calling a Servlet in Java Code through a Post Request – or: how Service Oriented we Are

4

For one of our current Java development efforts – a Web application based on JSP, Struts, Oracle ADF technologies – we had to develop functionality to transforms HTML documents into PDF files. Wrapping a previously built set of classes in a well defined interface, we quickly had the job done. Then we started to integrate these classes into the project where the functionality was needed. We ran into several issues with versions of the libraries used. Then we stepped back, and started to rethink.

Why did we try to completely integrate the Html2Pdf converter in the Web Application itself? Why not think much more service oriented? Why not make this facility available in a more generic fashion? So we decided to create a Servlet frontend for our Html2Pdf converter component and package and deploy it as a web application in its own right. At this point, the web application we were building that needed this conversion functionality – with XSL-FO and Apache FOP inside – could simply call on the servlet, sending in the HTML document and receiving back an output stream that held the PDF document. And anyone else could also call upon this service. It can even run in an entirely different servlet container. The interface is as simple as a URL, accessed through a post-request with a single parameter.

Having made this decision made us feel a lot better. Decoupling, no hassle with the order of jars on the classpath, no recoding the Html2Pdf converter to work with the libraries used by the main web application. Having the service available to other applications as well. It is all too good to be true.

Well of course there is some overhead: the call to the servlet will be somewhat slower than a local call to an integrated class would have been. Then again, compared to the actual time it takes to create the XSL-FO and have FOP render the PDF, this additional overhead is negligible. Another drawback of the service oriented solution is of course the additional web application we have to manage. Once it is running, it should not require any administration, but it is an extra administrative burden.

Posting the HttpRequest to the Service URL from the Java application

Calling the service from Java is as simple as accessing a URL using the URLConnection object. Well, actually, even though I know it to be simple, I still had to look in one or two books and Google a little. It is not like I make URL calls, sending Post Requests all the time. But with all the resources I found – and I especially liked this one: http://www.marcellosendos.ch/booking/documentation/chapter2.html – it took me less than 20 minutes to get it to work, a call from Java to my Html2PDF service setup as a servlet:

package model.utils;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.URL;
import java.net.URLConnection;

public class Html2PDFServletTester  {
  public Html2PDFServletTester() {
  }
  // the hard-coded URL to the Service I want to invoke (should be injected of course)
  private static final String BASE_URL = "http://10.0.0.155:8988/HTML2PDFConverter-Client-context-root/servlet/Html2PdfServlet";

  public String parseISToString(InputStream is){
    DataInputStream din = new DataInputStream(is);
    StringBuffer sb = new StringBuffer();
    try {
      String line = null;
      while((line=din.readLine()) != null){
      sb.append(line+"\n");
      }
    } catch(Exception ex){
        ex.getMessage();
      }
      finally {
        try {
          is.close();
        } catch(Exception ex){}
    }
    return sb.toString();
  }

  public void convert()
  {
    // see http://www.marcellosendos.ch/booking/documentation/chapter2.html for example code
    try {
      HTML2PDFConverter converter = new HTML2PDFConverter();
      File inputFile = new File("theInputHtmlDocument.htm");
      FileInputStream in = new FileInputStream(inputFile);
      String inputHtml = parseISToString(in);


      URL url = new URL(BASE_URL);
      URLConnection con = url.openConnection();
       // inform the connection that we will send output and accept input
      con.setDoInput(true);
      con.setDoOutput(true);

     // Don't use a cached version of URL connection.
     con.setUseCaches (false);
     con.setDefaultUseCaches (false);
     con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
     // define a new PrintWriter on the output stream
     PrintWriter outWriter = new PrintWriter(con.getOutputStream());

     // send data to the servlet
     outWriter.print("htmlText="+inputHtml);
     outWriter.close();

     InputStream input = con.getInputStream();
     File outputFile = new File("TheResultingConverted.pdf");
     FileOutputStream out = new FileOutputStream(outputFile);

     boolean eof = false;
     // read all bytes from the input and write them to the output
     while (!eof) {
       int byteValue = input.read();        // read  the stream
       out.write(byteValue);
       if (byteValue  == -1)
         eof = true;
     }
     out.close();
    } catch(FileNotFoundException fnfe)
    {
      fnfe.printStackTrace();
    } catch(IOException ioe)
    {
      ioe.printStackTrace();
    }
  }

public static void main(String[] args) {
    Html2PDFServletTester h = new Html2PDFServletTester();
    h.convert();
}

}

Thanks to my nameless friends who share their code and suggestions. Thanks to Rob B. for getting it right in the end. Next time, we can find it here in this post…

Share.

About Author

Lucas Jellema, active in IT (and with Oracle) since 1994. Oracle ACE Director for Fusion Middleware. Consultant, trainer and instructor on diverse areas including Oracle Database (SQL & PLSQL), Service Oriented Architecture, BPM, ADF, Java in various shapes and forms and many other things. Author of the Oracle Press book: Oracle SOA Suite 11g Handbook. Frequent presenter on conferences such as JavaOne, Oracle OpenWorld, ODTUG Kaleidoscope, Devoxx and OBUG. Presenter for Oracle University Celebrity specials.

4 Comments

  1. hello friends i m harpreet as software develope in one company….i m try to access one servlet class to another class .i m unable to access………..i m sending following code…..plz help………….
    package a1;
    class abc
    {
    public void dis()
    {
    System.out.println(“hellodata”);
    }
    }

    javaser.java
    ————–
    import a1.abc;
    import java.io.*;
    import javax.servlet.*;
    import javax.servlet.http.*;
    import java.util.*;
    import javax.servlet.ServletContext;
    public class javaser extends HttpServlet
    {
    public void doGet(HttpServletRequest request,
    HttpServletResponse response)
    throws ServletException, IOException
    {
    PrintWriter out = response.getWriter();

    out.println(“”);
    out.println(“”);
    out.println(“Servlet test”);
    a1.abc=new a1.abc();
    out.println(“”);
    out.println(“”);
    }

    }
    Microsoft Windows XP [Version 5.1.2600]
    (C) Copyright 1985-2001 Microsoft Corp.

    C:\Documents and Settings\Abc>f:

    F:\>cd java core

    F:\java core>cd a1
    The system cannot find the path specified.

    F:\java core>e:

    E:\>cd java core

    E:\java core>cd a1

    E:\java core\a1>javac abc.java

    E:\java core\a1>javac -classpath “servlet-api.jar” javaser.java
    javaser.java:1: package a1 does not exist
    import a1.abc;
    ^
    javaser.java:18: cannot find symbol
    symbol : variable a1
    location: class javaser
    a1.abc=new a1.abc();
    ^
    javaser.java:18: package a1 does not exist
    a1.abc=new a1.abc();
    ^
    3 errors

  2. Instead of writing the output byte-by-byte, using buffer may improve the process for big file:

    // read all bytes from the input and write them to the output
    int bufLen = 1