|
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 } |