javaextensions/pim/javasrc/com/nokia/mj/impl/pim/PIMListImpl.java
branchRCL_3
changeset 19 04becd199f91
child 67 63b81d807542
equal deleted inserted replaced
16:f5050f1da672 19:04becd199f91
       
     1 /*
       
     2 * Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:  PIM list implementation base.
       
    15  *
       
    16 */
       
    17 
       
    18 
       
    19 // PACKAGE
       
    20 package com.nokia.mj.impl.pim;
       
    21 
       
    22 // IMPORTS
       
    23 
       
    24 import javax.microedition.pim.FieldFullException;
       
    25 import javax.microedition.pim.PIM;
       
    26 import javax.microedition.pim.PIMException;
       
    27 import javax.microedition.pim.PIMItem;
       
    28 import javax.microedition.pim.PIMList;
       
    29 import javax.microedition.pim.UnsupportedFieldException;
       
    30 import java.util.Enumeration;
       
    31 import java.util.Date;
       
    32 import java.util.Vector;
       
    33 import com.nokia.mj.impl.pim.ErrorString;
       
    34 import com.nokia.mj.impl.pim.GenericException;
       
    35 import com.nokia.mj.impl.rt.support.ApplicationUtils;
       
    36 import com.nokia.mj.impl.rt.support.Finalizer;
       
    37 import com.nokia.mj.impl.rt.support.ShutdownListener;
       
    38 import com.nokia.mj.impl.pim.utils.NativeError;
       
    39 import com.nokia.mj.impl.utils.Logger;
       
    40 
       
    41 // CLASS DEFINITION
       
    42 /**
       
    43  * Base class for specialized PIMList classes.
       
    44  *
       
    45  * @par About item creation: New PIMItem-derived classes are created during list
       
    46  *      update. The list is updated whenever items are enumerated with one of
       
    47  *      the items() methods. During the update native-originated changes are
       
    48  *      synchronized. When items are enumerated for the first time from the
       
    49  *      list, whole content of the corresponding native database is considered
       
    50  *      as new items and are created at that time. See updateList() method.
       
    51  */
       
    52 public abstract class PIMListImpl implements PIMList
       
    53 {
       
    54     // Constants
       
    55 
       
    56     /** Label type Field. */
       
    57     private static final int LABEL_TYPE_FIELD = 1;
       
    58 
       
    59     /** Label type Attribute. */
       
    60     private static final int LABEL_TYPE_ATTRIBUTE = 2;
       
    61 
       
    62     /** Label type Array Element. */
       
    63     private static final int LABEL_TYPE_ARRAY_ELEMENT = 3;
       
    64 
       
    65     /** Enumeration flag: all items. See items(). */
       
    66     protected final static int ENUMERATION_ITEMS_ALL = 0;
       
    67 
       
    68     /** Enumeration flag: items matching given item. See items(). */
       
    69     protected final static int ENUMERATION_ITEMS_MATCHING_ITEM = 1;
       
    70 
       
    71     /** Enumeration flag: items matching given string. See items(). */
       
    72     protected final static int ENUMERATION_ITEMS_MATCHING_STRING = 2;
       
    73 
       
    74     /** Enumeration flag: items matching given category. See items(). */
       
    75     protected final static int ENUMERATION_ITEMS_MATCHING_CATEGORY = 3;
       
    76 
       
    77     // Member data
       
    78     private Finalizer iFinalizer;
       
    79 
       
    80     /** JNI native handle to the native side peer object. */
       
    81     protected int iListHandle;
       
    82 
       
    83     /**
       
    84      * Items.
       
    85      */
       
    86     protected ItemTable iItems;
       
    87 
       
    88     /**
       
    89      * Access mode, one of:
       
    90      *
       
    91      * @li PIM.READ_ONLY
       
    92      * @li PIM.WRITE_ONLY
       
    93      * @li PIM.READ_WRITE.
       
    94      */
       
    95     private int iMode = 0;
       
    96 
       
    97     /**
       
    98      * State flag, open or closed. New instance of PIMListImpl is always
       
    99      * initially open.
       
   100      */
       
   101     private boolean iIsOpen = true;
       
   102 
       
   103     // Constructors
       
   104 
       
   105     /**
       
   106      * Initializes the list with native side Event Source and list peer object
       
   107      * handles and registers the object for finalization.
       
   108      *
       
   109      * Given mode applies to all security vulnerable operations.
       
   110      */
       
   111     PIMListImpl(int aListHandle, int aMode)
       
   112     {
       
   113         iListHandle = aListHandle;
       
   114         Logger.LOG(Logger.EPim,Logger.EInfo,"+PIMListImpl() = iListHandle = "+iListHandle);
       
   115         setShutdownListener();
       
   116         iFinalizer = registerForFinalization();
       
   117         iMode = aMode;
       
   118 
       
   119         iItems = new ItemTable();
       
   120     }
       
   121 
       
   122     public Finalizer registerForFinalization()
       
   123     {
       
   124         return new Finalizer()
       
   125         {
       
   126             public void finalizeImpl()
       
   127             {
       
   128 
       
   129                 doFinalize();
       
   130 
       
   131             }
       
   132         };
       
   133 
       
   134     }
       
   135 
       
   136     void doFinalize()
       
   137     {
       
   138         if (iFinalizer == null)
       
   139         {
       
   140             return;
       
   141         }
       
   142         iFinalizer = null;
       
   143 
       
   144         if (iListHandle != 0)
       
   145         {
       
   146             _dispose(iListHandle);
       
   147             iListHandle = 0;
       
   148         }
       
   149     }
       
   150 
       
   151     /**
       
   152      * Registers for shutdown listener
       
   153      */
       
   154     private void setShutdownListener()
       
   155     {
       
   156         // Get the insatnce of ApplicationUtils.
       
   157         ApplicationUtils appUtils = ApplicationUtils.getInstance();
       
   158 
       
   159         // Get the name of the application.
       
   160         appUtils.addShutdownListener(new ShutdownListener()
       
   161         {
       
   162             public void shuttingDown()
       
   163             {
       
   164                 if (iListHandle != 0)
       
   165                 {
       
   166                     _dispose(iListHandle);
       
   167                     iListHandle = 0;
       
   168                 }
       
   169             }
       
   170         });
       
   171     }
       
   172 
       
   173     // New methods
       
   174 
       
   175     /**
       
   176      * Gets the list type. Used for resolving permissions.
       
   177      */
       
   178     abstract int getListType();
       
   179 
       
   180     /**
       
   181      * Determines whether this list is still open or has it been closed.
       
   182      */
       
   183     boolean isOpen()
       
   184     {
       
   185         return iIsOpen;
       
   186     }
       
   187 
       
   188     /**
       
   189      * Items that are associated with this list call this method when they are
       
   190      * committed. When an item is committed it is checked whether belongs to the
       
   191      * list already and added if not. If the item has been recently created and
       
   192      * never committed, it does not yet belong to the list.
       
   193      */
       
   194     void itemCommitted(PIMItemImpl aCommittedItem)
       
   195     {
       
   196         if (!iItems.containsItem(aCommittedItem))
       
   197         {
       
   198             int committedItemHandle = aCommittedItem.jniNativeHandle();
       
   199 
       
   200             int error = _addCommittedItem(iListHandle, committedItemHandle);
       
   201             if (!NativeError.checkSuccess(error))
       
   202             {
       
   203                 throw new GenericException(ErrorString.GENERAL_ERROR_COLON + error);
       
   204             }
       
   205 
       
   206             iItems.addItem(aCommittedItem);
       
   207         }
       
   208     }
       
   209 
       
   210     /**
       
   211      * Creates a new specialized item and associates it with the list. This is
       
   212      * the common implementation of createXyz() methods in specialized lists.
       
   213      * The polymorphic behaviour is implemented in the native side.
       
   214      */
       
   215     protected PIMItemImpl createItem()
       
   216     {
       
   217         int[] err = new int[1];
       
   218         int itemHandle = _createItem(iListHandle, err);
       
   219         if (!NativeError.checkSuccess(err[0]))
       
   220         {
       
   221             throw new GenericException(ErrorString.GENERAL_ERROR_COLON + err[0]);
       
   222         }
       
   223 
       
   224         PIMItemImpl item = createAssociatedItem(itemHandle);
       
   225         return item;
       
   226     }
       
   227 
       
   228     protected void removeItem(PIMItem aItem) throws PIMException
       
   229     {
       
   230         if (aItem == null)
       
   231         {
       
   232             throw new NullPointerException(ErrorString.ITEM_IS_NULL);
       
   233         }
       
   234 
       
   235         if (!(aItem instanceof PIMItemImpl))
       
   236         {
       
   237             throw new PIMException(ErrorString.REMOVAL_FAILED_COLON +
       
   238                                    ErrorString.INVALID_ITEM,
       
   239                                    PIMException.GENERAL_ERROR);
       
   240         }
       
   241 
       
   242         // Check that list is not closed
       
   243         if (!isOpen())
       
   244         {
       
   245             throw new PIMException(ErrorString.REMOVAL_FAILED_COLON +
       
   246                                    ErrorString.LIST_IS_CLOSED, PIMException.LIST_CLOSED);
       
   247         }
       
   248 
       
   249         PIMItemImpl item = (PIMItemImpl) aItem;
       
   250 
       
   251         if (!iItems.containsItem(item))
       
   252         {
       
   253             throw new PIMException(ErrorString.REMOVAL_FAILED_COLON +
       
   254                                    ErrorString.ITEM_IS_NOT_IN_THE_LIST,
       
   255                                    PIMException.GENERAL_ERROR);
       
   256         }
       
   257         ApplicationUtils appUtils = ApplicationUtils.getInstance();
       
   258         String action = null;
       
   259         switch (getListType())
       
   260         {
       
   261         case PIM.CONTACT_LIST:
       
   262             action = PIMPermissionImpl.ACTION_WRITE_CONTACTS;
       
   263             break;
       
   264         case PIM.EVENT_LIST:
       
   265             action = PIMPermissionImpl.ACTION_WRITE_EVENTS;
       
   266             break;
       
   267         case PIM.TODO_LIST:
       
   268             action = PIMPermissionImpl.ACTION_WRITE_TODOS;
       
   269             break;
       
   270         }
       
   271 
       
   272         // Get localized text info for the security dialog
       
   273         PIMPermissionImpl per = new PIMPermissionImpl(action, item.getShortInfo(), getName(), PIMPermissionImpl.OPERATION_ITEM_DELETION);
       
   274 
       
   275         // Ensure permission from PIM API security
       
   276         appUtils.checkPermission(per);
       
   277 
       
   278 
       
   279         // First remove the native side item and only if that
       
   280         // succeeds, the java side item.
       
   281 
       
   282         int itemHandle = item.jniNativeHandle();
       
   283         int err = _removeItem(iListHandle, itemHandle);
       
   284         NativeError.handleRemoveItemError(err);
       
   285 
       
   286         PIMItemImpl removedItem = iItems.removeItem(item);
       
   287 
       
   288         if (removedItem != null) // shouldn't be null
       
   289         {
       
   290             removedItem.removeListAssociation();
       
   291         }
       
   292     }
       
   293 
       
   294     /**
       
   295      * Adds or sets new value for the REVISION field. This function is used when
       
   296      * item is imported and after an import it should countain a new REVISION
       
   297      * field
       
   298      *
       
   299      * @param aItem
       
   300      *            Item to which the field is to be set
       
   301      * @param aField
       
   302      *            A specific REVISION field
       
   303      * @param aAttributes
       
   304      *            Attributes if any
       
   305      */
       
   306     protected void updateRevisionField(PIMItem aItem, int aField,
       
   307                                        int aAttributes)
       
   308     {
       
   309         // Get the associated list of this item
       
   310         PIMList list = aItem.getPIMList();
       
   311 
       
   312         // If the field is supported it can be added
       
   313         if (list.isSupportedField(aField))
       
   314         {
       
   315             Date thisDate = new Date();
       
   316             try
       
   317             {
       
   318                 // Check that if there is a value already
       
   319                 if (aItem.countValues(aField) > 0)
       
   320                 {
       
   321                     aItem.setDate(aField, 0, aAttributes, thisDate.getTime());
       
   322                 }
       
   323                 else
       
   324                 {
       
   325                     aItem.addDate(aField, aAttributes, thisDate.getTime());
       
   326                 }
       
   327             }
       
   328             catch (UnsupportedFieldException ufe)
       
   329             {
       
   330                 // Ignore; the value is not supported in the list
       
   331                 // this item belongs to. This exception should not
       
   332                 // be thrown but we still have to catch it
       
   333             }
       
   334             catch (FieldFullException ffe)
       
   335             {
       
   336                 // Ignore; no more than supported maximum number
       
   337                 // of values can be added. This exception should
       
   338                 // not be thrown but we still have catch it
       
   339             }
       
   340         }
       
   341     }
       
   342 
       
   343     // Methods from PIMList
       
   344 
       
   345     public synchronized String getName()
       
   346     {
       
   347         String name = _getName(iListHandle);
       
   348 
       
   349         if (name == null)
       
   350         {
       
   351             throw new java.lang.OutOfMemoryError();
       
   352         }
       
   353 
       
   354         return name;
       
   355     }
       
   356 
       
   357     public synchronized void close() throws PIMException
       
   358     {
       
   359         if (iIsOpen == true)
       
   360         {
       
   361             iIsOpen = false;
       
   362             int err = _close(iListHandle);
       
   363             NativeError.handlePIMListCloseError(err);
       
   364             iItems = null;
       
   365         }
       
   366         else
       
   367         {
       
   368             throw new PIMException(ErrorString.LIST_IS_ALREADY_CLOSED,
       
   369                                    PIMException.LIST_CLOSED);
       
   370         }
       
   371     }
       
   372 
       
   373     public synchronized Enumeration items() throws PIMException
       
   374     {
       
   375         // security checks must be done here because of TCK
       
   376         ensurePimPermission(PIM.READ_ONLY);
       
   377         return doItems(ENUMERATION_ITEMS_ALL, 0, null);
       
   378     }
       
   379 
       
   380     /**
       
   381      * @par Notes: The given item must originate from this list, which is
       
   382      *      required in the description of this method in the PIM API spec.
       
   383      *      Ambiguously, the ContactList, EventList and ToDoList permit the item
       
   384      *      to be basically any item that implements the Contact, Event or ToDo
       
   385      *      interface, respectively. However we will live up to the tighter
       
   386      *      restrictions - for which the TCK seems to test, too.
       
   387      */
       
   388     public synchronized Enumeration items(PIMItem aMatchingItem)
       
   389     throws PIMException
       
   390     {
       
   391         // security checks must be done here because of TCK
       
   392         ensurePimPermission(PIM.READ_ONLY);
       
   393 
       
   394         if (aMatchingItem == null)
       
   395         {
       
   396             throw new NullPointerException(ErrorString.ITEM_IS_NULL);
       
   397         }
       
   398 
       
   399         if (!(aMatchingItem instanceof PIMItemImpl))
       
   400         {
       
   401             throw new PIMException(ErrorString.INVALID_ITEM,
       
   402                                    PIMException.GENERAL_ERROR);
       
   403         }
       
   404 
       
   405         if (aMatchingItem.getPIMList() != this)
       
   406         {
       
   407             throw new IllegalArgumentException(
       
   408                 ErrorString.ITEM_DOES_NOT_ORIGINATE_FROM_THIS_LIST);
       
   409         }
       
   410 
       
   411         PIMItemImpl matchingItemImpl = (PIMItemImpl) aMatchingItem;
       
   412         Enumeration items = null;
       
   413 
       
   414         // The matching item is synchronized because, in some cases, the garbage
       
   415         // collector may collect the item before the native operation gets
       
   416         // executed in the JNI context. This synchronization prevents the GC to
       
   417         // collect
       
   418         // the object before the operation gets fully executed. Note that
       
   419         // without
       
   420         // the synchronization, aMatchingItem would be available for the GC
       
   421         // after
       
   422         // matchingItemImpl.jniNativeHandle() function call and because the
       
   423         // handle
       
   424         // is still used, it may cause that null is referenced in the native
       
   425         // side
       
   426         synchronized (matchingItemImpl)
       
   427         {
       
   428             int matchingItemHandle = matchingItemImpl.jniNativeHandle();
       
   429             items = doItems(ENUMERATION_ITEMS_MATCHING_ITEM,
       
   430                             matchingItemHandle, null);
       
   431         }
       
   432 
       
   433         return items;
       
   434     }
       
   435 
       
   436     public synchronized Enumeration items(String aMatchingValue)
       
   437     throws PIMException
       
   438     {
       
   439         // Ensure security permission
       
   440         ensurePimPermission(PIM.READ_ONLY);
       
   441 
       
   442         if (aMatchingValue == null)
       
   443         {
       
   444             throw new NullPointerException(ErrorString.SEARCHING_FAILED_COLON +
       
   445                                            ErrorString.STRING_VALUE_IS_NULL);
       
   446         }
       
   447 
       
   448         return doItems(ENUMERATION_ITEMS_MATCHING_STRING, 0, aMatchingValue);
       
   449     }
       
   450 
       
   451     public synchronized Enumeration itemsByCategory(String aCategory)
       
   452     throws PIMException
       
   453     {
       
   454         // aCategory may be null (PIMList.UNCATEGORIZED, which is null)
       
   455         // Ensure security permission
       
   456         ensurePimPermission(PIM.READ_ONLY);
       
   457 
       
   458         return doItems(ENUMERATION_ITEMS_MATCHING_CATEGORY, 0, aCategory);
       
   459     }
       
   460 
       
   461     public synchronized String[] getCategories() throws PIMException
       
   462     {
       
   463         int[] error = new int[1];
       
   464 
       
   465         String[] categories = _getCategories(iListHandle, error);
       
   466 
       
   467         NativeError.handleCategoryHandlingError(error[0]);
       
   468         return categories;
       
   469     }
       
   470 
       
   471     public synchronized boolean isCategory(String aCategory)
       
   472     throws PIMException
       
   473     {
       
   474         if (aCategory == null)
       
   475         {
       
   476             throw new NullPointerException(ErrorString.CATEGORY_MISSING);
       
   477         }
       
   478 
       
   479         int[] error = new int[1];
       
   480 
       
   481         boolean isCategory = _isCategory(iListHandle, aCategory, error);
       
   482 
       
   483         NativeError.handleCategoryHandlingError(error[0]);
       
   484         return isCategory;
       
   485     }
       
   486 
       
   487     public synchronized void addCategory(String aCategory) throws PIMException
       
   488     {
       
   489         // Ensure security permission
       
   490         ensurePimPermission(PIM.WRITE_ONLY);
       
   491 
       
   492         if (aCategory == null)
       
   493         {
       
   494             throw new NullPointerException(ErrorString.CATEGORY_IS_NULL);
       
   495         }
       
   496 
       
   497         int[] error = new int[1];
       
   498 
       
   499         _addCategory(iListHandle, aCategory, error);
       
   500 
       
   501         NativeError.handleCategoryHandlingError(error[0], aCategory);
       
   502     }
       
   503 
       
   504     public synchronized void deleteCategory(String aCategory,
       
   505                                             boolean aDeleteUnassignedItems) throws PIMException
       
   506     {
       
   507         checkModeMinimum(PIM.WRITE_ONLY);
       
   508         if (aCategory == null)
       
   509         {
       
   510             throw new NullPointerException(ErrorString.CATEGORY_IS_NULL);
       
   511         }
       
   512         ApplicationUtils appUtils = ApplicationUtils.getInstance();
       
   513 
       
   514         // Get localized text info for the security dialog
       
   515         String action = null;
       
   516         switch (getListType())
       
   517         {
       
   518         case PIM.CONTACT_LIST:
       
   519             action = PIMPermissionImpl.ACTION_WRITE_CONTACTS;
       
   520             break;
       
   521         case PIM.EVENT_LIST:
       
   522             action = PIMPermissionImpl.ACTION_WRITE_EVENTS;
       
   523             break;
       
   524         case PIM.TODO_LIST:
       
   525             action = PIMPermissionImpl.ACTION_WRITE_TODOS;
       
   526             break;
       
   527         }
       
   528 
       
   529         PIMPermissionImpl per = new PIMPermissionImpl(action, aCategory, getName(), PIMPermissionImpl.OPERATION_CATEGORY_DELETION);
       
   530 
       
   531         // Ensure permission from PIM API security
       
   532         appUtils.checkPermission(per);
       
   533 
       
   534         int[] error = new int[1];
       
   535 
       
   536         // Returns items that were assigned to the deleted category
       
   537         // but after that do not belong to any category
       
   538         int[] unassignedItemHandles = _deleteCategory(iListHandle, aCategory, error);
       
   539 
       
   540         NativeError.handleCategoryHandlingError(error[0], aCategory);
       
   541 
       
   542         // If deleting unassigned items was requested, delete them
       
   543         // one by one (if any present)
       
   544         if (aDeleteUnassignedItems && (unassignedItemHandles != null))
       
   545         {
       
   546             for (int i = 0; i < unassignedItemHandles.length; i++)
       
   547             {
       
   548                 int itemHandle = unassignedItemHandles[i];
       
   549                 PIMItemImpl item = iItems.getItem(itemHandle);
       
   550                 if (item != null)
       
   551                 {
       
   552                     // pops up the deletion confirmation dialogue, too
       
   553                     removeItem(item);
       
   554                 }
       
   555             }
       
   556         }
       
   557     }
       
   558 
       
   559     public synchronized void renameCategory(String aCurrentCategory,
       
   560                                             String aNewCategory) throws PIMException
       
   561     {
       
   562         // Ensure security permission
       
   563         ensurePimPermission(PIM.WRITE_ONLY);
       
   564 
       
   565         if (aCurrentCategory == null || aNewCategory == null)
       
   566         {
       
   567             throw new NullPointerException(ErrorString.CATEGORY_IS_NULL);
       
   568         }
       
   569 
       
   570         int error = _renameCategory(iListHandle, aCurrentCategory, aNewCategory);
       
   571 
       
   572         if (NativeError.checkArgumentError(error))
       
   573         {
       
   574             // We don't know which argument is invalid
       
   575             NativeError.handleCategoryHandlingError(error);
       
   576         }
       
   577         else
       
   578         {
       
   579             NativeError.handleCategoryHandlingError(error, aCurrentCategory);
       
   580         }
       
   581     }
       
   582 
       
   583     public synchronized int maxCategories()
       
   584     {
       
   585         return _maxCategories(iListHandle);
       
   586     }
       
   587 
       
   588     public synchronized boolean isSupportedField(int aField)
       
   589     {
       
   590         return _isSupportedField(iListHandle, aField);
       
   591     }
       
   592 
       
   593     public synchronized int[] getSupportedFields()
       
   594     {
       
   595         Logger.LOG(Logger.EPim,Logger.EInfo,"+getSupportedFields() = iListHandle = "+iListHandle);
       
   596         int[] supportedFields = _getSupportedFields(iListHandle);
       
   597 
       
   598         if (supportedFields == null)
       
   599         {
       
   600             throw new OutOfMemoryError();
       
   601         }
       
   602 
       
   603         return supportedFields;
       
   604     }
       
   605 
       
   606     public synchronized boolean isSupportedAttribute(int aField, int aAttribute)
       
   607     {
       
   608         return _isSupportedAttribute(iListHandle, aField, aAttribute);
       
   609     }
       
   610 
       
   611     public synchronized int[] getSupportedAttributes(int aField)
       
   612     {
       
   613         int[] error = new int[1];
       
   614 
       
   615         int[] supportedAttributes = _getSupportedAttributes(iListHandle, aField,
       
   616                                     error);
       
   617 
       
   618         NativeError.handleFieldHandlingError(error[0], aField);
       
   619         return supportedAttributes;
       
   620     }
       
   621 
       
   622     public synchronized boolean isSupportedArrayElement(int aStringArrayField,
       
   623             int aArrayElement)
       
   624     {
       
   625         return _isSupportedArrayElement(iListHandle, aStringArrayField, aArrayElement);
       
   626     }
       
   627 
       
   628     public synchronized int[] getSupportedArrayElements(int aStringArrayField)
       
   629     {
       
   630         int[] error = new int[1];
       
   631 
       
   632         int[] supportedArrayElements = _getSupportedArrayElements(iListHandle,
       
   633                                        aStringArrayField, error);
       
   634 
       
   635         NativeError.handleFieldHandlingError(error[0], aStringArrayField);
       
   636         return supportedArrayElements;
       
   637     }
       
   638 
       
   639     public synchronized int getFieldDataType(int aField)
       
   640     {
       
   641         int[] error = new int[1];
       
   642 
       
   643         int fieldDataType = _getFieldDataType(iListHandle, aField, error);
       
   644 
       
   645         NativeError.handleFieldHandlingError(error[0], aField);
       
   646         return fieldDataType;
       
   647     }
       
   648 
       
   649     public synchronized String getFieldLabel(int aField)
       
   650     {
       
   651         int[] labelSpec = new int[1];
       
   652         labelSpec[0] = aField;
       
   653 
       
   654         int[] error = new int[1];
       
   655 
       
   656         String label = _getLabel(iListHandle, LABEL_TYPE_FIELD, labelSpec, error);
       
   657 
       
   658         NativeError.handleFieldHandlingError(error[0], aField);
       
   659         return label;
       
   660     }
       
   661 
       
   662     public synchronized String getAttributeLabel(int aAttribute)
       
   663     {
       
   664         int[] labelSpec = new int[1];
       
   665         labelSpec[0] = aAttribute;
       
   666 
       
   667         int[] error = new int[1];
       
   668 
       
   669         String label = _getLabel(iListHandle, LABEL_TYPE_ATTRIBUTE, labelSpec, error);
       
   670 
       
   671         // Note that we use unusual exception descriptions here.
       
   672         NativeError.handlegetAttributeLabelError(error[0], aAttribute);
       
   673 
       
   674         return label;
       
   675     }
       
   676 
       
   677     public synchronized String getArrayElementLabel(int aStringArrayField,
       
   678             int aArrayElement)
       
   679     {
       
   680         int[] labelSpec = new int[2];
       
   681         labelSpec[0] = aStringArrayField;
       
   682         labelSpec[1] = aArrayElement;
       
   683 
       
   684         int[] error = new int[1];
       
   685 
       
   686         String label = _getLabel(
       
   687 
       
   688                            iListHandle, LABEL_TYPE_ARRAY_ELEMENT, labelSpec, error);
       
   689 
       
   690         // Note that we use unusual exception descriptions here.
       
   691         NativeError.handleArrayElementLabelError(error[0]);
       
   692 
       
   693         return label;
       
   694     }
       
   695 
       
   696     public synchronized int maxValues(int aField)
       
   697     {
       
   698         int[] error = new int[1];
       
   699 
       
   700         int maxValues = _maxValues(iListHandle, aField, error);
       
   701 
       
   702         NativeError.handleFieldHandlingError(error[0], aField);
       
   703         return maxValues;
       
   704     }
       
   705 
       
   706     public synchronized int stringArraySize(int aStringArrayField)
       
   707     {
       
   708         int[] error = new int[1];
       
   709 
       
   710         int stringArraySize = _stringArraySize(iListHandle, aStringArrayField,
       
   711                                                error);
       
   712 
       
   713         NativeError.handleFieldHandlingError(error[0], aStringArrayField);
       
   714         return stringArraySize;
       
   715     }
       
   716 
       
   717     // New methods
       
   718 
       
   719     /**
       
   720      * Updates list of items according to the changes in the native database.
       
   721      * Changes in items and categories are reflected appropriately.
       
   722      *
       
   723      * @par aMatchingItemHandle Handle to matching item if any
       
   724      *
       
   725      * @par NOTES: The handle to a matching item provides information that which
       
   726      *      fields must be loaded from the items if the list supports partial
       
   727      *      item loading. This is done because of the performance improvement of
       
   728      *      item handling with large databases
       
   729      *
       
   730      * @par About errors: Generally all errors are fatal during the update,
       
   731      *      because in case of out-of-memory situation the list is probably
       
   732      *      corrupt and it would be dangerous to continue execution.
       
   733      */
       
   734     protected void updateList(int aMatchingItemHandle) throws PIMException
       
   735     {
       
   736         int[] error = new int[1];
       
   737 
       
   738         int[] newAndRemovedItemHandles = _updateList(
       
   739 
       
   740                                              iListHandle, aMatchingItemHandle, error);
       
   741         NativeError.handleUpdateListError(error[0]);
       
   742 
       
   743         if (newAndRemovedItemHandles != null) // shouldn't be null
       
   744         {
       
   745             int removedItemsStart = 0;
       
   746 
       
   747             // Create and add new items and find the start of removed
       
   748             // item handles.
       
   749             for (int i = 0; i < newAndRemovedItemHandles.length; i++)
       
   750             {
       
   751                 if (newAndRemovedItemHandles[i] != 0)
       
   752                 {
       
   753                     int itemHandle = newAndRemovedItemHandles[i];
       
   754                     PIMItemImpl newItem = createAssociatedItem(itemHandle);
       
   755                     iItems.addItem(newItem);
       
   756                 }
       
   757                 else
       
   758                 {
       
   759                     // boundary element; start of removed item handles
       
   760                     removedItemsStart = i + 1;
       
   761                     break;
       
   762                 }
       
   763             }
       
   764 
       
   765             // Remove removed items
       
   766             // Loop from the removed items start to the end of the list.
       
   767             // May result to zero iterations.
       
   768             for (int i = removedItemsStart; i < newAndRemovedItemHandles.length; i++)
       
   769             {
       
   770                 int itemHandle = newAndRemovedItemHandles[i];
       
   771                 PIMItemImpl item = iItems.removeItem(itemHandle);
       
   772 
       
   773                 if (item != null) // shouldn't be null
       
   774                 {
       
   775                     item.removeListAssociation();
       
   776                 }
       
   777             }
       
   778         }
       
   779     }
       
   780 
       
   781     /**
       
   782      * Common implementation of items() calls.
       
   783      *
       
   784      * This is a binary size optimization of the four different PIMList.items()
       
   785      * calls, reducing the number of necessary JNI functions from four to one.
       
   786      *
       
   787      * Optimization adds complexity to the operation signature. Enumeration type
       
   788      * and associated matching arguments must be given.
       
   789      *
       
   790      * @param aEnumerationType
       
   791      *            Enumeration type, one of: ENUMERATION_ITEMS_ALL,
       
   792      *            ENUMERATION_ITEMS_MATCHING_ITEM,
       
   793      *            ENUMERATION_ITEMS_MATCHING_STRING or
       
   794      *            ENUMERATION_ITEMS_MATCHING_CATEGORY.
       
   795      *
       
   796      * @param aMatchingItemHandle
       
   797      *            Handle to matching item. Used with
       
   798      *            ENUMERATION_ITEMS_MATCHING_ITEM; ignored otherwise.
       
   799      *
       
   800      * @param aStringArg
       
   801      *            String argument. Used with ENUMERATION_ITEMS_MATCHING_STRING
       
   802      *            and ENUMERATION_ITEMS_MATCHING_CATEGORY; ignored otherwise.
       
   803      *            May be null for category matching.
       
   804      *
       
   805      * Arguments must be pre-checked.
       
   806      */
       
   807     protected Enumeration doItems(int aEnumerationType,
       
   808                                   int aMatchingItemHandle, String aStringArg) throws PIMException
       
   809     {
       
   810         updateList(aMatchingItemHandle);
       
   811         int[] error = new int[1];
       
   812 
       
   813         int[] itemHandles = _items(iListHandle, aEnumerationType,
       
   814                                    aMatchingItemHandle, // used for item matching
       
   815                                    aStringArg, // used for value or category matching
       
   816                                    error);
       
   817 
       
   818         return processItemsResults(itemHandles, error[0]);
       
   819     }
       
   820 
       
   821     /**
       
   822      * Creates an enumeration of items from an array of item handles and
       
   823      * processes any errors resulting from obtaining item handles from native
       
   824      * side.
       
   825      *
       
   826      * Note: Used by EventListImpl and ToDoListImpl, too.
       
   827      */
       
   828     protected Enumeration processItemsResults(int[] aItemHandles, int aError)
       
   829     throws PIMException
       
   830     {
       
   831         if (aItemHandles == null)
       
   832         {
       
   833             throw new OutOfMemoryError();
       
   834         }
       
   835         NativeError.handleProcessItemResultsError(aError);
       
   836 
       
   837         Vector items = new Vector(aItemHandles.length);
       
   838 
       
   839         for (int i = 0; i < aItemHandles.length; i++)
       
   840         {
       
   841             int itemHandle = aItemHandles[i];
       
   842             PIMItemImpl item = iItems.getItem(itemHandle);
       
   843 
       
   844             if (item != null) // shouldn't be null
       
   845             {
       
   846                 items.addElement(item);
       
   847             }
       
   848         }
       
   849 
       
   850         return items.elements();
       
   851     }
       
   852 
       
   853     /**
       
   854      * ensurePimPermission
       
   855      * Ensures indicated PIM API security permission for this list
       
   856      * This function is common for all list which need to verify PIM API
       
   857      * security permissions. It also check that the list has at least
       
   858      * the requested mode
       
   859      *
       
   860      * @param aMode The mode which is requested to be permitted
       
   861      */
       
   862     protected void ensurePimPermission(int aMode)
       
   863     {
       
   864         // Ensure that the list has at least the requested mode
       
   865         checkModeMinimum(aMode);
       
   866 
       
   867         PIMManager manager = (PIMManager)PIMManager.getInstance();
       
   868 
       
   869         //ensure permission
       
   870         manager.getPermission(getListType(), aMode);
       
   871 
       
   872     }
       
   873 
       
   874 
       
   875     /**
       
   876      * Creates new item of specialized type.
       
   877      */
       
   878     protected abstract PIMItemImpl createAssociatedItem(int aItemHandle);
       
   879 
       
   880     /**
       
   881      * Determines whether the list has <em>at least</em> given access mode.
       
   882      *
       
   883      * @return \c true if all modes in \a aMode are present; \c false otherwise.
       
   884      */
       
   885     boolean isModeMinimum(int aMode)
       
   886     {
       
   887         return ((iMode & aMode) == aMode);
       
   888     }
       
   889 
       
   890     /**
       
   891      * Checks whether the list has <em>at least</em> given access mode and
       
   892      * throws SecurityException if not.
       
   893      */
       
   894     void checkModeMinimum(int aMode)
       
   895     {
       
   896         if (!isModeMinimum(aMode))
       
   897         {
       
   898             throw new SecurityException();
       
   899         }
       
   900     }
       
   901 
       
   902     // Native operations
       
   903 
       
   904     private native void _dispose(int aPIMManagerHandle);
       
   905 
       
   906     /**
       
   907      * Creates a new native side specialized item that is associated with the
       
   908      * native side list but is not added to the list.
       
   909      *
       
   910      * @return Handle to the native side item or < 0 in error.
       
   911      */
       
   912     private native int _createItem(int aListHandle, int[] aError);
       
   913 
       
   914     /**
       
   915      * Removes given item from native database
       
   916      *
       
   917      * @return < 0 for error; KERR_NONE otherwise.
       
   918      */
       
   919     private native int _removeItem(int aListHandle, int aItemHandle);
       
   920 
       
   921     /**
       
   922      * Adds a new, first time committed item to the list.
       
   923      */
       
   924     private native int _addCommittedItem(int aListHandle, int aItemHandle);
       
   925 
       
   926     /**
       
   927      * @return List name, or null in error (taken as "out of memory").
       
   928      */
       
   929     private native String _getName(int aListHandle);
       
   930 
       
   931     /**
       
   932      * Closes the list.
       
   933      */
       
   934     private native int _close(int aListHandle);
       
   935 
       
   936     /**
       
   937      * Common JNI function for the four different items() operations. See
       
   938      * doItems().
       
   939      */
       
   940     private native int[] _items(int aListHandle, int aEnumerationType,
       
   941                                 int aMatchingItemHandle, String aStringArg, int[] aError);
       
   942 
       
   943     private native String[] _getCategories(int aListHandle, int[] aError);
       
   944 
       
   945     private native boolean _isCategory(int aListHandle, String aCategory,
       
   946                                        int[] aError);
       
   947 
       
   948     private native void _addCategory(int aListHandle, String aCategory,
       
   949                                      int[] aError);
       
   950 
       
   951     /**
       
   952      * @return The native handles of items that were in the removed category and
       
   953      *         do not belong to any category any more; null if the category was
       
   954      *         not removed (i.e. it did not exist).
       
   955      */
       
   956     private native int[] _deleteCategory(int aListHandle, String aCategory,
       
   957                                          int[] aError);
       
   958 
       
   959     /**
       
   960      * @return Error code.
       
   961      */
       
   962     private native int _renameCategory(int aListHandle, String aCurrentCategory,
       
   963                                        String aNewCategory);
       
   964 
       
   965     private native int _maxCategories(int aListHandle);
       
   966 
       
   967     private native boolean _isSupportedField(int aListHandle, int aField);
       
   968 
       
   969     /**
       
   970      * @return null on error.
       
   971      */
       
   972     private native int[] _getSupportedFields(int aListHandle);
       
   973 
       
   974     private native boolean _isSupportedAttribute(int aListHandle, int aField,
       
   975             int aAttribute);
       
   976 
       
   977     private native int[] _getSupportedAttributes(int aListHandle, int aField, int[] aError);
       
   978 
       
   979     private native boolean _isSupportedArrayElement(int aListHandle, int aStringArrayField,
       
   980             int aArrayElement);
       
   981 
       
   982     private native int[] _getSupportedArrayElements(int aListHandle, int aStringArrayField,
       
   983             int[] aError);
       
   984 
       
   985     private native int _getFieldDataType(int aListHandle, int aField, int[] aError);
       
   986 
       
   987     /**
       
   988      * Common implementation for all label getting operations.
       
   989      *
       
   990      * Contents of \a aLabelSpec argument:
       
   991      *
       
   992      * @li If \a aLabelType is LABEL_TYPE_FIELD, field constant (1 element).
       
   993      *
       
   994      * @li If \a aLabelType is LABEL_TYPE_ATTRIBUTE, attribute constant (1
       
   995      *     element)
       
   996      *
       
   997      * @li If \a aLabelType is LABEL_TYPE_ARRAY_ELEMENT, string array field
       
   998      *     constant and an array element field constant (2 elements).
       
   999      *
       
  1000      * @param aLabelType
       
  1001      *            Label type (field, attribute or array element label).
       
  1002      *
       
  1003      * @param aLabelSpec
       
  1004      *            Constants used as arguments for label getting functions.
       
  1005      *
       
  1006      * @return The label.
       
  1007      */
       
  1008     private native String _getLabel(int aListHandle, int aLabelType,
       
  1009                                     int[] aLabelSpec, int[] aError);
       
  1010 
       
  1011     private native int _maxValues(int aListHandle, int aField, int[] aError);
       
  1012 
       
  1013     private native int _stringArraySize(int aListHandle, int aStringArrayField,
       
  1014                                         int[] aError);
       
  1015 
       
  1016     /**
       
  1017      * Updates the list according to native-originated external changes. Makes
       
  1018      * the native side to resolve new, modified and removed items items in the
       
  1019      * native database and to create new native side peer objects, updating
       
  1020      * modified and removing removed items. Category changes are also reflected,
       
  1021      * but this does not affect the Java side.
       
  1022      *
       
  1023      * @return An array containing handles to new items, zero and handles to
       
  1024      *         removed items, contiguously, in that order.
       
  1025      */
       
  1026     private native int[] _updateList(int aListHandle, int aMatchingItemHandle,
       
  1027                                      int[] aError);
       
  1028 
       
  1029 }