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

PIMDatabase.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 java.util.Hashtable;
import java.util.Enumeration;
import java.util.Vector;
import javax.microedition.io.file.*;
import java.io.*;
import javax.microedition.io.Connector;
import javax.microedition.pim.PIMException;

import com.sun.midp.log.*;
import com.sun.midp.security.*;
import com.sun.midp.main.Configuration;

/**
 * Handles reading and writing PIM data.
 *
 */
public class PIMDatabase {

    /**
     * Inner class to request security token from SecurityInitializer.
     * SecurityInitializer should be able to check this inner class name.
     */
    static private class SecurityTrusted
        implements ImplicitlyTrustedClass {};

    /** Security token to allow access to implementation APIs */
    private static SecurityToken classSecurityToken =
        SecurityInitializer.requestToken(new SecurityTrusted());

    /** Name of root dir. */
    private String dir;
    /** Hashtable of categories. */
    private Hashtable categoriesMap = new Hashtable();
    /** File separator symbol. */
    private final String fileSep = "/";

    // private static final Debug debug = Debug.create(PIMDatabase.class);

    /** Directory structure of lists. */
    private static final String[] DIRECTORIES = {
        "contacts",
        "events",
        "todo"
    };

    /** Default names of lists. */
    String[][] LISTS = {
        { "DefaultContactList" },
        { "DefaultEventList" },
        { "DefaultTodoList" }
    };

    /**
     * Default constructor.
     *
     */
    public PIMDatabase() {
    }

    /**
     * Constructor for creating a database object for the given path.
     *
     * @param inpDir path of root directory
     * @throws IOException if an error occurs accessing the file
     */
    public PIMDatabase(String inpDir) throws IOException {
	this.dir = inpDir;
	String fcPrefix = "file:";
	if (dir.startsWith(fcPrefix)) { // remove file prefix
	    dir = dir.substring(fcPrefix.length());
	}
	FileConnection tmpDir;
	boolean tmpCond;
	String tmpStr, tmpStr1;

	com.sun.midp.io.j2me.file.Protocol conn =
	    new com.sun.midp.io.j2me.file.Protocol();

	tmpDir = (FileConnection)conn.openPrim(classSecurityToken, dir);
	tmpCond = tmpDir.exists();
	tmpDir.close();

        if (!tmpCond) { // Create directories if need
	    synchronized (this) {
	        tmpDir = (FileConnection)conn.openPrim
		    (classSecurityToken, dir);
                tmpDir.mkdir();
	        tmpStr = tmpDir.getURL().substring(fcPrefix.length());
	        tmpDir.close();
                // create list type directories with default lists
                for (int i = 0; i < DIRECTORIES.length; i++) {
                    tmpDir =
		        (FileConnection)conn.openPrim(classSecurityToken,
			    tmpStr + DIRECTORIES[i]);
                    tmpDir.mkdir();
 	            tmpStr1 = tmpDir.getURL().substring(fcPrefix.length());
	            tmpDir.close();
                    for (int j = 0; j < LISTS[i].length; j++) {
                        String listName =
			    Configuration.getProperty(LISTS[i][j]);
		        tmpDir = (FileConnection)conn.openPrim
			    (classSecurityToken, tmpStr1 + listName);
		        tmpDir.mkdir();
	                tmpDir.close();
                    }
                }
	    }
        }
    }

    /**
     *  Gets the path for given list type.
     *
     * @param listType - CONTACT_LIST, EVENT_LIST or  TODO_LIST
     *
     * @return the path
     */
    private String getTypeDir(int listType) {
        return dir + fileSep + DIRECTORIES[listType - 1];
    }

    /**
     *  Gets the path for given list name.
     *
     * @param listType - CONTACT_LIST, EVENT_LIST or  TODO_LIST
     * @param listName    name of list
     *
     * @return the path
     */
    private String getListDir(int listType, String listName) {
        return getTypeDir(listType) + fileSep + listName;
    }

    /**
     *  Gets the list of names for given list type.
     *
     * @param listType - CONTACT_LIST, EVENT_LIST or  TODO_LIST
     *
     * @return array of names
     */
    public String[] getListNames(int listType) {
	Vector vect_names = new Vector();
	Enumeration enListType = null;
	FileConnection tmpDir;

	com.sun.midp.io.j2me.file.Protocol conn =
	    new com.sun.midp.io.j2me.file.Protocol();

	try {
	    tmpDir = (FileConnection)conn.openPrim(classSecurityToken,
	        getTypeDir(listType));
	    enListType = tmpDir.list();
            tmpDir.close();
        } catch (IOException e) {
	    if (Logging.TRACE_ENABLED) {
                Logging.trace(e, "getListNames: FileConnection problem");
	    }
	}
	while (enListType.hasMoreElements()) {
	    String curr_name = (enListType.nextElement()).toString();
	    if (curr_name.endsWith(fileSep)) { // The last symbol is "/"
	        vect_names.addElement(curr_name.substring(0,
		    curr_name.length() - 1)); // save the list name
	    }
	}
        String[] names = new String[vect_names.size()];
	Enumeration dir_names = vect_names.elements();
	int i;
	for (i = 0; i < names.length; i++) {
	    names[i] = (dir_names.nextElement()).toString();
	}
        return names;
    }

    /**
     *  Gets the default list name for given list type.
     *
     * @param listType - CONTACT_LIST, EVENT_LIST or  TODO_LIST
     *
     * @return default name
     */
    public String getDefaultListName(int listType) {
        return Configuration.getProperty(LISTS[listType - 1][0]);
    }

    /**
     *  Gets the key table for given list name.
     *
     * @param listType - CONTACT_LIST, EVENT_LIST or  TODO_LIST
     * @param listName    name of list
     *
     * @return hashkey of keys
     * @throws PIMException in case of I/O error
     */
    public Hashtable getKeys(int listType, String listName)
        throws PIMException {
        Hashtable keys = new Hashtable();
	Enumeration enListDir = null;
	FileConnection tmpDir;

	com.sun.midp.io.j2me.file.Protocol conn =
	    new com.sun.midp.io.j2me.file.Protocol();

	try {
	    tmpDir = (FileConnection)conn.openPrim(classSecurityToken,
	        getTypeDir(listType) + "/" + listName);
	    enListDir = tmpDir.list();
            tmpDir.close();
        } catch (IOException e) {
            if (Logging.TRACE_ENABLED) {
                Logging.trace(e, "getKeys: FileConnection problem");
	    }
            throw new PIMException("getKeys: " + e.getMessage());
	}
	while (enListDir.hasMoreElements()) {
	    String curr_name = (enListDir.nextElement()).toString();
	    curr_name = curr_name.toLowerCase();
	    if (curr_name.endsWith(".vcf") || curr_name.endsWith(".vcs")) {
	        keys.put(curr_name, curr_name);
	    }
	}
        return keys;
    }

    /**
     *  Gets the element by key.
     *
     * @param listType - CONTACT_LIST, EVENT_LIST or  TODO_LIST
     * @param listName    name of list
     * @param key         key value
     *
     * @return data by key
     * @throws PIMException in case of I/O error
     */
    public byte[] getElement(int listType, String listName, String key)
        throws PIMException {
	FileConnection file = null;
	byte[] ret_v = null;

	com.sun.midp.io.j2me.file.Protocol conn =
	    new com.sun.midp.io.j2me.file.Protocol();

	try {
            file = (FileConnection)conn.openPrim(classSecurityToken,
	        getListDir(listType, listName) + fileSep + key,
		Connector.READ);
            long elemSize = file.fileSize();
            if (elemSize <= 0) { // no categories
                ret_v = new byte[0];
            } else { // read categories
                byte[] buffer = new byte[(int)elemSize];
                DataInputStream in = file.openDataInputStream();
                in.readFully(buffer);
                in.close();
                ret_v = buffer;
            }
            file.close();
        } catch (IOException e) {
            if (Logging.TRACE_ENABLED) {
                Logging.trace(e, "getElement: FileConnection problem");
	    }
            throw new PIMException("getElement: " + e.getMessage());
        } finally {
	    try {
	        if (file.isOpen()) {
	            file.close();
                }
	    } catch (IOException e) {
	        // do nothing
	    }
	}
	return ret_v;
    }

