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