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.impl.codec.xml;
10 import com.google.common.annotations.VisibleForTesting;
11 import com.google.common.base.Strings;
12 import com.google.common.collect.BiMap;
13 import com.google.common.collect.HashBiMap;
16 import org.opendaylight.yangtools.yang.common.QName;
18 final class RandomPrefix {
20 public static final char STARTING_CHAR = 'a';
21 public static final int CHARACTER_RANGE = 26;
22 public static final int PREFIX_MAX_LENGTH = 4;
24 public static final int MAX_COUNTER_VALUE = (int) Math.pow(CHARACTER_RANGE, PREFIX_MAX_LENGTH);
25 private static final int STARTING_WITH_XML = decode("xml");
27 private int counter = 0;
29 // BiMap to make values lookup faster
30 private final BiMap<URI, String> prefixes = HashBiMap.create();
32 Iterable<Map.Entry<URI, String>> getPrefixes() {
33 return prefixes.entrySet();
36 String encodeQName(final QName qname) {
37 return encodePrefix(qname) + ':' + qname.getLocalName();
40 String encodePrefix(final QName qname) {
41 String prefix = prefixes.get(qname.getNamespace());
46 // Reuse prefix from QName if possible
47 final String qNamePrefix = qname.getPrefix();
49 if (!Strings.isNullOrEmpty(qNamePrefix) && !qNamePrefix.startsWith("xml") && !alreadyUsedPrefix(qNamePrefix)) {
54 // Skip values starting with xml (Expecting only 4 chars max since division is calculated only once)
55 while (counter == STARTING_WITH_XML
56 || counter / CHARACTER_RANGE == STARTING_WITH_XML) {
60 // Reset in case of max prefix generated
61 if (counter >= MAX_COUNTER_VALUE) {
66 prefix = encode(counter);
68 } while (alreadyUsedPrefix(prefix));
71 prefixes.put(qname.getNamespace(), prefix);
75 private boolean alreadyUsedPrefix(final String prefix) {
76 return prefixes.values().contains(prefix);
80 static int decode(final String s) {
82 for (final char ch : s.toCharArray()) {
83 num *= CHARACTER_RANGE;
84 num += (ch - STARTING_CHAR);
90 static String encode(int num) {
95 final StringBuilder sb = new StringBuilder();
97 sb.append(((char) (num % CHARACTER_RANGE + STARTING_CHAR)));
98 num /= CHARACTER_RANGE;
101 return sb.reverse().toString();