Package com.funambol.syncclient.sps

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

/*
* 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 javax.microedition.pim.Event;
import javax.microedition.pim.EventList;
import javax.microedition.pim.PIMList;//CHANGE 15-03-2006 line added
import javax.microedition.pim.PIM;
import javax.microedition.pim.PIMException;

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

import net.rim.blackberry.api.pdap.BlackBerryEvent;
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 Event List
*
*/
public class EventDataStore extends DataStore
{
    protected static String TIMESTAMP_RECORDSTORE = "TimeStampEventRS";
    protected static String EVENT_UID_RECORDSTORE = "EventsUIDRS";
    private static long EVENT_KEY = 0xafd852c254393341L;

    protected static PersistentObject store;
    protected static Vector           changes;
   
    private PagedVector modifiedItems;

    static
    {
        store = PersistentStore.getPersistentObject(EVENT_KEY);

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

        changes = (Vector)store.getContents();
    }

    public EventDataStore()
    {
        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 a record exists in the store, update it;
     * if the record doesn't exist in the store, add it
     *
     * @param record Record to be added or updated
     * @throws DataAccessException
     */
    public Record setRecord(Record record, boolean modify) throws DataAccessException {
        try {
            EventList list = (EventList)PIM.getInstance().openPIMList(PIM.EVENT_LIST, PIM.READ_WRITE);

            Event event = getEvent(record.getKey(), list, modify);

            if (event == null) {
                Dialog.inform("Event is null.");
                return null;
            }

            String content = fixTag(record.getUid());

            EventParser parser = ParserFactory.getParserInstance(list, event, modify);
            parser.parseEvent(content);
            event.commit();

            String uid = event.getString(Event.UID, 0);
           
            // Save the event data in cache
            EventCache cache = new EventCache();
            cache.put(uid, parser.getCacheData());
            cache.save();

            // Set the record key
            record.setKey(uid);

            list.close();

        }
        catch (Exception e) {
            StaticDataHelper.log("[DEBUG]Exception in EventDataStore.setRecord(): " + e.toString());
            //e.printStackTrace();
            throw new DataAccessException(e.getMessage());
        }
       
        return record;
    }

    /**
     * Obtains or creates an Event object depending on the passed modify option
     *
     * @param key A string representing the event UID
     * @param list The events list of the device
     * @param modify Boolean flag that determines if the event needs to be created
     *               or searched for and obtained from the device's events list
     *
     * @return A new event object if the modify flag was set to false, otherwise
     *         searches for an event from the events list with a key matching
     *         an existing UID and returns that
     *
     * @throws Exception FIXME
     */
    private Event getEvent(String key, EventList list, boolean modify) throws Exception {
        if (!modify) {
            return list.createEvent();
        } else {
            Enumeration enumeration = list.items(key);
           
            while (enumeration.hasMoreElements()) {
                Event event = (Event)enumeration.nextElement();
               
                if (event.getString(Event.UID, 0).equals(key))
                    return event;
            }
            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 event database.
     * @param record
     * @throws DataAccessException
     */
    public void deleteRecord(Record record) throws DataAccessException
    {
        try
        {
            EventList list = (EventList)PIM.getInstance()
                                        .openPIMList(PIM.EVENT_LIST, PIM.READ_WRITE);
           
            Event event = getEvent(record.getKey(), list, true);
           
            if(event != null)
                list.removeEvent(event);
           
            list.close();
           
        }
        catch(Exception expn)
        {
            throw new DataAccessException(expn);
        }
    }

    /**
     * Rules to add to the datastore
     * a) If there is already a record with state 'N' and 'U' is received, don't update.
     * b) If there is already a record with state 'N' and 'D' is received, 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 its state with 'D'
     */
    public void addRecord(String uid, char state, Event event) throws Exception
    {
        String value = uid + "|" + state;

        /**
         * In case of a deleted record, the information won't be
         * available during the synchronization.
         * ??? hence it is store along with the update information ???
         * In case of an updated record, this is available
         * in the event database, so that it is not stored to save space
         */
        if (state == RECORD_STATE_DELETED)
        {
            EventList list = (EventList)PIM.getInstance()
                                        .openPIMList(PIM.EVENT_LIST, PIM.READ_WRITE);

            String data = getEventString(list, event);

            list.close();

            value += "|" + data;
        }

        int size = changes.size();//the number of components in this vector
        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
    {
        //CHANGE 06-04-2006
        return null;
       
        /*
        Enumeration  enumeration      = null ;
        EventList    list             = null ;
        Vector       noDeletedRecords = null ;
        Event        event            = null ;
        Record       record           = null ;

        try
        {
            noDeletedRecords = new Vector();

            list = (EventList)PIM.getInstance().openPIMList(PIM.EVENT_LIST, PIM.READ_WRITE);

            enumeration = list.items();

            while (enumeration.hasMoreElements())
            {
                event = (Event)enumeration.nextElement();

                record = new Record(event.getString(event.UID,0), RECORD_STATE_UNSIGNED, getEventString(list, event));

                noDeletedRecords.addElement(record);
            }

            list.close();

            return noDeletedRecords;

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

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

            String contanctAsString = null;

            EventList list = (EventList)PIM.getInstance()
                                        .openPIMList(PIM.EVENT_LIST, PIM.READ_WRITE);

            Event event = getEvent(uid, list, true);

            contanctAsString = getEventString(list, event);

            list.close();

            return contanctAsString;
        }
        catch (Throwable e)//Exception
        {
            StaticDataHelper.log(">>> EXCEPTION in EventDataStore.getEventAsString(String) --> " + e.toString());
            e.printStackTrace();
            throw new DataAccessException("Error in getting event");
        }
    }

    /**
     * Converts one event information from a
     * BlackBerry calendar event list into a String
     *
     * @param String: uid [event UID]
     * @param EventList: event list
     * @param Event: event.
     * @return String: returns null id event object is null else the method returns
     *         event information parsed to string.
     * @throws Exception,PIMException
     */
    private String getEventString(EventList list, Event event) throws Exception,
                                                                      PIMException
    {
        if (event == null) {
            Dialog.inform("Event is null.");
            return null;
        }

        EventParser parser = ParserFactory.getParserInstance(list, event, true);

        // Retrieve the event from cache and pass its data
        // to the parser.
        EventCache cache = new EventCache();
        String uid = event.getString(Event.UID, 0);
        parser.setCacheData(cache.get(uid));

        // Format the event.
        String data = parser.toString(event);

        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 = (EventList)PIM.getInstance()
                                 .openPIMList(PIM.EVENT_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();
    }

    public long getNextKey()
    {
        //found original comment: "da implementare"
        return 0;
    }
   
    /**
     * return no deleted records from device recordstore
     *
     * @return records found
     *
     * @throws DataAccessException
     **/
    public boolean getNextRecords(Vector v) throws DataAccessException
    {  
        boolean moreElements = true;
        Event event          = null;
        Record record        = null;

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

                event = (Event)items.nextElement();

                record = new Record(event.getString(event.UID,0), RECORD_STATE_UNSIGNED, getEventString((EventList)pimList, event));

                v.addElement(record);
            }

            return moreElements;
        }
        catch (Throwable e)//Exception
        {
            StaticDataHelper.log("Exception in EventDataStore.getNextRecords(Vector) -->\n" + e.toString());
            e.printStackTrace();
            throw new DataAccessException(e);
        }
    }
   
    /**
     * Prepares a vector of records representing the
     * items modified on the device starting from
     * the calendar events 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 calendar
     *            events store.
     *            Starting from the information contained in
     *            a {@code String} record in the calendar events
     *            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(EVENT_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, getEventAsString(uid));

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

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

        return moreElements;
    }

   
    /**
     * Resets the internal cursor of the paged vector
     *
     * @see PagedVector#reset()
     */
    public void resetModificationCursor() {
        modifiedItems.reset();
    }

    public void appendData(String data, long key)
    { }
}
TOP

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

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.