[an error occurred while processing this directive]
> developer > web app development
Document Management System using jBroker Web 2.0
by Zulfi Umrani, Sr. Software Engineer, Novell
Date Created: 2002-08-30 13:35:00.000
  Why build a DMS -- and why do it with jBroker Web
  About jBroker Web 2.0
  Demo: building a DMS Web Service using jBroker Web
  Summary and possible enhancements
  Code listing
  For more information

This article demonstrates the capabilities of jBroker Web 2.0 in implementing real-life enterprise applications. The demo builds a simple client for a Document Management System (DMS) that lists the documents for a user on the console, stores a document, and retrieves the document back.

why build a DMS -- and why do it with jBroker Web
Why build a DMS -- and why do it with jBroker Web

Professions like doctor, lawyer, accountant, and so on require heavy use of documents. The documents are generally paper and stored in folders in file cabinets, and managing them takes considerable effort and physical space. Electronic document storage can help by vastly reducing the storage space required and streamlining document management.

This is where a DMS fits in. A typical DMS carries out functions like storing, retrieving, and deleting documents. A DMS has two components: the server manages the documents, and the client interacts with the server to store and retrieve the documents. Paper documents can be converted into electronic format using devices like scanners and put into the DMS.

Given the need to build a DMS, it makes sense to make the DMS Web-based, XML-based, and Java-based-here's why:

Web-based Since a DMS can be used by different users from various remote places, it makes sense to build the DMS as a service accessible from the Web. Emerging standards like SOAP and WSDL can be used to build such Web Services. The Simple Object Access Protocol (SOAP) is an XML-based standard to access remote objects using XML. The Web Services Definition Language (WSDL) is also XML based and can be used to define various operations or functions that a Web Service supports
XML-based XML is the most widely used standard for information exchange.
Java-based Java is the most widely used platform for developing Internet applications. The Java platform includes standards like J2EE that provide scalable application containers. It is easy to deploy Java applications in J2EE as well.

jBroker Web meets all these requirements, as described next.

about jBroker Web 2.0
jBroker Web is a toolkit for developing Web Service client and server applications. The SDK contains compilers and tools for building Web Services and a runtime for executing and testing Web Services. jBroker Web is a 100 percent pure Java implementation and supports standards such as SOAP, WSDL, and JAXRPC. jBroker Web brings the familiar programming model of Java RMI to the world of Web Services.

How jBroker Web works   The figure below shows the two most widely used compilers from jBroker Web. The rmi2soap compiler takes a Java remote interface as input and produces a SOAP stub and skeleton for it. The skeleton is Java servlet based. You can implement a Web Service using the skeleton and deploy it into any J2EE container.

The stub can be used by clients to invoke Web Services remotely. The stub is a proxy for the remote service, and it defines methods for all operations in a WSDL or remote interface. When a method is invoked with parameters, the stub sends a SOAP request to the endpoint specified in the WSDL. The SOAP request is produced by serializing the in and in/out parameters into XML. The SOAP message is then sent to the endpoint using HTTP, and the response is received. Finally, the stub deserializes the out and in/out parameters into Java objects and returns those objects to the calling method.

Similarly, the skeleton is responsible for listening to requests, deserializing the in and in/out parameters, dispatching the request to the appropriate method implementation, serializing the out and in/out parameters, and finally returning the SOAP response. The wsdl2java compiler produces similar stubs and skeletons, except that the input to this compiler is a WSDL document rather than a Java remote interface.

Key jBroker Web features   These are the key jBroker Web features essential for any enterprise application:

  • High performance SOAP engine
  • WSDL and XML schema compilers
  • HTTP session management
  • SOAP with attachments
  • SOAP message handlers
  • Interoperability with other SOAP engines such as .NET
  • Easy deployments into J2EE containers

Learn more about jBroker Web.

demo: building a DMS Web Service using jBroker Web
You can start building Web Service using jBroker Web either from a Java remote interface or a WSDL document. Since WSDL is tedious to write, it makes sense to start with a Java remote interface. The remote interface should define all methods or operations the Web Service requires.

 

Step 1: create the DocumentManager interface

Below is a very simple DocumentManager interface that has store, retrieve, delete, and list document methods. It also has a login method that allows users to log into their account and manage documents. This interface can be used to generate the Web Services code (stub, skeleton, and so on) using jBroker Web's rmi2soap compiler.

