1 package com.android.hotspot2.omadm; 2 3 import java.io.IOException; 4 import java.io.InputStream; 5 import java.io.OutputStream; 6 import java.util.Collection; 7 import java.util.HashMap; 8 import java.util.Iterator; 9 import java.util.LinkedList; 10 import java.util.List; 11 import java.util.Map; 12 13 public abstract class OMANode { 14 private final OMAConstructed mParent; 15 private final String mName; 16 private final String mContext; 17 private final Map<String, String> mAttributes; 18 19 protected OMANode(OMAConstructed parent, String name, String context, 20 Map<String, String> avps) { 21 mParent = parent; 22 mName = name; 23 mContext = context; 24 mAttributes = avps; 25 } 26 27 protected static Map<String, String> buildAttributes(String[] avps) { 28 if (avps == null) { 29 return null; 30 } 31 Map<String, String> attributes = new HashMap<>(); 32 for (int n = 0; n < avps.length; n += 2) { 33 attributes.put(avps[n], avps[n + 1]); 34 } 35 return attributes; 36 } 37 38 protected Map<String, String> getAttributes() { 39 return mAttributes; 40 } 41 42 public OMAConstructed getParent() { 43 return mParent; 44 } 45 46 public String getName() { 47 return mName; 48 } 49 50 public String getContext() { 51 return mContext; 52 } 53 54 public List<String> getPath() { 55 LinkedList<String> path = new LinkedList<>(); 56 for (OMANode node = this; node != null; node = node.getParent()) { 57 path.addFirst(node.getName()); 58 } 59 return path; 60 } 61 62 public String getPathString() { 63 StringBuilder sb = new StringBuilder(); 64 for (String element : getPath()) { 65 sb.append('/').append(element); 66 } 67 return sb.toString(); 68 } 69 70 public abstract OMANode reparent(OMAConstructed parent); 71 72 public abstract String getScalarValue(Iterator<String> path) throws OMAException; 73 74 public abstract OMANode getListValue(Iterator<String> path) throws OMAException; 75 76 public abstract boolean isLeaf(); 77 78 public abstract Collection<OMANode> getChildren(); 79 80 public abstract OMANode getChild(String name) throws OMAException; 81 82 public abstract String getValue(); 83 84 public abstract OMANode addChild(String name, String context, String value, String path) 85 throws IOException; 86 87 public abstract void marshal(OutputStream out, int level) throws IOException; 88 89 public abstract void toString(StringBuilder sb, int level); 90 91 public abstract void fillPayload(StringBuilder sb); 92 93 public void toXml(StringBuilder sb) { 94 sb.append('<').append(MOTree.NodeTag); 95 if (mAttributes != null && !mAttributes.isEmpty()) { 96 for (Map.Entry<String, String> avp : mAttributes.entrySet()) { 97 sb.append(' ').append(avp.getKey()).append("=\"") 98 .append(avp.getValue()).append('"'); 99 } 100 } 101 sb.append(">\n"); 102 103 sb.append('<').append(MOTree.NodeNameTag).append('>'); 104 sb.append(getName()); 105 sb.append("</").append(MOTree.NodeNameTag).append(">\n"); 106 107 fillPayload(sb); 108 109 sb.append("</").append(MOTree.NodeTag).append(">\n"); 110 } 111 112 @Override 113 public String toString() { 114 StringBuilder sb = new StringBuilder(); 115 toString(sb, 0); 116 return sb.toString(); 117 } 118 119 public static OMAConstructed unmarshal(InputStream in) throws IOException { 120 OMANode node = buildNode(in, null); 121 if (node == null || node.isLeaf()) { 122 throw new IOException("Bad OMA tree"); 123 } 124 unmarshal(in, (OMAConstructed) node); 125 return (OMAConstructed) node; 126 } 127 128 private static void unmarshal(InputStream in, OMAConstructed parent) throws IOException { 129 for (; ; ) { 130 OMANode node = buildNode(in, parent); 131 if (node == null) { 132 return; 133 } else if (!node.isLeaf()) { 134 unmarshal(in, (OMAConstructed) node); 135 } 136 } 137 } 138 139 private static OMANode buildNode(InputStream in, OMAConstructed parent) throws IOException { 140 String name = OMAConstants.deserializeString(in); 141 if (name == null) { 142 return null; 143 } 144 145 String urn = null; 146 int next = in.read(); 147 if (next == '(') { 148 urn = OMAConstants.readURN(in); 149 next = in.read(); 150 } 151 152 if (next == '=') { 153 String value = OMAConstants.deserializeString(in); 154 return parent.addChild(name, urn, value, null); 155 } else if (next == '+') { 156 if (parent != null) { 157 return parent.addChild(name, urn, null, null); 158 } else { 159 return new OMAConstructed(null, name, urn); 160 } 161 } else { 162 throw new IOException("Parse error: expected = or + after node name"); 163 } 164 } 165 } 166