package cn.edu.tsinghua.hpc.syncbroker;
import java.text.CharacterIterator;
import java.text.StringCharacterIterator;
import java.util.HashMap;
import android.content.Context;
import android.telephony.TelephonyManager;
import android.util.Log;
/**
* Format the request XML.
*
* TODO: SIM Serial number is used as the uesrid.
*
* @author xrn
*
*/
public class SyncRequestBuilder {
// final private String phone;
final private String userID;
public SyncRequestBuilder(Context context) {
TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
// phone = tm.getLine1Number();
// userID = tm.getSimSerialNumber();
userID = tm.getSubscriberId();
}
public SyncRequestBuilder(Context context, String user) {
// TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
// phone = tm.getLine1Number();
// userID = tm.getSimSerialNumber();
// userID = tm.getSubscriberId();
if (user == null) {
TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
userID = tm.getSubscriberId();
} else {
userID = user;
}
}
private static String xmlRequestTemplate = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
"<%s>\n" + // Request tag
" <%s>%s</%s>\n" + // userID
" <%s>%s</%s>\n" + // cmd
" %s" + // main body
"</%s>"; // Request tag
public String buildXML(SyncCommand csc, HashMap<String, String> data)
throws ElementNotFound {
if ((data == null) || data.isEmpty()) {
return null;
}
String xml = String.format(xmlRequestTemplate,
XMLTag.Request.name(),
XMLTag.USERID.name(), userID, XMLTag.USERID.name(),
XMLTag.CMD.name(), SyncCommand.getSyncCommandOut(csc).name(), XMLTag.CMD.name(),
buildCommandBody(csc, data),
XMLTag.Request.name());
return xml;
}
private String buildField(String key, HashMap<String, String> data)
throws ElementNotFound {
if (data == null || !data.containsKey(key)) {
throw new ElementNotFound("Not enough data provided. Or it does not have the key: " + key);
}
return String.format("<%s>%s</%s>\n", key, escapeXML(data.get(key)), key);
}
private String buildCommandBody(SyncCommand csc,
HashMap<String, String> data) throws ElementNotFound {
StringBuilder body = new StringBuilder();
SyncCommandOut csco = SyncCommand.getSyncCommandOut(csc);
// insert <TAG> value into data if it is MARK, because the user is
// unaware of MARK.
if (csco == SyncCommandOut.MARK) {
data.put(XMLTag.TAG.name(), SyncCommand.getSyncCammandTag(csc).name());
}
for (XMLTag tag : SyncCommandTagList.getXMLTagList(csco)) {
body.append(buildField(tag.name(), data));
}
return body.toString();
}
/**
* Escape characters for text appearing as XML data, between tags.
*
* <P>
* The following characters are replaced with corresponding character
* entities :
* <table border='1' cellpadding='3' cellspacing='0'>
* <tr><th>Character</th><th>Encoding</th></tr>
* <tr><td><</td><td><</td></tr>
* <tr><td>></td><td>></td></tr>
* <tr><td>&</td><td>&</td></tr>
* <tr><td>"</td><td>"</td></tr>
* <tr><td>'</td><td>'</td></tr>
* </table>
*
* <P>
* Note that JSTL's {@code <c:out>} escapes the exact same set of characters
* as this method. <span class='highlight'>That is, {@code <c:out>} is good
* for escaping to produce valid XML, but not for producing safe
* HTML.</span>
*/
public static String escapeXML(String aText) {
final StringBuilder result = new StringBuilder();
final StringCharacterIterator iterator = new StringCharacterIterator(aText);
char character = iterator.current();
while (character != CharacterIterator.DONE) {
if (character == '<') {
result.append("<");
} else if (character == '>') {
result.append(">");
} else if (character == '\"') {
result.append(""");
} else if (character == '\'') {
result.append("'");
} else if (character == '&') {
result.append("&");
} else {
// the char is not a special one
// add it to the result as is
result.append(character);
}
character = iterator.next();
}
return result.toString();
}
}
/**
*
* Map each command to the required tags.
*
* */
final class SyncCommandTagList {
private static HashMap<SyncCommandOut, XMLTag[]> cmdTagTable;
static {
cmdTagTable = new HashMap<SyncCommandOut, XMLTag[]>();
cmdTagTable.put(SyncCommandOut.ADD, new XMLTag[] { XMLTag.DATA });
cmdTagTable.put(SyncCommandOut.UPDATE, new XMLTag[] { XMLTag.GUID,
XMLTag.DATA });
cmdTagTable.put(SyncCommandOut.MARK, new XMLTag[] { XMLTag.TAG,
XMLTag.FILTER });
cmdTagTable.put(SyncCommandOut.SEARCH, new XMLTag[] { XMLTag.FILTER });
cmdTagTable.put(SyncCommandOut.FIRSTSYNC,
new XMLTag[] { XMLTag.FILTER });
cmdTagTable.put(SyncCommandOut.REMOVE, new XMLTag[] { XMLTag.FILTER });
cmdTagTable.put(SyncCommandOut.GETCOUNT, new XMLTag[] { XMLTag.FILTER });
}
public static XMLTag[] getXMLTagList(SyncCommandOut csco) {
return cmdTagTable.get(csco);
}
}