Personal Information Management (PIM) API for Java Micro Edition is included in J2ME profiles as an optional package. It is developed as part of JSR 75 and there is no dependency of these PIM API upon any other APIs produced in JSR 75.

This API resides in a new J2ME package, javax.microedition.pim.

PIM APIs are very useful in following ways:

PIM API can be used to access the address book residing in the mobile device. You must be knowing that nearly all the mobile devices these days supports address book where you can store your contact. So if you want to access that address book, PIM APIs provides you support for that.

Similarly, you can access the TODO list and calendar using PIM API. One can say that you can access native PIM database using PIM API. This is a very useful support since you cannot access the files residing in the PIM folder of mobile device.

Security issues are also addressed in PIM API and only authorized Java applications can access the entries contained in the PIM lists.

Considering the limited J2ME CLDC space, PIM API implementation is memory and performance efficient.

If you are interested in synchronizing your address book, then import and export options are of great interest for you. Good thing is that import and export of address book entries in a vCard format (specified by the Internet Mail Consortium) is also provided by the PIM API.


Synchronization issues

You if are interested in playing with the PIM database entries, you should know that PIM API does not provide locking operations. On the other hand, PIM implementations ensure that all PIM records are atomic, synchronous, and serialized – which means that no corruption occurs with multiple accesses.

Tricky situation occurs when you write a multithreaded application and multiple threads try to access the PIM entries. In this situation, you as a developer have to deal with the situation by coordinating the access of threads to your PIM records. In other case, unintended consequences may result.

For example:
Categories in a particular contact list may be modified by a native application threads concurrently – which would mean that the contents will be over written by the thread the committed last.

It is right to say that PIM API is not required to handle multitasking environments and concurrent access to PIM data.


Creating contacts

You might be thinking about creating contacts in the test environment. You can create contacts in Ms Outlook and then copy those to the required directory.

Contact file have extension vcf. You should use SUN wireless toolkit for creating and testing mobile applications. It provides emulator as well. Place the contact files (vcf files) in the following directory:

..\j2mewtk\2.5.2\appdb\DefaultColorPhone\pim\conta cts\Contacts

Now you can access these contacts from your application.

There is another way to create contacts. You can write your own MIDlet which can create contacts. SUN wireless toolkit comes with a sample application for creating contacts which you can also use to create contacts. It is called PDAPDemo (JSR 75 FileConnection & PIM demonstration). If you use it, the created contacts will be places by default in the required directory.

J2ME - Personal Information Management-adding_contacts.jpg

PIMList

PIMList is an interface (javax.microedition.pim.PIMList) which represents the common functionality of a PIM list. ContactList, EventList and ToDoList are its sub-interfaces. A PIMList contain zero or more PIMItems.
PIMlist provides following methods:

Java Code:
void addCategory(java.lang.String category)
void close()
void deleteCategory(java.lang.String category, boolean deleteUnassignedItems)
java.lang.String getArrayElementLabel(int stringArrayField, int arrayElement)
java.lang.String getAttributeLabel(int attribute)
java.lang.String[] getCategories()
int getFieldDataType(int field)
java.lang.String getFieldLabel(int field)
java.lang.String getName()
int[] getSupportedArrayElements(int stringArrayField)
int[] getSupportedAttributes(int field)
int[] getSupportedFields()
boolean isCategory(java.lang.String category)
boolean isSupportedArrayElement(int stringArrayField, int arrayElement)
boolean isSupportedAttribute(int field, int attribute)
boolean isSupportedField(int field)
java.util.Enumeration items()
java.util.Enumeration items(PIMItem matchingItem)
java.util.Enumeration items(java.lang.String matchingValue)
java.util.Enumeration itemsByCategory(java.lang.String category)
int maxCategories()
int maxValues(int field)
void renameCategory(java.lang.String currentCategory, java.lang.String newCategory)
int stringArraySize(int stringArrayField)
Contact list

