⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 syncmanager.java

📁 j2me java syncml moblie
💻 JAVA
📖 第 1 页 / 共 5 页
字号:
/*
 * 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.syncml.spds;

import java.io.UnsupportedEncodingException;

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

import com.funambol.util.Base64;
import com.funambol.util.StringUtil;
import com.funambol.util.Log;

import com.funambol.syncml.protocol.SyncML;
import com.funambol.syncml.protocol.SyncMLStatus;
import com.funambol.syncml.protocol.SyncMLCommand;
import com.funambol.syncml.protocol.SyncFilter;
import com.funambol.util.XmlUtil;
import com.funambol.util.XmlException;
import com.funambol.util.BasicSyncListener;
import com.funambol.util.SyncListener;
import com.funambol.util.ChunkedString;

/**
 * The SyncManager is the engine of the synchronization process on the
 * client library. It initializes the sync, checks the server responses
 * and communicate with the SyncSource, which is the client-specific
 * source of data.
 * A client developer must prepare a SyncConfig to istantiate a
 * SyncManager, and then can sync its sources calling the sync()
 * method.
 */
public class SyncManager {

    //------------------------------------------------------------- Private data
    /* Fast sync sending add state*/
    private static final int STATE_SENDING_ADD = 1;
    /* Fast sync sending update state*/
    private static final int STATE_SENDING_REPLACE = 2;
    /* Fast sync sending delete state*/
    private static final int STATE_SENDING_DELETE = 3;
    /* Fast sync modification complete state*/
    private static final int STATE_MODIFICATION_COMPLETED = 4;
    /* SyncManager configuration*/
    private SyncConfig config;
    /* SyncSource to sync*/
    private SyncSource source;
    /* Device ID taken from DeviceConfig*/
    private String deviceId;
    /* Max SyncML Message Size taken from DeviceConfig*/
    private int maxMsgSize;
    /**
     * A flag indicating if the client has to prepare the <DevInf> part of the
     * initialization SyncML message containing the device capabilities. It can
     * be set to <code>true</code> in two falls:
     *
     * a) the <code>serverUrl</code> isn't on the list of the already
     * connected servers
     *
     * b) the device configuration is changed
     */
    private boolean sendDevInf = false;
    /**
     * A flag indicating if the client has to add the device capabilities to the
     * modification message as content of a <Results> element. This occurs when
     * the server has sent a <Get> command request, sollicitating items of type
     * './devinf12'
     */
    private boolean addDevInfResults = false;
    /**
     * String containing the last Url of the server the client was connected to
     */
    private String lastServerUrl;
    /**
     * The value of the <CmdID> element of <Get>, to be used building the
     * <Results> command
     */
    private String cmdIDget = null;
    /**
     * The value of the <MsgID> element of the message in which <Get> is, to be
     * used building the <Results> command
     */
    private String msgIDget = null;
    // state used for fast sync
    int state;
    // The alerts sent by server, indexed by source name, instantiated in
    // checkServerAlerts
    private Hashtable serverAlerts;
    // The alert code for the current source (i.e. the actual sync mode
    // eventually modified by ther server
    private int alertCode;
    // Server URL modified with session id.
    private String serverUrl;
    // FIXME: ca be avoided?
    private String login = null;
    private String sessionID = null;
    /**
     * This member stores the LUID/GUID mapping for the items added
     * to the current source during the sync.
     */
    private Hashtable mappings = null;
    /**
     * This member stores the Status commands to send back to the server
     * in the next message. It is modified at each item received,
     * and is cleared after the status are sent.
     */
    private Vector statusList = null;
    /**
     * This member is used to store the current message ID.
     * It is sent to the server in the MsgID tag.
     */
    private int msgID = 0;
    /**
     * This member is used to store the current command ID.
     * It is sent to the server in the CmdID tag.
     */
    private int cmdID = 0;
    /**
     * A single HttpTransportAgent for all the operations
     * performed in this Sync Manager
     */
    private HttpTransportAgent transportAgent;
    private static final int PROTOCOL_OVERHEAD = 3072;
    /**
     * This member is used to indicate if the SyncManager is busy, that is
     * if a sync is on going (SyncManager supports only one synchronization
     * at a time, and requests are queued in the synchronized method sync
     */
    private boolean busy;
    /**
     * Synchronization listener
     */
    private SyncListener listener;
    /**
     * Unique instance of a BasicSyncListener which is used when the user does
     * not set up a listener in the SyncSource. In order to avoid the creation
     * of multiple instances of this class we use this static variable
     */
    private static SyncListener basicListener = null;

