📄 syncmanager.java
字号:
} 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 that the synchronization is going to begin
boolean ok = listener.startSyncing(alertCode);
if (!ok) {
//User Aborts the slow sync request
Log.info("[SyncManager] Sync process aborted by the user");
return;
}
source.beginSync(alertCode);
listener.syncStarted(alertCode);
boolean done = false;
// the implementation of the client/server multi-messaging
// through a do while loop: while </final> tag is reached.
do {
listener.startSending(source.getClientAddNumber(),
source.getClientReplaceNumber(),
source.getClientDeleteNumber());
String modificationsMsg = prepareModificationMessage();
Log.info("Sending modification");
Log.debug(modificationsMsg);
response = postRequest(modificationsMsg);
modificationsMsg = null;
Log.info("response received");
Log.debug(response);
listener.endSending();
//listener.dataReceived(transportAgent.getResponseDate(),
// response.length());
// The startReceiving(n) is notified from within the
// processModifications because here we do not know the number
// of messages to be received
processModifications(new ChunkedString(response));
done = ((response.indexOf("<Final/>") >= 0) ||
(response.indexOf("</Final>") >= 0));
response = null;
listener.endReceiving();
} while (!done);
Log.info("Modification session succesfully completed");
listener.endSyncing();
// ================================================================
// Mapping phase
// ================================================================
listener.startMapping();
// Send the map message only if a mapping or a status has to be sent
if (statusList.size() > 0 || mappings.size() > 0) {
String mapMsg = prepareMappingMessage();
Log.info("Sending Mappings\n");
Log.debug(mapMsg);
try {
response = postRequest(mapMsg);
} catch (ReadResponseException rre) {
source.setLastAnchor(source.getNextAnchor());
//save last anchors if the mapping message has been sent but
//the response has not been received due to network problems
Log.info("[SyncManager] Last sync message sent - Error reading the response " + rre);
}
mapMsg = null;
if (response!=null) {
Log.info("response received");
Log.debug(response);
//listener.dataReceived(
// transportAgent.getResponseDate(), response.length());
// Check server response (can throws exception to the caller)
checkStatus(new ChunkedString(response), SyncML.TAG_SYNCHDR);
response = null;
} else {
Log.info("Response not received");
Log.info("Skipping check for status");
}
Log.info("Mapping session succesfully completed");
} else {
Log.info("No mapping message to send");
}
// TODO: following code must be run only for succesfull path or error reading inputstream
// the other cases must skip the following code
Log.debug("Notifying listener end mapping");
listener.endMapping();
Log.debug("Changing anchors");
// Set the last anchor to the next timestamp for the source
source.setLastAnchor(source.getNextAnchor());
Log.debug("source endSsync method call");
// Tell the source that the sync is finished
source.endSync();
} catch (CompressedSyncException compressedSyncException) {
Log.error("[SyncManager] CompressedSyncException: " + compressedSyncException);
//releaseResources();
throw compressedSyncException;
} finally {
// Notifies the listener that the session is over
Log.debug("Ending session");
listener.endSession(source.getStatus());
releaseResources();
}
}
private void releaseResources() {
// Release resources
this.mappings = null;
this.statusList = null;
this.source = null;
this.sessionID = null;
this.serverUrl = null;
this.busy = false;
}
/**
* To be invoked by every change of the device configuration and if the
* serverUrl is a new one (i.e., not already on the list
* <code>lastServerUrl</code>
*/
public void setFlagSendDevInf() {
sendDevInf = true;
}
public boolean isBusy() {
return busy;
}
//---------------------------------------------------------- Private methods
/**
* Checks if the current server URL is the same as by the last connection.
* If not, the current server URL is persisted in a record store on the
* device
*
* @param url
* The server URL coming from the SyncConfig
* @return true if the client wasn't ever connected to the corresponding
* server, false elsewhere
*/
private boolean isNewServerUrl(String url) {
//retrieve last server URL from the configuration
lastServerUrl = config.lastServerUrl;
if (StringUtil.equalsIgnoreCase(lastServerUrl, url)) {
// the server url is the same as by the last connection, the client
// may not send the device capabilities
return false;
} else {
// the server url is new, the value has to be stored (this is let to
// the SyncmlMPIConfig, while the SyncConfig isn't currently stored)
return true;//the url is different, client can send the device info
}
}
/**
* Posts the given message to the url specified by <code>serverUrl</code>.
*
* @param request the request msg
* @return the response of the server as a string
*
* @throws SyncException in case of network errors (thrown by sendMessage)
*/
private String postRequest(String request) throws SyncException {
transportAgent.setRequestURL(serverUrl);
return transportAgent.sendMessage(request);
}
/**
* TODO: check CHAL element in the 401 status returned.
*/
private boolean checkMD5(String msg) {
return false;
}
/**
* Checks if the given response message is authenticated by the server
*
* @param msg the message to be checked
* @param statusOf the command of which we want to check the status
*
* @throws SyncException in case of other errors
*/
private void checkStatus(ChunkedString msg, String statusOf)
throws SyncException {
Vector statusTags = null;
try {
statusTags = XmlUtil.getTagValues(
XmlUtil.getTagValues(
XmlUtil.getTagValues(msg, SyncML.TAG_SYNCML),
SyncML.TAG_SYNCBODY),
SyncML.TAG_STATUS);
} catch (XmlException xe) {
xe.printStackTrace();
Log.error("checkStatus: error parsing server status " + msg);
return;
}
for (int i = 0, l = statusTags.size(); i < l; i++) {
ChunkedString tag = (ChunkedString) statusTags.elementAt(i);
// Parse the status
SyncMLStatus status = SyncMLStatus.parse(tag);
if (status != null) {
// Consider only that status for the requested command
if (statusOf.equals(status.getCmd())) {
switch (status.getStatus()) {
case SyncMLStatus.SUCCESS: // 200
return;
case SyncMLStatus.REFRESH_REQUIRED: // 508
Log.info("Refresh required by server.");
return;
case SyncMLStatus.AUTHENTICATION_ACCEPTED: // 212
Log.info("Authentication accepted by the server.");
return;
case SyncMLStatus.INVALID_CREDENTIALS: // 401
// TODO: handle MD5 authentication.
if (checkMD5(msg.toString())) {
Log.error("MD5 authentication not supported");
throw new SyncException(
SyncException.AUTH_ERROR,
"MD5 authentication not supported");
} else {
Log.error("Invalid credentials: " + config.userName);
throw new SyncException(
SyncException.AUTH_ERROR,
"Authentication failed for: " + source.getSourceUri());
}
case SyncMLStatus.FORBIDDEN: // 403
throw new SyncException(
//SyncException.AUTH_ERROR,
SyncException.FORBIDDEN_ERROR,
"User not authorized: " + config.userName + " for source: " + source.getSourceUri());
case SyncMLStatus.NOT_FOUND: // 404
Log.error(this, "Source URI not found on server: " + source.getSourceUri());
throw new SyncException(
//SyncException.ACCESS_ERROR,
SyncException.NOT_FOUND_URI_ERROR,
"Source URI not found on server: " + source.getSourceUri());
case SyncMLStatus.SERVER_BUSY: // 503
throw new SyncException(
SyncException.SERVER_BUSY,
"Server busy, another sync in progress for " + source.getSourceUri());
case SyncMLStatus.PROCESSING_ERROR: // 506
throw new SyncException(
SyncException.BACKEND_ERROR,
"Error processing source: " + source.getSourceUri() + status.getStatusDataMessage());
case SyncMLStatus.BACKEND_AUTH_ERROR: // 506
throw new SyncException(
SyncException.BACKEND_AUTH_ERROR,
"Error processing source: " + source.getSourceUri() + status.getStatusDataMessage());
default:
// Unhandled status code
Log.debug("[SyncManger] Unhandled Status Code, throwing exception");
throw new SyncException(
SyncException.SERVER_ERROR,
"Error from server: " + status.getStatus());
}
}
}
}
// Should neven happen
Log.error("checkStatus: can't find Status in " + statusOf + " in server response");
throw new SyncException(
SyncException.SERVER_ERROR,
"Status Tag for " + statusOf + " not found in server response");
}
/**
* <p>Checks response status for the synchronized databases and saves their
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -