package net.sf.saxon.om;
import net.sf.saxon.style.StandardNames;
import net.sf.saxon.trans.DynamicError;
import net.sf.saxon.type.TypeHierarchy;
import java.io.Serializable;
import java.util.HashMap;
import java.util.StringTokenizer;
/**
* An object representing a collection of XML names, each containing a Namespace URI,
* a Namespace prefix, and a local name; plus a collection of namespaces, each
* consisting of a prefix/URI pair. <br>
* <p/>
* <p>The equivalence betweem names depends only on the URI and the local name.
* The prefix is retained for documentary purposes only: it is useful when
* reconstructing a document to use prefixes that the user is familiar with.</p>
* <p/>
* <p>The NamePool eliminates duplicate names if they have the same prefix, uri,
* and local part. It retains duplicates if they have different prefixes</p>
*
* @author Michael H. Kay
*/
public class NamePool implements Serializable {
// The NamePool holds two kinds of entry: name entries, representing
// expanded names (local name + prefix + URI), identified by a name code,
// and namespace entries (prefix + URI) identified by a namespace code.
//
// The data structure of the name table is as follows.
//
// There is a fixed size hash table; names are allocated to slots in this
// table by hashing on the local name. Each entry in the table is the head of
// a chain of NameEntry objects representing names that have the same hash code.
//
// Each NameEntry represents a distinct name (same URI and local name). It contains
// The local name as a string, plus a short integer representing the URI (as an
// offset into the array uris[]).
//
// The fingerprint of a name consists of the hash slot number (in the bottom 10 bits)
// concatenated with the depth of the entry down the chain of hash synonyms (in the
// next 10 bits). Fingerprints with depth 0 (i.e., in the range 0-1023) are reserved
// for predefined names (names of XSLT elements and attributes, and of built-in types).
// These names are not stored in the name pool, but are accessible as if they were.
//
// A nameCode contains the fingerprint in the bottom 20 bits. It also contains
// an 8-bit prefix index. This distinguishes the prefix used, among all the
// prefixes that have been used with this namespace URI. If the prefix index is
// zero, the prefix is null. Otherwise, it indexes an space-separated list of
// prefix Strings associated with the namespace URI.
/**
* FP_MASK is a mask used to obtain a fingerprint from a nameCode. Given a
* nameCode nc, the fingerprint is <code>nc & NamePool.FP_MASK</code>.
* (In practice, Saxon code often uses the literal constant 0xfffff.)
* The difference between a nameCode is that a nameCode contains information
* about the prefix of a name, the fingerprint depends only on the namespace
* URI and local name. Note that the "null" nameCode (-1) does not produce
* the "null" fingerprint (also -1) when this mask is applied.
*/
public static final int FP_MASK = 0xfffff;
// The default singular instance, used unless the user deliberately wants to
// manage name pools himself
private static NamePool defaultNamePool = new NamePool();
/**
* Get the singular default NamePool
*/
public static NamePool getDefaultNamePool() {
return defaultNamePool;
}
/**
* Set the default NamePool
* (used after loading a compiled stylesheet)
*/
public static void setDefaultNamePool(NamePool pool) {
defaultNamePool = pool;
}
private static class NameEntry implements Serializable {
String localName;
short uriCode;
NameEntry nextEntry; // next NameEntry with the same hashcode
public NameEntry(short uriCode, String localName) {
this.uriCode = uriCode;
this.localName = localName.intern();
this.nextEntry = null;
}
}
NameEntry[] hashslots = new NameEntry[1024];
String[] prefixes = new String[100];
short prefixesUsed = 0;
String[] uris = new String[100];
String[] prefixesForUri = new String[100];
short urisUsed = 0;
// General purpose cache for data held by clients of the namePool
private HashMap clientData;
private transient TypeHierarchy typeHierarchy;
public NamePool() {
prefixes[NamespaceConstant.NULL_CODE] = "";
uris[NamespaceConstant.NULL_CODE] = NamespaceConstant.NULL;
prefixesForUri[NamespaceConstant.NULL_CODE] = "";
prefixes[NamespaceConstant.XML_CODE] = "xml";
uris[NamespaceConstant.XML_CODE] = NamespaceConstant.XML;
prefixesForUri[NamespaceConstant.XML_CODE] = "xml ";
prefixes[NamespaceConstant.XSLT_CODE] = "xsl";
uris[NamespaceConstant.XSLT_CODE] = NamespaceConstant.XSLT;
prefixesForUri[NamespaceConstant.XSLT_CODE] = "xsl ";
prefixes[NamespaceConstant.SAXON_CODE] = "saxon";
uris[NamespaceConstant.SAXON_CODE] = NamespaceConstant.SAXON;
prefixesForUri[NamespaceConstant.SAXON_CODE] = "saxon ";
prefixes[NamespaceConstant.SCHEMA_CODE] = "xs";
uris[NamespaceConstant.SCHEMA_CODE] = NamespaceConstant.SCHEMA;
prefixesForUri[NamespaceConstant.SCHEMA_CODE] = "xs ";
prefixes[NamespaceConstant.XDT_CODE] = "xdt";
uris[NamespaceConstant.XDT_CODE] = NamespaceConstant.XDT;
prefixesForUri[NamespaceConstant.XDT_CODE] = "xdt ";
prefixes[NamespaceConstant.XSI_CODE] = "xsi";
uris[NamespaceConstant.XSI_CODE] = NamespaceConstant.SCHEMA_INSTANCE;
prefixesForUri[NamespaceConstant.XSI_CODE] = "xsi ";
prefixesUsed = 7;
urisUsed = 7;
}
/**
* Get the TypeHierarchy
*/
public final TypeHierarchy getTypeHierarchy() {
if (typeHierarchy == null) {
typeHierarchy = new TypeHierarchy();
}
return typeHierarchy;
}
/**
* Get a name entry corresponding to a given name code
*
* @return null if there is none.
*/
private NameEntry getNameEntry(int nameCode) {
int hash = nameCode & 0x3ff;
int depth = (nameCode >> 10) & 0x3ff;
NameEntry entry = hashslots[hash];
for (int i = 1; i < depth; i++) {
if (entry == null) {
return null;
}
entry = entry.nextEntry;
}
return entry;
}
/**
* Allocate the namespace code for a namespace prefix/URI pair.
* Create it if not already present
*
* @param prefix the namespace prefix
* @param uri the namespace URI
* @return an integer code identifying the namespace. The namespace code
* identifies both the prefix and the URI.
*/
public /**/synchronized/**/ int allocateNamespaceCode(String prefix, String uri) {
// System.err.println("allocate nscode for " + prefix + " = " + uri);
int prefixCode = allocateCodeForPrefix(prefix);
int uriCode = allocateCodeForURI(uri);
if (prefixCode != 0) {
// ensure the prefix is in the list of prefixes used with this URI
String key = prefix + ' ';
if (prefixesForUri[uriCode].indexOf(key) < 0) {
prefixesForUri[uriCode] += key;
}
}
return (prefixCode << 16) + uriCode;
}
/**
* Get the existing namespace code for a namespace prefix/URI pair.
*
* @return -1 if there is none present
*/
public int getNamespaceCode(String prefix, String uri) {
//System.err.println("get nscode for " + prefix + " = " + uri);
int prefixCode = getCodeForPrefix(prefix);
if (prefixCode < 0) {
return -1;
}
int uriCode = getCodeForURI(uri);
if (uriCode < 0) {
return -1;
}
if (prefixCode != 0) {
// ensure the prefix is in the list of prefixes used with this URI
String key = prefix + ' ';
if (prefixesForUri[uriCode].indexOf(key) < 0) {
return -1;
}
}
return (prefixCode << 16) + uriCode;
}
/**
* Allocate a namespace code for a given namecode
*
* @param namecode a code identifying an expanded QName, e.g. of an element or attribute
* @return a code identifying the namespace used in the given name. The namespace code
* identifies both the prefix and the URI. Return -1 if no namespace code has been allocated
* (in this case the caller should call allocateNamespaceCode() to get one).
*/
public int getNamespaceCode(int namecode) {
short uriCode;
int fp = namecode & 0xfffff;
if ((fp & 0xffc00) == 0) {
uriCode = StandardNames.getURICode(fp);
} else {
NameEntry entry = getNameEntry(namecode);
if (entry == null) {
return -1;
} else {
uriCode = entry.uriCode;
}
}
int prefixIndex = (namecode >> 20) & 0xff;
String prefix = getPrefixWithIndex(uriCode, prefixIndex);
if (prefix == null) {
return -1;
}
int prefixCode = getCodeForPrefix(prefix);
if (prefixCode == -1) {
return -1;
}
return (prefixCode << 16) + uriCode;
}
/**
* Allocate the uri code for a given URI;
* create one if not found
*/
public /**/synchronized/**/ short allocateCodeForURI(String uri) {
//System.err.println("allocate code for URI " + uri);
for (short j = 0; j < urisUsed; j++) {
if (uris[j].equals(uri)) {
return j;
}
}
if (urisUsed >= uris.length) {
if (urisUsed > 32000) {
throw new NamePoolLimitException("Too many namespace URIs");
}
String[] p = new String[urisUsed * 2];
String[] u = new String[urisUsed * 2];
System.arraycopy(prefixesForUri, 0, p, 0, urisUsed);
System.arraycopy(uris, 0, u, 0, urisUsed);
prefixesForUri = p;
uris = u;
}
uris[urisUsed] = uri;
prefixesForUri[urisUsed] = "";
return urisUsed++;
}
/**
* Get the uri code for a given URI
*
* @return -1 if not present in the name pool
*/
public short getCodeForURI(String uri) {
for (short j = 0; j < urisUsed; j++) {
if (uris[j].equals(uri)) {
return j;
}
}
return -1;
}
/**
* Allocate the prefix code for a given Prefix; create one if not found
*
* @param prefix the namespace prefix whose code is to be allocated or returned
* @return the numeric code for this prefix
*/
private short allocateCodeForPrefix(String prefix) {
// Not synchronized, because it's always called from a synchronized method
// exploit knowledge of the standard prefixes to shorten the search
short start = 1;
if (prefix.equals("")) {
return NamespaceConstant.NULL_CODE;
}
if (prefix.charAt(0) != 'x') {
if (prefix.equals("saxon")) {
return NamespaceConstant.SAXON_CODE;
}
start = NamespaceConstant.XSI_CODE + 1;
}
for (short i=start; i < prefixesUsed; i++) {
if (prefixes[i].equals(prefix)) {
return i;
}
}
if (prefixesUsed >= prefixes.length) {
if (prefixesUsed > 32000) {
throw new NamePoolLimitException("Too many namespace prefixes");
}
String[] p = new String[prefixesUsed * 2];
System.arraycopy(prefixes, 0, p, 0, prefixesUsed);
prefixes = p;
}
prefixes[prefixesUsed] = prefix;
return prefixesUsed++;
}
/**
* Get the prefix code for a given Prefix
*
* @return -1 if not found
*/
public short getCodeForPrefix(String prefix) {
for (short i = 0; i < prefixesUsed; i++) {
if (prefixes[i].equals(prefix)) {
return i;
}
}
return -1;
}
/**
* Suggest a prefix for a given URI. If there are several, it's undefined which one is returned.
* If there are no prefixes registered for this URI, return null.
*/
public String suggestPrefixForURI(String URI) {
short uriCode = getCodeForURI(URI);
if (uriCode == -1) {
return null;
}
StringTokenizer tok = new StringTokenizer(prefixesForUri[uriCode]);
if (tok.hasMoreElements()) {
return (String)tok.nextElement();
}
return null;
}
/**
* Get the index of a prefix among all the prefixes used with a given URI
*
* @return -1 if not found
*/
private int getPrefixIndex(short uriCode, String prefix) {
// look for quick wins
if (prefix.equals("")) {
return 0;
}
if (prefixesForUri[uriCode].equals(prefix + ' ')) {
return 1;
}
// search for the prefix in the list
int i = 1;
StringTokenizer tok = new StringTokenizer(prefixesForUri[uriCode]);
while (tok.hasMoreElements()) {
if (prefix.equals(tok.nextElement())) {
return i;
}
if (i++ == 255) {
throw new NamePoolLimitException("Too many prefixes for one namespace URI");
}
}
return -1;
}
/**
* Get a prefix among all the prefixes used with a given URI, given its index
*
* @return null if not found
*/
public String getPrefixWithIndex(short uriCode, int index) {
if (index == 0) {
return "";
}
StringTokenizer tok = new StringTokenizer(prefixesForUri[uriCode]);
int i = 1;
while (tok.hasMoreElements()) {
String prefix = (String)tok.nextElement();
if (i++ == index) {
return prefix;
}
}
return null;
}
/**
* Allocate a name from the pool, or a new Name if there is not a matching one there
*
* @param prefix
* @param uri - the namespace URI. The null URI is represented as an empty string.
* @param localName
* @return an integer (the "namecode") identifying the name within the namepool.
* The Name itself may be retrieved using the getName(int) method
*/
public synchronized int allocate(String prefix, String uri, String localName) {
if (NamespaceConstant.isReserved(uri) || uri.equals(NamespaceConstant.SAXON)) {
int fp = StandardNames.getFingerprint(uri, localName);
if (fp != -1) {
short uriCode = StandardNames.getURICode(fp);
int prefixIndex = getPrefixIndex(uriCode, prefix);
if (prefixIndex < 0) {
prefixesForUri[uriCode] += (prefix + ' ');
prefixIndex = getPrefixIndex(uriCode, prefix);
}
return (prefixIndex << 20) + fp;
}
}
// otherwise register the name in this NamePool
short uriCode = allocateCodeForURI(uri);
return allocateInternal(prefix, uriCode, localName);
}
/**
* Allocate a name from the pool, or a new Name if there is not a matching one there
*
* @param prefix - the namespace prefix
* @param uriCode - the code of the URI
* @param localName - the local part of the QName
* @return an integer (the "namecode") identifying the name within the namepool.
*/
public synchronized int allocate(String prefix, short uriCode, String localName) {
// System.err.println("Allocate " + prefix + " : " + uriCode + " : " + localName);
if (NamespaceConstant.isSpecialURICode(uriCode)) {
return allocate(prefix, getURIFromURICode(uriCode), localName);
} else {
return allocateInternal(prefix, uriCode, localName);
}
}
private int allocateInternal(String prefix, short uriCode, String localName) {
int hash = (localName.hashCode() & 0x7fffffff) % 1023;
int depth = 1;
int prefixIndex = getPrefixIndex(uriCode, prefix);
if (prefixIndex < 0) {
prefixesForUri[uriCode] += (prefix + ' ');
prefixIndex = getPrefixIndex(uriCode, prefix);
}
NameEntry entry;
if (hashslots[hash] == null) {
entry = new NameEntry(uriCode, localName);
hashslots[hash] = entry;
} else {
entry = hashslots[hash];
while (true) {
boolean sameLocalName = (entry.localName.equals(localName));
boolean sameURI = (entry.uriCode == uriCode);
if (sameLocalName && sameURI) {
// may need to add a new prefix to the entry
break;
} else {
NameEntry next = entry.nextEntry;
depth++;
if (depth >= 1024) {
throw new NamePoolLimitException("Saxon name pool is full");
}
if (next == null) {
NameEntry newentry = new NameEntry(uriCode, localName);
entry.nextEntry = newentry;
break;
} else {
entry = next;
}
}
}
}
// System.err.println("name code = " + prefixIndex + "/" + depth + "/" + hash);
return ((prefixIndex << 20) + (depth << 10) + hash);
}
/**
* Allocate a namespace code for the prefix/URI of a given namecode
*
* @param namecode a code identifying an expanded QName, e.g. of an element or attribute
* @return a code identifying the namespace used in the given name. The namespace code
* identifies both the prefix and the URI.
*/
public /**/synchronized/**/ int allocateNamespaceCode(int namecode) {
short uriCode;
int fp = namecode & 0xfffff;
if ((fp & 0xffc00) == 0) {
uriCode = StandardNames.getURICode(fp);
} else {
NameEntry entry = getNameEntry(namecode);
if (entry == null) {
unknownNameCode(namecode);
return -1; // to keep the compiler happy
} else {
uriCode = entry.uriCode;
}
}
int prefixIndex = (namecode >> 20) & 0xff;
String prefix = getPrefixWithIndex(uriCode, prefixIndex);
int prefixCode = allocateCodeForPrefix(prefix);
return (prefixCode << 16) + uriCode;
}
/**
* Get the namespace-URI of a name, given its name code or fingerprint
*/
public String getURI(int nameCode) {
if ((nameCode & 0xffc00) == 0) {
return StandardNames.getURI(nameCode & 0xfffff);
}
NameEntry entry = getNameEntry(nameCode);
if (entry == null) {
unknownNameCode(nameCode);
return null; // to keep the compiler happy
}
return uris[entry.uriCode];
}
/**
* Get the URI code of a name, given its name code or fingerprint
*/
public short getURICode(int nameCode) {
if ((nameCode & 0xffc00) == 0) {
return StandardNames.getURICode(nameCode & 0xfffff);
}
NameEntry entry = getNameEntry(nameCode);
if (entry == null) {
unknownNameCode(nameCode);
return -1;
}
return entry.uriCode;
}
/**
* Get the local part of a name, given its name code or fingerprint
*/
public String getLocalName(int nameCode) {
if ((nameCode & 0xffc00) == 0) {
return StandardNames.getLocalName(nameCode & 0xfffff);
}
NameEntry entry = getNameEntry(nameCode);
if (entry == null) {
unknownNameCode(nameCode);
return null;
}
return entry.localName;
}
/**
* Get the prefix part of a name, given its name code or fingerprint
*/
public String getPrefix(int nameCode) {
if ((nameCode & 0xffc00) == 0) {
return StandardNames.getPrefix(nameCode & 0xfffff);
}
short uriCode = getURICode(nameCode);
int prefixIndex = (nameCode >> 20) & 0xff;
return getPrefixWithIndex(uriCode, prefixIndex);
}
/**
* Get the display form of a name (the QName), given its name code or fingerprint
*/
public String getDisplayName(int nameCode) {
if ((nameCode & 0xffc00) == 0) {
// This indicates a standard name known to the system (but it might have a non-standard prefix)
int prefixIndex = (nameCode >> 20) & 0xff;
short uriCode = getURICode(nameCode);
String prefix = getPrefixWithIndex(uriCode, prefixIndex);
if (prefix.equals("")) {
return StandardNames.getLocalName(nameCode & 0xfffff);
} else {
return prefix + ':' + StandardNames.getLocalName(nameCode & 0xfffff);
}
}
NameEntry entry = getNameEntry(nameCode);
if (entry == null) {
unknownNameCode(nameCode);
return null;
}
int prefixIndex = (nameCode >> 20) & 0xff;
String prefix = getPrefixWithIndex(entry.uriCode, prefixIndex);
if (prefix == null || prefix.equals("")) {
return entry.localName;
} else {
return prefix + ':' + entry.localName;
}
}
/**
* Get the Clark form of a name, given its name code or fingerprint
*
* @return the local name if the name is in the null namespace, or "{uri}local"
* otherwise. The name is always interned.
*/
public String getClarkName(int nameCode) {
if ((nameCode & 0xffc00) == 0) {
return StandardNames.getClarkName(nameCode & 0xfffff);
}
NameEntry entry = getNameEntry(nameCode);
if (entry == null) {
unknownNameCode(nameCode);
return null;
}
if (entry.uriCode == 0) {
return entry.localName;
} else {
String n =
'{' + getURIFromURICode(entry.uriCode) + '}' + entry.localName;
return n.intern();
}
}
/**
* Allocate a fingerprint given a Clark Name
*/
public int allocateClarkName(String expandedName) {
String namespace;
String localName;
if (expandedName.charAt(0) == '{') {
int closeBrace = expandedName.indexOf('}');
if (closeBrace < 0) {
throw new IllegalArgumentException("No closing '}' in Clark name");
}
namespace = expandedName.substring(1, closeBrace);
if (closeBrace == expandedName.length()) {
throw new IllegalArgumentException("Missing local part in Clark name");
}
localName = expandedName.substring(closeBrace + 1);
} else {
namespace = "";
localName = expandedName;
}
return allocate("", namespace, localName);
}
/**
* Parse a Clark-format expanded name, returning the URI and local name
*/
public static String[] parseClarkName(String expandedName) {
String namespace;
String localName;
if (expandedName.charAt(0) == '{') {
int closeBrace = expandedName.indexOf('}');
if (closeBrace < 0) {
throw new IllegalArgumentException("No closing '}' in Clark name");
}
namespace = expandedName.substring(1, closeBrace);
if (closeBrace == expandedName.length()) {
throw new IllegalArgumentException("Missing local part in Clark name");
}
localName = expandedName.substring(closeBrace + 1);
} else {
namespace = "";
localName = expandedName;
}
String[] result = {namespace, localName};
return result;
}
/**
* Internal error: name not found in namepool
* (Usual cause is allocating a name code from one name pool and trying to
* find it in another)
*/
private void unknownNameCode(int nameCode) {
//System.err.println("Unknown name code " + nameCode);
//diagnosticDump();
//(new IllegalArgumentException("Unknown name")).printStackTrace();
throw new IllegalArgumentException("Unknown name code " + nameCode);
}
/**
* Get a fingerprint for the name with a given uri and local name.
* These must be present in the NamePool.
* The fingerprint has the property that if two fingerprint are the same, the names
* are the same (ie. same local name and same URI).
*
* @return -1 if not found
*/
public int getFingerprint(String uri, String localName) {
// A read-only version of allocate()
short uriCode;
if (uri.equals("")) {
uriCode = 0;
} else {
if (NamespaceConstant.isReserved(uri) || uri.equals(NamespaceConstant.SAXON)) {
int fp = StandardNames.getFingerprint(uri, localName);
if (fp != -1) {
return fp;
// otherwise, look for the name in this namepool
}
}
uriCode = -1;
for (short j = 0; j < urisUsed; j++) {
if (uris[j].equals(uri)) {
uriCode = j;
break;
}
}
if (uriCode == -1) {
return -1;
}
}
int hash = (localName.hashCode() & 0x7fffffff) % 1023;
int depth = 1;
NameEntry entry;
if (hashslots[hash] == null) {
return -1;
}
entry = hashslots[hash];
while (true) {
if (entry.uriCode == uriCode && entry.localName.equals(localName)) {
break;
} else {
NameEntry next = entry.nextEntry;
depth++;
if (next == null) {
return -1;
} else {
entry = next;
}
}
}
return (depth << 10) + hash;
}
/**
* Get the namespace URI from a namespace code.
*/
public String getURIFromNamespaceCode(int code) {
return uris[code & 0xffff];
}
/**
* Get the namespace URI from a URI code.
*/
public String getURIFromURICode(short code) {
return uris[code];
}
/**
* Get the namespace prefix from a namespace code.
*/
public String getPrefixFromNamespaceCode(int code) {
// System.err.println("get prefix for " + code);
return prefixes[code >> 16];
}
/**
* Get the nameCode for a lexical QName, given a namespace resolver.
* @param qname the lexical QName.
* @param useDefault if true, an absent prefix is resolved by the NamespaceResolver
* to the namespace URI assigned to the prefix "". If false, an absent prefix is
* interpreted as meaning the name is in no namespace.
* @param checker NameChecker used to check names against the XML 1.0 or 1.1 specification
* @return the corresponding nameCode
* @throws net.sf.saxon.trans.DynamicError if the string is not a valid lexical QName or
* if the namespace prefix has not been declared*
*/
public int allocateLexicalQName(CharSequence qname, boolean useDefault,
NamespaceResolver resolver, NameChecker checker)
throws DynamicError {
try {
String[] parts = checker.getQNameParts(qname);
String uri = resolver.getURIForPrefix(parts[0], useDefault);
if (uri == null) {
throw new DynamicError("Namespace prefix '" + parts[0] + "' has not been declared");
}
return allocate(parts[0], uri, parts[1]);
} catch (QNameException e) {
throw new DynamicError(e.getMessage());
}
}
/**
* Get fingerprint for expanded name in {uri}local format
*/
public int getFingerprintForExpandedName(String expandedName) {
String localName;
String namespace;
if (expandedName.charAt(0) == '{') {
int closeBrace = expandedName.indexOf('}');
if (closeBrace < 0) {
throw new IllegalArgumentException("No closing '}' in parameter name");
}
namespace = expandedName.substring(1, closeBrace);
if (closeBrace == expandedName.length()) {
throw new IllegalArgumentException("Missing local part in parameter name");
}
localName = expandedName.substring(closeBrace + 1);
} else {
namespace = "";
localName = expandedName;
}
return allocate("", namespace, localName);
}
/**
* Save client data on behalf of a user of the namepool
*/
public void setClientData(Class key, Object value) {
if (clientData == null) {
clientData = new HashMap(10);
}
clientData.put(key, value);
}
/**
* Retrieve client data on behalf of a user of the namepool
*/
public Object getClientData(Class key) {
if (clientData == null) {
return null;
}
return clientData.get(key);
}
/**
* Diagnostic print of the namepool contents.
*/
public synchronized void diagnosticDump() {
System.err.println("Contents of NamePool " + this);
for (int i = 0; i < 1024; i++) {
NameEntry entry = hashslots[i];
int depth = 0;
while (entry != null) {
System.err.println("Fingerprint " + depth + '/' + i);
System.err.println(" local name = " + entry.localName +
" uri code = " + entry.uriCode);
entry = entry.nextEntry;
depth++;
}
}
for (int p = 0; p < prefixesUsed; p++) {
System.err.println("Prefix " + p + " = " + prefixes[p]);
}
for (int u = 0; u < urisUsed; u++) {
System.err.println("URI " + u + " = " + uris[u]);
System.err.println("Prefixes for URI " + u + " = " + prefixesForUri[u]);
}
}
/**
* Statistics summarizing the namepool contents.
* This method outputs summary statistical information to System.err
*/
public synchronized void statistics() {
int slots = 0;
int entries = 0;
for (int i = 0; i < 1024; i++) {
NameEntry entry = hashslots[i];
if (entry != null) slots++;
while (entry != null) {
entry = entry.nextEntry;
entries++;
}
}
System.err.println("NamePool contents: " + entries + " entries in " + slots + " chains. " +
+ prefixesUsed + " prefixes, " + urisUsed + " URIs");
}
public static class NamePoolLimitException extends RuntimeException {
public NamePoolLimitException(String message) {
super(message);
}
}
}
//
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
// you may not use this file except in compliance with the License. You may obtain a copy of the
// License at http://www.mozilla.org/MPL/
//
// Software distributed under the License is distributed on an "AS IS" basis,
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
// See the License for the specific language governing rights and limitations under the License.
//
// The Original Code is: all this file.
//
// The Initial Developer of the Original Code is Michael H. Kay.
//
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
//
// Contributor(s): none.
//
|