package dms;



public interface DocumentManager extends java.rmi.Remote

{

   void storeDocument(byte[] bytes, String fileName) 

      throws java.rmi.RemoteException;

   String[] listDocuments() throws java.rmi.RemoteException;

   byte[] retrieveDocument(String fileName) 

      throws java.rmi.RemoteException;

   void deleteDocument(String fileName) 

      throws java.rmi.RemoteException;

   void login(String userID, String password) 

      throws java.rmi.RemoteException;

}

 

Step 2: write the server implementation

Once the skeleton is generated, you need to write the concrete implementation for all methods in the remote interface. One way to write the server implementation is to derive the implementation class from the generated skeleton and then write method implementations. The DMS allows the user to log in, so the server has to be session aware. Since jBroker Web 2.0 generates a skeleton that is servlet based and implements the javax.xml.rpc.server.ServletEndpointContext interface from JAX-RPC, you can make use of the HttpSession in the servlet API for session tracking. As shown in the getSession method, the call to getEndpointContext returns implementation of the ServletEndpointContext interface through which you can get the HttpSession.

private HttpSession getSession()

{

   return getEndpointContext().getHttpSession();

}

The server stores the login information in the HttpSession and checks for authorization each time a method is invoked. Here are the methods from server that are used for login purposes:

private final String _loggedin = "user_logged_in";



private void isLoggedIn()

{

   HttpSession session = getSession();

   Object login = session.getAttribute(_loggedin);

   if (login == null)

      throw new Error("please login first");

}   



public void login(String userID, String password) 

   throws java.rmi.RemoteException

{

   // get the password of the user

   String pswd = _userProfiles.getProperty(userID + ".password");



   // check if password matches

   if (!pswd.equals(password)) 

      throw new Error("password did not match");



   // get the HTTP session

   HttpSession session = getSession();

        

   // store the userID in the session

   session.setAttribute(_loggedin, userID);

   session.setAttribute(_uid_prop, userID);

}

Here is the storeDocument method from the server:

public void storeDocument(byte[] bytes, String docName) 

   throws java.rmi.RemoteException 

{

   try

   {

      // check if the user is logged in

      isLoggedIn();



      // get the user id of the logged in user

      String userID = getUserID();

           

      // get the file name for the document to be stored

      String fileName = getFileName(docName, userID);



      // write the bytes to the file

      FileOutputStream fos = new FileOutputStream(fileName);

      fos.write(bytes);

      fos.close();

   }

   catch(IOException ioe)

   {

      ioe.printStackTrace();

      throw new Error("error storing file:" + ioe.getMessage());

   }

}

For the complete Server.java listing, see Code listing.

 

Step 3: write the sample client

Clients for DMS can be written in many ways. You can write a GUI-based client using Java Swing or an HTML-based client using JavaServer Pages (JSP). Because the DMS is a Web Service, you could also write the client in an entirely different language - for example, the client could be a .NET client.

As planned, this demo builds a simple client that displays information on the console for the user. It lists the documents and then stores a document and retrieves it back. Note that because the client takes part in a session, it has to set the SESSION_MAINTAIN property of the stub. jBroker Web uses cookies to track sessions. Here is the client method that returns the remote proxy of the Web Service:

private static DocumentManager getDocumentManager(String[] args)

   throws Exception

{

   // get the initial context

   InitialContext ctx = new InitialContext();



   // lookup the service

   DocumentManagerService svc = (DocumentManagerService)

      ctx.lookup("xmlrpc:soap:dms.DocumentManagerService");



   // get the stub for port

   DocumentManager docMgr = svc.getDocumentManagerPort();



   // set the end point address

   ((Stub)docMgr)._setProperty(

      javax.xml.rpc.Stub.ENDPOINT_ADDRESS_PROPERTY,

      args.length > 0 ? args[0] : "http://localhost:9090/dms");



   // turn on the session with server

   // please note that the client has to explicitly ask to 

   // take part in the session with the server

   ((Stub)docMgr)._setProperty(

      javax.xml.rpc.Stub.SESSION_MAINTAIN_PROPERTY, Boolean.TRUE);

   // return remote interface

   return docMgr;

}

For the complete Server.java listing, see Code listing.

summary and possible enhancements

