📄 syncmanager.java
字号:
if(statusList.size() > 0 || mappings.size() > 0) {
String mapMsg = prepareMappingMessage();
Log.info("Sending Mappings\n");
Log.debug(mapMsg);
response = postRequest(mapMsg);
mapMsg = null;
Log.info("response received");
Log.debug(response);
//source.dataReceived(
// transportAgent.getResponseDate(), response.length());
// Check server response (can throws exception to the caller)
checkStatus(new ChunkedString(response), SyncML.TAG_SYNCHDR );
response = null;
Log.info("Mapping session succesfully completed");
} else {
Log.info("No mapping message to send");
}
// Set the last anchor to the next timestamp for the source
source.setLastAnchor(source.getNextAnchor());
// Tell the source that the sync is finished
source.endSync();
} finally {
// Release resources
this.mappings = null;
this.statusList = null;
this.source = null;
this.sessionID = null;
this.serverUrl = null;
}
}
/**
* 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;
}
//---------------------------------------------------------- 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,
"User not authorized: " + config.userName
+ " for source: " + source.getSourceUri());
case SyncMLStatus.NOT_FOUND: // 404
throw new SyncException(
SyncException.ACCESS_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());
default:
// Unhandled status code
//source.setLastAnchor(0l);
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
* serverAlerts
* <p>If this is the first sync for the source, the status code might change
* according to the value of the PARAM_FIRST_TIME_SYNC_MODE configuration
* property
* <p>If firstTimeSyncMode is not set, the alert is left unchanged. If it is
* set to a value, the specified value is used instead
*
* @param msg The message to be checked
*
* @throws SyncException In case of errors
**/
private void checkServerAlerts(ChunkedString msg) throws SyncException {
ChunkedString target = null;
ChunkedString code = null;
Vector alertTags = null;
serverAlerts = new Hashtable();
try {
alertTags = XmlUtil.getTagValues(
XmlUtil.getTagValues(
XmlUtil.getTagValues(
msg,
SyncML.TAG_SYNCML),
SyncML.TAG_SYNCBODY),
SyncML.TAG_ALERT);
for (int i=0, l = alertTags.size(); i < l; i++) {
ChunkedString alert = (ChunkedString)alertTags.elementAt(i);
code = XmlUtil.getTagValue(alert, SyncML.TAG_DATA);
Vector items = XmlUtil.getTagValues(alert, SyncML.TAG_ITEM);
for (int j=0, m = items.size(); j < m; j++) {
ChunkedString targetTag = (ChunkedString)items.elementAt(j);
target = XmlUtil.getTagValue(targetTag, SyncML.TAG_TARGET);
target = XmlUtil.getTagValue(target, SyncML.TAG_LOC_URI);
Log.info("The server alert code for "+target+" is "+code);
serverAlerts.put(target.toString(), code.toString());
}
}
} catch (XmlException xe) {
Log.error("checkServerAlerts: error parsing server alert " + msg);
xe.printStackTrace();
throw new SyncException(
SyncException.SERVER_ERROR,
"Invalid alert from server.");
}
}
/**
* Prepare a SyncML Message header.
*
* @param sessionid the session id to use.
* @param msgid the message id to use.
* @param src the source uri
* @param tgt the target uri
* @param tags other SyncML tags to insert in the header.
* (e.g. <Cred> or <Meta>).
*/
private String prepareSyncHeader(String sessionid,
String msgid,
String src,
String tgt,
String tags) {
StringBuffer ret = new StringBuffer();
ret.append("<SyncHdr>\n")
.append("<VerDTD>1.2</VerDTD>\n")
.append("<VerProto>SyncML/1.2</VerProto>\n")
.append("<SessionID>").append(sessionid).append("</SessionID>\n")
.append("<MsgID>").append(msgid).append("</MsgID>\n")
.append("<Target><LocURI>").append(tgt).append("</LocURI></Target>\n")
.append("<Source><LocURI>").append(src).append("</LocURI></Source>\n");
if(tags != null) {
ret.append(tags);
}
ret.append("</SyncHdr>\n");
return ret.toString();
}
/**
* Prepares inizialization SyncML message
*/
private String prepareInizializationMessage(int syncMode)
throws SyncException {
String b64login = new String(Base64.encode(login.getBytes()));
StringBuffer ret = new StringBuffer("<SyncML>\n");
// Add <Cred> and <Meta> to the syncHdr
StringBuffer tags = new StringBuffer("<Cred>\n");
tags.append("<Meta>")
.append("<Type xmlns=\"syncml:metinf\">syncml:auth-basic</Type>\n")
.append("<Format xmlns=\"syncml:metinf\">b64</Format>\n")
.append("</Meta>\n")
.append("<Data>").append(b64login).append("</Data>")
.append("</Cred>\n");
// Meta for the maxmsgsize
tags.append("<Meta><MaxMsgSize>")
.append(maxMsgSize)
.append("</MaxMsgSize></Meta>\n");
// Add SyncHdr
ret.append( prepareSyncHeader(sessionID, resetMsgID(),
deviceId, serverUrl,
tags.toString()) );
// Add SyncBody
ret.append("<SyncBody>\n")
.append(createAlerts(source, syncMode));
// Add DevInf
if (sendDevInf) {
ret.append(createPut(config.deviceConfig));
}
ret.append("<Final/>")
.append("</SyncBody>\n");
ret.append("</SyncML>\n");
tags = null;
return ret.toString();
}
/**
* Process the <Format> tag and return the requested modification
* in a String array.
*/
private String[] processFormat(ChunkedString xml) {
String[] ret = null;
try {
if (XmlUtil.getTag(xml, "Format") != -1) {
ChunkedString format = XmlUtil.getTagValue(xml, "Format");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -