Example: Using ToolboxME for iSeries, MIDP, and JDBC

The following source illustrates one way that your ToolboxME for iSeries™ application can use the Mobile Information Device Profile (MIDP) and JDBC to access a database and store information offline.

This example demonstrates how a real estate agent might be able to view and bid on properties that are currently for sale. The agent uses a Tier0 device to access information for the properties, which is stored in the iSeries server database.

When built as a working program, the example code below connects to a database created for this purpose.

To create a working version of the source code and to obtain the source for creating and populating the required database, you must download the example. You also may want to review the instructions for creating and running the example program.

Note: Read the Code example disclaimer for important legal information.
//////////////////////////////////////////////////////////////////////////////////
//
// ToolboxME for iSeries example. This program is an example MIDlet that shows how
// you might code a JdbcMe application for the MIDP profile. Refer to the 
// startApp, pauseApp, destroyApp and commandAction methods to see how it handles
// each requested transition.
//
//////////////////////////////////////////////////////////////////////////////////

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import java.sql.*;
import javax.microedition.rms.*;

import com.ibm.as400.micro.*;


public class JdbcMidpBid extends MIDlet implements CommandListener
{
    private static int BID_PROPERTY = 0;
    private Display   display;

    private TextField urlText = new TextField("urltext",
                                              "jdbc:as400://mySystem;user=myUid;password=myPwd;",
                                              65,
                                              TextField.ANY);
    private TextField jdbcmeText = new TextField("jdbcmetext", "meserver=myMEServer", 40, TextField.ANY);
    private TextField jdbcmeTraceText = new TextField("jdbcmetracetext", "0", 10, TextField.ANY);
    private final static String GETBIDS = "No bids are available, select here to download bids";
    private List      main = new List("JdbcMe Bid Demo", Choice.IMPLICIT);
    private List      listings = null;
    private Form      aboutBox;
    private Form      bidForm;
    private Form      settingsForm;
    private int       bidRow = 0;
    private String    bidTarget = null;
    private String    bidTargetKey = null;
    private TextField bidText = new TextField("bidtext", "", 10, TextField.NUMERIC);
    private Form      errorForm = null;

    private Command exitCommand   = new Command("Exit", Command.SCREEN, 0);
    private Command backCommand   = new Command("Back", Command.SCREEN, 0);
    private Command cancelCommand = new Command("Cancel", Command.SCREEN, 0);
    private Command goCommand     = new Command("Go", Command.SCREEN, 1);
    private Displayable   onErrorGoBackTo = null;

    /*
     * Construct a new JdbcMidpBid.
     */
    public JdbcMidpBid()
    {
        display = Display.getDisplay(this);
    }

    /**
     * Show the main screen
     */
    public void startApp()
    {
        main.append("Show Bids", null);
        main.append("Get New Bids", null);
        main.append("Settings", null);
        main.append("About", null);
        main.addCommand(exitCommand);
        main.setCommandListener(this);

        display.setCurrent(main);
    }

    public void commandAction(Command c, Displayable s)
    {
        // All exitCommand processing is the same.
        if (c == exitCommand)
        {
            destroyApp(false);
            notifyDestroyed();
            return;
        }
        if (s instanceof List)
        {
            List     current = (List)s;

            // An action occurred on the main page
            if (current == main)
            {
                int   idx = current.getSelectedIndex();
                switch (idx)
                {
                case 0:     // Show current bids
                    showBids();
                    break;
                case 1:     // Get New Bids
                    getNewBids();
                    break;
                case 2:     // Settings
                    doSettings();
                    break;
                case 3:     // About
                    aboutBox();
                    break;
                default : 
                    break;
                }
                return;
            } // current == main

            // An action occurred on the listings page
            if (current == listings)
            {
                if (c == backCommand)
                {
                    display.setCurrent(main);
                    return;
                }
                if (c == List.SELECT_COMMAND)
                {
                    int idx = listings.getSelectedIndex();
                    String stext = listings.getString(idx);
                    if (stext.equals(GETBIDS))
                    {
                        getNewBids();
                        return;
                    }
                    int   commaIdx = stext.indexOf(',');
                    bidTargetKey = stext.substring(0, commaIdx);
                    bidTarget = stext.substring(commaIdx+1) + "\n";
                    // Also keep track of which offline result set row
                    // This is. It happens to be the same as the index
                    // in the list.
                    bidRow = idx;

                    bidOnProperty();
                }
            } // current == listings
            return;
        } // instanceof List
        if (s instanceof Form)
        {
            Form     current = (Form)s;
            if (current == errorForm)
            {
                if (c == backCommand)
                    display.setCurrent(onErrorGoBackTo);

                return;
            } // errorForm
            if (current == settingsForm)
            {
                if (c == backCommand)
                {
                    // Done with settings.
                    display.setCurrent(main);
                    settingsForm = null;
                    return;
                }
            } // settingsForm
            if (current == aboutBox)
            {
                if (c == backCommand)
                {
                    // Done with about box.
                    display.setCurrent(main);
                    aboutBox = null;
                    return;
                }
            }
            if (current == bidForm)
            {
                if (c == cancelCommand)
                {
                    display.setCurrent(listings);
                    bidForm = null;
                    return;
                }
                if (c == goCommand)
                {
                    submitBid();
                    if (display.getCurrent() != bidForm)
                    {
                        // If we're no longer positioned at the
                        // bidForm, we will get rid of it.
                        bidForm = null;
                    }
                    return;
                }
                return;
            } // current == bidForm
        } // instanceof Form
    }

