Package com.funambol.syncclient.sps

Source Code of com.funambol.syncclient.sps.ContactDataStore

/*
* Funambol is a mobile platform developed by Funambol, Inc.
* Copyright (C) 2003 - 2007 Funambol, Inc.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License version 3 as published by
* the Free Software Foundation with the addition of the following permission
* added to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED
* WORK IN WHICH THE COPYRIGHT IS OWNED BY FUNAMBOL, FUNAMBOL DISCLAIMS THE
* WARRANTY OF NON INFRINGEMENT  OF THIRD PARTY RIGHTS.
*
* 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 for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program; if not, see http://www.gnu.org/licenses or write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA.
*
* You can contact Funambol, Inc. headquarters at 643 Bair Island Road, Suite
* 305, Redwood City, CA 94063, USA, or at email address info@funambol.com.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* In accordance with Section 7(b) of the GNU Affero General Public License
* version 3, these Appropriate Legal Notices must retain the display of the
* "Powered by Funambol" logo. If the display of the logo is not reasonably
* feasible for technical reasons, the Appropriate Legal Notices must display
* the words "Powered by Funambol".
*/
package com.funambol.syncclient.sps;

import java.util.Enumeration;
import java.util.Vector;

import javax.microedition.rms.RecordStore;

import net.rim.blackberry.api.pdap.BlackBerryContact;
//import javax.microedition.pim.Contact;
import net.rim.blackberry.api.pdap.BlackBerryContactList;
//import javax.microedition.pim.ContactList;

import javax.microedition.pim.PIM;
import javax.microedition.pim.PIMList;
import javax.microedition.pim.PIMException;

import com.funambol.syncclient.blackberry.parser.ContactParser;
import com.funambol.syncclient.blackberry.parser.ParserFactory;
import com.funambol.syncclient.util.PagedVector;
import com.funambol.syncclient.util.StaticDataHelper;

import net.rim.device.api.system.PersistentObject;
import net.rim.device.api.system.PersistentStore;
import net.rim.device.api.ui.component.Dialog;
import net.rim.device.api.util.StringMatch;



/**
* This class provide methods
* to access device database and BlackBerryContact List
*
*/
public class ContactDataStore extends DataStore {

    //---------------------------------------------------------------- Constants

    private static final long CONTACT_KEY = 0x9995d95ae7690965L;
    private static final String TIMESTAMP_RECORDSTORE   = "TimeStampContactRS"  ;
   
    //------------------------------------------------------------- Private Data

    //----------------------------------------------------------- Public methods

   
    /**
     * The persistent object of the device's store containing
     * the Vector with the changes occurred on the device
     */
    private static PersistentObject store;
   
    private static Vector changes;
   
    /**
     * The Vector containing the changes occurred on the device.
     * It is treated in predefined pages to avoid sending too many
     * items to be modified to the server in the SyncML message
     */
    private PagedVector modifiedItems;

    static
    {
        store = PersistentStore.getPersistentObject(CONTACT_KEY);

        if (store.getContents() == null)
        {
            store.setContents(new Vector());
            store.commit();
        }
        changes = (Vector)store.getContents();
    }


    public ContactDataStore(int page) {
        this();
        setPage(page);
    }

    public ContactDataStore() {
        super();
        modifiedItems = null;
    }

    /**
     * Set last timestamp in dedicate recordStore
     * @param lastTimestamp
     * @throws DataAccessException
     **/
    public void setLastTimestamp(long lastTimestamp)
    throws DataAccessException {

        RecordStore recordStore = null;

        try {

            recordStore = RecordStore.openRecordStore(TIMESTAMP_RECORDSTORE, true);

            int numRecords = recordStore.getNumRecords();

            String recordValue = String.valueOf(lastTimestamp);

            if (numRecords == 1) {
               
                recordStore.setRecord(1, recordValue.getBytes(), 0, (recordValue.getBytes()).length);
            } else {
               
                recordStore.addRecord(recordValue.getBytes(), 0, (recordValue.getBytes()).length);
            }


        } catch (Exception e) {
           
            StaticDataHelper.log("error:" + e.getMessage());
            throw new DataAccessException(e.getMessage());
        } finally {
           
            if (recordStore != null) {
               
                try {
                   
                    recordStore.closeRecordStore();
                    recordStore = null;
                } catch (Exception e) {
                   
                    throw new DataAccessException(e.getMessage());
                }
            }
        }
    }

