Cleanup use of Guava library
[yangtools.git] / yang / yang-data-codec-xml / src / main / java / org / opendaylight / yangtools / yang / data / codec / xml / RandomPrefix.java
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.yangtools.yang.data.codec.xml;
9
10 import static com.google.common.base.Preconditions.checkArgument;
11
12 import com.google.common.annotations.VisibleForTesting;
13 import com.google.common.collect.BiMap;
14 import com.google.common.collect.HashBiMap;
15 import java.net.URI;
16 import java.util.Map.Entry;
17 import javax.xml.XMLConstants;
18 import javax.xml.namespace.NamespaceContext;
19
20 class RandomPrefix {
21     // 32 characters, carefully chosen
22     private static final String LOOKUP = "abcdefghiknoprstABCDEFGHIKNOPRST";
23     private static final int MASK = 0x1f;
24     private static final int SHIFT = 5;
25
26     private int counter = 0;
27
28     // BiMap to make values lookup faster
29     private final BiMap<URI, String> prefixes = HashBiMap.create();
30     private final NamespaceContext context;
31
32     RandomPrefix(final NamespaceContext context) {
33         this.context = context;
34     }
35
36     Iterable<Entry<URI, String>> getPrefixes() {
37         return prefixes.entrySet();
38     }
39
40     String encodePrefix(final URI namespace) {
41         String prefix = prefixes.get(namespace);
42         if (prefix != null) {
43             return prefix;
44         }
45
46         if (context != null) {
47             prefix = context.getPrefix(namespace.toString());
48             if (prefix != null) {
49                 return prefix;
50             }
51         }
52
53         do {
54             prefix = encode(counter);
55             counter++;
56         } while (alreadyUsedPrefix(prefix));
57
58         prefixes.put(namespace, prefix);
59         return prefix;
60     }
61
62     private boolean alreadyUsedPrefix(final String prefix) {
63         if (context == null) {
64             return false;
65         }
66
67         // It seems JDK8 is violating the API contract of NamespaceContext by returning null for unbound prefixes,
68         // rather than specified NULL_NS_URI. Work this around by checking explicitly for null.
69         final String str = context.getNamespaceURI(prefix);
70         return str != null && !XMLConstants.NULL_NS_URI.equals(str);
71     }
72
73     @VisibleForTesting
74     static int decode(final String str) {
75         int ret = 0;
76         for (char c : str.toCharArray()) {
77             int idx = LOOKUP.indexOf(c);
78             checkArgument(idx != -1, "Invalid string %s", str);
79             ret = (ret << SHIFT) + idx;
80         }
81
82         return ret;
83     }
84
85     @VisibleForTesting
86     static String encode(int num) {
87         final StringBuilder sb = new StringBuilder();
88
89         do {
90             sb.append(LOOKUP.charAt(num & MASK));
91             num >>>= SHIFT;
92         } while (num != 0);
93
94         return sb.reverse().toString();
95     }
96 }