This brief demo shows that jBroker Web 2.0 can be used to develop sophisticated Web Service applications.

The demo has been kept simple intentionally, to make it easy and quick to understand. But the demo client could easily be enhanced in various ways:

Enhancement Description
Back-end for storing information An RDBMS or LDAP backend could be used to store user profile and documents using JDBC.
Transfer over HTTP SOAP with attachments could be used to transfer files over HTTP.
HTTP authentication HTTP authentication could also be used as an alternative to the security implementation shown here. The jBroker Web 2.0 documentation describes how to deploy Web Services with HTTP authentication.
Compression The files being transferred could be compressed by the SOAP message handlers that implement an appropriate compression algorithm.
code listing

Server.java

package dms;



import java.io.*;

import java.util.*;



import javax.servlet.http.*;



public class Server extends DocumentManager_ServiceSkeleton

{

   private final String _loggedin = "user_logged_in";



   /** Check if user is logged in. If not logged in throw Error */

   private void isLoggedIn()

   {

      HttpSession session = getSession();

      Object login = session.getAttribute(_loggedin);

      if (login == null)

         throw new Error("please login first");

   }



   /** Get the HTTP session */

   private HttpSession getSession()

   {

      return getEndpointContext().getHttpSession();

   }



   private final String _uid_prop = "uid";



   /** Get the userID of the user of the session */

   private String getUserID()

   {

      return (String) getSession().getValue(_uid_prop);

   }



   /** Store the bytes into a file */

   public void storeDocument(byte[] bytes, String docName) 

      throws java.rmi.RemoteException 

   {

      try {

         // check if the user is logged in

         isLoggedIn();



         // get the user id of the logged in user

         String userID = getUserID();

            

         // get the file name for the document to be stored

         String fileName = getFileName(docName, userID);



         // write the bytes to the file

         FileOutputStream fos = new FileOutputStream(fileName);

         fos.write(bytes);

         fos.close();

      } catch (IOException ioe) {

         ioe.printStackTrace();

         throw new Error("error storing file:" + ioe.getMessage());

      }

   }



   /** List the document for a user */

   public String[] listDocuments() throws java.rmi.RemoteException

   {

      isLoggedIn();

      String userID = getUserID();

        

      // get the directory name where user's documents are stored

      String dirName = getUserDirectory(userID);

      File dir = new File(dirName);



      // get the file names of all the files in the directory

      File[] files = dir.listFiles();

      String[] fileNames = new String[files.length];

      for (int i =0; i < files.length; i++)

         fileNames[i] = files[i].getName();

      return fileNames;

   }

    

   /** Retrieve the document and return the bytes from it */

   public byte[] retrieveDocument(String docName) 

      throws java.rmi.RemoteException

   {

      String fileName = null;

      try {

         isLoggedIn();

         String userID = getUserID();

            

         // get the file name of the document

         fileName = getFileName(docName, userID);        



         // read the file and return the bytes read

         FileInputStream fis = new FileInputStream(fileName);

         ByteArrayOutputStream baos = new ByteArrayOutputStream();

         int c;

         while((c = fis.read()) != -1) baos.write(c);

            byte[] bytes = baos.toByteArray();

         fis.close();

         return bytes;

      } catch(IOException ioe) {

         ioe.printStackTrace();

         throw new Error("error reading file "+fileName+":"+ 

         ioe.getMessage());

      }

   }



   /** Delete the document */

   public void deleteDocument(String docName)

      throws java.rmi.RemoteException

   {

      String fileName = null;

      isLoggedIn();

      String userID = getUserID();



      fileName = getFileName(docName, userID);

      File file = new File(fileName);

      file.delete();

   }



   /** Login into the user account */

   public void login(String userID, String password)

      throws java.rmi.RemoteException

   {

      // get the password of the user

      String pswd = _userProfiles.getProperty(userID + ".password");



      // check if password matches

      if (!pswd.equals(password)) 

          throw new Error("password did not match");



      // get the HTTP session

      HttpSession session = getSession();

        

      // store the userID in the session

      session.setAttribute(_loggedin, userID);

      session.setAttribute(_uid_prop, userID);

   }



   /** Get the file name of the document for a user */

   private String getFileName(String name, String userID)

   {

      // get the user directory name 

      String fileName = getUserDirectory(userID);

      // return the document file name

      return fileName + File.separator + name;

   }



