📄 syncmanager.java
字号:
/*
* 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 + -