[
Lists Home |
Date Index |
Thread Index
]
- From: David Megginson <david@megginson.com>
- To: XMLDev list <xml-dev@ic.ac.uk>
- Date: Wed, 15 Dec 1999 09:55:45 -0500 (EST)
I'm attaching a copy of the Java source code for the (short) NSUtils
class that I described in the last message. I'd be very grateful if
the Java specialists on the list could look this over, paying special
attention to synchronization problems.
// NSUtils.java - utilities for dealing with Namespaces
// Copyright (c) 1999 by Megginson Technologies Ltd.
// Free redistribution permitted.
// $Id: NSUtils.java,v 1.1 1999/12/15 14:44:06 david Exp $
package org.xml.sax.helpers;
import java.util.Hashtable;
/**
* Utilities for splitting and joining Namespace-qualified names.
*
* This class contains only static methods, and may not be instantiated.
* The methods in this class allow applications to split and
* rejoin Namespace-qualified names in the format {URI}localpart. The
* static methods use tables to cache the result of each split or
* join, so that applications can avoid repeating expensive Java
* String operations.
*
* @see org.xml.sax.DocumentHandler
* @see org.xml.sax.NamespaceHandler
*/
public final class NSUtils
{
////////////////////////////////////////////////////////////////////
// Private constructor to avoid instantiation.
////////////////////////////////////////////////////////////////////
private NSUtils ()
{
}
////////////////////////////////////////////////////////////////////
// Static tables.
////////////////////////////////////////////////////////////////////
// Table counter. Once this hits
// COUNTER_MAX, flush all of the tables
// and start over.
private static int counter = 0;
private static final int COUNTER_MAX = 1024;
// Singleton instance of this class.
private static NSUtils nsUtils;
// A reusable qname for searching.
private static QName qName;
// Internal hash tables for caching
// expensive string operations.
private static Hashtable splitNameTable;
private static Hashtable joinNameTable;
// Initialize the tables when the
// class is loaded.
static {
nsUtils = new NSUtils();
qName = nsUtils.makeQName(null, null);
resetTables();
}
////////////////////////////////////////////////////////////////////
// Public static utility methods.
////////////////////////////////////////////////////////////////////
/**
* Test whether a name is qualified with a Namespace URI.
*
* The name must appear in {URI}local format.
*
* @param name The name to test.
* @return true if the name has a URI part, false otherwise.
*/
public static boolean isQualified (String name)
{
return (name.charAt(0) == '{');
}
/**
* Split a name into its URI part and its local part.
*
* <p>Both the URI and local parts will be internalized. This
* function is extremely efficient: it uses a hash
* table to keep track of names it has already split, and
* won't do the same work twice. Since the same element and
* attribute names tend to appear over and over in an XML
* document, this method will not usually incur the
* overhead of Java String processing.</p>
*
* @param name The qualified name in {URI}local format.
* @return An array containing the URI part as the first
* member (or null if there is no URI part) and the
* local part as the second member.
* @see java.lang.String#intern
*/
public static String [] splitName (String name)
{
String parts[] = (String [])splitNameTable.get(name);
if (parts == null) {
parts = new String[2];
if (name.charAt(0) == '{') {
int endPos = name.indexOf('}');
if (endPos == -1) {
throw new
RuntimeException("Malformed Namespace name: " + name);
}
parts[0] = (name.substring(1, endPos)).intern();
parts[1] = (name.substring(endPos+1)).intern();
} else {
parts[0] = null;
parts[1] = name.intern();
}
incrCounter();
synchronized (splitNameTable) {
splitNameTable.put(name, parts);
}
}
return parts;
}
/**
* Join a URI part and a local part into a single qualified name.
*
* <p>The name will be merged into a single string in
* "{URI}local" format, and the merged string will be
* internalized.</p>
*
* @param uriPart The URI part of the name.
* @param localPart The local part of the name.
* @return The joined name in {URI}local format.
* @see java.lang.String#intern
*/
public static String joinName (String uriPart, String localPart)
{
qName.uri = uriPart;
qName.local = localPart;
String name = (String)joinNameTable.get(qName);
if (name == null) {
name = ("{" + uriPart + '}' + localPart).intern();
incrCounter();
synchronized (joinNameTable) {
joinNameTable.put(nsUtils.makeQName(uriPart.intern(),
localPart.intern()),
name);
}
}
return name;
}
////////////////////////////////////////////////////////////////////
// Internal methods.
////////////////////////////////////////////////////////////////////
private QName makeQName (String uri, String local)
{
return new QName(uri, local);
}
////////////////////////////////////////////////////////////////////
// Internal static methods.
////////////////////////////////////////////////////////////////////
/**
* Reset the internal cache.
*/
private static void resetTables ()
{
splitNameTable = new Hashtable();
joinNameTable = new Hashtable();
}
/**
* Increment the counter, and reset tables at COUNTER_MAX.
*/
private static void incrCounter ()
{
if (++counter == COUNTER_MAX) {
counter = 0;
resetTables();
}
}
/**
* Inner class for a split, qualified name.
*
* This class represents a two-part, Namespace-qualified
* name for the sake of hashing.
*/
class QName
{
QName (String uri, String local)
{
this.uri = uri;
this.local = local;
}
public boolean equals (Object o)
{
if (o instanceof QName) {
String uri2 = ((QName)o).uri;
String local2 = ((QName)o).local;
if (uri == uri2 && local == local2) {
return true;
} else if (uri == null && uri2 == null) {
return local.equals(local2);
} else if (uri == null) {
return false;
} else {
return uri.equals(uri2) && local.equals(local2);
}
} else {
return false;
}
}
public int hashCode ()
{
int hash = 0;
if (uri != null) {
hash += uri.hashCode();
}
if (local != null) {
hash += local.hashCode();
}
return hash;
}
String uri;
String local;
}
}
// end of NamespaceUtils.java
Thanks, and all the best,
David
--
David Megginson david@megginson.com
http://www.megginson.com/
|