   /** Get the user directory name */

   private String getUserDirectory(String userID)

   {

      String fileName = _dbPath + File.separator + userID;

      File file = new File(fileName);

      if (!file.exists()) file.mkdir();

      return fileName;

   }

    

   /** Name of the directory where user directories exists */

   private final static String _dbPath;

   static {

       String dbPath = System.getProperty("dbpath");



       // if not specified then user the pwd

       if (dbPath == null) dbPath = ".";

          _dbPath = dbPath;

   }



   private static Properties _userProfiles = new Properties();

    

   static {

      try {

         // read the properties file which contains information

         // about users. It has 3 properties for each user.

         // <userID>.password, <userID>.firstName and <userID>.lastName

         // where <userID> is the userID of the user.

         FileInputStream fis = new FileInputStream("users.properties");

         _userProfiles.load(fis);

      } catch(Throwable e) {

          e.printStackTrace();

      }

   }

}

 

Client.java

package dms;



import java.io.*;



import javax.xml.rpc.Stub;

import javax.naming.InitialContext;



public class Client

{

   private static String _userID = "docmgt-user";

   private static String _pswd   = "docmgt-pswd";



   private DocumentManager _docMgr = null;



   public static void main(String[] args) throws Exception

   {

      Client client = new Client();

      client.run(args);

   }



   private void run(String[] args) throws Exception

   {

      // get the remote object 

      _docMgr = getDocumentManager(args);

        

      // login into user's account

      _docMgr.login(_userID, _pswd);

        

      String[] files  = null;

        

      // list the documents for user

      files  = _docMgr.listDocuments();       

      listDocuments(files);

        

      // get bytes of the file to send

      String fileName = "LICENSE.html";

      byte[] bytes = getBytes(fileName);



      // store the document

      _docMgr.storeDocument(bytes, fileName);

        

      // list the documents for user

      files  = _docMgr.listDocuments();       

      listDocuments(files);

        

      // retrieve the document

      bytes = _docMgr.retrieveDocument(fileName);     



      // save document as file

      try {

          FileOutputStream fos = new FileOutputStream("lic.html");

          fos.write(bytes);

          fos.close();

      } catch(Throwable e) {

          e.printStackTrace();

      }



      // delete document

      _docMgr.deleteDocument(fileName);



      // list the documents for user

      files  = _docMgr.listDocuments();       

      listDocuments(files);

   }



   /** Get the proxy for web service */

   private static DocumentManager getDocumentManager(String[] args) 

      throws Exception 

   {

      // get the initial context

      InitialContext ctx = new InitialContext();



      // lookup the service

      DocumentManagerService svc = (DocumentManagerService)

         ctx.lookup("xmlrpc:soap:dms.DocumentManagerService");

        

      // get the stub for port

      DocumentManager docMgr = svc.getDocumentManagerPort();

        

      // set the end point address

      ((Stub)docMgr)._setProperty(

         javax.xml.rpc.Stub.ENDPOINT_ADDRESS_PROPERTY, 

         args.length > 0 ? args[0] :"http://localhost:9090/dms");

        

      // turn on the session with server

      // please note that the client has to explicitly ask to 

      // take part in the session with the server

      ((Stub)docMgr)._setProperty(

         javax.xml.rpc.Stub.SESSION_MAINTAIN_PROPERTY, Boolean.TRUE);



      // return remote interface

      return docMgr;

   }



   /** Print the file names to the console */

   private void listDocuments(String[] files) throws Exception

   {

      if (files.length == 0) {

         System.out.println("No document found!");

      } else {

         for (int i = 0; i < files.length; i++) 

            System.out.println(files[i]);

      }

   }



   /** Get the bytes from a file */

   static byte[] getBytes(String fileName) throws Exception

   {

      FileInputStream fis = new FileInputStream(fileName);

      ByteArrayOutputStream baos = new ByteArrayOutputStream();

      int c;

      while((c = fis.read()) != -1) baos.write(c);

      return baos.toByteArray();

   }

}
for more information
To see Visit
Implementation of SOAP jBroker Web
All-in-one download of the Reference Implementations of the Java APIs for XML Java Web Services Developer Pack
Java API for XML-based RPC JAX-RPC
Simple Object Access Protocol 1.1 SOAP