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