/* * Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version * 2 only, as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 2 for more details (a copy is * included at /legal/license.txt). * * You should have received a copy of the GNU General Public License * version 2 along with this work; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa * Clara, CA 95054 or visit www.sun.com if you need additional * information or have any questions. */ package com.sun.j2me.pim; import com.sun.j2me.log.Logging; import com.sun.j2me.main.Configuration; import java.io.IOException; import java.util.Calendar; import java.util.Date; import java.util.Enumeration; import java.util.Hashtable; import java.util.TimeZone; import javax.microedition.pim.PIMException; import javax.microedition.pim.PIM; import com.sun.j2me.pim.formats.FormatSupport; import com.sun.j2me.jsr75.StringUtil; /** * Implementations of shared PIM code. */ public class PIMBridge extends PIMHandler { /** * Contact table. */ private static Hashtable contactListFields = new Hashtable(); /** * Event table. */ private static Hashtable eventListFields = new Hashtable(); /** * Todo table. */ private static Hashtable todoListFields = new Hashtable(); /** * PIMItem data storage. */ private static PIMDatabase database; /** * Constant representing a Contact List. */ public static final int CONTACT_LIST = 1; /** * Constant representing an Event List. */ public static final int EVENT_LIST = 2; /** * Constant representing a ToDo List. */ public static final int TODO_LIST = 3; /** * Initialization flag. */ private static boolean initialized = false; /** * This class holds information about a single list. */ private class List { /** Type of the list: CONTACT_LIST, EVENT_LIST or TODO_LIST */ int type; /** Name of the list */ String name; /** * The only constructor for this list descriptor. * * @param listType CONTACT_LIST, EVENT_LIST or TODO_LIST * @param listName name of the list */ List(int listType, String listName) { type = listType; name = listName; } } /** * Set up data structures. */ public synchronized void initialize() { if (!initialized) { initializeMap(contactListFields, SupportedPIMFields.CONTACT_LIST_FIELDS); initializeMap(eventListFields, SupportedPIMFields.EVENT_LIST_FIELDS); initializeMap(todoListFields, SupportedPIMFields.TODO_LIST_FIELDS); try { database = new PIMDatabase( Configuration.getProperty("PIMRootDir") + "pim"); initialized = true; } catch (IOException e) { if (Logging.TRACE_ENABLED) { Logging.trace(e, "Unable to create PIMDatabase"); } } } } /** * Initialization one structure. * * @param map Hashtable for initialization * @param descriptors array of the field descriptors */ private void initializeMap(Hashtable map, PIMFieldDescriptor[] descriptors) { for (int i = 0; i < descriptors.length; i++) { map.put(new Integer(descriptors[i].getField()), descriptors[i]); } } /** * Gets the table of fields for given list type. * * @param listType CONTACT_LIST, EVENT_LIST or TODO_LIST * * @return hashtable of fields */ private Hashtable getFields(int listType) { Hashtable map; switch (listType) { case CONTACT_LIST: map = contactListFields; break; case EVENT_LIST: map = eventListFields; break; case TODO_LIST: map = todoListFields; break; default: throw new IllegalArgumentException("List type " + listType + " is not valid"); } return map; } /** * Gets the descriptor for given field. * * @param listType CONTACT_LIST, EVENT_LIST or TODO_LIST * @param field the field ID * * @return field descriptor */ private PIMFieldDescriptor getFieldDescriptor(int listType, int field) { return (PIMFieldDescriptor)getFields(listType).get(new Integer(field)); } /** * Gets all fields that are supported in the given list. * * @param listHandle handle of list * @return an int array containing all supported fields. */ public int[] getSupportedFields(Object listHandle) { initialize(); Hashtable map = getFields(((List)listHandle).type); Enumeration fieldNumbers = map.keys(); int len = map.size(); int[] result = new int[len]; for (int i = 0; i < len; i++) { result[i] = (fieldNumbers.nextElement()).hashCode(); } return result; } /** * Checks if field is supported in list. * @param listHandle handle of the list * @param field identifier of field * @return <code>true</code> if field supported */ public boolean isSupportedField(Object listHandle, int field) { initialize(); return getFieldDescriptor(((List)listHandle).type, field) != null; } /** * Checks if field has default value. * @param listHandle handle of the list * @param field identifier of field * @return <code>true</code> if field supported */ public boolean hasDefaultValue(Object listHandle, int field) { initialize(); return getFieldDescriptor(((List)listHandle).type, field) .hasDefaultValue(); } /** * Gets the data type of the field. * @param listHandle handle of the list * @param field identifier of field * @return data type identifier */ public int getFieldDataType(Object listHandle, int field) { initialize(); try { return getFieldDescriptor(((List)listHandle).type, field) .getDataType(); } catch (NullPointerException npe) { return -1; } } /** * Gets the label of the field. * @param listHandle handle of the list * @param field identifier of field * @return label of the field */ public String getFieldLabel(Object listHandle, int field) { initialize(); try { return getFieldDescriptor(((List)listHandle).type, field) .getLabel(); } catch (NullPointerException npe) { return null; } } /** * Gets the default integer value for the given field. This will * only * return a valid value if hasDefaultValue(listType, field) returns true. * @param listHandle handle of the list * @param field identifier of field * @return default value of the field */ public int getDefaultIntValue(Object listHandle, int field) { initialize(); PIMFieldDescriptor descriptor = getFieldDescriptor(((List)listHandle).type, field); return ((Integer) descriptor.getDefaultValue()).intValue(); } /** * Gets the default string value for the given field. This will * only * return a valid value if hasDefaultValue(listType, field) returns true. * @param listHandle handle of the list * @param field identifier of field * @return default value of the field */ public String getDefaultStringValue(Object listHandle, int field) { return null; } /** * Gets the default String[] value for the given field. This will * only * return a valid value if hasDefaultValue(listType, field) returns true. * @param listHandle handle of the list * @param field identifier of field * @return default value of the field */ public String[] getDefaultStringArrayValue(Object listHandle, int field) { int length = getStringArraySize(listHandle, field); return new String[length]; } /** * Gets the default date value for the given field. This will only * return a valid value if hasDefaultValue(listType, field) returns true. * @param listHandle handle of the list * @param field identifier of field * @return default value of the field */ public long getDefaultDateValue(Object listHandle, int field) { return 0; } /** * Gets the default byte[] value for the given field. This will * only * return a valid value if hasDefaultValue(listType, field) returns true. * @param listHandle handle of the list * @param field identifier of field * @return default value of the field */ public byte[] getDefaultBinaryValue(Object listHandle, int field) { return null; } /** * Gets the default boolean value for the given field. This will * only * return a valid value if hasDefaultValue(listType, field) returns true. * @param listHandle handle of the list * @param field identifier of field * @return default value of the field */ public boolean getDefaultBooleanValue(Object listHandle, int field) { return false; } /** * Gets the supported attributes for the given field. * @param listHandle handle of the list * @param field identifier of field * @return array of supported attributes of the field */ public int[] getSupportedAttributes(Object listHandle, int field) { initialize(); int listType = ((List)listHandle).type; long attributes = getFieldDescriptor(listType, field) .getSupportedAttributes(); int elementCount = 0; for (long a = attributes; a > 0; a >>= 1) { if ((a & 1) == 1) { elementCount++; } } int[] result = new int[elementCount]; if (elementCount > 0) { int a = 1; for (int i = 0; i < elementCount; i++) { while ((attributes & a) == 0) a <<= 1; result[i] = a; a <<= 1; } } return result; } /** * Gets a mask containing all possible attributes for the given field. * * @param listHandle handle of the list * @param field the field number * @return supported attribute mask */ public int getSupportedAttributesMask(Object listHandle, int field) { initialize(); return (int)getFieldDescriptor(((List)listHandle).type, field) .getSupportedAttributes(); } /** * Gets attribute label for the given field attribute. * * @param listHandle handle of the list * @param attribute identifier of attribute * @return attribute label */ public String getAttributeLabel(Object listHandle, int attribute) { initialize(); StringBuffer tag = new StringBuffer("PIM.Attributes."); if (attribute == 0) { tag.append("None"); } else { switch (((List)listHandle).type) { case CONTACT_LIST: tag.append("ContactList."); break; case EVENT_LIST: tag.append("EventList."); break; case TODO_LIST: tag.append("ToDoList."); break; default: return null; } int index = 0; while (attribute > 1) { index++; attribute = attribute >> 1; } tag.append(index); } String tagString = tag.toString(); String returnValue = Configuration.getProperty(tagString); if (returnValue == null) { returnValue = "Label_" + tagString; } return returnValue; } /** * Checks if attribute is supported. * * @param listHandle handle of the list * @param field the field number * @param attribute identifier of attribute * @return <code>true</code> if attribute is supported */ public boolean isSupportedAttribute(Object listHandle, int field, int attribute) { initialize(); if (attribute == PIMItem.ATTR_NONE) { return true; } else { long attributes = getFieldDescriptor(((List)listHandle).type, field) .getSupportedAttributes(); return (attributes & attribute) != 0; } } /** * Checks if size of the string array. * * @param listHandle handle of the list * @param field the field number * @return size of the string array */ public int getStringArraySize(Object listHandle, int field) { initialize(); try { return getFieldDescriptor(((List)listHandle).type, field) .getStringArraySize(); } catch (NullPointerException npe) { // debug.exception(Debug.LIGHT, npe); return 0; } } /** * Gets the array of supported elements. * * @param listHandle handle of the list * @param field the field number * @return array of supported elements */ public int[] getSupportedArrayElements(Object listHandle, int field) { int size = getStringArraySize(listHandle, field); int[] result = new int[size]; for (int i = 0; i < size; i++) { result[i] = i; } return result; } /** * Gets the array element label. * * @param listHandle handle of the list * @param field the field number * @param arrayElement the element identifier * @return label fro the array element */ public String getArrayElementLabel(Object listHandle, int field, int arrayElement) { initialize(); return getFieldDescriptor(((List)listHandle).type, field) .getElementlabel(arrayElement); } /** * Checks if the array element is supported. * * @param listHandle handle of the list * @param field the field number * @param arrayElement the element identifier * @return <code>true</code> if attribute element is supported */ public boolean isSupportedArrayElement(Object listHandle, int field, int arrayElement) { return arrayElement >= 0 && arrayElement < getStringArraySize(listHandle, field); } /** * Get the maximum number of values that can be stored in the given field. * * @param listHandle handle of the list * @param field the field type * @return the maximum value */ public int getMaximumValues(Object listHandle, int field) { initialize(); return getFieldDescriptor(((List)listHandle).type, field) .getMaximumValues(); } /** * Get the supported list names for the given list type. All list elements * must be unique within the list. * * @param listType the type of the list * @return a non-null array of supported list names. A copy of this array is * returned by PIM.listPIMLists() */ synchronized public String[] getListNames(int listType) { initialize(); int length = database.getListNames(listType).length; String[] names = new String[length]; for (int i = 0; i < length; i++) { names[i] = database.getListNames(listType)[i]; } return names; } /** * Get the name of the default list for the given type. * * @param listType the type of the list * @return the name of the default list, or null if no list of this type * is supported. */ public String getDefaultListName(int listType) { initialize(); return database.getDefaultListName(listType); } /** * Opens list. * * @param listType the type of the list * @param listName the name of the list * @param openMode open mode * @return list handle that will be used to access this list * @throws PIMException in case of I/O error. */ public Object openList(int listType, String listName, int openMode) throws PIMException { return new List(listType, listName); } /** * Closes list. * * @param listHandle handle of list * @throws PIMException in case of I/O error. */ public void closeList(Object listHandle) throws PIMException { } /** * Get list element keys. * * @param listHandle handle of the list * @return an array of objects representing PIM element keys. These keys * are to be passed to getListElement() and commitListElement(). * @throws PIMException in case of I/O error. */ synchronized public Object[] getListKeys(Object listHandle) throws PIMException { initialize(); Hashtable hash_keys = database.getKeys(((List)listHandle).type, ((List)listHandle).name); int len = hash_keys.size(); Object[] keys = new Object[len]; Enumeration en_keys = hash_keys.keys(); for (int i = 0; i < len; i++) { keys[i] = en_keys.nextElement().toString(); } return keys; } /** * Get the data for a list element. * @param listHandle handle of the list * @param elementKey the key of the requested element * @return a byte array containing the element data in a supported format * @throws PIMException in case of I/O error. */ public byte[] getListElement(Object listHandle, Object elementKey) throws PIMException { initialize(); return database.getElement(((List)listHandle).type, ((List)listHandle).name, (String)elementKey); } /** * Get categories for the specified list element. * @param listHandle handle of list * @param elementKey the key of the requested element * @return an array of categories names * @throws PIMException in case of I/O error. */ public String[] getListElementCategories(Object listHandle, Object elementKey) throws PIMException { return new String[0]; } /** * Commit a list element. * * @param listHandle handle of the list * @param elementKey the key of the element to be stored, or null if this * is a new element. * @param element element data in a form that can be interpreted * by getListElement() * @param categories list of categories which the list element belongs to * @return a non-null key for this element, to be used in future calls * to commitListElement() and getListElement() * @throws PIMException in case of I/O error. */ synchronized public Object commitListElement(Object listHandle, Object elementKey, byte[] element, String[] categories) throws PIMException { initialize(); elementKey = database.commitElement(((List)listHandle).type, ((List)listHandle).name, (String)elementKey, element); return elementKey; } /** * Gets the set of categories defined for a list. * * @param listHandle handle of the list * @return the set of defined categories * @throws PIMException If an error occurs or * the list is no longer accessible or closed. */ public String[] getCategories(Object listHandle) throws PIMException { initialize(); String result = database.getCategories(((List)listHandle).type, ((List)listHandle).name); return StringUtil.split(result, '\n', 0); } /** * Adds a category to the categories defined for a list. * * @param listHandle handle of list * @param category category name * @throws PIMException If an error occurs or * the list is no longer accessible or closed. * @see #getCategories */ public void addCategory(Object listHandle, String category) throws PIMException { initialize(); String cats = database.getCategories(((List)listHandle).type, ((List)listHandle).name); // the implementation expects that '\n' is never escaped in categories String cat_add = "\n" + category; if (cats.indexOf(cat_add + '\n') != -1 || cats.startsWith(category + '\n') || cats.endsWith(cat_add) || ((cats.length() > 0) && cats.equals(category))) { return; } if (cats.length() == 0 && category.length() > 0) { cats = category; } else { cats += cat_add; } database.setCategories(((List)listHandle).type, ((List)listHandle).name, cats); } /** * Deletes a category from the categories defined for a list. * * @param listHandle handle of list * @param category category name * @throws PIMException If an error occurs or * the list is no longer accessible or closed. * @see #getCategories */ public void deleteCategory(Object listHandle, String category) throws PIMException { initialize(); String cats = database.getCategories(((List)listHandle).type, ((List)listHandle).name); // the implementation expects that '\n' is never escaped in categories String cat_add = "\n" + category; int pos; if ((pos = cats.indexOf(cat_add + '\n')) != -1) { cats = cats.substring(0, pos) + cats.substring(pos + cat_add.length()); } else if (cats.startsWith(category + '\n')) { cats = cats.substring(cat_add.length()); } else if (cats.endsWith(cat_add)) { cats = cats.substring(0, cats.length() - cat_add.length()); } else if (cats.equals(category)) { cats = ""; } else { return; } database.setCategories(((List)listHandle).type, ((List)listHandle).name, cats); } /** * Rename a category. * * @param listHandle handle of list * @param currentCategory current category name * @param newCategory new category name * @throws PIMException If an error occurs or * the list is no longer accessible or closed. * @see #getCategories */ public void renameCategory(Object listHandle, String currentCategory, String newCategory) throws PIMException { deleteCategory(listHandle, currentCategory); addCategory(listHandle, newCategory); } }