java left logo
java middle logo
java right logo
 

Home arrow Java ME Tips
 
 
Main Menu
Home
Java Tutorials
Book Reviews
Java SE Tips
Java ME Tips
Java EE Tips
Other API Tips
Java Applications
Java Libraries
Java Games
Java Network
Java Forums
Java Blog




Most Visited Tips
Java SE Tips
Java ME Tips
Java EE Tips
Other API Tips
Java Applications
Java Libraries
Java Games
Book Reviews
Top Rated Tips
Java SE Tips
Java ME Tips
Java EE Tips
Other API Tips
Java Applications
Java Libraries
Java Games
Book Reviews


Statistics
Registered Users: 4096
Java SE Tips: 614
Java ME Tips: 202
Java EE Tips: 183
Other API Tips: 779
Java Applications: 298
Java Libraries: 209
Java Games: 16
Book Reviews:
 
 
 
How to create a Todo Management MIDlet E-mail
User Rating: / 12
PoorBest 

This example implements a Todo Management Midlet.


Image Image Image


/*--------------------------------------------------
* TodoMIDlet.java
*
* The main class for todo list MIDlet
*
* Example from the book:     Core J2ME Technology
* Copyright John W. Muchow   http://www.CoreJ2ME.com
* You may use/modify for any non-commercial purpose
*-------------------------------------------------*/
import java.io.*;
import java.util.*;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import javax.microedition.rms.*;

public class TodoMIDlet extends MIDlet implements ItemStateListener, CommandListener
{
  private Display display;      // Our display
  private Form fmMain;         // Main Form
  private FormAdd fmAdd;       // Form to add todo item
  private Command cmAdd,       // Command to add todo
                  cmPrefs,     // Command to set preferences
                  cmExit;      // Command to exit
  private Vector vecTodo;       // The "master" list of todo items
  private ChoiceGroup cgTodo;  // Todo items (read from vecTodo)
  protected DisplayManager displayMgr;  // Class to help manage screens

  //-------------------------------------------------
  // Record Stores. One for todo, one for preferences
  //-------------------------------------------------
  private RecordStore rsTodo;
  private RecordStore rsPref;
  private static final String REC_STORE_TODO = "TodoList";
  private static final String REC_STORE_PREF = "TodoPrefs";
  private boolean flagSortByPriority = false, // Sort by priority?
                  flagShowPriority = true;    // Show priorities ?

  //-------------------------------------------------
  // Re-use these input streams throughout the MIDlet
  //-------------------------------------------------
  // Read from a specified byte array
  private ByteArrayInputStream istrmBytes = null;
  // Read Java data types from the above byte array
  private DataInputStream istrmDataType = null;
  // If you change length of a todo entry, bump thisbyte[] recData = new byte[25];

  //-------------------------------------------------
  // Re-use these output streams throughout the MIDlet
  //-------------------------------------------------
  // Write data into an internal byte array
  ByteArrayOutputStream ostrmBytes = null;
  // Write Java data types into the above byte array
  DataOutputStream ostrmDataType = null;

  //-------------------------------------------------
  // Record Enumerator and compare class
  //-------------------------------------------------
  private RecordEnumeration e = null;
  private ComparatorInt comp = null;

  /*--------------------------------------------------
  * MIDlet constructor.
  *-------------------------------------------------*/
  public TodoMIDlet()
  {
    display = Display.getDisplay(this);

    // Create 'main' and 'add todo item' forms
    // Form for setting prefs is in commandAction()
    fmMain = new Form("Todo List");
    fmAdd = new FormAdd("Add Todo"this);

    // Todo list and vector
    cgTodo = new ChoiceGroup("", Choice.MULTIPLE);
    vecTodo = new Vector();

    // Commands
    cmAdd = new Command("Add Todo", Command.SCREEN, 2);
    cmPrefs = new Command("Preferences", Command.SCREEN, 3);
    cmExit = new Command("Exit", Command.EXIT, 1);

    // Add all to form and listen for events
    fmMain.addCommand(cmAdd);
    fmMain.addCommand(cmPrefs);
    fmMain.addCommand(cmExit);
    fmMain.append(cgTodo);
    fmMain.setCommandListener(this);
    fmMain.setItemStateListener(this);

    // Create a display manager object
    displayMgr = new DisplayManager(display, fmMain);

    // Open/create the record stores
    rsTodo = openRecStore(REC_STORE_TODO);
    rsPref = openRecStore(REC_STORE_PREF);

    // Initialize the streams
    initInputStreams();
    initOutputStreams();

    // Read preferences from rms
    refreshPreferences();

    // Initialize the enumeration for todo rms
    initEnumeration();

   // Read rms into vector
    writeRMS2Vector();

    // Build the todo list (choice group)
    rebuildTodoList();
  }

