Home | History | Annotate | Download | only in omadm
      1 package com.android.hotspot2.omadm;
      2 
      3 import org.xml.sax.SAXException;
      4 
      5 import java.io.IOException;
      6 import java.io.InputStream;
      7 import java.io.OutputStream;
      8 import java.nio.charset.StandardCharsets;
      9 import java.util.ArrayList;
     10 import java.util.HashMap;
     11 import java.util.Iterator;
     12 import java.util.List;
     13 import java.util.Map;
     14 
     15 public class MOTree {
     16     public static final String MgmtTreeTag = "MgmtTree";
     17 
     18     public static final String NodeTag = "Node";
     19     public static final String NodeNameTag = "NodeName";
     20     public static final String PathTag = "Path";
     21     public static final String ValueTag = "Value";
     22     public static final String RTPropTag = "RTProperties";
     23     public static final String TypeTag = "Type";
     24     public static final String DDFNameTag = "DDFName";
     25 
     26     private final String mUrn;
     27     private final String mDtdRev;
     28     private final OMAConstructed mRoot;
     29 
     30     public MOTree(XMLNode node, String urn) throws IOException, SAXException {
     31         Iterator<XMLNode> children = node.getChildren().iterator();
     32 
     33         String dtdRev = null;
     34 
     35         while (children.hasNext()) {
     36             XMLNode child = children.next();
     37             if (child.getTag().equals(OMAConstants.SyncMLVersionTag)) {
     38                 dtdRev = child.getText();
     39                 children.remove();
     40                 break;
     41             }
     42         }
     43 
     44         mUrn = urn;
     45         mDtdRev = dtdRev;
     46 
     47         mRoot = new MgmtTreeRoot(node, dtdRev);
     48 
     49         for (XMLNode child : node.getChildren()) {
     50             buildNode(mRoot, child);
     51         }
     52     }
     53 
     54     public MOTree(String urn, String rev, OMAConstructed root) throws IOException {
     55         mUrn = urn;
     56         mDtdRev = rev;
     57         mRoot = root;
     58     }
     59 
     60     public static MOTree buildMgmtTree(String urn, String rev, OMAConstructed root)
     61             throws IOException {
     62         OMAConstructed realRoot;
     63         switch (urn) {
     64             case OMAConstants.PPS_URN:
     65             case OMAConstants.DevInfoURN:
     66             case OMAConstants.DevDetailURN:
     67             case OMAConstants.DevDetailXURN:
     68                 realRoot = new MgmtTreeRoot(OMAConstants.OMAVersion);
     69                 realRoot.addChild(root);
     70                 return new MOTree(urn, rev, realRoot);
     71             default:
     72                 return new MOTree(urn, rev, root);
     73         }
     74     }
     75 
     76     public static boolean hasMgmtTreeTag(String text) {
     77         for (int n = 0; n < text.length(); n++) {
     78             char ch = text.charAt(n);
     79             if (ch > ' ') {
     80                 return text.regionMatches(true, n, '<' + MgmtTreeTag + '>',
     81                         0, MgmtTreeTag.length() + 2);
     82             }
     83         }
     84         return false;
     85     }
     86 
     87     private static class NodeData {
     88         private final String mName;
     89         private String mPath;
     90         private String mValue;
     91 
     92         private NodeData(String name) {
     93             mName = name;
     94         }
     95 
     96         private void setPath(String path) {
     97             mPath = path;
     98         }
     99 
    100         private void setValue(String value) {
    101             mValue = value;
    102         }
    103 
    104         public String getName() {
    105             return mName;
    106         }
    107 
    108         public String getPath() {
    109             return mPath;
    110         }
    111 
    112         public String getValue() {
    113             return mValue;
    114         }
    115     }
    116 
    117     private static void buildNode(OMANode parent, XMLNode node) throws IOException {
    118         if (!node.getTag().equals(NodeTag))
    119             throw new IOException("Node is a '" + node.getTag() + "' instead of a 'Node'");
    120 
    121         Map<String, XMLNode> checkMap = new HashMap<>(3);
    122         String context = null;
    123         List<NodeData> values = new ArrayList<>();
    124         List<XMLNode> children = new ArrayList<>();
    125 
    126         NodeData curValue = null;
    127 
    128         for (XMLNode child : node.getChildren()) {
    129             XMLNode old = checkMap.put(child.getTag(), child);
    130 
    131             switch (child.getTag()) {
    132                 case NodeNameTag:
    133                     if (curValue != null)
    134                         throw new IOException(NodeNameTag + " not expected");
    135                     curValue = new NodeData(child.getText());
    136 
    137                     break;
    138                 case PathTag:
    139                     if (curValue == null || curValue.getPath() != null)
    140                         throw new IOException(PathTag + " not expected");
    141                     curValue.setPath(child.getText());
    142 
    143                     break;
    144                 case ValueTag:
    145                     if (!children.isEmpty())
    146                         throw new IOException(ValueTag + " in constructed node");
    147                     if (curValue == null || curValue.getValue() != null)
    148                         throw new IOException(ValueTag + " not expected");
    149                     curValue.setValue(child.getText());
    150                     values.add(curValue);
    151                     curValue = null;
    152 
    153                     break;
    154                 case RTPropTag:
    155                     if (old != null)
    156                         throw new IOException("Duplicate " + RTPropTag);
    157                     XMLNode typeNode = getNextNode(child, TypeTag);
    158                     XMLNode ddfName = getNextNode(typeNode, DDFNameTag);
    159                     context = ddfName.getText();
    160                     if (context == null)
    161                         throw new IOException("No text in " + DDFNameTag);
    162 
    163                     break;
    164                 case NodeTag:
    165                     if (!values.isEmpty())
    166                         throw new IOException("Scalar node " + node.getText() + " has Node child");
    167                     children.add(child);
    168 
    169                     break;
    170             }
    171         }
    172 
    173         if (values.isEmpty()) {
    174             if (curValue == null)
    175                 throw new IOException("Missing name");
    176 
    177             OMANode subNode = parent.addChild(curValue.getName(),
    178                     context, null, curValue.getPath());
    179 
    180             for (XMLNode child : children) {
    181                 buildNode(subNode, child);
    182             }
    183         } else {
    184             if (!children.isEmpty())
    185                 throw new IOException("Got both sub nodes and value(s)");
    186 
    187             for (NodeData nodeData : values) {
    188                 parent.addChild(nodeData.getName(), context,
    189                         nodeData.getValue(), nodeData.getPath());
    190             }
    191         }
    192     }
    193 
    194     private static XMLNode getNextNode(XMLNode node, String tag) throws IOException {
    195         if (node == null)
    196             throw new IOException("No node for " + tag);
    197         if (node.getChildren().size() != 1)
    198             throw new IOException("Expected " + node.getTag() + " to have exactly one child");
    199         XMLNode child = node.getChildren().iterator().next();
    200         if (!child.getTag().equals(tag))
    201             throw new IOException("Expected " + node.getTag() + " to have child '" + tag +
    202                     "' instead of '" + child.getTag() + "'");
    203         return child;
    204     }
    205 
    206     public String getUrn() {
    207         return mUrn;
    208     }
    209 
    210     public String getDtdRev() {
    211         return mDtdRev;
    212     }
    213 
    214     public OMAConstructed getRoot() {
    215         return mRoot;
    216     }
    217 
    218     @Override
    219     public String toString() {
    220         StringBuilder sb = new StringBuilder();
    221         sb.append("MO Tree v").append(mDtdRev).append(", urn ").append(mUrn).append(")\n");
    222         sb.append(mRoot);
    223 
    224         return sb.toString();
    225     }
    226 
    227     public void marshal(OutputStream out) throws IOException {
    228         out.write("tree ".getBytes(StandardCharsets.UTF_8));
    229         OMAConstants.serializeString(mDtdRev, out);
    230         out.write(String.format("(%s)\n", mUrn).getBytes(StandardCharsets.UTF_8));
    231         mRoot.marshal(out, 0);
    232     }
    233 
    234     public static MOTree unmarshal(InputStream in) throws IOException {
    235         boolean strip = true;
    236         StringBuilder tree = new StringBuilder();
    237         for (; ; ) {
    238             int octet = in.read();
    239             if (octet < 0) {
    240                 return null;
    241             } else if (octet > ' ') {
    242                 tree.append((char) octet);
    243                 strip = false;
    244             } else if (!strip) {
    245                 break;
    246             }
    247         }
    248         if (!tree.toString().equals("tree")) {
    249             throw new IOException("Not a tree: " + tree);
    250         }
    251 
    252         String version = OMAConstants.deserializeString(in);
    253         int next = in.read();
    254         if (next != '(') {
    255             throw new IOException("Expected URN in tree definition");
    256         }
    257         String urn = OMAConstants.readURN(in);
    258 
    259         OMAConstructed root = OMANode.unmarshal(in);
    260 
    261         return new MOTree(urn, version, root);
    262     }
    263 
    264     public String toXml() {
    265         StringBuilder sb = new StringBuilder();
    266         mRoot.toXml(sb);
    267         return sb.toString();
    268     }
    269 }
    270