1ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistpackage com.android.hotspot2.pps;
2ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
3ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport com.android.hotspot2.Utils;
4ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
5ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.util.ArrayList;
6ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.util.Collections;
7ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.util.HashMap;
8ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.util.Iterator;
9ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.util.List;
10ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.util.Map;
11ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
12ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistpublic class DomainMatcher {
13ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
14ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public enum Match {None, Primary, Secondary}
15ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
16ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    private final Label mRoot;
17ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
18ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    private static class Label {
19ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        private final Map<String, Label> mSubDomains;
20ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        private final Match mMatch;
21ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
22ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        private Label(Match match) {
23ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            mMatch = match;
24ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            mSubDomains = match == Match.None ? new HashMap<String, Label>() : null;
25ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
26ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
27ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        private void addDomain(Iterator<String> labels, Match match) {
28ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            String labelName = labels.next();
29ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            if (labels.hasNext()) {
30ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                Label subLabel = new Label(Match.None);
31ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                mSubDomains.put(labelName, subLabel);
32ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                subLabel.addDomain(labels, match);
33ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            } else {
34ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                mSubDomains.put(labelName, new Label(match));
35ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            }
36ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
37ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
38ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        private Label getSubLabel(String labelString) {
39ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            return mSubDomains.get(labelString);
40ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
41ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
42ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        public Match getMatch() {
43ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            return mMatch;
44ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
45ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
46ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        private void toString(StringBuilder sb) {
47ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            if (mSubDomains != null) {
48ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                sb.append(".{");
49ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                for (Map.Entry<String, Label> entry : mSubDomains.entrySet()) {
50ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    sb.append(entry.getKey());
51ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    entry.getValue().toString(sb);
52ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                }
53ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                sb.append('}');
54ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            } else {
55ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                sb.append('=').append(mMatch);
56ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            }
57ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
58ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
59ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        @Override
60ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        public String toString() {
61ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            StringBuilder sb = new StringBuilder();
62ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            toString(sb);
63ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            return sb.toString();
64ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
65ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    }
66ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
67ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public DomainMatcher(List<String> primary, List<List<String>> secondary) {
68ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        mRoot = new Label(Match.None);
69ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        for (List<String> secondaryLabel : secondary) {
70ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            mRoot.addDomain(secondaryLabel.iterator(), Match.Secondary);
71ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
72ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        // Primary overwrites secondary.
73ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        mRoot.addDomain(primary.iterator(), Match.Primary);
74ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    }
75ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
76ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    /**
77ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist     * Check if domain is either a the same or a sub-domain of any of the domains in the domain tree
78ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist     * in this matcher, i.e. all or or a sub-set of the labels in domain matches a path in the tree.
79ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist     *
80ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist     * @param domain Domain to be checked.
81ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist     * @return None if domain is not a sub-domain, Primary if it matched one of the primary domains
82ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist     * or Secondary if it matched on of the secondary domains.
83ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist     */
84ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public Match isSubDomain(List<String> domain) {
85ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
86ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        Label label = mRoot;
87ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        for (String labelString : domain) {
88ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            label = label.getSubLabel(labelString);
89ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            if (label == null) {
90ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                return Match.None;
91ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            } else if (label.getMatch() != Match.None) {
92ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                return label.getMatch();
93ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            }
94ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
95ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        return Match.None;  // Domain is a super domain
96ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    }
97ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
98ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static boolean arg2SubdomainOfArg1(List<String> arg1, List<String> arg2) {
99ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        if (arg2.size() < arg1.size()) {
100ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            return false;
101ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
102ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
103ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        Iterator<String> l1 = arg1.iterator();
104ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        Iterator<String> l2 = arg2.iterator();
105ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
106ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        while (l1.hasNext()) {
107ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            if (!l1.next().equals(l2.next())) {
108ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                return false;
109ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            }
110ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
111ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        return true;
112ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    }
113ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
114ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    @Override
115ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public String toString() {
116ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        return "Domain matcher " + mRoot;
117ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    }
118ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
119ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    private static final String[] TestDomains = {
120ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            "garbage.apple.com",
121ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            "apple.com",
122ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            "com",
123ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            "jan.android.google.com.",
124ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            "jan.android.google.com",
125ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            "android.google.com",
126ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            "google.com",
127ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            "jan.android.google.net.",
128ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            "jan.android.google.net",
129ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            "android.google.net",
130ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            "google.net",
131ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            "net.",
132ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            "."
133ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    };
134ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
135ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public static void main(String[] args) {
136ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        DomainMatcher dm1 = new DomainMatcher(Utils.splitDomain("android.google.com"),
137ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                Collections.<List<String>>emptyList());
138ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        for (String domain : TestDomains) {
139ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            System.out.println(domain + ": " + dm1.isSubDomain(Utils.splitDomain(domain)));
140ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
141ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        List<List<String>> secondaries = new ArrayList<List<String>>();
142ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        secondaries.add(Utils.splitDomain("apple.com"));
143ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        secondaries.add(Utils.splitDomain("net"));
144ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        DomainMatcher dm2 = new DomainMatcher(Utils.splitDomain("android.google.com"), secondaries);
145ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        for (String domain : TestDomains) {
146ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            System.out.println(domain + ": " + dm2.isSubDomain(Utils.splitDomain(domain)));
147ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
148ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    }
149ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist}
150