FileDocCategorySizeDatePackage
PIMImpl.javaAPI DocphoneME MR2 API (J2ME)16657Wed May 02 18:00:28 BST 2007com.sun.kvem.midp.pim

PIMImpl.java

/*
 *   
 *
 * Copyright  1990-2007 Sun Microsystems, Inc. All Rights Reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License version
 * 2 only, as published by the Free Software Foundation.
 * 
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License version 2 for more details (a copy is
 * included at /legal/license.txt).
 * 
 * You should have received a copy of the GNU General Public License
 * version 2 along with this work; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 * 
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
 * Clara, CA 95054 or visit www.sun.com if you need additional
 * information or have any questions.
 */

package com.sun.kvem.midp.pim;

import com.sun.kvem.midp.pim.formats.VCalendar10Format;
import com.sun.kvem.midp.pim.formats.VCard21Format;
import com.sun.kvem.midp.pim.formats.VCard30Format;
import com.sun.midp.midlet.MIDletSuite;
import com.sun.midp.midlet.Scheduler;
import com.sun.midp.security.Permissions;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import javax.microedition.pim.PIM;
import javax.microedition.pim.PIMException;
import javax.microedition.pim.PIMItem;
import javax.microedition.pim.PIMList;

/**
 * Implementation of PIM.
 *
 */
public final class PIMImpl extends PIM {
    /**
     * Supported serial formats.    
     */
    private static final PIMFormat[] formats = {
        new VCalendar10Format(),
        new VCard21Format(),
        new VCard30Format()
    };
    
    /** PIMImpl constructor, called from PIM.getInstance(). */
    public PIMImpl() {
    }
    
    /**
     * Gets an array of PIM items from an encoded input
     * stream.
     * @param is data input stream
     * @param enc character encoding of stream data
     * @return array of PIM items
     * @throws PIMException if any error reading the PIM data
     * @throws UnsupportedEncodingException if encoding is not supported
     */
    public PIMItem[] fromSerialFormat(InputStream is, String enc)
            throws PIMException, UnsupportedEncodingException {
        return fromSerialFormat(is, enc, null);
    }

    /**
     * Gets an array of PIM items from an encoded input
     * stream and list.
     * @param is data input stream
     * @param enc character encoding of stream data
     * @param list populate from list
     * @return array of PIM items
     * @throws PIMException if any error reading the PIM data
     * @throws UnsupportedEncodingException if encoding is not supported
     */
    private PIMItem[] fromSerialFormat(InputStream is, String enc, PIMList list)
        throws PIMException, UnsupportedEncodingException {
        
        if (enc == null) {
            enc = "UTF-8" /* NO I18N */;
        }
        InputStream in = new MarkableInputStream(is);
        in.mark(Integer.MAX_VALUE);
        try {
            for (int i = 0; i < formats.length; i++) {
                try {
                    PIMItem[] items = formats[i].decode(in, enc, list);
                    if (items == null) {
                        throw new PIMException(
                            "Empty stream or insufficient data");
                    }
                    return items;
                } catch (UnsupportedPIMFormatException e) {
                    in.reset();
                    in.mark(Integer.MAX_VALUE);
                }
            }
            throw new PIMException("Format is not recognized");
        } catch (UnsupportedEncodingException e) {
            throw e;
        } catch (IOException e) {
            throw new PIMException(e.getMessage());
        }
    }

    /**
     * Gets the current PIM lists.
     * @param pimListType type of list to return
     * @return array of list names
     */    
    public String[] listPIMLists(int pimListType) {
        checkPermissions(pimListType, PIM.READ_ONLY);
        validatePimListType(pimListType);
        return PIMHandler.getInstance().getListNames(pimListType);
    }
        
    /**
     * Gets the permissions that need to be present to open a list
     *
     * @param listType CONTACT_LIST, EVENT_LIST or TODO_LIST
     * @param mode READ_ONLY, WRITE_ONLY or READ_WRITE
     * @return list of permissions to be checked
     * @throws IllegalArgumentException if one of the parameters
     * is out of bounds
     */
    private int[] getPermissions(int listType, int mode) {
        switch (listType) {
            case CONTACT_LIST:
                switch (mode) {
                    case READ_ONLY:
                        return new int[] { Permissions.PIM_CONTACT_READ };
                    case WRITE_ONLY:
                        return new int[] { Permissions.PIM_CONTACT_WRITE};
                    case READ_WRITE:
                        return new int[] {
                            Permissions.PIM_CONTACT_READ,
                            Permissions.PIM_CONTACT_WRITE };
                    default:
                        throw new IllegalArgumentException("Not a valid mode: "
                            + mode);
                }
            case EVENT_LIST:
                switch (mode) {
                    case READ_ONLY:
                        return new int[] { Permissions.PIM_EVENT_READ };
                    case WRITE_ONLY:
                        return new int[] { Permissions.PIM_EVENT_WRITE};
                    case READ_WRITE:
                        return new int[] {
                            Permissions.PIM_EVENT_READ,
                            Permissions.PIM_EVENT_WRITE };
                    default:
                        throw new IllegalArgumentException("Not a valid mode: "
                            + mode);
                }
            case TODO_LIST:
                switch (mode) {
                    case READ_ONLY:
                        return new int[] { Permissions.PIM_TODO_READ };
                    case WRITE_ONLY:
                        return new int[] { Permissions.PIM_TODO_WRITE};
                    case READ_WRITE:
                        return new int[] {
                            Permissions.PIM_TODO_READ,
                            Permissions.PIM_TODO_WRITE };
                    default:
                        throw new IllegalArgumentException("Not a valid mode: "
                            + mode);
                }
            default:
                throw new IllegalArgumentException("Not a valid list type: " 
                    + listType);
        }
    }
    