    /**
     *  Commits the PIM item by key.
     *
     * @param listType    CONTACT_LIST, EVENT_LIST or  TODO_LIST
     * @param listName    name of list
     * @param key         key of PIM item
     * @param data        data of PIM item
     *
     * @return key of PIM item
     * @throws PIMException in case of I/O error
     */
    public synchronized String commitElement(int listType, String listName,
			 String key, byte[] data) throws PIMException {
        String ret_v = null;
	if (key == null) {
            // make a new key
            Hashtable keySet = getKeys(listType, listName);
            String extension;
            switch (listType) {
                case PIMBridge.CONTACT_LIST: extension = ".vcf"; break;
                default: extension = ".vcs"; break;
            }
            key = 1 + extension;
	    int i = 1;
            while (keySet.containsKey(i + extension)) {
                key = (++i) + extension;
                // keep looking for a free file name
            }
        }
        String listDir = getListDir(listType, listName);
        FileConnection file = null;
	com.sun.midp.io.j2me.file.Protocol conn =
	    new com.sun.midp.io.j2me.file.Protocol();
        try {
            file = (FileConnection)conn.openPrim(classSecurityToken,
	        listDir + fileSep + key);
            if (data == null) {
	        if (file.exists()) {
                    file.delete();
		}
		file.close();
            } else {
	        if (!file.exists()) {
                    file.create();
		}
                DataOutputStream out = file.openDataOutputStream();
                out.write(data);
                out.close();
		file.close();
                ret_v = new String(key);
            }
        } catch (IOException e) {
            if (Logging.TRACE_ENABLED) {
                Logging.trace(e, "commitElement: FileConnection problem");
	    }
            throw new PIMException("commitElement: " + e.getMessage());
        } finally {
	    try {
	        if (file.isOpen()) {
	            file.close();
                }
	    } catch (IOException e) {
	        // do nothing
	    }
	}
	return ret_v;
    }

    /**
     *  Create the key string by the given PIM list.
     *
     * @param listType    CONTACT_LIST, EVENT_LIST or  TODO_LIST
     * @param listName    name of list
     *
     * @return key string
     */
    private String categoryKey(int listType, String listName) {
        return "" + listType + "." + listName;
    }

    /**
     *  Sets the new categories.
     *
     * @param listType    CONTACT_LIST, EVENT_LIST or  TODO_LIST
     * @param listName    name of list
     * @param categories  string of new categories
     * @throws PIMException in case of I/O error
     * @see #getCategories
     *
     */
    public synchronized void setCategories(int listType, String listName,
                            String categories) throws PIMException {
        FileConnection file = null;

	com.sun.midp.io.j2me.file.Protocol conn =
	    new com.sun.midp.io.j2me.file.Protocol();

	try {
            file = (FileConnection)conn.openPrim(classSecurityToken,
	        getListDir(listType, listName) + fileSep + "categories.txt");
	    if (!file.exists()) {
	        file.create();
	    } else {
                file.truncate(0);
            }
            DataOutputStream out = file.openDataOutputStream();
            out.write(categories.getBytes());
            out.close();
            file.close();
            categoriesMap.put(categoryKey(listType, listName), categories);
        } catch (IOException e) {
            if (Logging.TRACE_ENABLED) {
                Logging.trace(e, "setCategories: FileConnection problem");
	    }
            throw new PIMException("setCategories: " + e.getMessage());
        } finally {
	    try {
	        if (file.isOpen()) {
	            file.close();
                }
	    } catch (IOException e) {
	        // do nothing
	    }
	}
    }

    /**
     *  Gets the string of supported categories.
     *
     * @param listType    CONTACT_LIST, EVENT_LIST or  TODO_LIST
     * @param listName    name of list
     *
     * @return string of supported categories
     * @throws PIMException in case of I/O error
     * @see #setCategories
     */
    public synchronized String getCategories(int listType, String listName)
        throws PIMException {
        String key = categoryKey(listType, listName);
        String categories = (String) categoriesMap.get(key);

	com.sun.midp.io.j2me.file.Protocol conn =
	    new com.sun.midp.io.j2me.file.Protocol();

	if (categories == null) {
            FileConnection file = null;
	    try {
                file =  (FileConnection)conn.openPrim(classSecurityToken,
		    getListDir(listType, listName) + fileSep +
		    "categories.txt");
                if (!file.exists()) {
                    file.create();
		}
                long catSize = file.fileSize();
                if (catSize <= 0) { // no categories
                    categories = "";
                } else { // read categories
                    byte[] buffer = new byte[(int)catSize];
                    DataInputStream in = file.openDataInputStream();
                    in.readFully(buffer);
                    in.close();
                    categories = new String(buffer);
                }
                file.close();
                categoriesMap.put(key, categories);
            } catch (IOException e) {
		throw new PIMException("getCategories: " + e.getMessage());
            } finally {
	        try {
	            if (file.isOpen()) {
	                file.close();
                    }
	        } catch (IOException e) {
		    throw new PIMException("getCategories: " +
		        e.getMessage());
	        }
	    }
        }
        return categories;
    }

}