************************************* * * * DB/C Newsletter * * January 2000 * * * ************************************* News and Comments ALERT! There is a nasty bug in DB/C 9.0 and DB/C 9.1 with a datestamp of May 1998 or earlier. The problem is essentially that PAUSE and *W don't terminate on February 29, 2000. You can find out more about this problem in the FAQs at http://www.dbcsoftware.com/dbcfaq.html#feb29. The solution is to obtain the final release of DB/C 9.1. Thank you to those who sent comments about last month's article on sending email directly from a DB/C program. One detail of that article needs to be clarified. When you attempt to send email to another person, you actually make a TCP connection with your own mail server, not the destination email server. Thus if your email address is me@mycompany.com and you are trying to send email to you@yourcompany.com, then in the DB/C program you make a TCP connection to the email server at mycompany.com, not the email server at yourcompany.com. You never actually attempt to connect to the destination email server - that's the job of your email server. Now that the Y2K issue is dead, many businesses are making e-business the number one priority for their Information Systems departments. Web processing of orders, customer service, etc. is one very important e-business issue. Several customers have asked us how to do this, while still using their existing DB/C database. Our standard response is that we believe the combination of Java servlets and DB/C FS provides the best solution in this situation. The next question is invariably "how do you do that?". This month's article answers that question. don.wills@dbcsoftware.com ***************************************************************************** An Example of using DB/C FS in a Java Servlet Java servlets are web-server based programs that dynamically create HTML and handle processing of HTML forms. The web page at http://java.sun.com/products/servlet/ is a good starting point if you are not familiar with the Java servlet technology. This article describes a simple example of a Java servlet. Its function is to allow a customer to check on the status of an order. The example uses the Java Client Programming Interface of DB/C FS that is described in Chapter 2 in the DB/C FS 2.1 Reference. This API allows Java programs to access DB/C files that are managed by a DB/C FS server using traditional DATABUS-like methods (e.g. open(), read(), readks(), write(), insert(), etc.) The first page of our example prompts for user name and password. It looks like this: +-----------------------------------------------------------+ | Demo Servlet Login | | | | +---------------+ | | User name: | | | | +---------------+ ************* | | * Login * | | +---------------+ ************* | | Password: | | | | +---------------+ | | | | | +-----------------------------------------------------------+ This first page is a static (pre-defined) HTML page. The HTML for this page is shown at the end of this article. When the Login pushbutton is pushed, the doPost method of the Java servlet named DemoServlet is called. This method makes a connection to the DB/C FS server. Once the connection is established, a file named "user.isi" is opened and the record that corresponds with the user name is read. If the record is found and the password matches, then DemoServlet dynamically creates a screen that looks like this: +-----------------------------------------------------------+ | Check Shipment Status | | | | ************* | | * Check * | | +---------------+ ************* | | Order Number: | | | | +---------------+ ************* | | * Cancel * | | ************* | | | +-----------------------------------------------------------+ If the Check pushbutton is pressed, a file named "order.isi" is opened and the record that corresponds with the order number is read. Three different results may be displayed. The first result is if the order number is not in the file, then an error message is displayed with a pushbutton labeled "Try Again". The second result is if the order number has not yet been shipped. An appropriate message is displayed with a pushbutton that is labeled "Check Again". The third result is if the order number has been shipped. An appropriate message is displayed with the "Check Again" pushbutton. When the "Try Again" or "Check Again" pushbutton is pushed, the Check Shipment Status page is again displayed. These are the steps that you need to do to run this example: 1. Install DB/C FS including setting up the configuration files 2. Install a web server (Apache is highly recommended) 3. Install the Java servlet module or interface to the web server 4. Put the demologin.html page in the web server HTML directory 5. Compile DemoServlet.java and make it available to the servlet JVM 6. Make sure the fs.jar file is also available to the servlet JVM 7. Create test files "user" and "order" with some records 8. Start the web server, the servlet JVM, and the DB/C FS server 9. Test with your browser by loading the demologin.html page And that's all there is to it! The source for DemoServlet.java and demologin.html follow. // // start of DemoServlet.java program // import java.io.*; import java.util.*; import javax.servlet.*; import javax.servlet.http.*; public class DemoServlet extends HttpServlet { // the web server pages - the ???s need to be changed for your site private final String SERVLET = "http://www.???.com/servlets/DemoServlet"; private final String DEMOLOGIN = "http://www.???.com/demologin.html"; // the next four variables are the DB/C FS server connection information private final String FSSERVER = "fsserver.???.com"; // change this private final String DBASE = "database"; // database.dbd file must exist private final String USER = "USER"; // USER must be in dbcfspwd.cfg private final String PASS = "PASSWORD"; // ditto // "user" file format is 8 char user, 8 char password // "order" file format is 8 char order number, 8 char order date (YYYYMMDD), // 1 char order status (S = shipped), 8 char ship date (YYYYMMDD) // these variables are key length, record length and file names for the files private final int USERKEYLEN = 8; private final int USERRECLEN = 16; private final String USERFILENAME = "user.isi"; private final int ORDERKEYLEN = 8; private final int ORDERRECLEN = 27; private final String ORDERFILENAME = "order.isi"; private final String[] months = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; // the doPost method is called when a pushbutton is pressed // the processing to be done depends on the name of the pushbutton // in this example, pushbutton names end with "pb" public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String pushbutton; try { Enumeration list = request.getParameterNames(); // loop through the input elements from this page looking for the pushbutton // that was pressed (our convention is its name ends with "pb") while (true) { pushbutton = (String) list.nextElement(); if (pushbutton.endsWith("pb")) break; } } catch (NoSuchElementException e) { return; } if (pushbutton.equals("loginpb")) { // the Login pushbutton login(request, response); return; } if (pushbutton.equals("checkshipmentpb")) { // the Check pushbutton checkshipment( request, response ); return; } if (pushbutton.equals("checkagainpb")) { // the Check Again pushbuton showcheckshipmentpage(response); return; } if (pushbutton.equals("loginagainpb")) { // the other pushbuttons response.sendRedirect(DEMOLOGIN); return; } } // process the Login pushbutton action private void login(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { char[] record = new char[USERRECLEN]; // get the user and password that were entered String user = request.getParameter("username").trim(); String passwd = request.getParameter("password").trim(); // check for basic user name and password validity if (user == null || user.length() < 2 || user.length() > 8 || passwd == null || passwd.length() < 2) { badUser(response); return; } while (user.length() < 8) user += " "; // pad with blanks // connect with the DB/C FS server com.swc.fs.Connection connection = null; try { connection = new com.swc.fs.Connection(FSSERVER, DBASE, USER, PASS); } catch (Exception e) { fatal(response, 901, e.toString()); return; } // open the user file and attempt to read the record try { // create File for "user" and set the open options com.swc.fs.File userfile = new com.swc.fs.File(connection); userfile.setindexfile(USERFILENAME); userfile.setoptions(userfile.getoptions() + com.swc.fs.File.IFILEOPEN); userfile.setrecsize(USERRECLEN); userfile.setkeysize(USERKEYLEN); userfile.setrecordbuffer(record); // actually open the file userfile.open(); // read a record int n1 = userfile.readkey(user); userfile.close(); // if n1 = -1 then record not found if (n1 == -1 || !passwd.equals((new String(record, 8, 8)).trim())) { badUser(response); return; } } catch (Exception e1) { fatal(response, 902, e1.toString()); return; } // user and password matched, create a sessioninfo to save values sessioninfo si1 = new sessioninfo(); si1.connection = connection; si1.user = user.trim(); // save the reference to sessioninfo instance in a new HttpSession instance HttpSession session = request.getSession(true); session.putValue("sessioninfo", si1); showcheckshipmentpage(response); } // show the check shipment entry page public void showcheckshipmentpage(HttpServletResponse response) throws ServletException, IOException { // output text HTML response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println("Check Shipment Status"); out.println(""); out.println("

Check Shipment Status

"); out.println("

"); out.println(""); out.println(""); out.println("
"); out.println("ORDER NUMBER:"); out.println(""); out.println(""); out.println(""); out.println("

"); out.println(""); out.println("

"); out.close(); } // process the check shipment request public void checkshipment(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String orderdate = null; String shipstatus = null; String shipdate = null; char[] record = new char[ORDERRECLEN]; // get the order number that was entered String ordernum = request.getParameter("ordernumber").trim(); if (ordernum == null || ordernum.length() < 1 || ordernum.length() > 8) { badOrderNum(response); return; } while (ordernum.length() < 8) ordernum = "0" + ordernum; // right justify // get the pre-existing HttpSession instance HttpSession session = request.getSession(false); if (session == null) { fatal(response, 903, "HttpSession is null"); return; } // get the sessioninfo instance we saved before sessioninfo si1 = (sessioninfo) session.getValue("sessioninfo"); // open and read the order file try { // create the order File and set open options com.swc.fs.File orderfile = new com.swc.fs.File(si1.connection); orderfile.setindexfile(ORDERFILENAME); orderfile.setoptions(orderfile.getoptions() + com.swc.fs.File.IFILEOPEN); orderfile.setrecsize(ORDERRECLEN); orderfile.setkeysize(ORDERKEYLEN); // open the file orderfile.open(); orderfile.setrecordbuffer(record); int n1 = orderfile.readkey(ordernum); orderfile.close(); // if n1 = -1 then the record was not found if (n1 == -1) { badOrderNum(response); return; } orderdate = new String(record, 8, 8); shipstatus = new String(record, 16, 1); shipdate = new String(record, 17, 1); } catch (Exception e) { fatal(response, 904, e.toString()); return; } showShipmentStatus(response, ordernum, orderdate, shipstatus, shipdate); } // display the order and shipping status public void showShipmentStatus(HttpServletResponse response, String s1, String s2, String s3, String s4) throws ServletException, IOException { // output text HTML response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println("Shipment Status"); out.println(""); out.println("
"); out.println("

