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