    /**
     * Checks for all the permissions that need to be present to open a list
     *
     * @param pimListType CONTACT_LIST, EVENT_LIST or TODO_LIST
     * @param mode READ_ONLY, WRITE_ONLY or READ_WRITE
     * @throws IllegalArgumentException if one of the parameters is out of
     * bounds
     * @throws SecurityException if the application does not have the required
     * permissions
     */
    private void checkPermissions(int pimListType, int mode) {
        int[] permissions = getPermissions(pimListType, mode);
        MIDletSuite suite = Scheduler.getScheduler().getMIDletSuite();
        /*
         * Do a first pass on the permissions to make sure that none is
         * automatically denied. This is for the case when both read permission
         * and write permission are required. It is possible that, for example,
         * read permission is granted only after asking the user, but write
         * permission is automatically denied. In this case, the user should
         * not be asked a question at all.
         */
        for (int i = 0; i < permissions.length; i++) {
            String name = Permissions.getName(permissions[i]);
            int status = suite.checkPermission(name);
            if (status == 0) {
                // throw an exception
                suite.checkIfPermissionAllowed(permissions[i]);
            } else if (status == 1) {
                // don't check this permission again
                permissions[i] = -1;
            }
        }
        for (int i = 0; i < permissions.length; i++) {
            if (permissions[i] != -1) {
                try {
                    suite.checkForPermission(permissions[i], null);
                } catch (InterruptedException e) {
                    throw new SecurityException("Security check interrupted: "
                        + e.getMessage());
                }
            }
        }
    }

    /**
     * Opens the PIM list.
     *
     * @param pimListType CONTACT_LIST, EVENT_LIST or TODO_LIST
     * @param mode READ_ONLY, WRITE_ONLY or READ_WRITE
     * @return handle to opened PIM list
     * @throws PIMException if the list is not found
     */
    public PIMList openPIMList(int pimListType, int mode) throws PIMException {
        validatePimListType(pimListType);
        validateMode(mode);
        checkPermissions(pimListType, mode);
        String listName = PIMHandler.getInstance()
            .getDefaultListName(pimListType);
        if (listName == null) {
            throw new PIMException("List not available");
        }
        return openPIMListImpl(pimListType, mode, listName);
    }
    
    /**
     * Opens the PIM list.
     *
     * @param pimListType CONTACT_LIST, EVENT_LIST or TODO_LIST
     * @param mode READ_ONLY, WRITE_ONLY or READ_WRITE
     * @param name name of the list
     * @return handle to opened PIM list
     * @throws PIMException if the list is not found
     */
    public PIMList openPIMList(int pimListType, int mode, String name)
            throws PIMException {
        if (name == null) {
            throw new NullPointerException("PIM list name cannot be null");
        }
        validatePimListType(pimListType);
        validateMode(mode);
        checkPermissions(pimListType, mode);
        validateName(pimListType, name);
        return openPIMListImpl(pimListType, mode, name);
    }
    