  /*--------------------------------------------------
  * Show the main Form
  *-------------------------------------------------*/
  public void startApp ()
  {
    display.setCurrent(fmMain);
  }

  /*--------------------------------------------------
  * Shutting down. Cleanup all we created
  *-------------------------------------------------*/
  public void destroyApp (boolean unconditional)
  {
    // Cleanup for enumerator
    if (comp != null)
      comp.compareIntClose();
    if (e != null)
      e.destroy();

    // Cleanup streams
    try
    {
      if (istrmDataType != null)
        istrmDataType.close();

      if (istrmBytes != null)
        istrmBytes.close();

      if (ostrmDataType != null)
        ostrmDataType.close();

      if (ostrmBytes != null)
        ostrmBytes.close();
    }
    catch (Exception e)
    {
      db(e.toString());
    }

    // Cleanup rms
    closeRecStore(rsTodo);
    closeRecStore(rsPref);
  }

  /*--------------------------------------------------
  * No pause code necessary
  *-------------------------------------------------*/
  public void pauseApp ()
  { }

  /*--------------------------------------------------
  * Open input streams
  *-------------------------------------------------*/
  private void initInputStreams()
  {
    istrmBytes = new ByteArrayInputStream(recData);
    istrmDataType = new DataInputStream(istrmBytes);
  }

  /*--------------------------------------------------
  * Open output streams
  *-------------------------------------------------*/
  private void initOutputStreams()
  {
    ostrmBytes = new ByteArrayOutputStream();
    ostrmDataType = new DataOutputStream(ostrmBytes);
  }

  /*--------------------------------------------------
  * Initialize enumeration for todo rms
  *-------------------------------------------------*/
  private void initEnumeration()
  {
    // Are we to bother with sorting?
    if (flagSortByPriority)
      comp = new ComparatorInt();
    else
      // We must set this to null to clear out
      // any previous setting
      comp = null;

    try
    {
      e = rsTodo.enumerateRecords(null, comp, false);
    }
    catch (Exception e)
    {
      db(e.toString());
    }
  }

  /*--------------------------------------------------
  * Open a record store
  *-------------------------------------------------*/
  private RecordStore openRecStore(String name)
  {
    try
    {
      // Open the Record Store, creating it if necessary
      return RecordStore.openRecordStore(name, true);
    }
    catch (Exception e)
    {
      db(e.toString());
      return null;
    }
  }

  /*--------------------------------------------------
  * Close a record store
  *-------------------------------------------------*/
  private void closeRecStore(RecordStore rs)
  {
    try
    {
      rs.closeRecordStore();
    }
    catch (Exception e)
    {
      db(e.toString());
    }
  }

  /*--------------------------------------------------
  * Delete a record store
  *-------------------------------------------------*/
  private void deleteRecStore(String name)
  {
    try
    {
      RecordStore.deleteRecordStore(name);
    }
    catch (Exception e)
    {
      db(e.toString());
    }
  }

  /*--------------------------------------------------
  * Write new todo item
  *   - Write a new record into the rms
  *   - Write a new item into the vector
  *   - Recreate the vector from the rms (which will
  *     use the proper sort (using rms enumeration)
  *   - Rebuild todo list from vector
  *-------------------------------------------------*/
  protected void addTodoItem(int priority, String text)
  {
    try
    {
      // Toss any data in the internal array so writes
      // starts at beginning (of the internal array)
      ostrmBytes.reset();

      // Write priority and todo text
      ostrmDataType.writeInt(priority);
      ostrmDataType.writeUTF(text);

      // Clear any buffered data
      ostrmDataType.flush();

      // Get stream data into byte array and write record
      byte[] record = ostrmBytes.toByteArray();
      int recordId = rsTodo.addRecord(record, 0, record.length);

      // Create a new Todo item and insert it into our Vector
      TodoItem item = new TodoItem(priority, text, recordId);
      vecTodo.addElement(item);
    }
    catch (Exception e)
    {
      db(e.toString());
    }

    // Read rms into vector
    writeRMS2Vector();

    // Rebuild todo list
    rebuildTodoList();
  }

