--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/javaextensions/pim/javasrc/com/nokia/mj/impl/pim/PIMListImpl.java Tue Apr 27 16:30:29 2010 +0300
@@ -0,0 +1,1029 @@
+/*
+* Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: PIM list implementation base.
+ *
+*/
+
+
+// PACKAGE
+package com.nokia.mj.impl.pim;
+
+// IMPORTS
+
+import javax.microedition.pim.FieldFullException;
+import javax.microedition.pim.PIM;
+import javax.microedition.pim.PIMException;
+import javax.microedition.pim.PIMItem;
+import javax.microedition.pim.PIMList;
+import javax.microedition.pim.UnsupportedFieldException;
+import java.util.Enumeration;
+import java.util.Date;
+import java.util.Vector;
+import com.nokia.mj.impl.pim.ErrorString;
+import com.nokia.mj.impl.pim.GenericException;
+import com.nokia.mj.impl.rt.support.ApplicationUtils;
+import com.nokia.mj.impl.rt.support.Finalizer;
+import com.nokia.mj.impl.rt.support.ShutdownListener;
+import com.nokia.mj.impl.pim.utils.NativeError;
+import com.nokia.mj.impl.utils.Logger;
+
+// CLASS DEFINITION
+/**
+ * Base class for specialized PIMList classes.
+ *
+ * @par About item creation: New PIMItem-derived classes are created during list
+ * update. The list is updated whenever items are enumerated with one of
+ * the items() methods. During the update native-originated changes are
+ * synchronized. When items are enumerated for the first time from the
+ * list, whole content of the corresponding native database is considered
+ * as new items and are created at that time. See updateList() method.
+ */
+public abstract class PIMListImpl implements PIMList
+{
+ // Constants
+
+ /** Label type Field. */
+ private static final int LABEL_TYPE_FIELD = 1;
+
+ /** Label type Attribute. */
+ private static final int LABEL_TYPE_ATTRIBUTE = 2;
+
+ /** Label type Array Element. */
+ private static final int LABEL_TYPE_ARRAY_ELEMENT = 3;
+
+ /** Enumeration flag: all items. See items(). */
+ protected final static int ENUMERATION_ITEMS_ALL = 0;
+
+ /** Enumeration flag: items matching given item. See items(). */
+ protected final static int ENUMERATION_ITEMS_MATCHING_ITEM = 1;
+
+ /** Enumeration flag: items matching given string. See items(). */
+ protected final static int ENUMERATION_ITEMS_MATCHING_STRING = 2;
+
+ /** Enumeration flag: items matching given category. See items(). */
+ protected final static int ENUMERATION_ITEMS_MATCHING_CATEGORY = 3;
+
+ // Member data
+ private Finalizer iFinalizer;
+
+ /** JNI native handle to the native side peer object. */
+ protected int iListHandle;
+
+ /**
+ * Items.
+ */
+ protected ItemTable iItems;
+
+ /**
+ * Access mode, one of:
+ *
+ * @li PIM.READ_ONLY
+ * @li PIM.WRITE_ONLY
+ * @li PIM.READ_WRITE.
+ */
+ private int iMode = 0;
+
+ /**
+ * State flag, open or closed. New instance of PIMListImpl is always
+ * initially open.
+ */
+ private boolean iIsOpen = true;
+
+ // Constructors
+
+ /**
+ * Initializes the list with native side Event Source and list peer object
+ * handles and registers the object for finalization.
+ *
+ * Given mode applies to all security vulnerable operations.
+ */
+ PIMListImpl(int aListHandle, int aMode)
+ {
+ iListHandle = aListHandle;
+ Logger.LOG(Logger.EPim,Logger.EInfo,"+PIMListImpl() = iListHandle = "+iListHandle);
+ setShutdownListener();
+ iFinalizer = registerForFinalization();
+ iMode = aMode;
+
+ iItems = new ItemTable();
+ }
+
+ public Finalizer registerForFinalization()
+ {
+ return new Finalizer()
+ {
+ public void finalizeImpl()
+ {
+
+ doFinalize();
+
+ }
+ };
+
+ }
+
+ void doFinalize()
+ {
+ if (iFinalizer == null)
+ {
+ return;
+ }
+ iFinalizer = null;
+
+ if (iListHandle != 0)
+ {
+ _dispose(iListHandle);
+ iListHandle = 0;
+ }
+ }
+
+ /**
+ * Registers for shutdown listener
+ */
+ private void setShutdownListener()
+ {
+ // Get the insatnce of ApplicationUtils.
+ ApplicationUtils appUtils = ApplicationUtils.getInstance();
+
+ // Get the name of the application.
+ appUtils.addShutdownListener(new ShutdownListener()
+ {
+ public void shuttingDown()
+ {
+ if (iListHandle != 0)
+ {
+ _dispose(iListHandle);
+ iListHandle = 0;
+ }
+ }
+ });
+ }
+
+ // New methods
+
+ /**
+ * Gets the list type. Used for resolving permissions.
+ */
+ abstract int getListType();
+
+ /**
+ * Determines whether this list is still open or has it been closed.
+ */
+ boolean isOpen()
+ {
+ return iIsOpen;
+ }
+
+ /**
+ * Items that are associated with this list call this method when they are
+ * committed. When an item is committed it is checked whether belongs to the
+ * list already and added if not. If the item has been recently created and
+ * never committed, it does not yet belong to the list.
+ */
+ void itemCommitted(PIMItemImpl aCommittedItem)
+ {
+ if (!iItems.containsItem(aCommittedItem))
+ {
+ int committedItemHandle = aCommittedItem.jniNativeHandle();
+
+ int error = _addCommittedItem(iListHandle, committedItemHandle);
+ if (!NativeError.checkSuccess(error))
+ {
+ throw new GenericException(ErrorString.GENERAL_ERROR_COLON + error);
+ }
+
+ iItems.addItem(aCommittedItem);
+ }
+ }
+
+ /**
+ * Creates a new specialized item and associates it with the list. This is
+ * the common implementation of createXyz() methods in specialized lists.
+ * The polymorphic behaviour is implemented in the native side.
+ */
+ protected PIMItemImpl createItem()
+ {
+ int[] err = new int[1];
+ int itemHandle = _createItem(iListHandle, err);
+ if (!NativeError.checkSuccess(err[0]))
+ {
+ throw new GenericException(ErrorString.GENERAL_ERROR_COLON + err[0]);
+ }
+
+ PIMItemImpl item = createAssociatedItem(itemHandle);
+ return item;
+ }
+
+ protected void removeItem(PIMItem aItem) throws PIMException
+ {
+ if (aItem == null)
+ {
+ throw new NullPointerException(ErrorString.ITEM_IS_NULL);
+ }
+
+ if (!(aItem instanceof PIMItemImpl))
+ {
+ throw new PIMException(ErrorString.REMOVAL_FAILED_COLON +
+ ErrorString.INVALID_ITEM,
+ PIMException.GENERAL_ERROR);
+ }
+
+ // Check that list is not closed
+ if (!isOpen())
+ {
+ throw new PIMException(ErrorString.REMOVAL_FAILED_COLON +
+ ErrorString.LIST_IS_CLOSED, PIMException.LIST_CLOSED);
+ }
+
+ PIMItemImpl item = (PIMItemImpl) aItem;
+
+ if (!iItems.containsItem(item))
+ {
+ throw new PIMException(ErrorString.REMOVAL_FAILED_COLON +
+ ErrorString.ITEM_IS_NOT_IN_THE_LIST,
+ PIMException.GENERAL_ERROR);
+ }
+ ApplicationUtils appUtils = ApplicationUtils.getInstance();
+ String action = null;
+ switch (getListType())
+ {
+ case PIM.CONTACT_LIST:
+ action = PIMPermissionImpl.ACTION_WRITE_CONTACTS;
+ break;
+ case PIM.EVENT_LIST:
+ action = PIMPermissionImpl.ACTION_WRITE_EVENTS;
+ break;
+ case PIM.TODO_LIST:
+ action = PIMPermissionImpl.ACTION_WRITE_TODOS;
+ break;
+ }
+
+ // Get localized text info for the security dialog
+ PIMPermissionImpl per = new PIMPermissionImpl(action, item.getShortInfo(), getName(), PIMPermissionImpl.OPERATION_ITEM_DELETION);
+
+ // Ensure permission from PIM API security
+ appUtils.checkPermission(per);
+
+
+ // First remove the native side item and only if that
+ // succeeds, the java side item.
+
+ int itemHandle = item.jniNativeHandle();
+ int err = _removeItem(iListHandle, itemHandle);
+ NativeError.handleRemoveItemError(err);
+
+ PIMItemImpl removedItem = iItems.removeItem(item);
+
+ if (removedItem != null) // shouldn't be null
+ {
+ removedItem.removeListAssociation();
+ }
+ }
+
+ /**
+ * Adds or sets new value for the REVISION field. This function is used when
+ * item is imported and after an import it should countain a new REVISION
+ * field
+ *
+ * @param aItem
+ * Item to which the field is to be set
+ * @param aField
+ * A specific REVISION field
+ * @param aAttributes
+ * Attributes if any
+ */
+ protected void updateRevisionField(PIMItem aItem, int aField,
+ int aAttributes)
+ {
+ // Get the associated list of this item
+ PIMList list = aItem.getPIMList();
+
+ // If the field is supported it can be added
+ if (list.isSupportedField(aField))
+ {
+ Date thisDate = new Date();
+ try
+ {
+ // Check that if there is a value already
+ if (aItem.countValues(aField) > 0)
+ {
+ aItem.setDate(aField, 0, aAttributes, thisDate.getTime());
+ }
+ else
+ {
+ aItem.addDate(aField, aAttributes, thisDate.getTime());
+ }
+ }
+ catch (UnsupportedFieldException ufe)
+ {
+ // Ignore; the value is not supported in the list
+ // this item belongs to. This exception should not
+ // be thrown but we still have to catch it
+ }
+ catch (FieldFullException ffe)
+ {
+ // Ignore; no more than supported maximum number
+ // of values can be added. This exception should
+ // not be thrown but we still have catch it
+ }
+ }
+ }
+
+ // Methods from PIMList
+
+ public synchronized String getName()
+ {
+ String name = _getName(iListHandle);
+
+ if (name == null)
+ {
+ throw new java.lang.OutOfMemoryError();
+ }
+
+ return name;
+ }
+
+ public synchronized void close() throws PIMException
+ {
+ if (iIsOpen == true)
+ {
+ iIsOpen = false;
+ int err = _close(iListHandle);
+ NativeError.handlePIMListCloseError(err);
+ iItems = null;
+ }
+ else
+ {
+ throw new PIMException(ErrorString.LIST_IS_ALREADY_CLOSED,
+ PIMException.LIST_CLOSED);
+ }
+ }
+
+ public synchronized Enumeration items() throws PIMException
+ {
+ // security checks must be done here because of TCK
+ ensurePimPermission(PIM.READ_ONLY);
+ return doItems(ENUMERATION_ITEMS_ALL, 0, null);
+ }
+
+ /**
+ * @par Notes: The given item must originate from this list, which is
+ * required in the description of this method in the PIM API spec.
+ * Ambiguously, the ContactList, EventList and ToDoList permit the item
+ * to be basically any item that implements the Contact, Event or ToDo
+ * interface, respectively. However we will live up to the tighter
+ * restrictions - for which the TCK seems to test, too.
+ */
+ public synchronized Enumeration items(PIMItem aMatchingItem)
+ throws PIMException
+ {
+ // security checks must be done here because of TCK
+ ensurePimPermission(PIM.READ_ONLY);
+
+ if (aMatchingItem == null)
+ {
+ throw new NullPointerException(ErrorString.ITEM_IS_NULL);
+ }
+
+ if (!(aMatchingItem instanceof PIMItemImpl))
+ {
+ throw new PIMException(ErrorString.INVALID_ITEM,
+ PIMException.GENERAL_ERROR);
+ }
+
+ if (aMatchingItem.getPIMList() != this)
+ {
+ throw new IllegalArgumentException(
+ ErrorString.ITEM_DOES_NOT_ORIGINATE_FROM_THIS_LIST);
+ }
+
+ PIMItemImpl matchingItemImpl = (PIMItemImpl) aMatchingItem;
+ Enumeration items = null;
+
+ // The matching item is synchronized because, in some cases, the garbage
+ // collector may collect the item before the native operation gets
+ // executed in the JNI context. This synchronization prevents the GC to
+ // collect
+ // the object before the operation gets fully executed. Note that
+ // without
+ // the synchronization, aMatchingItem would be available for the GC
+ // after
+ // matchingItemImpl.jniNativeHandle() function call and because the
+ // handle
+ // is still used, it may cause that null is referenced in the native
+ // side
+ synchronized (matchingItemImpl)
+ {
+ int matchingItemHandle = matchingItemImpl.jniNativeHandle();
+ items = doItems(ENUMERATION_ITEMS_MATCHING_ITEM,
+ matchingItemHandle, null);
+ }
+
+ return items;
+ }
+
+ public synchronized Enumeration items(String aMatchingValue)
+ throws PIMException
+ {
+ // Ensure security permission
+ ensurePimPermission(PIM.READ_ONLY);
+
+ if (aMatchingValue == null)
+ {
+ throw new NullPointerException(ErrorString.SEARCHING_FAILED_COLON +
+ ErrorString.STRING_VALUE_IS_NULL);
+ }
+
+ return doItems(ENUMERATION_ITEMS_MATCHING_STRING, 0, aMatchingValue);
+ }
+
+ public synchronized Enumeration itemsByCategory(String aCategory)
+ throws PIMException
+ {
+ // aCategory may be null (PIMList.UNCATEGORIZED, which is null)
+ // Ensure security permission
+ ensurePimPermission(PIM.READ_ONLY);
+
+ return doItems(ENUMERATION_ITEMS_MATCHING_CATEGORY, 0, aCategory);
+ }
+
+ public synchronized String[] getCategories() throws PIMException
+ {
+ int[] error = new int[1];
+
+ String[] categories = _getCategories(iListHandle, error);
+
+ NativeError.handleCategoryHandlingError(error[0]);
+ return categories;
+ }
+
+ public synchronized boolean isCategory(String aCategory)
+ throws PIMException
+ {
+ if (aCategory == null)
+ {
+ throw new NullPointerException(ErrorString.CATEGORY_MISSING);
+ }
+
+ int[] error = new int[1];
+
+ boolean isCategory = _isCategory(iListHandle, aCategory, error);
+
+ NativeError.handleCategoryHandlingError(error[0]);
+ return isCategory;
+ }
+
+ public synchronized void addCategory(String aCategory) throws PIMException
+ {
+ // Ensure security permission
+ ensurePimPermission(PIM.WRITE_ONLY);
+
+ if (aCategory == null)
+ {
+ throw new NullPointerException(ErrorString.CATEGORY_IS_NULL);
+ }
+
+ int[] error = new int[1];
+
+ _addCategory(iListHandle, aCategory, error);
+
+ NativeError.handleCategoryHandlingError(error[0], aCategory);
+ }
+
+ public synchronized void deleteCategory(String aCategory,
+ boolean aDeleteUnassignedItems) throws PIMException
+ {
+ checkModeMinimum(PIM.WRITE_ONLY);
+ if (aCategory == null)
+ {
+ throw new NullPointerException(ErrorString.CATEGORY_IS_NULL);
+ }
+ ApplicationUtils appUtils = ApplicationUtils.getInstance();
+
+ // Get localized text info for the security dialog
+ String action = null;
+ switch (getListType())
+ {
+ case PIM.CONTACT_LIST:
+ action = PIMPermissionImpl.ACTION_WRITE_CONTACTS;
+ break;
+ case PIM.EVENT_LIST:
+ action = PIMPermissionImpl.ACTION_WRITE_EVENTS;
+ break;
+ case PIM.TODO_LIST:
+ action = PIMPermissionImpl.ACTION_WRITE_TODOS;
+ break;
+ }
+
+ PIMPermissionImpl per = new PIMPermissionImpl(action, aCategory, getName(), PIMPermissionImpl.OPERATION_CATEGORY_DELETION);
+
+ // Ensure permission from PIM API security
+ appUtils.checkPermission(per);
+
+ int[] error = new int[1];
+
+ // Returns items that were assigned to the deleted category
+ // but after that do not belong to any category
+ int[] unassignedItemHandles = _deleteCategory(iListHandle, aCategory, error);
+
+ NativeError.handleCategoryHandlingError(error[0], aCategory);
+
+ // If deleting unassigned items was requested, delete them
+ // one by one (if any present)
+ if (aDeleteUnassignedItems && (unassignedItemHandles != null))
+ {
+ for (int i = 0; i < unassignedItemHandles.length; i++)
+ {
+ int itemHandle = unassignedItemHandles[i];
+ PIMItemImpl item = iItems.getItem(itemHandle);
+ if (item != null)
+ {
+ // pops up the deletion confirmation dialogue, too
+ removeItem(item);
+ }
+ }
+ }
+ }
+
+ public synchronized void renameCategory(String aCurrentCategory,
+ String aNewCategory) throws PIMException
+ {
+ // Ensure security permission
+ ensurePimPermission(PIM.WRITE_ONLY);
+
+ if (aCurrentCategory == null || aNewCategory == null)
+ {
+ throw new NullPointerException(ErrorString.CATEGORY_IS_NULL);
+ }
+
+ int error = _renameCategory(iListHandle, aCurrentCategory, aNewCategory);
+
+ if (NativeError.checkArgumentError(error))
+ {
+ // We don't know which argument is invalid
+ NativeError.handleCategoryHandlingError(error);
+ }
+ else
+ {
+ NativeError.handleCategoryHandlingError(error, aCurrentCategory);
+ }
+ }
+
+ public synchronized int maxCategories()
+ {
+ return _maxCategories(iListHandle);
+ }
+
+ public synchronized boolean isSupportedField(int aField)
+ {
+ return _isSupportedField(iListHandle, aField);
+ }
+
+ public synchronized int[] getSupportedFields()
+ {
+ Logger.LOG(Logger.EPim,Logger.EInfo,"+getSupportedFields() = iListHandle = "+iListHandle);
+ int[] supportedFields = _getSupportedFields(iListHandle);
+
+ if (supportedFields == null)
+ {
+ throw new OutOfMemoryError();
+ }
+
+ return supportedFields;
+ }
+
+ public synchronized boolean isSupportedAttribute(int aField, int aAttribute)
+ {
+ return _isSupportedAttribute(iListHandle, aField, aAttribute);
+ }
+
+ public synchronized int[] getSupportedAttributes(int aField)
+ {
+ int[] error = new int[1];
+
+ int[] supportedAttributes = _getSupportedAttributes(iListHandle, aField,
+ error);
+
+ NativeError.handleFieldHandlingError(error[0], aField);
+ return supportedAttributes;
+ }
+
+ public synchronized boolean isSupportedArrayElement(int aStringArrayField,
+ int aArrayElement)
+ {
+ return _isSupportedArrayElement(iListHandle, aStringArrayField, aArrayElement);
+ }
+
+ public synchronized int[] getSupportedArrayElements(int aStringArrayField)
+ {
+ int[] error = new int[1];
+
+ int[] supportedArrayElements = _getSupportedArrayElements(iListHandle,
+ aStringArrayField, error);
+
+ NativeError.handleFieldHandlingError(error[0], aStringArrayField);
+ return supportedArrayElements;
+ }
+
+ public synchronized int getFieldDataType(int aField)
+ {
+ int[] error = new int[1];
+
+ int fieldDataType = _getFieldDataType(iListHandle, aField, error);
+
+ NativeError.handleFieldHandlingError(error[0], aField);
+ return fieldDataType;
+ }
+
+ public synchronized String getFieldLabel(int aField)
+ {
+ int[] labelSpec = new int[1];
+ labelSpec[0] = aField;
+
+ int[] error = new int[1];
+
+ String label = _getLabel(iListHandle, LABEL_TYPE_FIELD, labelSpec, error);
+
+ NativeError.handleFieldHandlingError(error[0], aField);
+ return label;
+ }
+
+ public synchronized String getAttributeLabel(int aAttribute)
+ {
+ int[] labelSpec = new int[1];
+ labelSpec[0] = aAttribute;
+
+ int[] error = new int[1];
+
+ String label = _getLabel(iListHandle, LABEL_TYPE_ATTRIBUTE, labelSpec, error);
+
+ // Note that we use unusual exception descriptions here.
+ NativeError.handlegetAttributeLabelError(error[0], aAttribute);
+
+ return label;
+ }
+
+ public synchronized String getArrayElementLabel(int aStringArrayField,
+ int aArrayElement)
+ {
+ int[] labelSpec = new int[2];
+ labelSpec[0] = aStringArrayField;
+ labelSpec[1] = aArrayElement;
+
+ int[] error = new int[1];
+
+ String label = _getLabel(
+
+ iListHandle, LABEL_TYPE_ARRAY_ELEMENT, labelSpec, error);
+
+ // Note that we use unusual exception descriptions here.
+ NativeError.handleArrayElementLabelError(error[0]);
+
+ return label;
+ }
+
+ public synchronized int maxValues(int aField)
+ {
+ int[] error = new int[1];
+
+ int maxValues = _maxValues(iListHandle, aField, error);
+
+ NativeError.handleFieldHandlingError(error[0], aField);
+ return maxValues;
+ }
+
+ public synchronized int stringArraySize(int aStringArrayField)
+ {
+ int[] error = new int[1];
+
+ int stringArraySize = _stringArraySize(iListHandle, aStringArrayField,
+ error);
+
+ NativeError.handleFieldHandlingError(error[0], aStringArrayField);
+ return stringArraySize;
+ }
+
+ // New methods
+
+ /**
+ * Updates list of items according to the changes in the native database.
+ * Changes in items and categories are reflected appropriately.
+ *
+ * @par aMatchingItemHandle Handle to matching item if any
+ *
+ * @par NOTES: The handle to a matching item provides information that which
+ * fields must be loaded from the items if the list supports partial
+ * item loading. This is done because of the performance improvement of
+ * item handling with large databases
+ *
+ * @par About errors: Generally all errors are fatal during the update,
+ * because in case of out-of-memory situation the list is probably
+ * corrupt and it would be dangerous to continue execution.
+ */
+ protected void updateList(int aMatchingItemHandle) throws PIMException
+ {
+ int[] error = new int[1];
+
+ int[] newAndRemovedItemHandles = _updateList(
+
+ iListHandle, aMatchingItemHandle, error);
+ NativeError.handleUpdateListError(error[0]);
+
+ if (newAndRemovedItemHandles != null) // shouldn't be null
+ {
+ int removedItemsStart = 0;
+
+ // Create and add new items and find the start of removed
+ // item handles.
+ for (int i = 0; i < newAndRemovedItemHandles.length; i++)
+ {
+ if (newAndRemovedItemHandles[i] != 0)
+ {
+ int itemHandle = newAndRemovedItemHandles[i];
+ PIMItemImpl newItem = createAssociatedItem(itemHandle);
+ iItems.addItem(newItem);
+ }
+ else
+ {
+ // boundary element; start of removed item handles
+ removedItemsStart = i + 1;
+ break;
+ }
+ }
+
+ // Remove removed items
+ // Loop from the removed items start to the end of the list.
+ // May result to zero iterations.
+ for (int i = removedItemsStart; i < newAndRemovedItemHandles.length; i++)
+ {
+ int itemHandle = newAndRemovedItemHandles[i];
+ PIMItemImpl item = iItems.removeItem(itemHandle);
+
+ if (item != null) // shouldn't be null
+ {
+ item.removeListAssociation();
+ }
+ }
+ }
+ }
+
+ /**
+ * Common implementation of items() calls.
+ *
+ * This is a binary size optimization of the four different PIMList.items()
+ * calls, reducing the number of necessary JNI functions from four to one.
+ *
+ * Optimization adds complexity to the operation signature. Enumeration type
+ * and associated matching arguments must be given.
+ *
+ * @param aEnumerationType
+ * Enumeration type, one of: ENUMERATION_ITEMS_ALL,
+ * ENUMERATION_ITEMS_MATCHING_ITEM,
+ * ENUMERATION_ITEMS_MATCHING_STRING or
+ * ENUMERATION_ITEMS_MATCHING_CATEGORY.
+ *
+ * @param aMatchingItemHandle
+ * Handle to matching item. Used with
+ * ENUMERATION_ITEMS_MATCHING_ITEM; ignored otherwise.
+ *
+ * @param aStringArg
+ * String argument. Used with ENUMERATION_ITEMS_MATCHING_STRING
+ * and ENUMERATION_ITEMS_MATCHING_CATEGORY; ignored otherwise.
+ * May be null for category matching.
+ *
+ * Arguments must be pre-checked.
+ */
+ protected Enumeration doItems(int aEnumerationType,
+ int aMatchingItemHandle, String aStringArg) throws PIMException
+ {
+ updateList(aMatchingItemHandle);
+ int[] error = new int[1];
+
+ int[] itemHandles = _items(iListHandle, aEnumerationType,
+ aMatchingItemHandle, // used for item matching
+ aStringArg, // used for value or category matching
+ error);
+
+ return processItemsResults(itemHandles, error[0]);
+ }
+
+ /**
+ * Creates an enumeration of items from an array of item handles and
+ * processes any errors resulting from obtaining item handles from native
+ * side.
+ *
+ * Note: Used by EventListImpl and ToDoListImpl, too.
+ */
+ protected Enumeration processItemsResults(int[] aItemHandles, int aError)
+ throws PIMException
+ {
+ if (aItemHandles == null)
+ {
+ throw new OutOfMemoryError();
+ }
+ NativeError.handleProcessItemResultsError(aError);
+
+ Vector items = new Vector(aItemHandles.length);
+
+ for (int i = 0; i < aItemHandles.length; i++)
+ {
+ int itemHandle = aItemHandles[i];
+ PIMItemImpl item = iItems.getItem(itemHandle);
+
+ if (item != null) // shouldn't be null
+ {
+ items.addElement(item);
+ }
+ }
+
+ return items.elements();
+ }
+
+ /**
+ * ensurePimPermission
+ * Ensures indicated PIM API security permission for this list
+ * This function is common for all list which need to verify PIM API
+ * security permissions. It also check that the list has at least
+ * the requested mode
+ *
+ * @param aMode The mode which is requested to be permitted
+ */
+ protected void ensurePimPermission(int aMode)
+ {
+ // Ensure that the list has at least the requested mode
+ checkModeMinimum(aMode);
+
+ PIMManager manager = (PIMManager)PIMManager.getInstance();
+
+ //ensure permission
+ manager.getPermission(getListType(), aMode);
+
+ }
+
+
+ /**
+ * Creates new item of specialized type.
+ */
+ protected abstract PIMItemImpl createAssociatedItem(int aItemHandle);
+
+ /**
+ * Determines whether the list has <em>at least</em> given access mode.
+ *
+ * @return \c true if all modes in \a aMode are present; \c false otherwise.
+ */
+ boolean isModeMinimum(int aMode)
+ {
+ return ((iMode & aMode) == aMode);
+ }
+
+ /**
+ * Checks whether the list has <em>at least</em> given access mode and
+ * throws SecurityException if not.
+ */
+ void checkModeMinimum(int aMode)
+ {
+ if (!isModeMinimum(aMode))
+ {
+ throw new SecurityException();
+ }
+ }
+
+ // Native operations
+
+ private native void _dispose(int aPIMManagerHandle);
+
+ /**
+ * Creates a new native side specialized item that is associated with the
+ * native side list but is not added to the list.
+ *
+ * @return Handle to the native side item or < 0 in error.
+ */
+ private native int _createItem(int aListHandle, int[] aError);
+
+ /**
+ * Removes given item from native database
+ *
+ * @return < 0 for error; KERR_NONE otherwise.
+ */
+ private native int _removeItem(int aListHandle, int aItemHandle);
+
+ /**
+ * Adds a new, first time committed item to the list.
+ */
+ private native int _addCommittedItem(int aListHandle, int aItemHandle);
+
+ /**
+ * @return List name, or null in error (taken as "out of memory").
+ */
+ private native String _getName(int aListHandle);
+
+ /**
+ * Closes the list.
+ */
+ private native int _close(int aListHandle);
+
+ /**
+ * Common JNI function for the four different items() operations. See
+ * doItems().
+ */
+ private native int[] _items(int aListHandle, int aEnumerationType,
+ int aMatchingItemHandle, String aStringArg, int[] aError);
+
+ private native String[] _getCategories(int aListHandle, int[] aError);
+
+ private native boolean _isCategory(int aListHandle, String aCategory,
+ int[] aError);
+
+ private native void _addCategory(int aListHandle, String aCategory,
+ int[] aError);
+
+ /**
+ * @return The native handles of items that were in the removed category and
+ * do not belong to any category any more; null if the category was
+ * not removed (i.e. it did not exist).
+ */
+ private native int[] _deleteCategory(int aListHandle, String aCategory,
+ int[] aError);
+
+ /**
+ * @return Error code.
+ */
+ private native int _renameCategory(int aListHandle, String aCurrentCategory,
+ String aNewCategory);
+
+ private native int _maxCategories(int aListHandle);
+
+ private native boolean _isSupportedField(int aListHandle, int aField);
+
+ /**
+ * @return null on error.
+ */
+ private native int[] _getSupportedFields(int aListHandle);
+
+ private native boolean _isSupportedAttribute(int aListHandle, int aField,
+ int aAttribute);
+
+ private native int[] _getSupportedAttributes(int aListHandle, int aField, int[] aError);
+
+ private native boolean _isSupportedArrayElement(int aListHandle, int aStringArrayField,
+ int aArrayElement);
+
+ private native int[] _getSupportedArrayElements(int aListHandle, int aStringArrayField,
+ int[] aError);
+
+ private native int _getFieldDataType(int aListHandle, int aField, int[] aError);
+
+ /**
+ * Common implementation for all label getting operations.
+ *
+ * Contents of \a aLabelSpec argument:
+ *
+ * @li If \a aLabelType is LABEL_TYPE_FIELD, field constant (1 element).
+ *
+ * @li If \a aLabelType is LABEL_TYPE_ATTRIBUTE, attribute constant (1
+ * element)
+ *
+ * @li If \a aLabelType is LABEL_TYPE_ARRAY_ELEMENT, string array field
+ * constant and an array element field constant (2 elements).
+ *
+ * @param aLabelType
+ * Label type (field, attribute or array element label).
+ *
+ * @param aLabelSpec
+ * Constants used as arguments for label getting functions.
+ *
+ * @return The label.
+ */
+ private native String _getLabel(int aListHandle, int aLabelType,
+ int[] aLabelSpec, int[] aError);
+
+ private native int _maxValues(int aListHandle, int aField, int[] aError);
+
+ private native int _stringArraySize(int aListHandle, int aStringArrayField,
+ int[] aError);
+
+ /**
+ * Updates the list according to native-originated external changes. Makes
+ * the native side to resolve new, modified and removed items items in the
+ * native database and to create new native side peer objects, updating
+ * modified and removing removed items. Category changes are also reflected,
+ * but this does not affect the Java side.
+ *
+ * @return An array containing handles to new items, zero and handles to
+ * removed items, contiguously, in that order.
+ */
+ private native int[] _updateList(int aListHandle, int aMatchingItemHandle,
+ int[] aError);
+
+}