Chapter 14. Database Maintenance

Table of Contents

Using DBMaint
Using DBMaint
DBMaint and Defineable Objects
A Step-By-Step Example
Directory Structure
Example Step-by-Step
Conclusion
Contributors

Note

If you find this EDG documentation helpful please consider DONATING! to keep the doc alive and current.

 Maintainer:Geeta Ramani

Expresso includes a powerful controller object for database maintenance. This controller can present add, update, search and delete options to authorized user without having to write any code beyond the underlying database object (or not even that, when using "AutoDBObject" classes).

This eliminates the need to create custom table maintenance code in your application, yet still retains complete flexibility of presentation, as we will see.

There are many examples of the use of the database maintenance Controller in Expresso itself.

The DBMaint controller is designed to allow easy extensibility. This is done by making each of the commands that DBMaint responds to an extensible object in itself. These objects are stored in the com.jcorporate.services.controller.dbmaint package, and may be extended for custom functionality if required.

Using DBMaint

In order to use DBMaint you first must define a secured database object (SecuredDBObject). This is in practice very simple:

  • Decide which package your new object will reside in. It should not be within the directories used by Expresso. We recommend a package name of the form "com.javacorporate.ext.application.dbobj", where "application" is the application you are working to create - for example, if it is a Human Resources application, you might choose "hr", so the package name would be "com.javacorporate.ext.hr.dbobj". The object name should reflect it's intended purpose: let's say you are creating an object to maintain an Employee database, you might name it "Employee".

  • Copy an existing SecuredDBObject definition out of Expresso to use as a template - saves some typing! We recommend the object com.javacorporate.common.dbobj.User as a nice simple example.

  • Modify the copied object, replacing all instances of the name "User" with the name "Employee", modifying the package definition, and of course the target table and field definitions to match the table you wish to have in your database. See the JavaDoc documentation for the SecuredDBObject object for details.

  • You may at this point decide to manually create the table to hold the Employee object - there is a way to have Expresso do this for you, discussed in the section on Schema objects.

  • Compile your new object so that it's class file is available.

Now you create a link to your new database object using the DBMaint servlet:

  • Select the web page you are going to call the maintenance function from: Let's assume it's called "hr.html".

  • On this page, create a link for the List, Add, and Search functions for your new object - you may want to use the images and format that are used within Expresso - these can be copied from a page such as "server.html" in the /components/expresso directory of the HTML download.

  • Each link should have the following form: "/DBMaint.do?dbobj=com.javacorporate.ext.hr.dbobj.Employee&state=Add"

  • The last parameter (cmd) can have one of three values:

    • Add: Bring up a full-screen form to accept a new entry for this database object

    • List: List all existing records database object

    • Search: Bring up a form to accept search criteria for locating one or more records for this object

      Of course, the List option must be used with caution if the number of records is likely to get large (there is a facility to limit the number of records shown and to provide pagination, however). There is also an Update argument, see the JavaDoc for the DBMaint object for details.

  • Create a database object security entry for your new object: See the help file for "Database Object Security" for information on how to do this.

That's it - you now have a fully functional, secured database maintenance servlet.

Using DBMaint

Once you have coded your SecuredDBObject, you can immediately take advantage of the "Automatic" database maintenance capability of Expresso - the DBMaint Controller. This Controller allows you to provide to your users, Add, Update, Delete and Search capabilities for any SecuredDBObject, without any coding at all!

The servlet works on any SecuredDBObject, specified as a parameter, and can perform any of a number of different commands. For example:

1.  /DBMaint.do?dbobj=com.yourcompany.dbobj.Customer&state=List

will list all records (subject to a page size specified in Expresso and discussed later) in the table corresponding to the Customer DBObject. (Assuming the user issuing the request has Search permission on Customer.)

The list of options for "state" (which is extensible by coding new objects for the com.jcorporate.expresso.services.controller.dbmaint package) includes:

  • Search: Present a query form for the user to enter search criteria to look up records.

  • Add: Present a blank form for the user to enter a new record.

  • Update: (requires "key" parameter as well) Presents an existing record for the user to update.

  • List: Lists the records (or the current query results) and allows the user to select a record for update.

  • SearchList: Given special parameters for a given key, display all records that match the given criteria. You do this by matching the parameter field names to the DBObject field. For example, if you add the parameters &id=10 to the parameter, then if you had a field named id, it would set that field name to 10 and perform a search against the database.

    A classic example of this is displaying all setup items for your schema:

    /DBMaint.do?dbobj=com.jcorporate.expresso.services.dbobj.Setup
    &SchemaClass=com.jcorporate.expresso.core.ExpressoSchema&state=SearchList
    
    The URL would normally appear all on one line. The results would be a listing of all setup codes belonging to the Expresso Schema. Substitute the SchemaClass parameter value for your own schemas to have the same result.

All of the forms present icons for the user to move from mode to mode, making DBMaint a complete database maintenance application for your DBObject.

Expresso's own administrative pages provide good examples of the use of DBMaint. See the Expresso Users Guide for details of DBMaint's operation.

DBMaint and Defineable Objects

As introduced in the earlier chapters on DBObjects, as of Expresso 5.1, DBMaint is designed to cope with any class implementing the DataObject interfaces. Some of these objects such as JoinedDataObject and AutoDBObject also need other parameters to properly instantiate other than the class name. These classes implement the com.jcorporate.expresso.core.dataobjects.Defineable interface. The way to get the name of the definition to the Definable object is added the definition parameter. An example is:

	/DBMaint.do?dbobj=[objectname]&definition=[definitionName]&state=List
The actual value to insert as the definition name varies depending on the object. For example, AutoDBObject uses database table names for definition names, JoinedDataObject uses the path to the xml file describing the join. Check the javadocs for the class you wish DBMaint to use for information on using the definition.

A Step-By-Step Example

This is an example of building a simple application to allow maintenance of a customer database, complete with security. The application will use a customer maintenance form as a beginning for a more sophisticated sales tracking application.

Directory Structure

A word first about directory structure. Assume that the root of the Expresso directory is at $Expresso_dir. So for example, under this directory would be folders like "expresso" (containing the html/jsp pages for the Expresso application itself like "toc.jsp" and "frame.jsp", an "images" folder and so on.) $Expresso_dir would also contain the WEB-INF folder, within which you should have the usual "classes" folder, the "lib" folder and so on. Drilling down into the classes folder, you should see "com/jcorporate/expresso" with further subfolders. These, along with the lib archives, hold most (or all?) the classes that do the main work in setting up the Expresso framework.

Note

You could of course choose to not follow this directory structure. The important thing to know is that the classes you write should be within the WEB-INF/classes folder (in some logical order) because we want to stay within the same context as is Expresso. For a detailed discussion about this, read the thread entitled "EXPRESSO DEVELOPER'S GUIDE CHAPTER ZERO" in the "Expresso discussions about features, installation, direction & ideas" group of the Expresso forum.

Also note that should you change your directory structure, you will have to appropriately change the code below as well as the name of the Schema class in step 6 below.

Classes

The classes for the sales application that we will build will belong to a package called com.jcorporate.ext.sales.dbobj. So first create a directory called "ext" in $Expresso-dir/WEB-INF/classes/com/jcorporate. Then within "ext", create a directory called "sales" and within "sales" yet another directory called "dbobj". The (two) classes that we write for this application will be placed in this directory: $Expresso_dir/WEB-INF/classes/com/jcorporate/ext/sales/dbobj.

jsps

The jsps for the sales application will be held in $Expresso-dir/expresso/components/sales. If you follow this convention, when we are done, you will get an clickable icon for the Sales Application on your Expresso homepage left-hand nav bar. The jsps needed for maintaining the Sales database will be held in $Expresso-dir/expresso/components/sales/dbmaint/.