  /*--------------------------------------------------
  * Save preferences to record store
  *-------------------------------------------------*/
  protected void savePreferences(boolean sort, boolean showSort)
  {
    // No changes we made
    if (sort == flagSortByPriority && showSort == flagShowPriority)
      return;

    // Save the current sort status
    boolean previouslySorted = flagSortByPriority;
    boolean previouslyShowPriority = flagShowPriority;

    try
    {
      // Update prefs in private variables
      flagSortByPriority = sort;
      flagShowPriority = showSort;

      // Toss any data in the internal array so writes
      // starts at beginning (of the internal array)
      ostrmBytes.reset();

      // Write the sort order and keep completed flags
      ostrmDataType.writeBoolean(flagSortByPriority);
      ostrmDataType.writeBoolean(flagShowPriority);

      // Clear any buffered data
      ostrmDataType.flush();

      // Get stream data into byte array and write record
      byte[] record = ostrmBytes.toByteArray();

      // Always write preferences at first record
      // We cannot request to set the first record unless
      // the record store has contents.
      // If empty => add a record
      // If not   => overwrite the first record
      if (rsPref.getNumRecords() == 0)
        rsPref.addRecord(record, 0, record.length);
      else
        rsPref.setRecord(1, record, 0, record.length);
    }
    catch (Exception e)
    {
      db(e.toString());
    }

    // If the sort order was changed, rebuild enumeration
    if (previouslySorted != flagSortByPriority)
      initEnumeration();

    // If we are going from non-sorted to sorted
    // or changing whether or not to show priority 
    // then we must update what's currently displayed
    if ((!previouslySorted && flagSortByPriority||
        (previouslyShowPriority != flagShowPriority))
    {
      // Read rms into vector
      writeRMS2Vector();
      // Rebuild todo list
      rebuildTodoList();
    }
  }

  /*--------------------------------------------------
  * Read preferences from record store
  *-------------------------------------------------*/
  private void refreshPreferences()
  {
    try
    {
      // Record store is empty
      if (rsPref.getNumRecords() == 0)
      {
        // Write into the store the default preferences
        savePreferences(flagSortByPriority, flagShowPriority);
        return;
      }

      // Reset input back to the beginning
      istrmBytes.reset();

      // Read configuration data stored in the first record
      rsPref.getRecord(1, recData, 0);
      flagSortByPriority = istrmDataType.readBoolean();
      flagShowPriority = istrmDataType.readBoolean();

      System.out.println("Sort: " + flagSortByPriority);
      System.out.println("Show: " + flagShowPriority);
    }
    catch (Exception e)
    {
      db(e.toString());
    }
  }

  /*--------------------------------------------------
  * Create the vector from record store contents
  *-------------------------------------------------*/
  private void writeRMS2Vector()
  {
    // Cleanout the vector
    vecTodo.removeAllElements();

    try
    {
      // Rebuild enumeration for any changes
      e.rebuild();

      while (e.hasNextElement())
      {
        // Reset input back to the beginning
        istrmBytes.reset();

        // Get data into the byte array
        int id = e.nextRecordId();
        rsTodo.getRecord(id, recData, 0);

        // Create a new Todo item and insert it into our Vector
        TodoItem item = new TodoItem(istrmDataType.readInt(), istrmDataType.readUTF(), id);
        vecTodo.addElement(item);
      }
    }
    catch (Exception e)
    {
      db(e.toString());
    }
  }

  /*--------------------------------------------------
  * Store the current vector contents to the rms
  *-------------------------------------------------*/
  private void writeVector2RMS()
  {
    try
    {
      byte[] record;

      for (int i = 0; i < vecTodo.size(); i++)
      {
        TodoItem item = (TodoItemvecTodo.elementAt(i);

        int priority = item.getPriority();
        String text = item.getText();

        // Toss any data in the internal array so writes
        // starts at beginning (of the internal array)
        ostrmBytes.reset();

        // Write priority and todo text
        ostrmDataType.writeInt(priority);
        ostrmDataType.writeUTF(text);

        // Clear any buffered data
        ostrmDataType.flush();

        // Get stream data into byte array and write record
        record = ostrmBytes.toByteArray();
        rsTodo.addRecord(record, 0, record.length);
      }
    }
    catch (Exception e)
    {
      db(e.toString());
    }
  }

  /*--------------------------------------------------
  * Rebuild todo list (ChoiceGroup) from the Vector
  *-------------------------------------------------*/
  protected void rebuildTodoList()
  {
    // Clear out the ChoiceGroup.
    for (int i = cgTodo.size(); i > 0; i--)
      cgTodo.delete(i - 1);

    TodoItem item;
    int priority;
    String text;
    StringBuffer strb;

    for (int i = 0; i < vecTodo.size(); i++)
    {
      // Get a todo item from vector
      item = (TodoItemvecTodo.elementAt(i);

      // Read values from todoitem class
      priority = item.getPriority();
      text = item.getText();

      // Are we are to show priority as part of the text?
      strb = new StringBuffer((flagShowPriority ? (Integer.toString(priority"-")""));
      strb.append(text);

      // Append to todo choicegroup
      cgTodo.append(strb.toString()null);
    }
  }

  /*--------------------------------------------------
  * This method is called when a todo item has been
  * selected in the choicegroup. We treat this as
  * a request to delete the item
  *-------------------------------------------------*/
  public void itemStateChanged(Item item)
  {
    ChoiceGroup cg;

    // Cast the item to a ChoiceGroup type
    cg = (ChoiceGroupitem;

    // Create an array that mirrors the ChoiceGroup
    // and populate with those items selected
    boolean selected[] new boolean[cg.size()];
    cg.getSelectedFlags(selected);

    // Unfortunately, there is no (easy) way to determine
    // which item in the choiceGroup was "clicked" to
    // initiate this event. The best we can do is look at
    // each entry and determine its current selection state

    // For each element, see if it is selected
    // If so, delete it. Once we have found a selected
    // item, we can exit - there will never be more than
    // one item selected at any time
    for (int i = 0; i < cg.size(); i++)
    {
      if (selected[i])
      {
        // Get the record id from the todoItem 
        // and delete record from rms
        TodoItem todoitem = (TodoItemvecTodo.elementAt(i);
        try
        {
          rsTodo.deleteRecord(todoitem.getRecordId());
        }
        catch (Exception e)
        {
          db(e.toString());
        }
        break;
      }
    }
    // Read rms into vector
    writeRMS2Vector();
    // Rebuild todo list
    rebuildTodoList();
  }

  /*--------------------------------------------------
  * Process events for the main form
  *-------------------------------------------------*/
  public void commandAction(Command c, Displayable d)
  {
    if (c == cmExit)
    {
      destroyApp(false);
      notifyDestroyed();
    }
    else
    {
      if (c == cmAdd)
      {
        // Reset the textfield and choicegroup
        // on the 'add todo' form
        fmAdd.tfTodo.setString("");
        fmAdd.cgPriority.setSelectedIndex(0true);

        // Push current displayable and activate 'add todo' form
        displayMgr.pushDisplayable(fmAdd);
      }
      else if (c == cmPrefs)
      {
        boolean flags[] {flagSortByPriority, flagShowPriority};

        // Push current displayable and show preferences form 
        // passing in current preference settings        
        displayMgr.pushDisplayable(new FormPrefs("Preferences", this, flags));
      }
    }
  }

  /*--------------------------------------------------
  * Simple message to console for debug/errors
  *-------------------------------------------------*/
  private void db(String str)
  {
    System.err.println("Msg: " + str);
  }
}


/*--------------------------------------------------
* Use a stack to push and pop displayable objects
*
* public void pushDisplayable(Displayable)
* public void popDisplayable()
* public void home()  
*
* Example from the book:     Core J2ME Technology
* Copyright John W. Muchow   http://www.CoreJ2ME.com
* You may use/modify for any non-commercial purpose
*-------------------------------------------------*/

class DisplayManager extends Stack
{
  private Display display;      // Reference to Display object
  private Displayable mainDisplayable; // Main displayable for MIDlet
  private Alert alStackError;  // Alert for error conditions

  /*--------------------------------------------------
  * Display manager constructor
  *-------------------------------------------------*/
  public DisplayManager(Display display, Displayable mainDisplayable)
  {
    // Only one display object per midlet, this is it
    this.display = display;
    this.mainDisplayable = mainDisplayable;
    // Create an alert displayed when an error occurs
    alStackError = new Alert("Displayable Stack Error");
    alStackError.setTimeout(Alert.FOREVER);  // Modal
  }

  /*--------------------------------------------------
  * Push the current displayable onto stack and set
  * the passed in displayable as active
  *-------------------------------------------------*/
  public void pushDisplayable(Displayable newDisplayable)
  {
    push(display.getCurrent());
    display.setCurrent(newDisplayable);
  }

  /*--------------------------------------------------
  * Return to the main displayable object of MIDlet
  *-------------------------------------------------*/
  public void home()
  {
    while (elementCount > 1)
      pop();
    display.setCurrent(mainDisplayable);
  }
  /*--------------------------------------------------
  * Pop displayable from stack and set as active
  *-------------------------------------------------*/
  public void popDisplayable()
  {
    // If the stack is not empty, pop next displayable
    if (empty() == false)
      display.setCurrent((Displayablepop());
    else
      // On error show an alert
      // Once acknowldeged, set 'mainDisplayable' as active
      display.setCurrent(alStackError, mainDisplayable);
  }
}

/*--------------------------------------------------
* FormAdd.java
*
* Form for adding new todoitems
* Supporting class for TodoMIDlet
*
* Example from the book:     Core J2ME Technology
* Copyright John W. Muchow   http://www.CoreJ2ME.com
* You may use/modify for any non-commercial purpose
*-------------------------------------------------*/
class FormAdd extends Form implements CommandListener
{
  private Command cmBack,
                  cmSave;
  protected TextField tfTodo;
  protected ChoiceGroup cgPriority;
  private TodoMIDlet midlet;

  public FormAdd(String title, TodoMIDlet midlet)
  {
    // Call the Form constructor
    super(title);

    // Save reference to MIDlet so we can access
    // the display manager class and rms
    this.midlet = midlet;

    // Commands
    cmSave = new Command("Save", Command.SCREEN, 1);
    cmBack = new Command("Back", Command.BACK, 2);

    // Create textfield for entering todo items
    tfTodo = new TextField("Todo", null, 15, TextField.ANY);

    // Create choicegroup and append options (no images)
    cgPriority = new ChoiceGroup("Priority", Choice.EXCLUSIVE);
    cgPriority.append("Today"null);
    cgPriority.append("Tomorrow"null);
    cgPriority.append("This Week"null);
    cgPriority.append("This Month"null);
    cgPriority.append("Someday"null);

    // Add stuff to form and listen for events
    addCommand(cmSave);
    addCommand(cmBack);
    append(tfTodo);
    append(cgPriority);
    setCommandListener(this);
  }

  public void commandAction(Command c, Displayable s)
  {
    if (c == cmSave)
    {
      // Add a new todo item
      // Notice we bump priority by 1. This is because the 
      // choicegroup entries start at zero. We would like 
      // the records in the rms to store priorities starting
      // at 1. Thus, if a user requests to display priorities 
      // on the todo list, the highest priority is 1 (not zero)
      midlet.addTodoItem(cgPriority.getSelectedIndex() 1,
                     tfTodo.getString());
    }

    // Any other event and we go back to the main form...
    // Pop the last displayable off the stack
    midlet.displayMgr.popDisplayable();
  }
}

/*--------------------------------------------------
* ComparatorInt.java
*
* Sorts rms records based on todo item priority
* Provides compare() method for RecordEnumerator
* Supporting class for TodoMIDlet
*
* Example from the book:     Core J2ME Technology
* Copyright John W. Muchow   http://www.CoreJ2ME.com
* You may use/modify for any non-commercial purpose
*-------------------------------------------------*/

class ComparatorInt implements RecordComparator
{
  private byte[] record = new byte[10];

  // Read from a specified byte array
  private ByteArrayInputStream strmBytes = null;

  // Read Java data types from the above byte array
  private DataInputStream strmDataType = null;

  public void compareIntClose()
  {
    try
    {
      if (strmBytes != null)
        strmBytes.close();
      if (strmDataType != null)
        strmDataType.close();
    }
    catch (Exception e)
    {}
  }

  public int compare(byte[] rec1, byte[] rec2)
  {
    int x1, x2;

    try
    {
      // If either record is larger than our buffer, reallocate
      int maxsize = Math.max(rec1.length, rec2.length);
      if (maxsize > record.length)
        record = new byte[maxsize];

      // Read record #1
      // We want the priority which is first "field"
      strmBytes = new ByteArrayInputStream(rec1);
      strmDataType = new DataInputStream(strmBytes);
      x1 = strmDataType.readInt();

      // Read record #2
      strmBytes = new ByteArrayInputStream(rec2);
      strmDataType = new DataInputStream(strmBytes);
      x2 = strmDataType.readInt();

      // Compare record #1 and #2
      if (x1 == x2)
        return RecordComparator.EQUIVALENT;
      else if (x1 < x2)
        return RecordComparator.PRECEDES;
      else
        return RecordComparator.FOLLOWS;

    }
    catch (Exception e)
    {
      return RecordComparator.EQUIVALENT;
    }
  }
}  

/*--------------------------------------------------
* TodoItem.java
*
* Holds data/methods for a single todo item
* Supporting class for todoMIDlet
*
* Example from the book:     Core J2ME Technology
* Copyright John W. Muchow   http://www.CoreJ2ME.com
* You may use/modify for any non-commercial purpose
*-------------------------------------------------*/
class TodoItem
{
  private int priority;
  private String text;
  private int recordId;

  public TodoItem(int priority, String text, int recordId)
  {
    this.priority = priority;
    this.text = text;
    this.recordId = recordId;
  }

  public int getPriority()
  {
    return priority;
  }

  public void setPriority(int priority)
  {
    this.priority = priority;
  }

  public String getText()
  {
    return text;
  }

  public void setText(String text)
  {
    this.text = text;
  }
  public int getRecordId()
  {
    return recordId;
  }
}  

/*--------------------------------------------------
* FormPrefs.java
*
* Form for specifying user preferences
* Supporting class for TodoMIDlet
*
* Example from the book:     Core J2ME Technology
* Copyright John W. Muchow   http://www.CoreJ2ME.com
* You may use/modify for any non-commercial purpose
*-------------------------------------------------*/
class FormPrefs extends Form implements CommandListener
{
  private Command cmBack,
                  cmSave;
  private TodoMIDlet midlet;
  private ChoiceGroup cgPrefs;

  public FormPrefs(String title, TodoMIDlet midlet, boolean flags[])

  {
    // Call the Form constructor
    super(title);

    // Save reference to MIDlet so we can access
    // the display manager class and rms
    this.midlet = midlet;

    // Commands
    cmSave = new Command("Save", Command.SCREEN, 1);
    cmBack = new Command("Back", Command.BACK, 2);

    // Choicegroup for sort order and showing priority
    cgPrefs = new ChoiceGroup("Preferences", Choice.MULTIPLE);
    cgPrefs.append("Sort by Priority"null);
    cgPrefs.append("Show Priority"null);

    // Set the current status of each entry
    cgPrefs.setSelectedFlags(flags);

    // Add to form and listen for events
    append(cgPrefs);
    addCommand(cmBack);
    addCommand(cmSave);
    setCommandListener(this);
  }

  public void commandAction(Command c, Displayable s)
  {
    if (c == cmSave)
    {
      // Save the preferences
      midlet.savePreferences(cgPrefs.isSelected(0),
                             cgPrefs.isSelected(1));
    }

    // Any other event and we go back to the main form...
    // Pop the last displayable off the stack
    midlet.displayMgr.popDisplayable();
  }
}

 Related Tips

 
< Prev   Next >

Page 1 of 0 ( 0 comments )

You can share your information about this topic using the form below!

Please do not post your questions with this form! Thanks.


Name (required)


E-Mail (required)

Your email will not be displayed on the site - only to our administrator
Homepage(optional)



Comment Enable HTML code : Yes No



 
       
         
     
 
 
 
   
 
 
java bottom left
java bottom middle
java bottom right
RSS 0.91 FeedRSS 1.0 FeedRSS 2.0 FeedATOM FeedOPML Feed

Home - About Us - Privacy Policy
Copyright 2005 - 2008 www.java-tips.org
Java is a trademark of Sun Microsystems, Inc.