    public void aboutBox()
    {
        aboutBox = new Form("aboutbox");
        aboutBox.setTitle("About");
        aboutBox.append(new StringItem("", "Midp RealEstate example for JdbcMe "));
        aboutBox.addCommand(backCommand);
        aboutBox.setCommandListener(this);
        display.setCurrent(aboutBox);
    }

    /**
     *  The settings form.
     */
    public void doSettings()
    {
        settingsForm = new Form("settingsform");
        settingsForm.setTitle("Settings");
        settingsForm.append(new StringItem("", "DB URL"));
        settingsForm.append(urlText);
        settingsForm.append(new StringItem("", "JdbcMe server"));
        settingsForm.append(jdbcmeText);
        settingsForm.append(new StringItem("", "Trace"));

        settingsForm.addCommand(backCommand);
        settingsForm.setCommandListener(this);
        display.setCurrent(settingsForm);
    }


    /**
     * Show the bid screen for the bid target
     * that we selected.
     */
    public void bidOnProperty()
    {
        StringItem item = new StringItem("", bidTarget);

        bidText = new TextField("bidtext", "", 10, TextField.NUMERIC);
        bidText.setString("");

        bidForm = new Form("bidform");
        bidForm.setTitle("Submit a bid for:");
        BID_PROPERTY = 0;
        bidForm.append(item);
        bidForm.append(new StringItem("", "Your bid:"));
        bidForm.append(bidText);
        bidForm.addCommand(cancelCommand);
        bidForm.addCommand(goCommand);
        bidForm.setCommandListener(this);
        display.setCurrent(bidForm);
    }

    /**
     * Update the listings card with the
     * current list of bids that we are interested in.
     */
    public void getNewBids()
    {
        // Reset the old listing
        listings = null;
        listings = new List("JdbcMe Bids", Choice.IMPLICIT);
        java.sql.Connection     conn = null;
        Statement               stmt = null;
        try
        {
            conn = DriverManager.getConnection(urlText.getString() + ";" + jdbcmeText.getString());

            stmt = conn.createStatement();

            // Since we do not want the prepared statement to persist,
            // a normal statement is really better in this environemnt.
            String sql = "select mls, address, currentbid from qjdbcme.realestate where currentbid <> 0";

            boolean results =((JdbcMeStatement)stmt).executeToOfflineData(sql,
                                                                          "JdbcMidpBidListings",
                                                                          0,
                                                                          0);
            if (results)
            {
                setupListingsFromOfflineData();
            }
            else
            {
                listings.append("No bids found", null);
                listings.addCommand(backCommand);
                listings.setCommandListener(this);
            }
        }
        catch (Exception e)
        {
            // Currently no valid listings retrieved, so lets
            // reset it to empty.
            listings = new List("JdbcMe Bids", Choice.IMPLICIT);
            listings.append(GETBIDS, null);
            listings.addCommand(backCommand);
            listings.setCommandListener(this);

            // Return to main after showing the error.
            showError(main, e);
            return;
        }
        finally
        {
            if (conn != null)
            {
                try
                {
                    conn.close();
                }
                catch (Exception e)
                {
                }
            }
            conn = null;
            stmt = null;
        }
        showBids();
    }

