001: /*
002: *
003: *
004: * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: */
026:
027: package com.sun.kvem.midp.pim;
028:
029: import javax.microedition.pim.PIMException;
030: import javax.microedition.pim.PIM;
031: import java.io.*;
032: import java.util.Hashtable;
033: import java.util.Enumeration;
034: import com.sun.midp.log.*;
035: import com.sun.midp.main.Configuration;
036: import com.sun.kvem.midp.pim.formats.FormatSupport;
037:
038: /**
039: * Implementations of shared PIM code.
040: */
041: public class PIMBridge extends PIMHandler {
042:
043: /**
044: * Contact table.
045: */
046: private static Hashtable contactListFields = new Hashtable();
047:
048: /**
049: * Event table.
050: */
051: private static Hashtable eventListFields = new Hashtable();
052:
053: /**
054: * Todo table.
055: */
056: private static Hashtable todoListFields = new Hashtable();
057:
058: /**
059: * PIMItem data storage.
060: */
061: private static PIMDatabase database;
062:
063: /**
064: * Constant representing a Contact List.
065: */
066: public static final int CONTACT_LIST = 1;
067:
068: /**
069: * Constant representing an Event List.
070: */
071: public static final int EVENT_LIST = 2;
072:
073: /**
074: * Constant representing a ToDo List.
075: */
076: public static final int TODO_LIST = 3;
077:
078: /**
079: * Initialization flag.
080: */
081: private static boolean initialized = false;
082:
083: /**
084: * This class holds information about a single list.
085: */
086: private class List {
087: /** Type of the list: CONTACT_LIST, EVENT_LIST or TODO_LIST */
088: int type;
089:
090: /** Name of the list */
091: String name;
092:
093: /**
094: * The only constructor for this list descriptor.
095: *
096: * @param listType CONTACT_LIST, EVENT_LIST or TODO_LIST
097: * @param listName name of the list
098: */
099: List(int listType, String listName) {
100: type = listType;
101: name = listName;
102: }
103: }
104:
105: /**
106: * Set up data structures.
107: */
108: public synchronized void initialize() {
109: if (!initialized) {
110: initializeMap(contactListFields,
111: SupportedPIMFields.CONTACT_LIST_FIELDS);
112: initializeMap(eventListFields,
113: SupportedPIMFields.EVENT_LIST_FIELDS);
114: initializeMap(todoListFields,
115: SupportedPIMFields.TODO_LIST_FIELDS);
116: try {
117: database = new PIMDatabase(Configuration
118: .getProperty("PIMRootDir")
119: + "pim");
120: initialized = true;
121: } catch (IOException e) {
122: if (Logging.TRACE_ENABLED) {
123: Logging.trace(e, "Unable to create PIMDatabase");
124: }
125: }
126: }
127: }
128:
129: /**
130: * Initialization one structure.
131: *
132: * @param map Hashtable for initialization
133: * @param descriptors array of the field descriptors
134: */
135: private void initializeMap(Hashtable map,
136: PIMFieldDescriptor[] descriptors) {
137: for (int i = 0; i < descriptors.length; i++) {
138: map.put(new Integer(descriptors[i].getField()),
139: descriptors[i]);
140: }
141: }
142:
143: /**
144: * Gets the table of fields for given list type.
145: *
146: * @param listType CONTACT_LIST, EVENT_LIST or TODO_LIST
147: *
148: * @return hashtable of fields
149: */
150: private Hashtable getFields(int listType) {
151: Hashtable map;
152: switch (listType) {
153: case CONTACT_LIST:
154: map = contactListFields;
155: break;
156: case EVENT_LIST:
157: map = eventListFields;
158: break;
159: case TODO_LIST:
160: map = todoListFields;
161: break;
162: default:
163: throw new IllegalArgumentException("List type " + listType
164: + " is not valid");
165: }
166: return map;
167: }
168:
169: /**
170: * Gets the descriptor for given field.
171: *
172: * @param listType CONTACT_LIST, EVENT_LIST or TODO_LIST
173: * @param field the field ID
174: *
175: * @return field descriptor
176: */
177: private PIMFieldDescriptor getFieldDescriptor(int listType,
178: int field) {
179: return (PIMFieldDescriptor) getFields(listType).get(
180: new Integer(field));
181: }
182:
183: /**
184: * Gets all fields that are supported in this list. All fields supported by
185: * this list, including both standard and extended, are returned in this
186: * array.
187: *
188: * @param listHandle handle of list
189: * @return an int array containing all fields supported by this list. The
190: * order of the fields returned is unspecified. If there are no
191: * supported fields, a zero-length array is returned.
192: */
193: public int[] getSupportedFields(Object listHandle) {
194: initialize();
195:
196: Hashtable map = getFields(((List) listHandle).type);
197: Enumeration fieldNumbers = map.keys();
198: int len = map.size();
199: int[] result = new int[len];
200:
201: for (int i = 0; i < len; i++) {
202: result[i] = (fieldNumbers.nextElement()).hashCode();
203: }
204:
205: return result;
206: }
207:
208: /**
209: * Checks if field is supported in list.
210: * @param listHandle handle of the list
211: * @param field identifier of field
212: * @return <code>true</code> if field supported
213: */
214: public boolean isSupportedField(Object listHandle, int field) {
215: initialize();
216: return getFieldDescriptor(((List) listHandle).type, field) != null;
217: }
218:
219: /**
220: * Checks if field has default value.
221: * @param listHandle handle of the list
222: * @param field identifier of field
223: * @return <code>true</code> if field supported
224: */
225: public boolean hasDefaultValue(Object listHandle, int field) {
226: initialize();
227: return getFieldDescriptor(((List) listHandle).type, field)
228: .hasDefaultValue();
229: }
230:
231: /**
232: * Gets the data type of the field.
233: * @param listHandle handle of the list
234: * @param field identifier of field
235: * @return data type identifier
236: */
237: public int getFieldDataType(Object listHandle, int field) {
238: initialize();
239: try {
240: return getFieldDescriptor(((List) listHandle).type, field)
241: .getDataType();
242: } catch (NullPointerException npe) {
243: return -1;
244: }
245: }
246:
247: /**
248: * Gets the label of the field.
249: * @param listHandle handle of the list
250: * @param field identifier of field
251: * @return label of the field
252: */
253: public String getFieldLabel(Object listHandle, int field) {
254: initialize();
255: try {
256: return getFieldDescriptor(((List) listHandle).type, field)
257: .getLabel();
258: } catch (NullPointerException npe) {
259: return null;
260: }
261: }
262:
263: /**
264: * Gets the default integer value for the given field. This will
265: * only
266: * return a valid value if hasDefaultValue(listType, field) returns true.
267: * @param listHandle handle of the list
268: * @param field identifier of field
269: * @return default value of the field
270: */
271: public int getDefaultIntValue(Object listHandle, int field) {
272: initialize();
273: PIMFieldDescriptor descriptor = getFieldDescriptor(
274: ((List) listHandle).type, field);
275: return ((Integer) descriptor.getDefaultValue()).intValue();
276: }
277:
278: /**
279: * Gets the default string value for the given field. This will
280: * only
281: * return a valid value if hasDefaultValue(listType, field) returns true.
282: * @param listHandle handle of the list
283: * @param field identifier of field
284: * @return default value of the field
285: */
286: public String getDefaultStringValue(Object listHandle, int field) {
287: return null;
288: }
289:
290: /**
291: * Gets the default String[] value for the given field. This will
292: * only
293: * return a valid value if hasDefaultValue(listType, field) returns true.
294: * @param listHandle handle of the list
295: * @param field identifier of field
296: * @return default value of the field
297: */
298: public String[] getDefaultStringArrayValue(Object listHandle,
299: int field) {
300: int length = getStringArraySize(listHandle, field);
301: return new String[length];
302: }
303:
304: /**
305: * Gets the default date value for the given field. This will only
306: * return a valid value if hasDefaultValue(listType, field) returns true.
307: * @param listHandle handle of the list
308: * @param field identifier of field
309: * @return default value of the field
310: */
311: public long getDefaultDateValue(Object listHandle, int field) {
312: return 0;
313: }
314:
315: /**
316: * Gets the default byte[] value for the given field. This will
317: * only
318: * return a valid value if hasDefaultValue(listType, field) returns true.
319: * @param listHandle handle of the list
320: * @param field identifier of field
321: * @return default value of the field
322: */
323: public byte[] getDefaultBinaryValue(Object listHandle, int field) {
324: return null;
325: }
326:
327: /**
328: * Gets the default boolean value for the given field. This will
329: * only
330: * return a valid value if hasDefaultValue(listType, field) returns true.
331: * @param listHandle handle of the list
332: * @param field identifier of field
333: * @return default value of the field
334: */
335: public boolean getDefaultBooleanValue(Object listHandle, int field) {
336: return false;
337: }
338:
339: /**
340: * Gets the supported attributes for the given field.
341: * @param listHandle handle of the list
342: * @param field identifier of field
343: * @return array of supported attributes of the field
344: */
345: public int[] getSupportedAttributes(Object listHandle, int field) {
346: initialize();
347: int listType = ((List) listHandle).type;
348: long attributes = getFieldDescriptor(listType, field)
349: .getSupportedAttributes();
350: int elementCount = listType == PIM.CONTACT_LIST ? 1 : 0;
351: for (long a = attributes; a > 0; a >>= 1) {
352: if ((a & 1) == 1) {
353: elementCount++;
354: }
355: }
356: int[] result = new int[elementCount];
357: if (elementCount > 0) {
358: int a = 1;
359: int i;
360: if (listType == PIM.CONTACT_LIST) {
361: result[0] = PIMItem.ATTR_NONE;
362: i = 1;
363: } else {
364: i = 0;
365: }
366: for (; i < elementCount; i++) {
367: while ((attributes & a) == 0)
368: a <<= 1;
369: result[i] = a;
370: a <<= 1;
371: }
372: }
373: return result;
374: }
375:
376: /**
377: * Gets a mask containing all possible attributes for the given field.
378: *
379: * @param listHandle handle of the list
380: * @param field the field number
381: * @return supported attribute mask
382: */
383: public int getSupportedAttributesMask(Object listHandle, int field) {
384: initialize();
385: return (int) getFieldDescriptor(((List) listHandle).type, field)
386: .getSupportedAttributes();
387: }
388:
389: /**
390: * Gets attribute label for the given field attribute.
391: *
392: * @param listHandle handle of the list
393: * @param attribute identifier of attribute
394: * @return attribute label
395: */
396: public String getAttributeLabel(Object listHandle, int attribute) {
397: initialize();
398: StringBuffer tag = new StringBuffer("PIM.Attributes.");
399: if (attribute == 0) {
400: tag.append("None");
401: } else {
402: switch (((List) listHandle).type) {
403: case CONTACT_LIST:
404: tag.append("ContactList.");
405: break;
406: case EVENT_LIST:
407: tag.append("EventList.");
408: break;
409: case TODO_LIST:
410: tag.append("ToDoList.");
411: break;
412: default:
413: return null;
414: }
415: int index = 0;
416: while (attribute > 1) {
417: index++;
418: attribute = attribute >> 1;
419: }
420: tag.append(index);
421: }
422: String tagString = tag.toString();
423: String returnValue = Configuration.getPropertyDefault(
424: tagString, "Label_" + tagString);
425: return returnValue;
426: }
427:
428: /**
429: * Checks if attribute is supported.
430: *
431: * @param listHandle handle of the list
432: * @param field the field number
433: * @param attribute identifier of attribute
434: * @return <code>true</code> if attribute is supported
435: */
436: public boolean isSupportedAttribute(Object listHandle, int field,
437: int attribute) {
438: initialize();
439: if (attribute == PIMItem.ATTR_NONE) {
440: return true;
441: } else {
442: long attributes = getFieldDescriptor(
443: ((List) listHandle).type, field)
444: .getSupportedAttributes();
445: return (attributes & attribute) != 0;
446: }
447: }
448:
449: /**
450: * Checks if size of the string array.
451: *
452: * @param listHandle handle of the list
453: * @param field the field number
454: * @return size of the string array
455: */
456: public int getStringArraySize(Object listHandle, int field) {
457: initialize();
458: try {
459: return getFieldDescriptor(((List) listHandle).type, field)
460: .getStringArraySize();
461: } catch (NullPointerException npe) {
462: // debug.exception(Debug.LIGHT, npe);
463: return 0;
464: }
465: }
466:
467: /**
468: * Gets the array of supported elements.
469: *
470: * @param listHandle handle of the list
471: * @param field the field number
472: * @return array of supported elements
473: */
474: public int[] getSupportedArrayElements(Object listHandle, int field) {
475: int size = getStringArraySize(listHandle, field);
476: int[] result = new int[size];
477: for (int i = 0; i < size; i++) {
478: result[i] = i;
479: }
480: return result;
481: }
482:
483: /**
484: * Gets the array element label.
485: *
486: * @param listHandle handle of the list
487: * @param field the field number
488: * @param arrayElement the element identifier
489: * @return label fro the array element
490: */
491: public String getArrayElementLabel(Object listHandle, int field,
492: int arrayElement) {
493: initialize();
494: return getFieldDescriptor(((List) listHandle).type, field)
495: .getElementlabel(arrayElement);
496: }
497:
498: /**
499: * Checks if the array element is supported.
500: *
501: * @param listHandle handle of the list
502: * @param field the field number
503: * @param arrayElement the element identifier
504: * @return <code>true</code> if attribute element is supported
505: */
506: public boolean isSupportedArrayElement(Object listHandle,
507: int field, int arrayElement) {
508: return arrayElement >= 0
509: && arrayElement < getStringArraySize(listHandle, field);
510: }
511:
512: /**
513: * Get the maximum number of values that can be stored in the given field.
514: *
515: * @param listHandle handle of the list
516: * @param field the field type
517: * @return the maximum value
518: */
519: public int getMaximumValues(Object listHandle, int field) {
520: initialize();
521: return getFieldDescriptor(((List) listHandle).type, field)
522: .getMaximumValues();
523: }
524:
525: /**
526: * Get the supported list names for the given list type. All list elements
527: * must be unique within the list.
528: *
529: * @param listType the type of the list
530: * @return a non-null array of supported list names. A copy of this array is
531: * returned by PIM.listPIMLists()
532: */
533: synchronized public String[] getListNames(int listType) {
534: initialize();
535: int length = database.getListNames(listType).length;
536: String[] names = new String[length];
537: for (int i = 0; i < length; i++) {
538: names[i] = database.getListNames(listType)[i];
539: }
540: return names;
541: }
542:
543: /**
544: * Get the name of the default list for the given type.
545: *
546: * @param listType the type of the list
547: * @return the name of the default list, or null if no list of this type
548: * is supported.
549: */
550: public String getDefaultListName(int listType) {
551: initialize();
552: return database.getDefaultListName(listType);
553: }
554:
555: /**
556: * Opens list.
557: *
558: * @param listType the type of the list
559: * @param listName the name of the list
560: * @param openMode open mode
561: * @return list handle that will be used to access this list
562: * @throws PIMException in case of I/O error.
563: */
564: public Object openList(int listType, String listName, int openMode)
565: throws PIMException {
566: return new List(listType, listName);
567: }
568:
569: /**
570: * Closes list.
571: *
572: * @param listHandle handle of list
573: * @throws PIMException in case of I/O error.
574: */
575: public void closeList(Object listHandle) throws PIMException {
576: }
577:
578: /**
579: * Get list element keys.
580: *
581: * @param listHandle handle of the list
582: * @return an array of objects representing PIM element keys. These keys
583: * are to be passed to getListElement() and commitListElement().
584: * @throws PIMException in case of I/O error.
585: */
586: synchronized public Object[] getListKeys(Object listHandle)
587: throws PIMException {
588: initialize();
589:
590: Hashtable hash_keys = database.getKeys(
591: ((List) listHandle).type, ((List) listHandle).name);
592: int len = hash_keys.size();
593: Object[] keys = new Object[len];
594: Enumeration en_keys = hash_keys.keys();
595:
596: for (int i = 0; i < len; i++) {
597: keys[i] = en_keys.nextElement().toString();
598: }
599:
600: return keys;
601: }
602:
603: /**
604: * Get the data for a list element.
605: * @param listHandle handle of the list
606: * @param elementKey the key of the requested element
607: * @return a byte array containing the element data in a supported format
608: * @throws PIMException in case of I/O error.
609: */
610: public byte[] getListElement(Object listHandle, Object elementKey)
611: throws PIMException {
612: initialize();
613: return database.getElement(((List) listHandle).type,
614: ((List) listHandle).name, (String) elementKey);
615:
616: }
617:
618: /**
619: * Get categories for the specified list element.
620: * @param listHandle handle of list
621: * @param elementKey the key of the requested element
622: * @return an array of categories names
623: * @throws PIMException in case of I/O error.
624: */
625: public String[] getListElementCategories(Object listHandle,
626: Object elementKey) throws PIMException {
627:
628: return new String[0];
629: }
630:
631: /**
632: * Commit a list element.
633: *
634: * @param listHandle handle of the list
635: * @param elementKey the key of the element to be stored, or null if this
636: * is a new element.
637: * @param element element data in a form that can be interpreted
638: * by getListElement()
639: * @param categories list of categories which the list element belongs to
640: * @return a non-null key for this element, to be used in future calls
641: * to commitListElement() and getListElement()
642: * @throws PIMException in case of I/O error.
643: */
644: synchronized public Object commitListElement(Object listHandle,
645: Object elementKey, byte[] element, String[] categories)
646: throws PIMException {
647: initialize();
648: elementKey = database.commitElement(((List) listHandle).type,
649: ((List) listHandle).name, (String) elementKey, element);
650: return elementKey;
651: }
652:
653: /**
654: * Gets the set of categories defined for a list.
655: *
656: * @param listHandle handle of the list
657: * @return the set of defined categories
658: * @throws PIMException If an error occurs or
659: * the list is no longer accessible or closed.
660: */
661: public String[] getCategories(Object listHandle)
662: throws PIMException {
663: initialize();
664: String result = database.getCategories(
665: ((List) listHandle).type, ((List) listHandle).name);
666: return FormatSupport.split(result, '\n', 0);
667: }
668:
669: /**
670: * Adds a category to the categories defined for a list.
671: *
672: * @param listHandle handle of list
673: * @param category category name
674: * @throws PIMException If an error occurs or
675: * the list is no longer accessible or closed.
676: * @see #getCategories
677: */
678: public void addCategory(Object listHandle, String category)
679: throws PIMException {
680: initialize();
681: String cats = database.getCategories(((List) listHandle).type,
682: ((List) listHandle).name);
683: // the implementation expects that '\n' is never escaped in categories
684: String cat_add = "\n" + category;
685: if (cats.indexOf(cat_add + '\n') != -1
686: || cats.startsWith(category + '\n')
687: || cats.endsWith(cat_add)
688: || ((cats.length() > 0) && cats.equals(category))) {
689: return;
690: }
691: if (cats.length() == 0 && category.length() > 0) {
692: cats = category;
693: } else {
694: cats += cat_add;
695: }
696: database.setCategories(((List) listHandle).type,
697: ((List) listHandle).name, cats);
698: }
699:
700: /**
701: * Deletes a category from the categories defined for a list.
702: *
703: * @param listHandle handle of list
704: * @param category category name
705: * @throws PIMException If an error occurs or
706: * the list is no longer accessible or closed.
707: * @see #getCategories
708: */
709: public void deleteCategory(Object listHandle, String category)
710: throws PIMException {
711: initialize();
712: String cats = database.getCategories(((List) listHandle).type,
713: ((List) listHandle).name);
714: // the implementation expects that '\n' is never escaped in categories
715: String cat_add = "\n" + category;
716: int pos;
717: if ((pos = cats.indexOf(cat_add + '\n')) != -1) {
718: cats = cats.substring(0, pos)
719: + cats.substring(pos + cat_add.length());
720: } else if (cats.startsWith(category + '\n')) {
721: cats = cats.substring(cat_add.length());
722: } else if (cats.endsWith(cat_add)) {
723: cats = cats.substring(0, cats.length() - cat_add.length());
724: } else if (cats.equals(category)) {
725: cats = "";
726: } else {
727: return;
728: }
729: database.setCategories(((List) listHandle).type,
730: ((List) listHandle).name, cats);
731: }
732:
733: /**
734: * Rename a category.
735: *
736: * @param listHandle handle of list
737: * @param currentCategory current category name
738: * @param newCategory new category name
739: * @throws PIMException If an error occurs or
740: * the list is no longer accessible or closed.
741: * @see #getCategories
742: */
743: public void renameCategory(Object listHandle,
744: String currentCategory, String newCategory)
745: throws PIMException {
746: deleteCategory(listHandle, currentCategory);
747: addCategory(listHandle, newCategory);
748: }
749: }
|