2 * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.yangtools.yang.data.codec.xml;
10 import static com.google.common.base.Preconditions.checkArgument;
12 import com.google.common.annotations.VisibleForTesting;
13 import com.google.common.collect.BiMap;
14 import com.google.common.collect.HashBiMap;
15 import java.util.Map.Entry;
16 import javax.xml.XMLConstants;
17 import javax.xml.namespace.NamespaceContext;
18 import org.opendaylight.yangtools.yang.common.XMLNamespace;
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;
26 private int counter = 0;
28 // BiMap to make values lookup faster
29 private final BiMap<XMLNamespace, String> prefixes = HashBiMap.create();
30 private final NamespaceContext context;
32 RandomPrefix(final NamespaceContext context) {
33 this.context = context;
36 Iterable<Entry<XMLNamespace, String>> getPrefixes() {
37 return prefixes.entrySet();
40 String encodePrefix(final XMLNamespace namespace) {
41 String prefix = prefixes.get(namespace);
46 if (context != null) {
47 prefix = context.getPrefix(namespace.toString());
54 prefix = encode(counter);
56 } while (alreadyUsedPrefix(prefix));
58 prefixes.put(namespace, prefix);
62 private boolean alreadyUsedPrefix(final String prefix) {
63 if (context == null) {
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);
74 static int decode(final String str) {
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;
86 static String encode(int num) {
87 final StringBuilder sb = new StringBuilder();
90 sb.append(LOOKUP.charAt(num & MASK));
94 return sb.reverse().toString();