    //------------------------------------------------------------- Constructors
    /**
     * SyncManager constructor
     *
     * @param conf is the configuration data filled by the client
     *
     */
    public SyncManager(SyncConfig conf) {
        this.config = conf;
        this.login = conf.userName + ":" + conf.password;
        this.source = null;

        // Cache device info
        this.deviceId = config.deviceConfig.devID;
        this.maxMsgSize = config.deviceConfig.maxMsgSize;

        this.state = 0;
        this.serverAlerts = null;
        this.alertCode = 0;

        // mapping table
        this.mappings = null;

        this.busy = false;

        // status commands
        statusList = null;
        transportAgent =
                new HttpTransportAgent(
                config.syncUrl,
                config.userAgent,
                "UTF-8",
                conf.compress, conf.forceCookies);
    }

    //----------------------------------------------------------- Public methods
    /**
     * Synchronizes synchronization source, using the preferred sync
     * mode defined for that SyncSource.
     *
     * @param source the SyncSource to synchronize
     *
     * @throws SyncException
     *                  If an error occurs during synchronization
     *
     */
    public void sync(SyncSource source) throws SyncException {
        sync(source, source.getSyncMode());
    }

    /**
     * Synchronizes synchronization source
     *
     * @param source the SyncSource to synchronize
     * @param syncMode the sync mode
     * @throws SyncException
     *                  If an error occurs during synchronization
     */
    public synchronized void sync(SyncSource src, int syncMode)
            throws SyncException {


        
        busy = true;

        // Get the SyncListener associated to the source.
        // If it does not exist we use the dummy listener
        listener = src.getListener();
        if (listener == null) {
            if (basicListener == null) {
                listener = new BasicSyncListener();
                basicListener = listener;
            } else {
                listener = basicListener;
            }
        }

        // Notifies the listener that a new sync is about to start
        listener.startSession();

        if (syncMode == SyncML.ALERT_CODE_NONE) {
            Log.info("Source not active.");
            listener.endSession(SyncSource.STATUS_SUCCESS);
            return;
        }

        try {
            String response = null;

            // Set source attribute
            this.source = src;

            // Set initial state
            nextState(STATE_SENDING_ADD);

            //Set NEXT Anchor referring to current timestamp
            this.source.setNextAnchor(System.currentTimeMillis());

            this.sessionID = String.valueOf(System.currentTimeMillis());
            this.serverUrl = config.syncUrl;

            //deciding if the device capabilities have to be sent
            if (isNewServerUrl(serverUrl)) {
                setFlagSendDevInf();
            }

            // ================================================================
            // Initialization phase
            // ================================================================

            Log.info("Sending init message");
            listener.startConnecting();
            //Format request message to be sent to the server
            String initMsg = prepareInizializationMessage(syncMode);
            Log.debug(initMsg);

            response = postRequest(initMsg);
            initMsg = null;

            Log.info("Response received");
            Log.debug("Response: " + response);

            // TODO: today the SyncSource does not need to process this data.
            // When we support large object we may want to change this
            listener.dataReceived(transportAgent.getResponseDate(),
                    response.length());

            ChunkedString chunkedResp = new ChunkedString(response);
            // Check server response (can throws exception and break the sync)
            checkStatus(chunkedResp, SyncML.TAG_SYNCHDR);
            checkStatus(chunkedResp, SyncML.TAG_ALERT);

            // client interpretes server alerts and store them into "serverAlerts"
            checkServerAlerts(chunkedResp);

            // save the alert code for the current source
            String name = source.getName();
            Log.debug(name);
            alertCode = getSourceAlertCode(name);
            Log.info("Alert code: " + alertCode);
            Log.info("Initialization succesfully completed");
            listener.endConnecting(alertCode);

            // if the server has required device capabilities in the response, these
            // are added within the next client request in the <Results> method
            addDevInfResults = isGetCommandFromServer(chunkedResp);

            // Get the server URL with the session ID
            try {
                serverUrl = XmlUtil.getTagValue(chunkedResp, "RespURI").toString();

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -