Home | History | Annotate | Download | only in xml
      1 /*
      2  * Copyright (C) 2009 Google Inc.  All rights reserved.
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.google.polo.wire.xml;
     18 
     19 import com.google.polo.exception.PoloException;
     20 import com.google.polo.exception.ProtocolErrorException;
     21 import com.google.polo.json.JSONArray;
     22 import com.google.polo.json.JSONException;
     23 import com.google.polo.json.JSONObject;
     24 import com.google.polo.json.XML;
     25 import com.google.polo.pairing.PoloUtil;
     26 import com.google.polo.pairing.message.ConfigurationAckMessage;
     27 import com.google.polo.pairing.message.ConfigurationMessage;
     28 import com.google.polo.pairing.message.EncodingOption;
     29 import com.google.polo.pairing.message.EncodingOption.EncodingType;
     30 import com.google.polo.pairing.message.OptionsMessage;
     31 import com.google.polo.pairing.message.OptionsMessage.ProtocolRole;
     32 import com.google.polo.pairing.message.PairingRequestAckMessage;
     33 import com.google.polo.pairing.message.PairingRequestMessage;
     34 import com.google.polo.pairing.message.PoloMessage;
     35 import com.google.polo.pairing.message.PoloMessage.PoloMessageType;
     36 import com.google.polo.pairing.message.SecretAckMessage;
     37 import com.google.polo.pairing.message.SecretMessage;
     38 
     39 /**
     40  * A collection of methods to convert {@link PoloMessage}s to and from XML
     41  * format.
     42  * <p>
     43  * This wire format was specified by a third party; it uses a proprietary
     44  * 64-byte message header/delimiter, and message internals are inconsistent with
     45  * the protocol buffer in several places.
     46  */
     47 public class XmlMessageBuilder {
     48 
     49   /*
     50    * Status types.
     51    * NOTE(mikey): These do not match the values defined by
     52    * OuterMessage.MessageType in polo.proto.
     53    */
     54 
     55   public static final int STATUS_OK = 1;
     56   public static final int STATUS_ERROR = 2;
     57 
     58   /*
     59    * Key names for XML versions of messages.
     60    */
     61 
     62   // OuterMessage XML key names
     63   private static final String OUTER_FIELD_TYPE = "msg_type";
     64   private static final String OUTER_FIELD_STATUS = "status";
     65   private static final String OUTER_FIELD_MSG_ID = "msg_id";
     66   private static final String OUTER_FIELD_PAYLOAD = "pairing_msg";
     67 
     68   // PairingRequestMessage XML key names
     69   private static final String PAIRING_REQUEST_FIELD_PROTOCOL_VERSION =
     70       "proto_version";
     71 
     72   // OptionsMessage XML key names
     73   private static final String OPTIONS_FIELD_PREFERRED_ROLE = "pref_role";
     74   private static final String OPTIONS_FIELD_OUTPUT_ENCODINGS = "out_encodings";
     75   private static final String OPTIONS_FIELD_INPUT_ENCODINGS = "in_encodings";
     76 
     77   // ConfigurationMessage XML key names
     78   private static final String CONFIG_FIELD_CLIENT_ROLE = "role";
     79 
     80   // EncodingOption XML key names
     81   private static final String ENCODING_FIELD_TYPE = "type";
     82   private static final String ENCODING_FIELD_SYMBOL_LENGTH = "min_length";
     83   private static final String ENCODING_FIELD_MAX_LENGTH = "max_length";
     84   private static final String ENCODING_SUBFIELD_ENCODING = "encoding";
     85 
     86   // SecretMessage XML key names
     87   private static final String SECRET_FIELD_SECRET = "bytes";
     88 
     89   // Payload container names
     90   private static final String MESSAGE_CONTAINER_NAME_PAIRING_REQUEST =
     91       "pairing_req";
     92   private static final String MESSAGE_CONTAINER_NAME_PAIRING_REQUEST_ACK =
     93       "pairing_req_ack";
     94   private static final String MESSAGE_CONTAINER_NAME_OPTIONS = "config_options";
     95   private static final String MESSAGE_CONTAINER_NAME_CONFIG = "config";
     96   private static final String MESSAGE_CONTAINER_NAME_SECRET = "secret";
     97   private static final String PAIRING_REQUEST_FIELD_SERVICE_NAME = "svc_name";
     98   private static final String PAIRING_REQUEST_FIELD_CLIENT_NAME = "client_name";
     99   private static final String PAIRING_REQUEST_ACK_FIELD_SERVER_NAME =
    100       "server_name";
    101 
    102   //
    103   // Encoding types -- these do not match polo.proto's enum.
    104   //
    105 
    106   public static final int ENCODING_TYPE_NUMERIC = 1;
    107   public static final int ENCODING_TYPE_HEXADECIMAL = 2;
    108   public static final int ENCODING_TYPE_ALPHANUMERIC = 3;
    109   public static final int ENCODING_TYPE_QRCODE = 4;
    110 
    111   /**
    112    * Cache of the last message id header value received.  The value should be
    113    * copied to any response.
    114    */
    115   private String mLastMessageId;
    116 
    117   public XmlMessageBuilder() {
    118     mLastMessageId = null;
    119   }
    120 
    121   /**
    122    * Builds a {@link PoloMessage} from the XML version of the outer message.
    123    *
    124    * @param outerXml        the outermost XML string
    125    * @return  a new {@link PoloMessage}
    126    * @throws PoloException  on error parsing the message
    127    */
    128   PoloMessage outerXMLToPoloMessage(String outerXml) throws PoloException {
    129     JSONObject outerMessage;
    130     try {
    131       outerMessage = XML.toJSONObject(outerXml);
    132     } catch (JSONException e) {
    133         throw new PoloException(e);
    134     }
    135 
    136     JSONObject payload;
    137     PoloMessageType messageType;
    138     try {
    139       payload = outerMessage.getJSONObject(OUTER_FIELD_PAYLOAD);
    140 
    141       int status = payload.getInt(OUTER_FIELD_STATUS);
    142       if (status != STATUS_OK) {
    143         throw new ProtocolErrorException("Peer reported an error.");
    144       }
    145 
    146       int msgIntVal = payload.getInt(OUTER_FIELD_TYPE);
    147       messageType = PoloMessageType.fromIntVal(msgIntVal);
    148     } catch (JSONException e) {
    149       throw new PoloException("Bad outer message.", e);
    150     }
    151 
    152     if (outerMessage.has("msg_id")) {
    153       try {
    154         mLastMessageId = outerMessage.getString("msg_id");
    155       } catch (JSONException e) {
    156       }
    157     } else {
    158       mLastMessageId = null;
    159     }
    160 
    161     switch (messageType) {
    162       case PAIRING_REQUEST:
    163         return getPairingRequest(payload);
    164       case PAIRING_REQUEST_ACK:
    165         return getPairingRequestAck(payload);
    166       case OPTIONS:
    167         return getOptionsMessage(payload);
    168       case CONFIGURATION:
    169         return getConfigMessage(payload);
    170       case CONFIGURATION_ACK:
    171         return getConfigAckMessage(payload);
    172       case SECRET:
    173         return getSecretMessage(payload);
    174       case SECRET_ACK:
    175         return getSecretAckMessage(payload);
    176       default:
    177         return null;
    178     }
    179 
    180   }
    181 
    182   /*
    183    * Methods to convert XML inner messages to PoloMessage instances.
    184    *
    185    * NOTE(mikey): These methods are implemented in terms of JSONObject
    186    * as a convenient way to represent hierarchical key->(dict|list|value)
    187    * structures.
    188    *
    189    * Note that these methods are very similar to those found in
    190    * JsonWireAdapter.  However, the XML wire format was specified with slight
    191    * differences compared to the protocol buffer definition.  For example,
    192    * in the OptionsMessage, encodings are wrapped in an "<options>" container.
    193    *
    194    * Also, many fields names have slight differences compared to the names in
    195    * the protocol buffer (for example, in PairingRequestMessage, "service_name"
    196    * is called "svc_name".)
    197    */
    198 
    199   /**
    200    * Generates a new {@link PairingRequestMessage} from a JSON payload.
    201    *
    202    * @param  body           the JSON payload
    203    * @return  the new message
    204    * @throws PoloException  on error parsing the {@link JSONObject}
    205    */
    206   PairingRequestMessage getPairingRequest(JSONObject body)
    207       throws PoloException {
    208     try {
    209       JSONObject jsonObj = body.getJSONObject(
    210           MESSAGE_CONTAINER_NAME_PAIRING_REQUEST);
    211       String serviceName = jsonObj.getString(
    212           PAIRING_REQUEST_FIELD_SERVICE_NAME);
    213       String clientName = null;
    214       if (jsonObj.has(PAIRING_REQUEST_FIELD_CLIENT_NAME)) {
    215         clientName = jsonObj.getString(PAIRING_REQUEST_FIELD_CLIENT_NAME);
    216       }
    217       return new PairingRequestMessage(serviceName, clientName);
    218     } catch (JSONException e) {
    219       throw new PoloException("Malformed message.", e);
    220     }
    221   }
    222 
    223   /**
    224    * Generates a new {@link PairingRequestAckMessage} from a JSON payload.
    225    *
    226    * @param  body           the JSON payload
    227    * @return                the new message
    228    * @throws PoloException  on error parsing the {@link JSONObject}
    229    */
    230   PairingRequestAckMessage getPairingRequestAck(JSONObject body)
    231       throws PoloException {
    232     try {
    233       JSONObject jsonObj = body.getJSONObject(
    234           MESSAGE_CONTAINER_NAME_PAIRING_REQUEST_ACK);
    235       String serverName = null;
    236       if (jsonObj.has(PAIRING_REQUEST_ACK_FIELD_SERVER_NAME)) {
    237         serverName = jsonObj.getString(PAIRING_REQUEST_ACK_FIELD_SERVER_NAME);
    238       }
    239       return new PairingRequestAckMessage(serverName);
    240     } catch (JSONException e) {
    241       throw new PoloException("Malformed message.", e);
    242     }
    243   }
    244 
    245   /**
    246    * Generates a new {@link OptionsMessage} from a JSON payload.
    247    *
    248    * @param  body           the JSON payload
    249    * @return                the new message
    250    * @throws PoloException  on error parsing the {@link JSONObject}
    251    */
    252   OptionsMessage getOptionsMessage(JSONObject body) throws PoloException {
    253     OptionsMessage options = new OptionsMessage();
    254     JSONObject jsonOptions;
    255     try {
    256       jsonOptions = body.getJSONObject(MESSAGE_CONTAINER_NAME_OPTIONS);
    257 
    258       JSONObject inEnc = jsonOptions.getJSONObject(
    259           OPTIONS_FIELD_INPUT_ENCODINGS);
    260       JSONObject outEnc = jsonOptions.getJSONObject(
    261           OPTIONS_FIELD_OUTPUT_ENCODINGS);
    262 
    263       // Input encodings
    264       JSONArray inEncodings = new JSONArray();
    265       try {
    266         inEncodings = inEnc.getJSONArray(ENCODING_SUBFIELD_ENCODING);
    267       } catch (JSONException e) {
    268         if (inEnc.has(ENCODING_SUBFIELD_ENCODING)) {
    269           JSONObject enc = inEnc.getJSONObject(ENCODING_SUBFIELD_ENCODING);
    270           inEncodings.put(enc);
    271         }
    272       }
    273 
    274       for (int i = 0; i < inEncodings.length(); i++) {
    275         JSONObject enc = inEncodings.getJSONObject(i);
    276         options.addInputEncoding(getEncodingOption(enc));
    277       }
    278 
    279       // Output encodings
    280       JSONArray outEncodings = new JSONArray();
    281       try {
    282         outEncodings = outEnc.getJSONArray(ENCODING_SUBFIELD_ENCODING);
    283       } catch (JSONException e) {
    284         if (outEnc.has(ENCODING_SUBFIELD_ENCODING)) {
    285           JSONObject enc = outEnc.getJSONObject(ENCODING_SUBFIELD_ENCODING);
    286           outEncodings.put(enc);
    287         }
    288       }
    289 
    290       for (int i = 0; i < outEncodings.length(); i++) {
    291         JSONObject enc = outEncodings.getJSONObject(i);
    292         options.addOutputEncoding(getEncodingOption(enc));
    293       }
    294 
    295       // Role
    296       ProtocolRole role = ProtocolRole.fromIntVal(
    297           jsonOptions.getInt(OPTIONS_FIELD_PREFERRED_ROLE));
    298       options.setProtocolRolePreference(role);
    299     } catch (JSONException e) {
    300       throw new PoloException("Malformed message.", e);
    301     }
    302 
    303     return options;
    304   }
    305 
    306   /**
    307    * Generates a new {@link ConfigurationMessage} from a JSON payload.
    308    *
    309    * @param  body           the JSON payload
    310    * @return                the new message
    311    * @throws PoloException  on error parsing the {@link JSONObject}
    312    */
    313   ConfigurationMessage getConfigMessage(JSONObject body)
    314   throws PoloException {
    315     try {
    316       EncodingOption encoding = getEncodingOption(
    317           body.getJSONObject(MESSAGE_CONTAINER_NAME_CONFIG)
    318               .getJSONObject(ENCODING_SUBFIELD_ENCODING));
    319       ProtocolRole role = ProtocolRole.fromIntVal(
    320           body.getJSONObject(MESSAGE_CONTAINER_NAME_CONFIG)
    321               .getInt(CONFIG_FIELD_CLIENT_ROLE));
    322       return new ConfigurationMessage(encoding, role);
    323     } catch (JSONException e) {
    324       throw new PoloException("Malformed message.", e);
    325     }
    326   }
    327 
    328   /**
    329    * Generates a new {@link ConfigurationAckMessage} from a JSON payload.
    330    *
    331    * @param  body           the JSON payload
    332    * @return                the new message
    333    */
    334   ConfigurationAckMessage getConfigAckMessage(JSONObject body) {
    335     return new ConfigurationAckMessage();
    336   }
    337 
    338   /**
    339    * Generates a new {@link SecretMessage} from a JSON payload.
    340    *
    341    * @param  body           the JSON payload
    342    * @return                the new message
    343    * @throws PoloException  on error parsing the {@link JSONObject}
    344    */
    345   SecretMessage getSecretMessage(JSONObject body) throws PoloException {
    346     String secret;
    347     try {
    348       secret = body.getJSONObject(MESSAGE_CONTAINER_NAME_SECRET)
    349           .getString(SECRET_FIELD_SECRET);
    350     } catch (JSONException e) {
    351       throw new PoloException("Malformed message.", e);
    352     }
    353     byte[] secretBytes = PoloUtil.hexStringToBytes(secret);
    354     return new SecretMessage(secretBytes);
    355   }
    356 
    357   /**
    358    * Generates a new {@link SecretAckMessage} from a JSON payload.
    359    *
    360    * @param body  the JSON payload
    361    * @return      the new message
    362    */
    363   SecretAckMessage getSecretAckMessage(JSONObject body) {
    364     return new SecretAckMessage(null);
    365   }
    366 
    367   /**
    368    * Generates a new {@link EncodingOption} from a JSON sub-dictionary.
    369    *
    370    * @param  option         the JSON sub-dictionary describing the option
    371    * @return                the new {@link EncodingOption}
    372    * @throws JSONException  on error parsing the {@link JSONObject}
    373    */
    374   EncodingOption getEncodingOption(JSONObject option) throws JSONException {
    375     int length = option.getInt(ENCODING_FIELD_SYMBOL_LENGTH);
    376     int intType = option.getInt(ENCODING_FIELD_TYPE);
    377     EncodingType type = encodingTypeFromIntValue(intType);
    378     return new EncodingOption(type, length);
    379   }
    380 
    381   /**
    382    * Converts a {@link PoloMessage} to an XML string.
    383    *
    384    * @param message         the message to convert
    385    * @return                the same message, as translated to XML
    386    */
    387   public String poloMessageToXML(PoloMessage message) {
    388     try {
    389       if (message instanceof PairingRequestMessage) {
    390         return toXML((PairingRequestMessage) message);
    391       } else if (message instanceof PairingRequestAckMessage) {
    392         return toXML((PairingRequestAckMessage) message);
    393       } else if (message instanceof OptionsMessage) {
    394         return toXML((OptionsMessage) message);
    395       } else if (message instanceof ConfigurationMessage) {
    396         return toXML((ConfigurationMessage) message);
    397       } else if (message instanceof ConfigurationAckMessage) {
    398         return toXML((ConfigurationAckMessage) message);
    399       } else if (message instanceof SecretMessage) {
    400         return toXML((SecretMessage) message);
    401       } else if (message instanceof SecretAckMessage) {
    402         return toXML((SecretAckMessage) message);
    403       }
    404       return null;
    405     } catch (JSONException e) {
    406       e.printStackTrace();
    407       return "";
    408     }
    409 
    410   }
    411 
    412   /**
    413    * Generates a String corresponding to a full wire message (wrapped in
    414    * an outer message) for the given payload.
    415    */
    416   public String getOuterXML(PoloMessage message, int status) {
    417     StringBuffer out = new StringBuffer();
    418 
    419 
    420     out.append("<" + OUTER_FIELD_PAYLOAD + ">\n");
    421 
    422     // status
    423     out.append("<" + OUTER_FIELD_STATUS + ">");
    424     out.append(status);
    425     out.append("</" + OUTER_FIELD_STATUS + ">\n");
    426 
    427     // msg_id (optional)
    428     if (mLastMessageId != null) {
    429       out.append("<" + OUTER_FIELD_MSG_ID + ">");
    430       out.append(mLastMessageId);
    431       out.append("</" + OUTER_FIELD_MSG_ID + ">\n");
    432     }
    433 
    434     // payload
    435     if (message != null) {
    436       int msgType = message.getType().getAsInt();
    437       out.append("<" + OUTER_FIELD_TYPE + ">");
    438       out.append(msgType);
    439       out.append("</" + OUTER_FIELD_TYPE + ">\n");
    440 
    441       out.append(poloMessageToXML(message));
    442       out.append("\n");
    443     }
    444 
    445     out.append("</" + OUTER_FIELD_PAYLOAD + ">\n");
    446     return out.toString();
    447   }
    448 
    449 
    450 
    451   /**
    452    * Generates an error payload corresponding to an outer message with an
    453    * error code in the status field.  The error code is determined by the type
    454    * of the exception.
    455    *
    456    * @param exception       the {@link Exception} to use to determine the error
    457    *                        code
    458    * @return                a string outer message
    459    * @throws PoloException  on error building the message
    460    */
    461   public String getErrorXML(Exception exception)
    462       throws PoloException {
    463     return getOuterXML(null, STATUS_ERROR);
    464   }
    465 
    466   /**
    467    * Translates a {@link PairingRequestMessage} to an XML string.
    468    *
    469    * @throws JSONException  on error generating the {@link String}.
    470    */
    471   String toXML(PairingRequestMessage message) throws JSONException {
    472     JSONObject jsonObj = new JSONObject();
    473     JSONObject pairingReq = new JSONObject();
    474     jsonObj.put(MESSAGE_CONTAINER_NAME_PAIRING_REQUEST, pairingReq);
    475     pairingReq.put(PAIRING_REQUEST_FIELD_SERVICE_NAME,
    476         message.getServiceName());
    477     if (message.hasClientName()) {
    478       pairingReq.put(PAIRING_REQUEST_FIELD_CLIENT_NAME,
    479           message.getServiceName());
    480     }
    481     pairingReq.put(PAIRING_REQUEST_FIELD_PROTOCOL_VERSION, 1);
    482     return XML.toString(jsonObj);
    483   }
    484 
    485   /**
    486    * Translates a {@link PairingRequestAckMessage} to an XML string.
    487    *
    488    * @throws JSONException  on error generating the {@link String}.
    489    */
    490   String toXML(PairingRequestAckMessage message) throws JSONException {
    491     JSONObject jsonObj = new JSONObject();
    492     JSONObject pairingReq = new JSONObject();
    493     jsonObj.put(MESSAGE_CONTAINER_NAME_PAIRING_REQUEST_ACK, pairingReq);
    494     if (message.hasServerName()) {
    495       jsonObj.put(PAIRING_REQUEST_ACK_FIELD_SERVER_NAME,
    496           message.getServerName());
    497     }
    498     pairingReq.put(PAIRING_REQUEST_FIELD_PROTOCOL_VERSION, 1);
    499     return XML.toString(jsonObj);
    500   }
    501 
    502   /**
    503    * Translates a {@link OptionsMessage} to an XML string.
    504    *
    505    * @throws JSONException  on error generating the {@link String}.
    506    */
    507  String toXML(OptionsMessage message) throws JSONException {
    508     JSONObject jsonObj = new JSONObject();
    509     JSONObject options = new JSONObject();
    510 
    511     JSONObject inEncs = new JSONObject();
    512     JSONArray inEncsArray = new JSONArray();
    513     for (EncodingOption encoding : message.getInputEncodingSet()) {
    514       inEncsArray.put(encodingToJson(encoding));
    515     }
    516     inEncs.put(ENCODING_SUBFIELD_ENCODING, inEncsArray);
    517     options.put(OPTIONS_FIELD_INPUT_ENCODINGS, inEncs);
    518 
    519     JSONObject outEncs = new JSONObject();
    520     JSONArray outEncsArray = new JSONArray();
    521     for (EncodingOption encoding : message.getOutputEncodingSet()) {
    522       outEncsArray.put(encodingToJson(encoding));
    523     }
    524     outEncs.put(ENCODING_SUBFIELD_ENCODING, outEncsArray);
    525     options.put(OPTIONS_FIELD_OUTPUT_ENCODINGS, outEncs);
    526 
    527     options.put(OPTIONS_FIELD_PREFERRED_ROLE,
    528         message.getProtocolRolePreference().ordinal());
    529     jsonObj.put(MESSAGE_CONTAINER_NAME_OPTIONS, options);
    530     return XML.toString(jsonObj);
    531   }
    532 
    533   /**
    534    * Translates a {@link ConfigurationMessage} to an XML string.
    535    *
    536    * @throws JSONException  on error generating the {@link String}.
    537    */
    538   String toXML(ConfigurationMessage message) throws JSONException {
    539     JSONObject jsonObj = new JSONObject();
    540     JSONObject config = new JSONObject();
    541     JSONObject encoding = encodingToJson(message.getEncoding());
    542     config.put(ENCODING_SUBFIELD_ENCODING, encoding);
    543     config.put(CONFIG_FIELD_CLIENT_ROLE, message.getClientRole().ordinal());
    544     jsonObj.put(MESSAGE_CONTAINER_NAME_CONFIG, config);
    545     return XML.toString(jsonObj);
    546   }
    547 
    548   /**
    549    * Translates a {@link ConfigurationAckMessage} to an XML string.
    550    */
    551  String toXML(ConfigurationAckMessage message) {
    552     return "";
    553   }
    554 
    555  /**
    556   * Translates a {@link SecretMessage} to an XML string.
    557   *
    558   * @throws JSONException  on error generating the {@link String}.
    559   */
    560   String toXML(SecretMessage message) throws JSONException {
    561     JSONObject jsonObj = new JSONObject();
    562     JSONObject secret = new JSONObject();
    563     String bytesStr = PoloUtil.bytesToHexString(message.getSecret());
    564     secret.put(SECRET_FIELD_SECRET, bytesStr);
    565     jsonObj.put(MESSAGE_CONTAINER_NAME_SECRET, secret);
    566     return XML.toString(jsonObj);
    567   }
    568 
    569   /**
    570    * Translates a {@link SecretAckMessage} to an XML string.
    571    */
    572   String toXML(SecretAckMessage message) {
    573     return "";
    574   }
    575 
    576   /**
    577    * Translates a {@link EncodingOption} to a {@link JSONObject}.
    578    *
    579    * @throws JSONException  on error generating the {@link JSONObject}
    580    */
    581   JSONObject encodingToJson(EncodingOption encoding) throws JSONException {
    582     JSONObject result = new JSONObject();
    583     int intType = encodingTypeToIntVal(encoding.getType());
    584     result.put(ENCODING_FIELD_TYPE, intType);
    585     result.put(ENCODING_FIELD_SYMBOL_LENGTH, encoding.getSymbolLength());
    586     result.put(ENCODING_FIELD_MAX_LENGTH, encoding.getSymbolLength());
    587     return result;
    588   }
    589 
    590   /**
    591    * Converts an {@link EncodingType} to the numeric value used on the wire.
    592    * <p>
    593    * Note that in this implementation, the values used on the wire do not match
    594    * those returned by {@link EncodingType#getAsInt()}, hence the extra method.
    595    *
    596    * @param type  the {@link EncodingType}
    597    * @return      an integer representation
    598    */
    599   private static int encodingTypeToIntVal(EncodingType type) {
    600     switch (type) {
    601       case ENCODING_ALPHANUMERIC:
    602         return ENCODING_TYPE_ALPHANUMERIC;
    603       case ENCODING_NUMERIC:
    604         return ENCODING_TYPE_NUMERIC;
    605       case ENCODING_HEXADECIMAL:
    606         return ENCODING_TYPE_HEXADECIMAL;
    607       case ENCODING_QRCODE:
    608         return ENCODING_TYPE_QRCODE;
    609       case ENCODING_UNKNOWN:
    610       default:
    611         return 0;
    612     }
    613   }
    614 
    615   /**
    616    * Converts a numeric value used on the wire to the corresponding
    617    * {@link EncodingType}.
    618    * <p>
    619    * Note that in this implementation, the values used on the wire do not match
    620    * those returned by {@link EncodingType#getAsInt()}, hence the extra method.
    621    *
    622    * @param intType  the value used on the wire
    623    * @return         the corresponding {@link EncodingType}
    624    */
    625   private static EncodingType encodingTypeFromIntValue(int intType) {
    626     EncodingType type = EncodingType.ENCODING_UNKNOWN;
    627     switch (intType) {
    628       case ENCODING_TYPE_ALPHANUMERIC:
    629         type = EncodingType.ENCODING_ALPHANUMERIC;
    630         break;
    631       case ENCODING_TYPE_NUMERIC:
    632         type = EncodingType.ENCODING_NUMERIC;
    633         break;
    634       case ENCODING_TYPE_HEXADECIMAL:
    635         type = EncodingType.ENCODING_HEXADECIMAL;
    636         break;
    637       case ENCODING_TYPE_QRCODE:
    638         type = EncodingType.ENCODING_QRCODE;
    639         break;
    640       default:
    641         type = EncodingType.ENCODING_UNKNOWN;
    642       break;
    643     }
    644     return type;
    645   }
    646 
    647 }
    648