    /**
     * @return last timestamp from dedicate recordstore
     * @throws DataAccessException
     **/
    public long getLastTimestamp()
    throws DataAccessException {

        RecordStore recordStore = null;

        long lastTimestamp = 0;

        try {

            recordStore = RecordStore.openRecordStore(TIMESTAMP_RECORDSTORE, true);

            int numRecords = recordStore.getNumRecords();

            if (numRecords == 0) {
                lastTimestamp = 0;
            } else {
                lastTimestamp = Long.parseLong(new String(recordStore.getRecord(1)));
            }

        } catch (Exception e) {
            StaticDataHelper.log("error:" + e.getMessage());
            throw new DataAccessException(e.getMessage());
        } finally {
            if (recordStore != null) {
                try {
                    recordStore.closeRecordStore();
                    recordStore = null;
                } catch (Exception e) {
                    throw new DataAccessException(e.getMessage());
                }
            }
        }

        return lastTimestamp;

    }

    /**
     * if record exist in database, update records
     * if record not exist in database, add record
     * @param record record to store
     * @throws DataAccessException
     **/
    public Record setRecord(Record record, boolean modify) throws DataAccessException {
       
        try {

            BlackBerryContactList list = (BlackBerryContactList)PIM.getInstance().openPIMList(PIM.CONTACT_LIST, PIM.READ_WRITE);

            BlackBerryContact contact = getContact(record.getKey(), list, modify);

            if (contact == null) {
               
                Dialog.inform("BlackBerryContact is null.");
                return null;
            }
           
            String content = fixTag(record.getUid());

            ContactParser parser = ParserFactory.getParserInstance(list, contact, modify);

            parser.parseContact(content);

            contact.commit();

            String uid = contact.getString(BlackBerryContact.UID, 0);

            record.setKey(uid);

            list.close();
           
        }
        catch (Exception e) {
            System.out.println(">>> Improper data from server (vCard instead of SIF-C): " + e.getMessage());
            //e.printStackTrace();
            throw new DataAccessException(e.getMessage());
        }
       
        return record;
    }

    /**
     * Obtains/Creates a BlackBerryContact object depending on the modify option.
     * @param String: key [contact UID]
     * @param BlackBerryContactList: contact list
     * @param boolean: modify flag determines if the contact needs to be created/searched for from
     *        contact list the.
     * @return BlackBerryContact : returns a new contact object if modify flag was ser to false.else searches
     * for contacts from the contact list for key matching existing UID and returns that.
     * @throws Exception
     */
    private BlackBerryContact getContact(String key, BlackBerryContactList list, boolean modify) throws Exception{
        if(!modify) {
            return (BlackBerryContact)list.createContact();//casting added
        } else {
            Enumeration enumeration = list.items();
            while(enumeration.hasMoreElements()) {
                BlackBerryContact contact = (BlackBerryContact)enumeration.nextElement();
                if(contact.getString(BlackBerryContact.UID, 0).equals(key)) {
                    return contact;
                }
            }
            return null;
        }
    }

    /**
     * Sync4j escapes <. This method replaces.
     * @param content
     * @return
     */
    private String fixTag(String content) {
        StringBuffer contentBuffer = new StringBuffer(content);
        StringMatch matcher = new StringMatch("<");
        int matchOffset = matcher.indexOf(contentBuffer, 0);
        while(matchOffset != -1){
            contentBuffer.delete(matchOffset,matchOffset+4);
            contentBuffer.insert(matchOffset,"<");
            matchOffset = matcher.indexOf(contentBuffer, 0);
        }
        return contentBuffer.toString();

    }

    /**
     * Delete a record from the contact database.
     * @param record
     * @throws DataAccessException
     */
    public void deleteRecord(Record record) throws DataAccessException {
        try {
            BlackBerryContactList list = (BlackBerryContactList) PIM.getInstance().openPIMList(PIM.CONTACT_LIST, PIM.READ_WRITE);
            BlackBerryContact contact = getContact(record.getKey(), list, true);
            if(contact != null)
                list.removeContact(contact);
            list.close();
        }catch(Exception expn) {
            throw new DataAccessException(expn);
        }
    }

