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

📄 syncmanager.java

📁 SyncML的java实现类库 funambol公司发布的
💻 JAVA
📖 第 1 页 / 共 5 页
字号:
/*
 * Copyright (C) 2003-2007 Funambol
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * 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 General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

package com.funambol.syncml.spds;

import com.funambol.util.ChunkedString;
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;

/**
 * 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;
    
    //------------------------------------------------------------- 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;
        // status commands
        statusList = null;
        transportAgent =
                new HttpTransportAgent(
                config.syncUrl,
                config.userAgent,
                "UTF-8",
                conf.compress);
    }
    
    //----------------------------------------------------------- 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
     *
     * @throws SyncException
     *                  If an error occurs during synchronization
     */
    public void sync(SyncSource src, int syncMode)
    throws SyncException {
        
        if (syncMode == SyncML.ALERT_CODE_NONE) {
            Log.info("Source not active.");
            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");
            //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);
            
            source.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("Initialization succesfully completed");
            
            // 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();
            } catch(XmlException xe) {
                Log.error("Error parsing RespURI from server " + xe.toString());
                throw new SyncException(
                        SyncException.SERVER_ERROR,
                        "Cannot find the Response URI in server response.");
            }
            
            chunkedResp = null;
            
            response = null;
            
            
            // ================================================================
            // Sync phase
            // ================================================================
            
            // init mapping table
            this.mappings   = new Hashtable();
            // init status commands list
            this.statusList = new Vector();
            
            // Notifies the SyncSource that the synchronization is going to begin
            source.beginSync(alertCode);
            
            boolean done = false;
            
            // the implementation of the client/server multi-messaging
            // through a do while loop: while </final> tag is reached.
            do {
                
                String modificationsMsg = prepareModificationMessage();
                Log.info("Sending modification");
                Log.debug(modificationsMsg);
                
                response = postRequest(modificationsMsg);
                modificationsMsg = null;
                
                Log.info("response received");
                Log.debug(response);
                
                //source.dataReceived(
                //    transportAgent.getResponseDate(), response.length());
                
                processModifications(new ChunkedString(response));
                
                done = ((response.indexOf("<Final/>") >= 0) ||
                        (response.indexOf("</Final>") >= 0));
                
                response = null;
                
            }
            while (!done);
            
            Log.info("Modification session succesfully completed");
            
            // ================================================================
            // Mapping phase
            // ================================================================
            
            // Send the map message only if a mapping or a status has to be sent

⌨️ 快捷键说明

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