PtsPrimitiveSerializer.java
上传用户:szyujian
上传日期:2016-09-20
资源大小:320k
文件大小:21k
源码类别:

android开发

开发平台:

C/C++

  1. /*
  2.  * Copyright (C) 2007-2008 Esmertec AG.
  3.  * Copyright (C) 2007-2008 The Android Open Source Project
  4.  *
  5.  * Licensed under the Apache License, Version 2.0 (the "License");
  6.  * you may not use this file except in compliance with the License.
  7.  * You may obtain a copy of the License at
  8.  *
  9.  *      http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package com.android.im.imps;
  18. import java.io.IOException;
  19. import java.io.OutputStream;
  20. import java.io.OutputStreamWriter;
  21. import java.io.Writer;
  22. import java.util.ArrayList;
  23. import java.util.HashMap;
  24. import java.util.regex.Matcher;
  25. import java.util.regex.Pattern;
  26. import com.android.im.imps.ImpsConstants.ImpsVersion;
  27. public class PtsPrimitiveSerializer implements PrimitiveSerializer {
  28.     private final String mPreampleHead;
  29.     // The ccc is the Transaction-ID in range 0-999 without preceding zero.
  30.     private static final Pattern sTxIdPattern = Pattern.compile("(0|[1-9]\d{0,2})");
  31.     // If the value of the parameter contains spaces ( ), quotes ("),
  32.     // commas (,),parentheses (()),equal (=) or ampersand (&) characters,
  33.     // it SHALL be wrapped with quotes (").
  34.     private static final Pattern sCharsToBeQuoted = Pattern.compile("[ ",\(\)=&]");
  35.     public PtsPrimitiveSerializer(ImpsVersion impsVersion) throws SerializerException {
  36.         if (impsVersion == ImpsVersion.IMPS_VERSION_12) {
  37.             mPreampleHead = "WV12";
  38.         } else if (impsVersion == ImpsVersion.IMPS_VERSION_13) {
  39.             mPreampleHead = "WV13";
  40.         } else {
  41.             throw new SerializerException("Unsupported IMPS version");
  42.         }
  43.     }
  44.     public void serialize(Primitive p, OutputStream out)
  45.             throws IOException, SerializerException {
  46.         String txId = p.getTransactionID();
  47.         if (txId == null) {
  48.             if (!ImpsTags.Polling_Request.equals(p.getType())) {
  49.                 throw new SerializerException("null Transaction-ID for non polling request");
  50.             }
  51.             // FIXME: what should this be? Temporarily use 0
  52.             txId = "0";
  53.         } else {
  54.             Matcher m = sTxIdPattern.matcher(txId);
  55.             if (!m.matches()) {
  56.                 throw new SerializerException(
  57.                         "Transaction-ID must be in range 0-999 without preceding zero");
  58.             }
  59.         }
  60.         // TODO: use buffered writer?
  61.         Writer writer = new OutputStreamWriter(out, "UTF-8");
  62.         writer.write(mPreampleHead);
  63.         String code = PtsCodes.getTxCode(p.getType());
  64.         if (code == null) {
  65.             throw new SerializerException("Unsupported transaction type "
  66.                     + p.getType());
  67.         }
  68.         writer.write(code);
  69.         writer.write(txId);
  70.         if (p.getSessionId() != null) {
  71.             writer.write(" SI=");
  72.             writer.write(p.getSessionId());
  73.         }
  74.         PrimitiveElement content = p.getContentElement();
  75.         if (content != null && content.getChildCount() > 0) {
  76.             ArrayList<PrimitiveElement> infoElems = content.getChildren();
  77.             ArrayList<String> users = new ArrayList<String>();
  78.             ArrayList<String> lists = new ArrayList<String>();
  79.             int len = infoElems.size();
  80.             for (int i = 0; i < len; i++) {
  81.                 PrimitiveElement elem = infoElems.get(i);
  82.                 String elemName = elem.getTagName();
  83.                 // workaround for multiple elements
  84.                 if (ImpsTags.User.equals(elemName)) {
  85.                     users.add(elem.getChildContents(ImpsTags.UserID));
  86.                     continue;
  87.                 } else if (ImpsTags.UserID.equals(elemName)) {
  88.                     users.add(elem.getContents());
  89.                     continue;
  90.                 } else if (ImpsTags.ContactList.equals(elemName)) {
  91.                     lists.add(elem.getContents());
  92.                     continue;
  93.                 }
  94.                 String elemCode = PtsCodes.getElementCode(elemName, p.getType());
  95.                 if (elemCode == null) {
  96.                     throw new SerializerException("Don't know how to encode element "
  97.                             + elemName);
  98.                 }
  99.                 writer.write(' ');
  100.                 writer.write(elemCode);
  101.                 // so far all top level information elements have values.
  102.                 writer.write('=');
  103.                 String value;
  104.                 ElemValueEncoder encoder = ElemValueEncoder.getEncoder(elemName);
  105.                 if (encoder == null) {
  106.                     // default simple value
  107.                     value = escapeValueString(elem.getContents());
  108.                 } else {
  109.                     value = encoder.encodeValue(p, elem);
  110.                 }
  111.                 if (value == null) {
  112.                     throw new SerializerException("Empty value for element "
  113.                             + elemName);
  114.                 }
  115.                 writer.write(value);
  116.             }
  117.             writeMultiValue(writer, PtsCodes.getElementCode(ImpsTags.UserID, p.getType()), users);
  118.             writeMultiValue(writer, PtsCodes.getElementCode(ImpsTags.ContactList, p.getType()), lists);
  119.         }
  120.         writer.close();
  121.     }
  122.     private void writeMultiValue(Writer writer, String code, ArrayList<String> values)
  123.             throws IOException {
  124.         if (values.size() == 0) {
  125.             return;
  126.         }
  127.         writer.write(' ');
  128.         writer.write(code);
  129.         writer.write('=');
  130.         if (values.size() == 1) {
  131.             writer.write(escapeValueString(values.get(0)));
  132.         } else {
  133.             writer.write('(');
  134.             int valueCount = values.size();
  135.             for (int i = 0; i < valueCount; i++) {
  136.                 if (i > 0) {
  137.                     writer.write(',');
  138.                 }
  139.                 writer.write(escapeValueString(values.get(i)));
  140.             }
  141.             writer.write(')');
  142.         }
  143.     }
  144.     static String escapeValueString(String contents) {
  145.         Matcher m = sCharsToBeQuoted.matcher(contents);
  146.         if (m.find()) {
  147.             if (contents.indexOf('"') != -1) {
  148.                 contents = contents.replace(""", """");
  149.             }
  150.             return """ + contents + """;
  151.         }
  152.         return contents;
  153.     }
  154.     static void appendPairValue(StringBuilder buf, String first, String second) {
  155.         buf.append('(');
  156.         if (first != null) {
  157.             buf.append(first);
  158.         }
  159.         buf.append(',');
  160.         buf.append(second);
  161.         buf.append(')');
  162.     }
  163.     /**
  164.      * Appends a name and value pair like "(<name>,<value>)".
  165.      */
  166.     static boolean appendNameAndValue(StringBuilder buf, String name, String value,
  167.             HashMap<String, String> nameCodes, HashMap<String, String> valueCodes,
  168.             boolean ignoreUnsupportedValue) {
  169.         String nameCode = nameCodes.get(name);
  170.         if (nameCode == null) {
  171.             ImpsLog.log("PTS: Ignoring value " + name);
  172.             return false;
  173.         }
  174.         String valueCode = null;
  175.         if (valueCodes != null) {
  176.             valueCode = valueCodes.get(value);
  177.         }
  178.         if (valueCode != null) {
  179.             value = valueCode;
  180.         } else {
  181.             if (ignoreUnsupportedValue) {
  182.                 return false;
  183.             }
  184.             value = escapeValueString(value);
  185.         }
  186.         appendPairValue(buf, nameCode, value);
  187.         return true;
  188.     }
  189.     static abstract class ElemValueEncoder {
  190.         public abstract String encodeValue(Primitive p, PrimitiveElement elem)
  191.                 throws SerializerException;
  192.         public static ElemValueEncoder getEncoder(String elemName) {
  193.             return sEncoders.get(elemName);
  194.         }
  195.         private static HashMap<String, ElemValueEncoder> sEncoders;
  196.         static {
  197.             sEncoders = new HashMap<String, ElemValueEncoder>();
  198.             sEncoders.put(ImpsTags.ClientID, new ClientIdEncoder());
  199.             sEncoders.put(ImpsTags.CapabilityList, new CapabilityEncoder());
  200.             sEncoders.put(ImpsTags.Functions, new ServiceTreeEncoder());
  201.             sEncoders.put(ImpsTags.Result, new ResultEncoder());
  202.             sEncoders.put(ImpsTags.ContactListProperties, new ProperitiesEncoder(
  203.                     PtsCodes.sContactListPropsToCode));
  204.             sEncoders.put(ImpsTags.PresenceSubList, new PresenceSubListEncoder());
  205.             ElemValueEncoder nickListEncoder = new NickListEncoder();
  206.             sEncoders.put(ImpsTags.NickList, nickListEncoder);
  207.             sEncoders.put(ImpsTags.AddNickList, nickListEncoder);
  208.             sEncoders.put(ImpsTags.RemoveNickList, nickListEncoder);
  209.         }
  210.     }
  211.     static class PresenceSubListEncoder extends ElemValueEncoder {
  212.         private boolean mEncodePresenceValue;
  213.         @Override
  214.         public String encodeValue(Primitive p, PrimitiveElement elem)
  215.                 throws SerializerException {
  216.             if (elem.getChildCount() == 0) {
  217.                 throw new SerializerException("No presence in the PresenceSubList");
  218.             }
  219.             StringBuilder buf = new StringBuilder();
  220.             mEncodePresenceValue = ImpsTags.UpdatePresence_Request.equals(p.getType());
  221.             ArrayList<PrimitiveElement> presences = elem.getChildren();
  222.             int presenceCount = presences.size();
  223.             if (presenceCount == 1) {
  224.                 if (mEncodePresenceValue) {
  225.                     // Append an extra pair of braces according to the Spec
  226.                     buf.append('(');
  227.                     encodePresence(buf, presences.get(0));
  228.                     buf.append(')');
  229.                 } else {
  230.                     encodePresence(buf, presences.get(0));
  231.                 }
  232.             } else {
  233.                 buf.append('(');
  234.                 for (int i = 0; i < presenceCount; i++) {
  235.                     if (i > 0) {
  236.                         buf.append(',');
  237.                     }
  238.                     encodePresence(buf, presences.get(i));
  239.                 }
  240.                 buf.append(')');
  241.             }
  242.             return buf.toString();
  243.         }
  244.         private void encodePresence(StringBuilder buf, PrimitiveElement p)
  245.                 throws SerializerException {
  246.             boolean hasQualifier = p.getChild(ImpsTags.Qualifier) != null;
  247.             String presenceName = p.getTagName();
  248.             String presenceNameCode = getPresenceCode(presenceName);
  249.             if (!mEncodePresenceValue) {
  250.                 encodeNoValuePresence(buf, p);
  251.             } else {
  252.                 buf.append('(');
  253.                 buf.append(presenceNameCode);
  254.                 buf.append(',');
  255.                 if (hasQualifier) {
  256.                     buf.append(p.getChildContents(ImpsTags.Qualifier));
  257.                     buf.append(',');
  258.                 }
  259.                 // All the presences with value have this kind of structure:
  260.                 // <name, qualifier, value>
  261.                 // And for the values, there are three different hierarchies:
  262.                 // 1. Simply use PresenceValue to indicate the value, most of the
  263.                 //    presences has adapted this way. -> SingleValue
  264.                 // 2. Use special tags for multiple values of this presence, eg. ClientInfo
  265.                 //    has adapted this way. -> MultiValue
  266.                 // 3. Has one or more children for the presence, and each child have
  267.                 //    multiple values. eg. CommCap has adapted this way. -> ExtMultiValue
  268.                 if (isMultiValuePresence(presenceName)) {
  269.                     // condition 2: multiple value
  270.                     int emptyValueSize = hasQualifier ? 1 : 0;
  271.                     ArrayList<PrimitiveElement> children = p.getChildren();
  272.                     if (children.size() > emptyValueSize) {
  273.                         buf.append('(');
  274.                         int childCount = children.size();
  275.                         int j = 0;  // used for first value check
  276.                         for (int i = 0; i < childCount; i++, j++) {
  277.                             PrimitiveElement value = children.get(i);
  278.                             if (ImpsTags.Qualifier.equals(value.getTagName())) {
  279.                                 j--;
  280.                                 continue;
  281.                             }
  282.                             if (j > 0) {
  283.                                 buf.append(',');
  284.                             }
  285.                             buf.append('(');
  286.                             buf.append(getPresenceCode(value.getTagName()));
  287.                             buf.append(',');
  288.                             buf.append(PtsCodes.getPAValueCode(value.getContents()));
  289.                             buf.append(')');
  290.                         }
  291.                         buf.append(')');
  292.                     }
  293.                 } else if (isExtMultiValuePresence(presenceName)) {
  294.                     // condition 3: extended multiple value
  295.                     // TODO: Implementation
  296.                 } else {
  297.                     // Condition 1: single value
  298.                     if (p.getChild(ImpsTags.PresenceValue) == null) {
  299.                         throw new SerializerException("Can't find presence value for " + presenceName);
  300.                     }
  301.                     buf.append(PtsCodes.getPAValueCode(p.getChildContents(ImpsTags.PresenceValue)));
  302.                 }
  303.                 buf.append(')');
  304.             }
  305.         }
  306.         private void encodeNoValuePresence(StringBuilder buf, PrimitiveElement p)
  307.                 throws SerializerException {
  308.             if (p.getChildCount() == 0) {
  309.                 buf.append(getPresenceCode(p.getTagName()));
  310.             } else {
  311.                 ArrayList<PrimitiveElement> children = p.getChildren();
  312.                 int childCount = children.size();
  313.                 buf.append('(');
  314.                 buf.append(getPresenceCode(p.getTagName()));
  315.                 buf.append(",(");
  316.                 for (int i = 0; i < childCount; i++) {
  317.                     if (i > 0) {
  318.                         buf.append(',');
  319.                     }
  320.                     encodeNoValuePresence(buf, children.get(i));
  321.                 }
  322.                 buf.append("))");
  323.             }
  324.         }
  325.         private String getPresenceCode(String tagname) throws SerializerException {
  326.             String code = PtsCodes.getPresenceAttributeCode(tagname);
  327.             if (code == null) {
  328.                 throw new SerializerException("Unsupport presence attribute: " + tagname);
  329.             }
  330.             return code;
  331.         }
  332.         private boolean isMultiValuePresence(String presenceName) {
  333.             if (ImpsTags.ClientInfo.equals(presenceName)) {
  334.                 return true;
  335.             }
  336.             // TODO: Add more supported extended multiple presence here
  337.             return false;
  338.         }
  339.         private boolean isExtMultiValuePresence(String presenceName) {
  340.             // TODO: Add supported extended multiple presence here
  341.             return false;
  342.         }
  343.     }
  344.     static class ClientIdEncoder extends ElemValueEncoder {
  345.         @Override
  346.         public String encodeValue(Primitive p, PrimitiveElement elem)
  347.                 throws SerializerException {
  348.             String value = elem.getChildContents(ImpsTags.URL);
  349.             if (value == null) {
  350.                 value = elem.getChildContents(ImpsTags.MSISDN);
  351.             }
  352.             return escapeValueString(value);
  353.         }
  354.     }
  355.     static class CapabilityEncoder extends ElemValueEncoder {
  356.         @Override
  357.         public String encodeValue(Primitive p, PrimitiveElement elem)
  358.                 throws SerializerException {
  359.             ArrayList<PrimitiveElement> caps = elem.getChildren();
  360.             int i, len;
  361.             StringBuilder result = new StringBuilder();
  362.             result.append('(');
  363.             for (i = 0, len = caps.size(); i < len; i++) {
  364.                 PrimitiveElement capElem = caps.get(i);
  365.                 String capName = capElem.getTagName();
  366.                 String capValue = capElem.getContents();
  367.                 if (i > 0) {
  368.                     result.append(',');
  369.                 }
  370.                 if (!appendNameAndValue(result, capName, capValue,
  371.                         PtsCodes.sCapElementToCode, PtsCodes.sCapValueToCode,
  372.                         ImpsTags.SupportedCIRMethod.equals(capName))) {
  373.                     result.deleteCharAt(result.length() - 1);
  374.                 }
  375.             }
  376.             result.append(')');
  377.             return result.toString();
  378.         }
  379.     }
  380.     static class ServiceTreeEncoder extends ElemValueEncoder {
  381.         @Override
  382.         public String encodeValue(Primitive p, PrimitiveElement elem)
  383.                 throws SerializerException {
  384.             StringBuilder buf = new StringBuilder();
  385.             buf.append('(');
  386.             appendFeature(buf, elem.getFirstChild());
  387.             buf.append(')');
  388.             return buf.toString();
  389.         }
  390.         private void appendFeature(StringBuilder buf, PrimitiveElement elem)
  391.                 throws SerializerException {
  392.             int childCount = elem.getChildCount();
  393.             if (childCount > 0) {
  394.                 ArrayList<PrimitiveElement> children = elem.getChildren();
  395.                 for (int i = 0; i < childCount; i++) {
  396.                     appendFeature(buf, children.get(i));
  397.                 }
  398.             } else {
  399.                 String code = PtsCodes.getServiceTreeCode(elem.getTagName());
  400.                 if (code == null) {
  401.                     throw new SerializerException("Invalid service tree tag:"
  402.                             + elem.getTagName());
  403.                 }
  404.                 if (buf.length() > 1) {
  405.                     buf.append(',');
  406.                 }
  407.                 buf.append(code);
  408.             }
  409.         }
  410.     }
  411.     static class ResultEncoder extends ElemValueEncoder {
  412.         @Override
  413.         public String encodeValue(Primitive p, PrimitiveElement elem)
  414.                 throws SerializerException {
  415.             String code = elem.getChildContents(ImpsTags.Code);
  416.             String desc = elem.getChildContents(ImpsTags.Description);
  417.             // Client never sends partial success result, the DetailedResult is
  418.             // ignored.
  419.             if (desc == null) {
  420.                 return code;
  421.             } else {
  422.                 StringBuilder res = new StringBuilder();
  423.                 appendPairValue(res, code, escapeValueString(desc));
  424.                 return res.toString();
  425.             }
  426.         }
  427.     }
  428.     static class NickListEncoder extends ElemValueEncoder {
  429.         @Override
  430.         public String encodeValue(Primitive p, PrimitiveElement elem)
  431.                 throws SerializerException {
  432.             StringBuilder buf = new StringBuilder();
  433.             ArrayList<PrimitiveElement> children = elem.getChildren();
  434.             int count = children.size();
  435.             buf.append('(');
  436.             for (int i = 0; i < count; i++) {
  437.                 PrimitiveElement child = children.get(i);
  438.                 String tagName = child.getTagName();
  439.                 String nickName = null;
  440.                 String userId = null;
  441.                 if (tagName.equals(ImpsTags.NickName)) {
  442.                     nickName = child.getChildContents(ImpsTags.Name);
  443.                     userId = child.getChildContents(ImpsTags.UserID);
  444.                 } else if (tagName.equals(ImpsTags.UserID)) {
  445.                     userId = child.getContents();
  446.                 }
  447.                 if (i > 0) {
  448.                     buf.append(',');
  449.                 }
  450.                 if (nickName != null) {
  451.                     nickName = escapeValueString(nickName);
  452.                 }
  453.                 appendPairValue(buf, nickName, escapeValueString(userId));
  454.             }
  455.             buf.append(')');
  456.             return buf.toString();
  457.         }
  458.     }
  459.     static class ProperitiesEncoder extends ElemValueEncoder {
  460.         private HashMap<String, String> mPropNameCodes;
  461.         public ProperitiesEncoder(HashMap<String, String> propNameCodes) {
  462.             mPropNameCodes = propNameCodes;
  463.         }
  464.         @Override
  465.         public String encodeValue(Primitive p, PrimitiveElement elem)
  466.                 throws SerializerException {
  467.             ArrayList<PrimitiveElement> props = elem.getChildren();
  468.             StringBuilder result = new StringBuilder();
  469.             result.append('(');
  470.             int count = props.size();
  471.             for (int i = 0; i < count; i++) {
  472.                 PrimitiveElement property = props.get(i);
  473.                 String name;
  474.                 String value;
  475.                 if (property.getTagName().equals(ImpsTags.Property)) {
  476.                     name = property.getChildContents(ImpsTags.Name);
  477.                     value = property.getChildContents(ImpsTags.Value);
  478.                 } else {
  479.                     name = property.getTagName();
  480.                     value = property.getContents();
  481.                 }
  482.                 if (i > 0) {
  483.                     result.append(',');
  484.                 }
  485.                 appendNameAndValue(result, name, value, mPropNameCodes, null, false);
  486.             }
  487.             result.append(')');
  488.             return result.toString();
  489.         }
  490.     }
  491. }