You may also at this time want to look inside the folder $Expresso-dir/expresso/. The jsps and html pages for the apps that Expresso itself uses (like Login, Dbmaint, etc.) are stored in this directory. For example the dbmaint jsps that Expresso uses are in the subdirectory $Expresso-dir/expresso/jsp/dbmaint. Further, jsps for eforum, ePoll, etc. are held in $Expresso-dir/expresso/components/eforum and $Expresso-dir/expresso/components/epoll.

Example Step-by-Step

  1. Define a database object, "Customer" by creating a Customer.java as follows:

    Let's assume for the sake of this example that you've installed Expresso in /usr/java/lib/com/jcorporate. Your CLASSPATH would then have to include /usr/java/lib. (Of course, the CLASSPATH for your servlet engine also has to include this directory - see the installation section for details).

    1. First we create the directory /usr/java/lib/com/jcorporate/ext, where we are going to define "extensions" to the Jcorporate Expresso framework. The package name could just as easily be outside the jcorporate directory if so desired.

    2. Within the "ext" directory, we create a directory for our package, called "sales" (e.g. we create /usr/java/lib/com/jcorporate/expresso/ext/sales). Inside this we create another directory, called "dbobj" to hold our database objects.

      This long directory hierarchy is fairly typical to Java applications and helps keep packages well organized - again, we are only using these particular names in this example, if you want a different organization, that's OK too.

    3. Within the ext/dbobj directory, we create our database object, called "Customer.java". The following code defines our object:

      The comments within the source help describe the purpose of each section in the Code for Customer.java:

      /*
      * Customer.java
      */
      
      package com.jcorporate.ext.sales.dbobj;
      
      import com.jcorporate.expresso.core.dbobj.*;
      import com.jcorporate.expresso.core.db.DBConnection;
      import com.jcorporate.expresso.core.db.DBException;
      
      /**
      * A Customer object stores information about customers for our demo 
      * sales application.
      */
      public class Customer extends SecuredDBObject {
      
              private String thisClass = (this.getClass().getName() + ".");
      
         /**
           * There are three possible constructors for SecuredDBObjects
           * Usually there is no need to extend them for objects we implement
           */
          public Customer () throws DBException {
            super();
          } /* Customer() */
      
      
          /**
           * This constructor is used when a connection to the database
           * is supplied by the calling object
           */
           public Customer(DBConnection theConnection) throws DBException {
             super(theConnection);
           } /* User(DBConnection) */
      
           /**
            * This constructor is called by the DBMaintservlet
            * and supplies the name of the user trying to connect to the 
            * database object.
            */
            public Customer(DBConnection theConnection, String theUser) throws DBException {
              super(theConnection, theUser);
            } /* Customer(DBConnection, String) */
           /**
            * The setupFields method does the real work of establishing the 
            * definition of the DB object.
            */
            public void setupFields() throws DBException {
      
              /* Establish the primary database table for this object. */
              /* Note that there may be more than one, but this is the default */
              /* table */
              setTargetTable("CUSTOMER");
      
              /* Set a description for this object. This is a human-readable */
              /* string that appears at the top of forms when used with DBMaint */
              setDescription("Customers");
      
              /* Define each of the fields in the table */
              /* Note that the field types used here are "internal", and can be */
              /* mapped to other types for the underlying relational database */
              addField("CustomerNumber","int", 0,  false, "Customer ID Number");
              addField("CustomerName","varchar", 80, false, "Customer Name");
              addField("Phone", "varchar", 15, true, "Phone Number");
              addField("EMail", "varchar", 80, false, "Customer EMail");
      
              /* ... you could of course add many more fields for a production */
              /* object */
              /* addKey is called for each field in the primary key */
              addKey("CustomerNumber");
      
           } /* setupFields() */
                         
      
           /**
            * A utility method used when generating lists of objects
            */
           public DBObject getThisDBObj() throws DBException {
             return (Customer) new Customer();
           } /* getThisDBObj() */
      
       } /* Customer */
      

  2. Now compile the Customer.java object and correct any errors.

    If you have trouble compiling, remember that the CLASSPATH would have to include $Expresso-dir/WEB-INF/classes, the archives struts.jar, junit.jar, activation.jar, and log4j-core.jar in the $Expresso-dir/lib directory, as well as /common/lib/servlet.jar in the expresso root directory. (If you did not install the -complete bundle, you may need to download some of the jar files needed and/or find their exact location in your set-up.)

  3. Create a Schema object "Sales" by creating a Sales.java:

    The Schema object identifies the whole application and it's required DBObjects to the Expresso framework. It enables you to use Expresso's automatic facilities for creating tables and configuration values to your advantage, saving work when setting up your application.

    In the same "dbobj" directory, create a java file "Sales.java" as below. This simple Schema would be extended as you add new objects to your new application.

    Code for Sales.java:

    
     /**
     * Schema object for the Sales demo application
     */
      package com.jcorporate.ext.sales.dbobj;
    
      import com.jcorporate.expresso.core.dbobj.*;
      import com.jcorporate.expresso.core.db.DBException;
    
      public class Sales extends Schema {
    
        /**
        * Default Constructor
        */
       public Sales() throws DBException {
          super();
             
          /* add is called for each object to be a "member" of this schema */
          addDBObject("com.jcorporate.ext.sales.dbobj.Customer");
    
        } /* constructor */ 
    
    
       /**
         * Return the path, relative to the classpath, of the MessageBundle file for
         * this schema. For example, the Expresso schema
         * (com.jcorporate.expresso.core.ExpressoSchema) returns
         * "com/jcorporate/expresso/core", as this is where it's message files are stored.
         *
         * @return
         */
        public String getMessageBundlePath(){
            return ("com/jcorporate/ext/sales/dbobj");
        }
        /* getMessageBundlePath() */
    
    
        public String getDefaultDescription(){
            return ("Example Sales Schema");
        }
    
        public String getDefaultComponentCode(){
        /*  The framework finds the jsp pages here (within the "components" subdirectory)*/
            return ("sales"); 
        }
    
       /* Other methods are optional in the Schema object - see the Javadoc */
       /* for details */
                    
     } /* End Sales Schema*/
    
    

  4. Again, compile the Sales.java object and correct any errors.

  5. Next, we create and configure the jsps for this application.

    There are three things you need to do.

    • First create a subdirectory called "sales" in $Expresso-dir/expresso/components/ and save frame.jsp as below in it:

      Code for frame.jsp:

      <%@ page language="java" %>
      <%@ page import="com.jcorporate.expresso.core.misc.StringUtil" %>
      <%@ page import="com.jcorporate.expresso.core.misc.ConfigManager" %>
      <%@ page import="com.jcorporate.expresso.services.dbobj.Setup" %>
      <%@ page import="com.jcorporate.expresso.core.db.DBException" %>
      <%@ page import="com.jcorporate.expresso.core.jsdkapi.GenericSession" %>
      <%@ page import="com.jcorporate.expresso.core.servlet.CheckLogin" %>
      
      <html>
      
      <head>
      
      <meta http-equiv="cache-control" content="no-cache">
      <meta http-equiv="expires" content="0">
      <meta name="pragma" CONTENT="no-cache">
      <title>Sales App Home Page</title>
      
      </head>
      
      <body bgcolor="WHITE" link="#0000cc" vlink="#0000cc">
      
      <%
      String db = "";
      db = GenericSession.getAttributeString(request, "db");
              if (db == null || db.equals("") ) {
                  db = "default";
              }
      
      String contextPath = StringUtil.notNull(Setup.getValue(db, "ContextPath"));
      %>
      <center>
      <table border=1 cellpadding="4" cellspacing="0">
      
      <tr><th>Maintain the Customer table in the Sales database</th></tr>
      <tr><td>
      <a href="<%= contextPath %>/DBMaintCustomer.do?dbobj=com.jcorporate.ext.sales.dbobj.Customer&state=Add">Add a Customer!</a>
      </td></tr>
      <tr><td>
      <a href="<%= contextPath %>/DBMaintCustomer.do?back=&fields=&dbobj=com.jcorporate.ext.sales.dbobj.Customer&state=List">Manage Customers!</a>
      </td></tr>
      <tr><td>
      <a href="<%= contextPath %>/DBMaintCustomer.do?back=&fields=&dbobj=com.jcorporate.ext.sales.dbobj.Customer&state=Search">Search for Customer!</a>
      </td></tr>
      </table>
      </center>
      
      </body>
      </html>
      

      The main thing to notice here is the structure of the links: For example, reference to the the link "<%= contextPath %>/DBMaintCustomer.do?dbobj=com.jcorporate.ext.sales.dbobj.Customer&state=Add says that the DBMaintCustomer is being invoked to act on the dbobject called "Customer" with a state of "Add". Further on, you will see that we will edit the strus-config.xml file to say that when we invoke DBMaintCustomer, we actually mean DBMaint (the "type" attribute for the "action" DBMaintCustomer will explicitly point to the class "com.jcorporate.expresso.services.controller.DBMaint"). The source of this class will tell you that the "states" which are allowed include "Add", "List", "Search", etc. - which is why this link as shown works.

    • Second, create a subdirectory "dbmaint" in $Expresso-dir/expresso/components/sales.

      (Refer to the note above regarding directory structure.) Copy "update.jsp", "search.jsp", "list.jsp", "add.jsp" and header.inc and tabs.inc from $Expresso_dir/expresso/jsp/dbmaint/ into $Expresso-dir/expresso/components/sales/dbmaint.

    • Finally, you have to edit the struts-config.xml in the $Expresso-dir/config directory.

      (Make a backup first!!) Scroll down to the "Action Mapping Definitions" portion and add the following below the "Database Maintanance" portion for the "DbMaint"(You could just cut and paste the DBMaint portion and then edit the path values):

          <!-- Customer Database Maintainance for Sales Application -->
          <action path="/DBMaintCustomer"
                  type="com.jcorporate.expresso.services.controller.DBMaint"
                  name="default"
                  scope="request"
                  validate="false">
              <forward name="Update" path="/expresso/components/sales/dbmaint/update.jsp" />
              <forward name="Search" path="/expresso/components/sales/dbmaint/search.jsp" />
              <forward name="SearchList" path="/expresso/components/sales/dbmaint/list.jsp" />
              <forward name="List" path="/expresso/components/sales/dbmaint/list.jsp" />
              <forward name="Add" path="/expresso/components/sales/dbmaint/add.jsp" />
          </action>
          <!-- End Customer Database Maintainance for Sales Application -->
      

  6. Reload struts-config.xml

    Just go to: http://<hostname>:<port>/expresso/admin/reload.do (Expresso will out-do itself by displaying a page which says "OK". ;-)

  7. Register your new Schema as follows:

    Now you must tell the Expresso framework about the existence of your new schema, so that the Initialize function can correctly access your Schema object as follows:

    • In your web browser, go to the Expresso pages that you downloaded from the jcorporate site (i.e. yourserver/expresso/frame.jsp).

    • Click the "Applications" link in the left-hand column.Scroll down to the bottom of the page.

    • On the line entitled "Application Schema Objects" click the "plus" sign to add a new entry.

    • For the "Schema Class File" field, enter "com.jcorporate.ext.sales.dbobj.Sales", the name of the object for the Schema we just created.Careful with case/spelling/path!! Mistakes are easily made here and Expresso will not notify you - things will just not work!!. Further, if you chose a different directory structure fom the one mentioned in this document, your schema class file should reflect that change.

    • For the "Schema Description" field, enter "Sales Application".For component code, enter "sales"

  8. Run the DBCreate servlet as follows:

    This step will create the database table for your new (Customer) object, and also insert default security entries so that the "Admin" group (and the Admin user) will have full access to the newly created table.

    • Go back to your expresso/frame.jsp in your browser window.

    • Click the "Setup" link in the left-hand column.

    • Click on "Create/Verify Database Structure and Perform Initial Setup". On the resulting page, leave all boxes checked and click the "Run" button.

    • In a moment or two, you will see output confirming that the Customer table has been initialized and that security entries have been created.

    • When you are done admiring the messages on the screen, click on "Setup" in the left navigational frame.

  9. Log In as Admin

    Click on the "Login" icon on top right of the page to log yourself in as Admin using a user name and password of "Admin" and "" respectively. As your new Schema object is only accessible as Admin at this point, that is who you must be in order to test it out. Later of course you can add security for other groups/users (described in the next step).

  10. Secure the Sales Schema as follows:

    • Click on the "Security" link on the left hand navigational frame. Then click on the "Administer Database Object Security" link in the table that appears. If all the steps above went through correctly, you should see "Sales Application" as well as "General" against the dropdown list labelled "Choose Schema". If you don't see the Sales schema listed, you need to recheck your work so far because none of the subsequent steps will work.

    • Choose the "Sales Application" schema, and click on "Set Security".

    • The resulting page should have a table with exactly one entry: Customers. Check all the boxes and click on "Update".

  11. Finally check the application as follows:

    • Bring up your Expresso Home Page (http://<hostname>:<port>/expresso/frame.jsp) on your browser window. If you followed the suggested directory structure, you should see a link on your Expresso pages (frame.jsp) to the Sales application labelled "Sales Application". (You may have to reload/restart the servlet engine!.) You may of course also directly access the Sales App with a uri which is something like: http://www.yourcompany.com/expresso/components/sales/frame.jsp or http://www.yourcompany.com:8080/expresso/components/sales/frame.jsp.

    • Now pick your favourite administrative task, and from here on life's a bed of roses!

      Note

      When you add columns to the Customer table be careful to follow the table column data types: the error messages that appear if you don't are not particularly helpful!). The following four-tuple, for example, should work:

      1234, Geeta Ramani, 800-123-4567 and geeta.ramani@cmpco.com

  12. This completes the DBMaint-Step-by-Step example.

    You can extend it as follows:

    • Create more tables by writing appropriate dbObject classes (one for each table you want created).

    • Then add these classes to the $Expresso_dir/WEB-INF/classes/com/jcorporate/ext/sales/dbobj folder.

    • Rewrite the schema Sales.java so that all these objects are added in the constructor.

    • Recompile everything.

    • Then go to the "Applications" link, scroll down to the bottom and click on the "Application Schema Objects" link. You should see a page listing the Sales schema that we had created earlier). Click on it and in the subsequent page click on "Delete". This "delete" step is most probably NOT neccessary, but I haven't tested it.

    • You can now carry out steps 7 through 11 and you should be done!

  13. A Final Note.

    Of course you should be able to give the jsps whatever look and feel you want by editting the appropriate "views" in the /sales/dbmaint folder. A biggie here is to just modify the default.css stylesheets. You can get some amazing results just by tweaking here. This way, you automatically get the color scheme that fits your application. If you don't care about changing the "default" look and feel that Expresso has already provided, you may cut short your work by replacing Step 5 above as follows:

    • Change the links in $Expresso-dir/expresso/components/sales/frame.jsp to point instead to DBMaint.do?dbobj=com.jcorporate.ext.sales.dbobj.Customer&state=Add, etc.

    • You don't need to create any new jsps.

    • Don't bother to edit struts-config.xml.

    Carry on with Steps 7 through 11 and you should be done.

Conclusion

Contributors

The following persons have contributed their time to this chapter:

Note

Was this EDG documentation helpful? Do you wish to express your appreciation for the time expended over years developing the EDG doc? We now accept and appreciate monetary donations. Your support will keep the EDG doc alive and current. Please click the Donate button and enter ANY amount you think the EDG doc is worth. In appreciation of a $35+ donation, we'll give you a subscription service by emailing you notifications of doc updates; and donations $75+ will also receive an Expresso T-shirt. All online donation forms are SSL secured and payment can be made via Credit Card or your Paypal account. Thank you in advance.

Copyright © 2001-2004 Jcorporate Ltd. All rights reserved.