Newsletter sign-up
View all newsletters

Sign up for our technology specific newsletters.

Enterprise Java
Email Address:

High-availability mobile applications

Mobile databases and J2ME tools

  • Digg
  • Reddit
  • SlashDot
  • Stumble
  • del.icio.us
  • Technorati
  • dzone

Page 3 of 7

An example application

Now, through a simple example, we examine typical usage scenarios and key components of mobile database applications.

Mobile contact manager in action

The example is a mobile contact manager application provided by PointBase. ContactManager is included in PointBase 4.x distributions. For your convenience, I have included the source code in a download zip file in Resources. If you want to build and run the examples yourself, you still must download the appropriate jar files from PointBase.

The application itself is simple: it mainly duplicates features commonly found in advanced address book applications. For example, it allows the user to store contact name, address, and phone numbers with pictures; provides intuitive browsing and searching interfaces; and synchronizes with backend database servers. Figures 1 and 2 demonstrate the application in action in the standalone mode and synchronized mode, respectively. The screenshots are from a Pocket PC powered by Insignia's Jeode PersonalJava VM and a Mac OS X laptop powered by J2SE. The same byte-code application runs without modification on many platforms, demonstrating Java's power.

Figure 1. Standalone ContactManager in action on Pocket PC Jeode PersonalJava

Figure 2. Two synchronized ContactManager spokes in action on Mac OS X. Click on thumbnail to view full-size image.

The client-side application UI (user interface) is written with AWT (Abstract Window Toolkit), the only standard UI library supported on PersonalJava or J2ME/FP/PP devices. Behind those UI drivers, we have another code layer that provides access to a generic on-device JDBC database. The database access layer also provides logics to synchronize mobile databases with backend databases through PointBase's proprietary UniSync synchronization server. Now, we focus on the code in the data access layer, which is contained in a single class: DBManager.

On-device data access

Class DBManager is a singleton class that provides a single point of entry to the database from the application. The Singleton pattern avoids threading complexities for embedded databases. The code snippet below shows DBManager's constructor and initialization method. It connects to the database, loads the table schema, populates the table with sample data, and creates SQL statement templates (PreparedStatement) for later use. As we can see, everything here is standard JDBC. For enterprise Java developers, the following code should be easy to understand:

Listing 1. Connect to mobile database and initialize access objects

class DBManager {
  // DBManager is a singleton class.
  private static DBManager instance;
  private String driver;
  private String url;
  private String user;
  private String password;
  private boolean delay;
  private Connection connection;
  private Statement statement;
  private PreparedStatement insert;
  private PreparedStatement find;
  private PreparedStatement delete;
  private PreparedStatement update;
  private PreparedStatement all;
  static DBManager getInstance() {
    if (instance == null) {
      instance = new DBManager();
    }
    return instance;
  }
  private DBManager() {
    // Get parameters from runtime properties.
    // This allows us to switch to different JDBC databases
    // without changing the application code.
    Properties properties = ContactManager.getProperties();
    driver =
      properties.getProperty("driver", "com.pointbase.me.jdbc.jdbcDriver");
    url =
      properties.getProperty("url", "jdbc:pointbase:micro:pbdemo");
    user =
      properties.getProperty("user", "PBPUBLIC");
    password =
      properties.getProperty("password", "PBPUBLIC");
    delay =
      properties.getProperty("delayread","true").equals("true");
    connect();
  }
  private void connect() {
    try {
      // Load the driver class.
      Class.forName(driver);
      // If the database doesn't exist, create a new database.
      connection = DriverManager.getConnection(url, user, password);
      // Create template statement objects.
      statement = connection.createStatement();
      createStatement();
      // If the database is newly created, load the schema.
      boolean newdb=initDatabase();
      // Load sample data for the new tables.
      if(newdb) {
         SampleDataCreator.insert(connection);
      }
    } catch (Exception e) {
      e.printStackTrace();
      System.exit(1);
    }
  }
  void disconnect() {
    try {
      connection.commit();
      statement.close();
      insert.close();
      find.close();
      delete.close();
      update.close();
      all.close();
      connection.close();
      System.exit(0);
    } catch (Exception e) {
      e.printStackTrace();
      System.exit(1);
    }
  }
  // Create the table and load the schema.
  private boolean initDatabase() {
    try {
      String sql = "CREATE TABLE NameCard (ID INT PRIMARY KEY, "+
        "Name VARCHAR(254), Company VARCHAR(254), Title VARCHAR(254), "+
        "Address1 VARCHAR(254), Address2 VARCHAR(254), "+
        "Phone VARCHAR(254), Email VARCHAR(254), "+
        "Picture Binary(1000000))";
      // If the table already exists, this will throw an exception.
      statement.executeUpdate(sql);
      // This means the database already exists.
      return true;
    } catch (SQLException e) {
      // Ignore the error - the table already exists, which is good
      // so we don't need to add demo data later on.
      return false;
    }
  }
  // Create statement templates.
  private void createStatement() {
    try {
      insert = connection.prepareStatement(
        "INSERT INTO NameCard (ID, Name, Company, Title, Address1, "+
        "Address2, Phone, Email, Picture) "+
        "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)");
      find = connection.prepareStatement(
        "SELECT * FROM NameCard WHERE (Name LIKE ?) "+
        "AND (Company LIKE ?) AND (Title LIKE ?) "+
        "AND ((Address1 LIKE ?) OR (Address2 LIKE ?)) "+
        "AND (Phone LIKE ?) AND (Email LIKE ?)");
      delete = connection.prepareStatement(
        "DELETE FROM NameCard WHERE ID = ?");
      update = connection.prepareStatement(
        "UPDATE NameCard SET ID=?, Name=?, Company=?, Title=?, "+
        "Address1=?, Address2=?, Phone=?, Email=?, Picture=? "+
        "WHERE ID = ?");
      all = connection.prepareStatement(
        "SELECT ID, Name, Company, Title, Address1, Address2, "+
        "Phone, Email FROM NameCard");
    } catch (SQLException e) {
      e.printStackTrace();
    }
  }
  
  // Other methods.
}


Other methods in DBManager provide access to the database via simple JDBC API calls. The following code snippet demonstrates methods for searching and manipulating name-card records. These methods heavily use the SQL templates we defined before.

  • Digg
  • Reddit
  • SlashDot
  • Stumble
  • del.icio.us
  • Technorati
  • dzone
Comment
Login
Forgot your account info?
Add comment
Anonymous comments subject to approval. Register here for member benefits.
Have a JavaWorld account? Log in here. Register now for a free account.
Resources