A mobile device contains all the contacts in a contact list. This is referred as ContactList (javax.microedition.pim.ContactList) in PIM API.
It is responsible for determining which of the fields from a Contact are retained when a Contact is persisted into the List. Remember that not all the contact fields are supported by the platforms. Supported contact fields vary according to the platforms.
ContactList is an interface and it extends from PIMList.
Following methods are provided by ContactList.
Java Code:
Contact createContact()
Contact importContact(Contact contact)
void removeContact(Contact contact)
In order to iterate through all the contact, you need to first fetch the contact list from the mobile device. Lets see how this is done:

Java Code:
PIM pim = PIM.getInstance();
ContactList contactList = null;

try {
contactList =
(ContactList)pim.openPIMList(PIM.CONTACT_LIST,PIM.READ_WRITE );
Enumeration en;
en = contactList.items();
Contact contact;
while(en.hasMoreElements())
{
contact = (Contact)en.nextElement();
…
}
catch( PIMException pimEx ){
// no contact list available!
System.out.println("EX - No contact list available.");
}
catch( SecurityException securityEx){
// the application is not allowed to access the list
System.out.println("EX - Access denied.");
}
PIMItem

PIMItem is an interface (javax.microedition.pim.PIMItem) that represents the common interfaces of an item for a PIM list. Contact, Event and ToDo extends from it.
A PIM item represents a collection of data for a single PIM entry. A PIM item is created from a particular PIM list and is associated with that list for the life of the item. For example Contact is created from ContactList. PIM items can have its data imported and exported using standard byte based formats. The formats that can be imported and exported for an item, are defined by the implementing classes.
Following methods are provided by PIMItem:
Java Code:
void  addBinary(int field, int attributes, byte[] value, int offset, int length)
void addBoolean(int field, int attributes, boolean value)
void addDate(int field, int attributes, long value)
void addInt(int field, int attributes, int value)
void addString(int field, int attributes, java.lang.String value)
void addStringArray(int field, int attributes, java.lang.String[] value)
void addToCategory(java.lang.String category)
void commit()
int countValues(int field)
int getAttributes(int field, int index)
byte[] getBinary(int field, int index)
boolean getBoolean(int field, int index)
java.lang.String[] getCategories()
long getDate(int field, int index)
int[] getFields()
int getInt(int field, int index)
PIMList getPIMList()
java.lang.String getString(int field, int index)
java.lang.String[] getStringArray(int field, int index)
boolean isModified()
int maxCategories()
void removeFromCategory(java.lang.String category)
void removeValue(int field, int index)
void setBinary(int field, int index, int attributes, byte[] value, int offset, int length)
void setBoolean(int field, int index, int attributes, boolean value)
void setDate(int field, int index, int attributes, long value)
void setInt(int field, int index, int attributes, int value)
void setString(int field, int index, int attributes, java.lang.String value)
void setStringArray(int field, int index, int attributes, java.lang.String[] value)
Contact

Each contact entry in a PIM Contact database is represented by Contact. The supported field list for a Contact depends on vCard specification from the Internet Mail Consortium. These set of fields included in this Contact class provides relevant information about a contact.
ContactList restricts what fields a Contact can retain. This reflects that some native Contact databases do not support all of the fields available in a Contact item. The following methods are used to determine if a particular contact field is supported by the ContactList.

Java Code:
PIMList.isSupportedField(int)
PIMList.getSupportedAttributes(int)
If you attempt to access a non supported field/attribute, you will get UnsupportedFieldException exception.
Java Code:
// fetching DOB
if (contactList.isSupportedField(Contact.BIRTHDAY))
{
System.out.println("BirthDay: " +
contact.getDate(Contact.BIRTHDAY,0));
}
else
{
System.out.println(“DOB is not supported.”);
}

Following are standard fields supported by contacts:

Field name / data type

NAME, ADDR / PIMItem.STRING_ARRAY
EMAIL, FORMATTED_NAME, NICKNAME, NOTE, ORG, TEL, TITLE, UID, URL / PIMItem.STRING
BIRTHDAY, REVISION / PIMItem.DATE
PHOTO, PUBLIC_KEY / PIMItem.BINARY
PHOTO_URL, PUBLIC_KEY_STRING / PIMItem.STRING
CLASS / PIMItem.INT


Example (Creating contacts)

Time for an example. The following example will show you how to use Contact and ContactList to add contacts. First, we have to open the contact list is read write mode and then we will create the contact will the required fields. Finally commit operation is done.

Java Code:
ContactList contacts = null;
 try {
    contacts = (ContactList) PIM.getInstance().openPIMList(PIM.CONTACT_LIST, PIM.READ_WRITE);
 } catch (PIMException e) {
    // An error occurred
    return;
 }
 Contact contact = contacts.createContact();
 String[] addr = new String[contacts.stringArraySize(Contact.ADDR)];
 String[] name = new String[contacts.stringArraySize(Contact.NAME)];

 if (contacts.isSupportedField(Contact.NAME_FORMATTED)
      contact.addString(Contact.NAME_FORMATTED, PIMItem.ATTR_NONE, "Mr. John Q. Public, Esq.");
 if (contacts.isSupportedArrayElement(Contact.NAME, Contact.NAME_FAMILY))
      name[Contact.NAME_FAMILY] = "Public";
 if (contacts.isSupportedArrayElement(Contact.NAME, Contact.NAME_GIVEN))
      name[Contact.NAME_GIVEN] = "John";
 contact.addStringArray(Contact.NAME, PIMItem.ATTR_NONE, name);
 if (contacts.isSupportedArrayElement(Contact.ADDR, Contact.ADDR_COUNTRY))
      addr[Contact.ADDR_COUNTRY] = "USA";
 if (contacts.isSupportedArrayElement(Contact.ADDR, Contact.ADDR_LOCALITY))
      addr[Contact.ADDR_LOCALITY] = "Coolsville";
 if (contacts.isSupportedArrayElement(Contact.ADDR, Contact.ADDR_POSTALCODE))
      addr[Contact.ADDR_POSTALCODE] = "91921-1234";
 if (contacts.isSupportedArrayElement(Contact.ADDR, Contact.ADDR_STREET))
      addr[Contact.ADDR_STREET] = "123 Main Street";
 if (contacts.isSupportedField(Contact.ADDR))
    contact.addStringArray(Contact.ADDR, Contact.ATTR_HOME, addr);
 if (contacts.isSupportedField(Contact.TEL))
    contact.addString(Contact.TEL, Contact.ATTR_HOME, "613-123-4567");
 if (contacts.maxCategories() != 0
       && contacts.isCategory("Friends"))
    contact.addToCategory("Friends");
 if (contacts.isSupportedField(Contact.BIRTHDAY))
    contact.addDate(Contact.BIRTHDAY, PIMItem.ATTR_NONE, new Date().getTime());
 if (contacts.isSupportedField(Contact.EMAIL)) {
    contact.addString(Contact.EMAIL, Contact.ATTR_HOME | Contact.ATTR_PREFERRED, "jqpublic@xyz.dom1.com");
 }
 try {
      contact.commit();
 } catch (PIMException e) {
      // An error occured
 }
 try {
      contacts.close();
 } catch (PIMException e) {
 }
Example (catching UnsupportedFieldException)

In the following example, we will create contacts with optionally supported fields. What if a field is not supported by the platform? We will get UnsupportedFieldException and if try catch block is properly used; we can ignore contacts which does not contain all the fields.

Java Code:
ContactList contacts = null;
  try {
    contacts = (ContactList) PIM.getInstance().openPIMList(PIM.CONTACT_LIST, PIM.READ_WRITE);
  } catch (PIMException e) {
      // An error occurred
      return;
  }
  Contact contact = contacts.createContact();

  String[] name = new String[contacts.stringArraySize(Contact.NAME)];
  name[Contact.NAME_GIVEN] = "Laiq";
  name[Contact.NAME_FAMILY] = "Toni";

  String[] addr = new String[contacts.stringArraySize(Contact.ADDR)];
  addr[Contact.ADDR_COUNTRY] = "Canada";
  addr[Contact.ADDR_LOCALITY] = "K-Area";
  addr[Contact.ADDR_POSTALCODE] = "70776";
  addr[Contact.ADDR_STREET] = "12 Irvine St.";

  try {
     contact.addString(Contact.NAME_FORMATTED, PIMItem.ATTR_NONE, "Mr. John Q. Public, Esq.");
     contact.addStringArray(Contact.NAME, PIMItem.ATTR_NONE, name);
     contact.addStringArray(Contact.ADDR, Contact.ATTR_HOME, addr);
     contact.addString(Contact.TEL, Contact.ATTR_HOME, "613-123-4567");
     contact.addToCategory("Friends");
     contact.addDate(Contact.BIRTHDAY, PIMItem.ATTR_NONE, new Date().getTime());
     contact.addString(Contact.EMAIL, Contact.ATTR_HOME | Contact.ATTR_PREFERRED, "laiq@domain.com");

  } catch (UnsupportedFieldException e) {
    // In this case, we choose not to save the contact at all if any of the
    // fields are not supported on this platform.
    System.out.println("Contact not saved");
    return;
  }

  try {
      contact.commit();
  } catch (PIMException e) {
      // An error occured
  }
  try {
      contacts.close();
  } catch (PIMException e) {
  }

ToDo List and ToDo items

ToDoList is an interface extending from PIMList. We have already talked about PIMList, so you must be having some idea what can be done with ToDoList. It represents a ToDo list containing ToDo items and is responsible for determining which of the fields from a ToDo are retained when a ToDo is persisted into the List. Similar to ContactList, the fields supported depends on the platform and we have to use PIMList.isSupportedField(int) to find if a field is supported on the given platform. We get java.lang.IllegalArgumentException if we try to access a field that is not supported on the given platform. So using try catch block will serve the purpose.

ToDoList provides following methods:

Java Code:
ToDo  	createToDo()
ToDo 	importToDo(ToDo item)
java.util.Enumeration 	items(int field, long startDate, long endDate)
void 	removeToDo(ToDo item)
ToDo (javax.microedition.pim.ToDo) is an interface and like Contact, extends from PIMItem. It represents a single ToDo item in a PIMToDo database.

Consider the following example. We create todos with fields of our interest. But before adding the field,w e should check if its supported on the platform or not.


Java Code:
ToDoList todos = null;
 try {
    todos = (ToDoList) PIM.getInstance().openPIMList(PIM.TODO_LIST, PIM.READ_WRITE);
 } catch (PIMException e) {
    // An error occurred
    return;
 }
 ToDo todo = todos.createToDo();
 if (todos.isSupportedField(Event.SUMMARY))
      todo.addString(ToDo.SUMMARY, PIMItem.ATTR_NONE, "Do shopping.");
 if (todos.isSupportedField(Event.DUE))
      todo.addDate(ToDo.DUE, PIMItem.ATTR_NONE, new Date().getTime());
 if (todos.isSupportedField(Event.NOTE))
      todo.addString(ToDo.NOTE, PIMItem.ATTR_NONE, "No NIKE stuff.");
 if (todos.isSupportedField(Event.PRIORITY))
      todo.addInt(ToDo.PRIORITY, PIMItem.ATTR_NONE, 2);
 if (todos.maxCategories() != 0 && todos.isCategory("Work"))
      todo.addToCategory("Work");
 }
 try {
      todo.commit();
 } catch (PIMException e) {
      // An error occured
 }
 try {
      todos.close();
 } catch (PIMException e) {
 }

Conclusion

PIM API is very useful and interesting that really makes accessing and manipulating contacts and todos easier. You can now easily access the PIM database of your mobile device and can do experiments.

Happy Coding !!!