    public void setupListingsFromOfflineData()
    {
        // Skip the first four rows in the record store
        // (eyecatcher, version, num columns, sql column
        // types)
        // and each subsequent row in the record store is
        // a single column. Our query returns 3 columns which
        // we will return concatenated as a single string.
        ResultSet         rs = null;
        listings.addCommand(backCommand);
        listings.setCommandListener(this);
        try
        {
            int                     i = 5;
            int                     max = 0;
            StringBuffer   buf  = new StringBuffer(20);

            // Creator and dbtype unused in MIDP
            rs = new JdbcMeOfflineResultSet("JdbcMidpBidListings", 0, 0);
            if (rs == null)
            {
                // New listings...
                listings = new List("JdbcMe Bids", Choice.IMPLICIT);
                listings.append(GETBIDS, null);
                listings.addCommand(backCommand);
                listings.setCommandListener(this);
                return;
            }

            i = 0;
            String      s = null;
            while (rs.next())
            {
                ++i;

                s = rs.getString(1);
                buf.append(s);

                buf.append(",");
                s = rs.getString(2);
                buf.append(s);

                buf.append(", $");
                s = rs.getString(3);
                buf.append(s);

                listings.append(buf.toString(), null);
                buf.setLength(0);
            } 

            if (i == 0)
            {
                listings.append("No bids found", null);
                return;
            }
        }
        catch (Exception e)
        {
            // Currently no valid listings retrieved, so lets
            // reset it to empty.
            listings = new List("JdbcMe Bids", Choice.IMPLICIT);
            listings.append(GETBIDS, null);
            listings.addCommand(backCommand);
            listings.setCommandListener(this);

            // Return to main after showing the error.
            showError(main, e);
            return;
        }
        finally
        {
            if (rs != null)
            {
                try
                {
                    rs.close();
                }
                catch (Exception e)
                {
                }
                rs = null;
            }
            System.gc();
        }
    }

    /**
     * Update the listings card with the
     * current list of bids that we are interested in.
     */
    public void submitBid()
    {
        java.sql.Connection     conn = null;
        Statement               stmt = null;
        try
        {
            conn = DriverManager.getConnection(urlText.getString() + ";" + jdbcmeText.getString());

            stmt = conn.createStatement();

            // Since we do not want the prepared statement to persist,
            // a normal statement is really better in this environemnt.
            StringBuffer   buf = new StringBuffer(100);
            buf.append("Update QJdbcMe.RealEstate Set CurrentBid = ");
            buf.append(bidText.getString());
            buf.append(" Where MLS = '");
            buf.append(bidTargetKey);
            buf.append("' and CurrentBid < ");
            buf.append(bidText.getString());
            String      sql = buf.toString();

            int   updated = stmt.executeUpdate(sql);
            if (updated == 1)
            {
                // BID Accepted.
                String oldS = listings.getString(bidRow);
                int   commaIdx = bidTarget.indexOf(',');
                String bidAddr = bidTarget.substring(0, commaIdx);

                String newS = bidTargetKey + "," + bidAddr + ", $" + bidText.getString();

                ResultSet         rs = null;
                try
                {
                    // Creator and dbtype unused in MIDP
                    rs = new JdbcMeOfflineResultSet("JdbcMidpBidListings", 0, 0);
                    rs.absolute(bidRow+1);
                    rs.updateString(3, bidText.getString());
                    rs.close();
                }
                catch (Exception e)
                {
                    if (rs != null)
                        rs.close();
                }

                // Also update our live list of that result set.
                listings.set(bidRow, newS, null);
                display.setCurrent(listings);
                conn.commit();
            }
            else
            {
                conn.rollback();
                throw new SQLException("Failed to bid, someone beat you to it");
            }
        }
        catch (SQLException e)
        {
            // Return to the bid form after showing the error.
            showError(bidForm, e);
            return;
        }
        finally
        {
            if (conn != null)
            {
                try
                {
                    conn.close();
                }
                catch (Exception e)
                {
                }
            }
            conn = null;
            stmt = null;
        }

        // Exit without exception, then show the current bids
        showBids();
    }

    /**
     * Show an error condition.
     */
    public void showError(Displayable d, Exception e)
    {
        String s = e.toString();

        onErrorGoBackTo = d;
        errorForm = new Form("Error");
        errorForm.setTitle("SQL Error");
        errorForm.append(new StringItem("", s));
        errorForm.addCommand(backCommand);
        errorForm.setCommandListener(this);
        display.setCurrent(errorForm);
    }

    /**
     * Show the current bids.
     */
    public void showBids()
    {
        if (listings == null)
        {
            // If we have no current listings, lets set
            // them up.
            listings = new List("JdbcMe Bids", Choice.IMPLICIT);
            setupListingsFromOfflineData();
        }
        display.setCurrent(listings);
    }

    /**
     * Time to pause, free any space we do not need right now.
     */
    public void pauseApp()
    {
        display.setCurrent(null);
    }

    /**
     * Destroy must cleanup everything.
     */
    public void destroyApp(boolean unconditional)
    {
    }
}