    /**
     * Rules to add to the datastore
     * a) If there is already record with state 'N' and 'U' is recieved don't update.
     * b) If there is already record with state 'N' and 'D' is recieved remove the entry
     * c) If there is a record with state 'U' and 'U' is got ignore it
     * d) If there is a record with state 'U' and 'D' is got replace it with 'D'
     */
    public void addRecord(String uid, char state, BlackBerryContact contact) throws Exception{
        String value = uid + "|" + state;

        /**
         * In case of deleted record, the information would not be available during sync.
         * hence it is store along with the update information. In update/new case it is
         * available in the contact db so it is not store to save space
         */
        if(state == RECORD_STATE_DELETED) {
            BlackBerryContactList list = (BlackBerryContactList) PIM.getInstance().openPIMList(PIM.CONTACT_LIST, PIM.READ_WRITE);

            String data = getContactString(list, contact);

            list.close();

            value += "|" + data;

        }

        int size = changes.size();
        String data = "";
        boolean dataSet = false;
        
        if(changes.contains(value))
            return;

        for(int i=size-1;i >= 0; --i) {
            data = (String)changes.elementAt(i);
            String dataUID = data.substring(0, data.indexOf("|"));
            char dataState = data.substring(data.indexOf("|")+1).charAt(0);
            if(!dataUID.equals(uid)) {
                continue;
            } else if(dataState == RECORD_STATE_NEW && state == RECORD_STATE_UPDATED) {
                dataSet = true;
            } else if (dataState == RECORD_STATE_NEW && state == RECORD_STATE_DELETED) {
                changes.removeElement(data);
                i = i-1;
                dataSet = true;
            }
            else if(dataState == RECORD_STATE_UPDATED && state == RECORD_STATE_DELETED) {
                 changes.setElementAt(value,i);
                 changes.removeElement(data);
                 dataSet = true;
             }
        }

        if(!dataSet) {
           changes.addElement(value);
        }
        
        store.commit();
    }
   
    /**
     * return no deleted records from device recordstore
     *
     * @return find records
     * @throws DataAccessException
     **/
    public Vector getNoDeletedRecords()
    throws DataAccessException {

            return null;
    }
 
    /**
     * return no deleted records from device recordstore
     *
     * @return find records
     * @throws DataAccessException
     **/
    public boolean getNextRecords(Vector v)
    throws DataAccessException {
        boolean      moreElements     = true;
        BlackBerryContact      contact          = null;
        Record       record           = null;
    
        try {

            for (int i=0; i<page; ++i) {
                moreElements = items.hasMoreElements();
                if (!moreElements) {
                    break;
                }

                contact = (BlackBerryContact)items.nextElement();

                record = new Record(contact.getString(contact.UID,0), RECORD_STATE_UNSIGNED, getContactString(pimList, contact));

                v.addElement(record);

            }

            return moreElements;

        } catch(Exception e) {
            StaticDataHelper.log(">>> EXCEPTION in ContactDataStore.getNextRecords(Vector) --> " + e.toString());
            e.printStackTrace();
            throw new DataAccessException(e);
        }

    }

    /**
     * Prepares a vector of records representing the
     * items modified on the device starting from
     * the contacts in the device's store. Former
     * these records were prepared sorted by modification
     * state ('N', 'R', 'D'), but now they are added
     * all together to the vector passed. The 'D'
     * status is used to differentiate between Replaced
     * and New status, to avoid to create a record
     * consisting of the information payload too where
     * you don't need such information to simply give
     * the command to delete an item
     *
     * @param v The reference to a Vector to be modified
     *          by adding Record objects to it
     *
     * @param sep A separation character ('|') preceding
     *            the character representing the state
     *            of the modification ('N'ew, 'R'eplaced,
     *            'D'eleted). Former the status character
     *            instead of the separator was passed, but
     *            now you need a placeholder to determine
     *            the exact position of the status character
     *            in the record string coming from the contacts
     *            store.
     *            Starting from the information contained in
     *            a {@code String} record in the contacts store,
     *            a new {@code Record} record for each item
     *            modified on the device is created
     *           
     * @return {@code true} if {@code <Final/>} command from
     *         server not reached (there are more elements to be
     *         processed)
     *        
     * @throws DataAccessException
     */
    public boolean getNextRecords(Vector v, char sep) throws DataAccessException {
       
        boolean moreElements = true
   
        if (modifiedItems == null) {
  
            /*
             * the persistent object of the device's store containing
             * the Vector with the changes occurred on the device
             */
            store = PersistentStore.getPersistentObject(CONTACT_KEY);
           
            if (store.getContents() == null) {
                store.setContents(new Vector(MAX_ITEM_NUMBER));
                store.commit();
            }
           
            /*
             * the Vector containing the changes occurred on the device.
             * It is treated in predefined-size pages to avoid sending
             * to the server in the SyncML message too many items to be
             * modified
             */
            modifiedItems = new PagedVector((Vector)store.getContents(), MAX_ITEM_NUMBER);
        }

        Vector ids = new Vector();

        moreElements = modifiedItems.getNextPage(ids);

        int size = ids.size();
        Record rec = null;

        for (int i = 0; i < size; i++) {
           
            String record = (String)ids.elementAt(i);

            //sep is always the '|' character passed to this method
            int idx = record.indexOf(sep);
            if (idx != -1) {
           
                String uid = record.substring(0, idx);
               
                /**
                 * The character ('N', 'D', 'R')
                 * immediately following the separator '|'
                 */
                char state = record.charAt(idx+1);

                try {
           
                    if (state == RECORD_STATE_DELETED)
                        rec = new Record(record);
                    else
                        rec = new Record(uid, state, getContactAsString(uid));

                    v.addElement(rec);
                }
                catch (DataAccessException e) {
                   
                    StaticDataHelper.log(">>> EXCEPTION in ContactDataStore.getNextRecords(Vector, char) --> " + e.toString());

                    throw new DataAccessException(e);
                }
            }
            else {
               
                // Should never happen
                StaticDataHelper.log("Invalid record:" + record);
            }
        }

        return moreElements;
    }
   
   

    /**
     * returns a given contact as an xml string
     * @param uid
     * @return
     * @throws DataAccessException
     */
    private String getContactAsString(String uid) throws DataAccessException {
       
        try {

            String contanctAsString = null;

            BlackBerryContact contact = getContact(uid, (BlackBerryContactList)pimList, true);

            contanctAsString = getContactString((BlackBerryContactList)pimList, contact);

            return contanctAsString;

        } catch(Exception e) {
           
            e.printStackTrace();
            throw new DataAccessException(e);
        }
    }


    /**
     * Converts one contact information from a black berry list to string format.
     * @param String: uid [contact UID]
     * @param BlackBerryContactList: contact list
     * @param BlackBerryContact: contact.
     * @return String : returns null id contact object is null else the method returns
     *         contact information parsed to string.
     * @throws Exception,PIMException
     */
    private String getContactString(PIMList list, BlackBerryContact contact) throws Exception, PIMException {
       
        if (contact == null) {
           
            Dialog.inform("BlackBerryContact is null.");
            return null;
        }

        ContactParser parser = ParserFactory.getParserInstance((BlackBerryContactList)list, contact, true);

        String data = parser.toString(contact);

        return data;
    }

    /**
     * execute init recordstore operations
     */
    public void startDSOperations() {
       
        if (pimList != null) {
           
            try {
               
                pimList.close();
            } catch (Exception e) {
               
                StaticDataHelper.log("PIM database error: " + e.getMessage());
                e.printStackTrace();
                return;
            }
            items = null;
        }
       
        try {
           
            pimList = PIM.getInstance().openPIMList(PIM.CONTACT_LIST, PIM.READ_WRITE);
            items = pimList.items();
        } catch (Exception e) {
           
            StaticDataHelper.log("PIM database error: " + e.getMessage());
            e.printStackTrace();
            return;
        }
    }

    /**
     * execute commit recordstore operations
     * remove records signed as DELETED 'D'
     * mark UNSIGNED ' ' records signed as NEW 'N' and UPDATED 'U'
     *
     * @throws DataAccessException
     *
     */
    public void commitDSOperations() throws DataAccessException {
       
        changes.removeAllElements();
        store.commit();

        if (pimList != null) {
           
            try {
               
                pimList.close();
            } catch (Exception e) {
               
                //
                // There is nothing we can do...
                //
                StaticDataHelper.log(e.getMessage());
            }
           
            items = null;
        }
    }

    /**
     * reset modifiedItems cursor
     */
    public void resetModificationCursor() {
       
        modifiedItems.reset();
    }
   
    public long getNextKey() {
       
        //found comment: "da implementare"
        return 0;
    }
   
    public void appendData(String data, long key) {
   
    }
}
TOP

Related Classes of com.funambol.syncclient.sps.ContactDataStore

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.