Shipment Status


"); out.println(""); out.println("
"); out.println("Order number: " + s1 + "
"); out.println("Order date: "); out.println(months[Integer.parseInt(s2.substring(4,6))-1]); out.println(" " + s2.substring(6,8) + ", " + s2.substring(0,4)); if (s3.equals("N")) out.println("
Order not yet shipped."); else { out.println("
Ship date: "); out.println(months[Integer.parseInt(s4.substring(4,6))-1]); out.println(" " + s4.substring(6,8) + ", " + s4.substring(0,4)); } out.println("

"); out.println(""); out.println("

"); out.close(); } // bad user name or password public void badUser(HttpServletResponse response) throws ServletException, IOException { // output text HTML response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println("Error"); out.println(""); out.println(""); out.println("

Invalid user or password.

"); out.println(""); out.println("
"); out.close(); } // bad order number public void badOrderNum(HttpServletResponse response) throws ServletException, IOException { // output text HTML response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println("Order does not exist"); out.println(""); out.println(""); out.println("

Order number is not on file.


"); out.println(""); out.println("
"); out.close(); } // fatal error private void fatal(HttpServletResponse response, int errnum, String errmsg) throws ServletException, IOException { // output text HTML response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println("Fatal Error"); out.println(""); out.println("

Fatal Error

"); out.println(""); out.println("


Internal error number "); out.println(String.valueOf(errnum)); out.println(" has occurred that will make it impossible to continue."); out.println(""); out.println("

"); out.close(); // and die throw new ServletException("DemoServlet: " + errnum + ": " + errmsg); } } // this class lives across calls to the doPost method class sessioninfo { public com.swc.fs.Connection connection; public String user; } // // end of DemoServlet.java program // Here is the HTML source for the demologin.html page (be sure to change the "www.???.com" value): Demo Servlet Login

Demo Servlet Login

USER NAME:

PASSWORD:

***************************************************************************** Subscribing to the DB/C Newsletter If you don't already have the DB/C Newsletter delivered to your email address and would like to have it emailed to you when it is produced, just send an email message to 'request@dbcsoftware.com' and put the line 'subscribe dbcnews' in the body of the email message (omit the ' characters). The newsletter will be delivered to the email address from which the message was sent. To stop delivery, put the line 'unsubscribe dbcnews' in the body of the message.