    /**
     * Does the same as openPIMList, without any validation
     * 
     * @param pimListType CONTACT_LIST, EVENT_LIST or TODO_LIST
     * @param mode READ_ONLY, WRITE_ONLY or READ_WRITE
     * @param name name of the list
     * @return handle to opened PIM list
     * @throws PIMException if the list is not found
     */
    private PIMList openPIMListImpl(int pimListType, int mode, String name)
            throws PIMException {
    
        AbstractPIMList list;
        PIMHandler handler = PIMHandler.getInstance();
        Object listHandle = handler.openList(pimListType, name, mode);
        
        switch (pimListType) {
            case PIM.CONTACT_LIST:
                list = new ContactListImpl(name, mode, listHandle);
                break;
            case PIM.EVENT_LIST:
                list = new EventListImpl(name, mode, listHandle);
                break;
            case PIM.TODO_LIST:
                list = new ToDoListImpl(name, mode, listHandle);
                break;
            default:
                // pimListType has been verified
                throw new Error("Unreachable code");
        }
        Object[] keys = handler.getListKeys(listHandle);
        for (int i = 0; i < keys.length; i++) {
            byte[] data = handler.getListElement(listHandle, keys[i]);
            String [] categories = handler.getListElementCategories(listHandle,
                keys[i]);
            try {
                PIMItem[] items =
                    fromSerialFormat(new ByteArrayInputStream(data), 
                        "UTF-8", list);
                for (int j = 0; j < items.length; j++) {
                    AbstractPIMItem item = (AbstractPIMItem) items[j];
                    item.setKey(keys[i]);
                    list.addItem(item);
                    item.setDefaultValues();
                    for (int index = 0; index < categories.length; index ++) {
                        item.addToCategory(categories[index]);
                    }
                    item.setModified(false);
                }
            } catch (UnsupportedEncodingException e) {
                throw new Error("UTF-8 not supported");
            } catch (PIMException e) {
                // skip element
            }
        }
        return list;
    }
    
    /**
     * Gets the list of supported serial formats.
     * 
     * @param pimListType CONTACT_LIST, EVENT_LIST or TODO_LIST
     * @return array of format names
     */
    public String[] supportedSerialFormats(int pimListType) {
        validatePimListType(pimListType);
        int supportedFormatCount = 0;
        for (int i = 0; i < formats.length; i++) {
            if (formats[i].isTypeSupported(pimListType)) {
                supportedFormatCount ++;
            }
        }
        String[] supportedFormats = new String[supportedFormatCount];
        for (int i = 0; i < formats.length; i++) {
            if (formats[i].isTypeSupported(pimListType)) {
                supportedFormats[--supportedFormatCount] = formats[i].getName();
            }
        }
        return supportedFormats;
    }

    /**
     * Converts to serial format.
     * @param item the PIM item to be processed
     * @param os the target output stream
     * @param enc the character encoding for output strings
     * @param dataFormat the serialized format
     * @throws PIMException if any error writing the PIM data
     * @throws UnsupportedEncodingException if encoding is not supported
     */    
    public void toSerialFormat(PIMItem item,
        OutputStream os,
        String enc,
        String dataFormat) throws PIMException, UnsupportedEncodingException {
        
        if (enc == null) {
            enc = "UTF-8" /* NO I18N */;
        }
        if (dataFormat == null) {
            throw new NullPointerException("Null data format");
        }
        if (dataFormat.trim().length() == 0) {
            throw new IllegalArgumentException("Empty data format");
        }
        if (item == null) {
            throw new NullPointerException("Null PIM item");
        }

        try {
            for (int i = 0; i < formats.length; i++) {
                if (formats[i].getName().equals(dataFormat)) {
                    formats[i].encode(os, enc, item);
                    return;
                }
            }
            throw new IllegalArgumentException("Data format '" + dataFormat
                + "' is not supported");
        } catch (UnsupportedEncodingException e) {
            throw e;
        } catch (IOException e) {
            throw new PIMException(e.getMessage());
        }
    }
    
    /**
     * Ensures that the given PIM list type is valid.
     * @param pimListType a PIM list type
     * @throws IllegalArgumentException if the list type is not valid.
     */    
    private void validatePimListType(int pimListType) {
        switch (pimListType) {
            case PIM.CONTACT_LIST:
            case PIM.EVENT_LIST:
            case PIM.TODO_LIST:
                // ok
                break;
            default:
                throw new IllegalArgumentException("Not a valid PIM list type: "
                    + pimListType);
        }
    }
    
    /**
     * Ensures that the given PIM list mode is valid.
     * @param mode READ_ONLY, WRITE_ONLY or READ_WRITE
     */
    private void validateMode(int mode) {
        switch (mode) {
            case READ_ONLY:
            case WRITE_ONLY:
            case READ_WRITE:
                break;
            default:
                throw new IllegalArgumentException(
                    "Invalid PIM list mode: " + mode);
        }
    }

    /**
     * Ensures that the given PIM list name is valid.
     *
     * @param pimListType CONTACT_LIST, EVENT_LIST or TODO_LIST
     * @param name name of the list
     * @throws PIMException if list with the specified name is not found
     */
    private void validateName(int pimListType, String name) 
            throws PIMException {
        String[] names = PIMHandler.getInstance().getListNames(pimListType);
        for (int i = 0; i < names.length; i++) {
            if (name.equals(names[i])) {
                return;
            }
        }
        throw new PIMException("PIM list does not exist: '" + name + "'");
    }

}