1 package com.android.hotspot2.omadm; 2 3 import java.io.IOException; 4 import java.io.OutputStream; 5 import java.nio.charset.StandardCharsets; 6 import java.util.Collection; 7 import java.util.Collections; 8 import java.util.Iterator; 9 import java.util.Map; 10 11 public class OMAConstructed extends OMANode { 12 private final MultiValueMap<OMANode> mChildren; 13 14 public OMAConstructed(OMAConstructed parent, String name, String context, String... avps) { 15 this(parent, name, context, new MultiValueMap<OMANode>(), buildAttributes(avps)); 16 } 17 18 protected OMAConstructed(OMAConstructed parent, String name, String context, 19 MultiValueMap<OMANode> children, Map<String, String> avps) { 20 super(parent, name, context, avps); 21 mChildren = children; 22 } 23 24 @Override 25 public OMANode addChild(String name, String context, String value, String pathString) 26 throws IOException { 27 if (pathString == null) { 28 OMANode child = value != null ? 29 new OMAScalar(this, name, context, value) : 30 new OMAConstructed(this, name, context); 31 mChildren.put(name, child); 32 return child; 33 } else { 34 OMANode target = this; 35 while (target.getParent() != null) 36 target = target.getParent(); 37 38 for (String element : pathString.split("/")) { 39 target = target.getChild(element); 40 if (target == null) 41 throw new IOException("No child node '" + element + "' in " + getPathString()); 42 else if (target.isLeaf()) 43 throw new IOException("Cannot add child to leaf node: " + getPathString()); 44 } 45 return target.addChild(name, context, value, null); 46 } 47 } 48 49 @Override 50 public OMAConstructed reparent(OMAConstructed parent) { 51 return new OMAConstructed(parent, getName(), getContext(), mChildren, getAttributes()); 52 } 53 54 public void addChild(OMANode child) { 55 mChildren.put(child.getName(), child.reparent(this)); 56 } 57 58 public String getScalarValue(Iterator<String> path) throws OMAException { 59 if (!path.hasNext()) { 60 throw new OMAException("Path too short for " + getPathString()); 61 } 62 String tag = path.next(); 63 OMANode child = mChildren.get(tag); 64 if (child != null) { 65 return child.getScalarValue(path); 66 } else { 67 return null; 68 } 69 } 70 71 @Override 72 public OMANode getListValue(Iterator<String> path) throws OMAException { 73 if (!path.hasNext()) { 74 return null; 75 } 76 String tag = path.next(); 77 OMANode child; 78 if (tag.equals("?")) { 79 child = mChildren.getSingletonValue(); 80 } else { 81 child = mChildren.get(tag); 82 } 83 84 if (child == null) { 85 return null; 86 } else if (path.hasNext()) { 87 return child.getListValue(path); 88 } else { 89 return child; 90 } 91 } 92 93 @Override 94 public boolean isLeaf() { 95 return false; 96 } 97 98 @Override 99 public Collection<OMANode> getChildren() { 100 return Collections.unmodifiableCollection(mChildren.values()); 101 } 102 103 public OMANode getChild(String name) { 104 return mChildren.get(name); 105 } 106 107 public OMANode replaceNode(OMANode oldNode, OMANode newNode) { 108 return mChildren.replace(oldNode.getName(), oldNode, newNode); 109 } 110 111 public OMANode removeNode(String key, OMANode node) { 112 if (key.equals("?")) { 113 return mChildren.remove(node); 114 } else { 115 return mChildren.remove(key, node); 116 } 117 } 118 119 @Override 120 public String getValue() { 121 throw new UnsupportedOperationException(); 122 } 123 124 @Override 125 public void toString(StringBuilder sb, int level) { 126 sb.append(getPathString()); 127 if (getContext() != null) { 128 sb.append(" (").append(getContext()).append(')'); 129 } 130 sb.append('\n'); 131 132 for (OMANode node : mChildren.values()) { 133 node.toString(sb, level + 1); 134 } 135 } 136 137 @Override 138 public void marshal(OutputStream out, int level) throws IOException { 139 OMAConstants.indent(level, out); 140 OMAConstants.serializeString(getName(), out); 141 if (getContext() != null) { 142 out.write(String.format("(%s)", getContext()).getBytes(StandardCharsets.UTF_8)); 143 } 144 out.write(new byte[]{'+', '\n'}); 145 146 for (OMANode child : mChildren.values()) { 147 child.marshal(out, level + 1); 148 } 149 OMAConstants.indent(level, out); 150 out.write(".\n".getBytes(StandardCharsets.UTF_8)); 151 } 152 153 @Override 154 public void fillPayload(StringBuilder sb) { 155 if (getContext() != null) { 156 sb.append('<').append(MOTree.RTPropTag).append(">\n"); 157 sb.append('<').append(MOTree.TypeTag).append(">\n"); 158 sb.append('<').append(MOTree.DDFNameTag).append(">"); 159 sb.append(getContext()); 160 sb.append("</").append(MOTree.DDFNameTag).append(">\n"); 161 sb.append("</").append(MOTree.TypeTag).append(">\n"); 162 sb.append("</").append(MOTree.RTPropTag).append(">\n"); 163 } 164 165 for (OMANode child : getChildren()) { 166 child.toXml(sb); 167 } 168 } 169 } 170