You are viewing a plain text version of this content. The canonical link for it is here.
Posted to soap-dev@ws.apache.org by sn...@apache.org on 2002/11/18 15:23:06 UTC

cvs commit: xml-soap/java/src/org/apache/soap/util/xml NSStack.java

snichol     2002/11/18 06:23:06

  Modified:    java/src/org/apache/soap/util/xml NSStack.java
  Log:
  Submitted by: Pavel Ausianik <Pa...@epam.com>
  
  I have prepared patch for NSStack, moving from growing number of Vectors to
  3 arrays per stack.
  I also used intern() String comparison, but this only do benefits for large
  number of comparisons, and it may happen that having just String.equals()
  could be better.
  
  Revision  Changes    Path
  1.5       +200 -135  xml-soap/java/src/org/apache/soap/util/xml/NSStack.java
  
  Index: NSStack.java
  ===================================================================
  RCS file: /home/cvs/xml-soap/java/src/org/apache/soap/util/xml/NSStack.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- NSStack.java	10 Nov 2000 15:20:58 -0000	1.4
  +++ NSStack.java	18 Nov 2002 14:23:06 -0000	1.5
  @@ -2,7 +2,7 @@
    * The Apache Software License, Version 1.1
    *
    *
  - * Copyright (c) 2000 The Apache Software Foundation.  All rights 
  + * Copyright (c) 2000 The Apache Software Foundation.  All rights
    * reserved.
    *
    * Redistribution and use in source and binary forms, with or without
  @@ -10,7 +10,7 @@
    * are met:
    *
    * 1. Redistributions of source code must retain the above copyright
  - *    notice, this list of conditions and the following disclaimer. 
  + *    notice, this list of conditions and the following disclaimer.
    *
    * 2. Redistributions in binary form must reproduce the above copyright
    *    notice, this list of conditions and the following disclaimer in
  @@ -18,7 +18,7 @@
    *    distribution.
    *
    * 3. The end-user documentation included with the redistribution,
  - *    if any, must include the following acknowledgment:  
  + *    if any, must include the following acknowledgment:
    *       "This product includes software developed by the
    *        Apache Software Foundation (http://www.apache.org/)."
    *    Alternately, this acknowledgment may appear in the software itself,
  @@ -26,7 +26,7 @@
    *
    * 4. The names "SOAP" and "Apache Software Foundation" must
    *    not be used to endorse or promote products derived from this
  - *    software without prior written permission. For written 
  + *    software without prior written permission. For written
    *    permission, please contact apache@apache.org.
    *
    * 5. Products derived from this software may not be called "Apache",
  @@ -57,9 +57,10 @@
   
   package org.apache.soap.util.xml;
   
  -import java.io.*;
  -import java.util.*;
  -import org.apache.soap.util.xml.* ;
  +import java.io.IOException;
  +import java.io.Writer;
  +
  +import org.apache.soap.util.xml.*;
   
   /**
    * This class implements a namespace stack for XML apps to use. If
  @@ -79,134 +80,198 @@
    * declaration.
    *
    * @author Sanjiva Weerawarana (sanjiva@watson.ibm.com)
  + * @author Pavel Ausianik &lt;Pavel_Ausianik@epam.com&gt;
    */
  -public class NSStack {
  -  Vector nss = new Vector (); // vector holding vectors of ns decls (stack)
  -  int nssCount = 0;           // number of items on the stack
  -  Vector tos;                 // the vector @ the top of the stack
  -  private final static String nsPrefixPrefix = "ns";
  -  private int nsPrefixCount = 1;
  -
  -  /**
  -   * Enter a new scope: after calling this I'm ready to accept new
  -   * declarations into that scope.
  -   */
  -  public void pushScope () {
  -    nss.addElement (tos = new Vector ());
  -    nssCount++;
  -  }
  -
  -  /**
  -   * Leave a scope: this removes any NS declarations that were added
  -   * in the last scope. Note that I don't bother to validate that you
  -   * don't call popScope too many times; that's your problem.
  -   */
  -  public void popScope () {
  -    nss.removeElementAt (--nssCount);
  -    tos = (nssCount != 0) ? (Vector) nss.elementAt (nssCount-1) : null;
  -  }
  -
  -  /**
  -   * Add a new declaration to the current scope. This is visible within
  -   * the current scope as well as from any nested scopes. 
  -   *
  -   * @param prefix the prefix to be used for this namespace
  -   * @param URI the namespace name of this namespace.
  -   */
  -  synchronized public void addNSDeclaration (String prefix, String URI) {
  -    tos.addElement (new NSDecl (prefix, URI));
  -  }
  -
  -  /**
  -   * Add a new declaration to the current scope using a unique prefix
  -   * and return the prefix. This is useful when one just wants to add a
  -   * decl and doesn't want to have to deal with creating unique prefixes.
  -   * If the namespace name is already declared and in scope, then the 
  -   * previously declared prefix is returned.
  -   *
  -   * @param URI the namespace name of this namespace
  -   * @return the unique prefix created or previously declared
  -   *         for this namespace
  -   */
  -  synchronized public String addNSDeclaration (String URI) {
  -    String uniquePrefix = getPrefixFromURI (URI);
  -    if (uniquePrefix == null) {
  -      do {
  -              uniquePrefix = nsPrefixPrefix + nsPrefixCount++;
  -      } while (getURIFromPrefix (uniquePrefix) != null);
  -      addNSDeclaration (uniquePrefix, URI);
  -    }
  -    return uniquePrefix;
  -  }
  -
  -  /**
  -   * Return the prefix associated with the given namespace name by
  -   * looking thru all the namespace declarations that are in scope.
  -   *
  -   * @param URI the namespace name for whom a declared prefix is desired
  -   * @return the prefix or null if namespace name not found
  -   */
  -  public String getPrefixFromURI (String URI) {
  -    for (int i = nssCount-1; i >= 0; i--) {
  -      Vector scope = (Vector) nss.elementAt (i);
  -      for (Enumeration e = scope.elements (); e.hasMoreElements (); ) {
  -        NSDecl nsd = (NSDecl) e.nextElement ();
  -        if (nsd.URI.equals (URI)) {
  -          return nsd.prefix;
  -        }
  -      }
  -    }
  -    return null;
  -  }
  -
  -  /**
  -   * Return the prefix associated with the given namespace name by
  -   * looking thru all the namespace declarations that are in scope.
  -   * If the namespace declaration is not found, create one and
  -   * return the generated prefix.
  -   *
  -   * @param URI the namespace name for whom a declared prefix is desired
  -   * @return the prefix (will never return null)
  -   */
  -  synchronized public String getPrefixFromURI (String namespaceURI,
  -                                               Writer sink)
  -    throws IOException {
  -    String prefix = getPrefixFromURI (namespaceURI);
  -
  -    if (prefix == null) {
  -      prefix = addNSDeclaration (namespaceURI);
  -
  -      sink.write (" xmlns:" + prefix + "=\"" + namespaceURI + '\"');
  -    }
  -
  -    return prefix;
  -  }
  -
  -  /**
  -   * Return the namespace name associated with the given prefix by
  -   * looking thru all the namespace declarations that are in scope.
  -   *
  -   * @param prefix the prefix for whom a declared namespace name is desired
  -   * @return the namespace name or null if prefix not found
  -   */
  -  public String getURIFromPrefix (String prefix) {
  -    for (int i = nssCount-1; i >= 0; i--) {
  -      Vector scope = (Vector) nss.elementAt (i);
  -      for (Enumeration e = scope.elements (); e.hasMoreElements (); ) {
  -        NSDecl nsd = (NSDecl) e.nextElement ();
  -        if (nsd.prefix.equals (prefix)) {
  -          return nsd.URI;
  -        }
  -      }
  -    }
  -    return null;
  -  }
  -
  -  // MJD - debug
  -  public String toString()
  -  {
  -    return nss.toString();
  -  }
  -  // MJD - debug
  +public final class NSStack {
  +    private String[] URIStack;
  +    private String[] prefixStack;
  +
  +    private int[] scope;
  +    private int top = 0;
  +    private int iterator = -1;
  +    private final static String NSPREFIX = "ns";
  +    private int nsPrefixCount = 0;
  +
  +    private static String[] predefinedNamespaces;
  +
  +    private static final int START_ARRAY_SIZE = 32;
  +
  +    public NSStack() {
  +        URIStack = new String[START_ARRAY_SIZE];
  +        prefixStack = new String[START_ARRAY_SIZE];
  +        scope = new int[START_ARRAY_SIZE];
  +        scope[0] = -1;
  +    }
  +
  +    /**
  +     * Creates a predefined Namespace string
  +     * Assuming that in the single application , the number of names is the same
  +     * between calls. We'll benefit from caching on continuous operations
  +     */
  +    synchronized private static String getPredefinedNamespace(int nsCount) {
  +        if (predefinedNamespaces == null)
  +        {
  +            predefinedNamespaces =  new String[START_ARRAY_SIZE];
  +            for (int i=0; i<START_ARRAY_SIZE; i++)
  +                predefinedNamespaces[i] = NSPREFIX + (i+1);
  +        } else if (nsCount >= predefinedNamespaces.length) {
  +            int length  = predefinedNamespaces.length;
  +            String[] newnamespace = new String[length * 2];
  +            System.arraycopy(predefinedNamespaces, 0, newnamespace, 0, length);
  +            for (int i=0; i<length; i++)
  +                predefinedNamespaces[i+length] = NSPREFIX + (i+length+1);
  +        }
  +        return predefinedNamespaces[nsCount];
  +    }
  +
  +    /**
  +     * Enter a new scope: after calling this I'm ready to accept new
  +     * declarations into that scope.
  +     */
  +    public void pushScope() {
  +
  +        top++;
  +        int length = scope.length;
  +
  +        if (top >= length) {
  +            int newscope[] = new int[length * 2];
  +            System.arraycopy(scope, 0, newscope, 0, length);
  +            scope = newscope;
  +        }
  +
  +        scope[top] = iterator;
  +
  +    }
  +
  +    /**
  +     * Leave a scope: this removes any NS declarations that were added
  +     * in the last scope. Note that I don't bother to validate that you
  +     * don't call popScope too many times; that's your problem.
  +     */
  +    public void popScope() {
  +        scope[top] = 0;
  +        top--;
  +        iterator = top >= 0 ? scope[top] : 0;
  +    }
  +
  +    /**
  +     * Add a new declaration to the current scope. This is visible within
  +     * the current scope as well as from any nested scopes.
  +     *
  +     * @param prefix the prefix to be used for this namespace
  +     * @param URI the namespace name of this namespace.
  +     */
  +    public void addNSDeclaration(String prefix, String namespaceURI) {
  +        int length = URIStack.length;
  +        iterator++;
  +
  +        if (iterator >= length) {
  +            String newstack[] = new String[length * 2];
  +            System.arraycopy(URIStack, 0, newstack, 0, length);
  +            URIStack = newstack;
  +            newstack = new String[length * 2];
  +            System.arraycopy(prefixStack, 0, newstack, 0, length);
  +            prefixStack = newstack;
  +        }
  +        // scope too small - expand - very unlikely
  +        URIStack[iterator] = namespaceURI.intern();
  +        prefixStack[iterator] = prefix.intern();
  +    }
  +
  +    /**
  +     * Add a new declaration to the current scope using a unique prefix
  +     * and return the prefix. This is useful when one just wants to add a
  +     * decl and doesn't want to have to deal with creating unique prefixes.
  +     * If the namespace name is already declared and in scope, then the
  +     * previously declared prefix is returned.
  +     *
  +     * @param URI the namespace name of this namespace
  +     * @return the unique prefix created or previously declared
  +     *         for this namespace
  +     */
  +    public String addNSDeclaration(String URI) {
  +        String uniquePrefix = getPrefixFromURI(URI);
  +        if (uniquePrefix == null) {
  +            do {
  +                uniquePrefix = getPredefinedNamespace(nsPrefixCount++);
  +            } while (getURIFromPrefix(uniquePrefix) != null);
  +            addNSDeclaration(uniquePrefix, URI);
  +        }
  +        return uniquePrefix;
  +    }
  +
  +    /**
  +     * Return the prefix associated with the given namespace name by
  +     * looking thru all the namespace declarations that are in scope.
  +     *
  +     * @param URI the namespace name for whom a declared prefix is desired
  +     * @return the prefix or null if namespace name not found
  +     */
  +    public String getPrefixFromURI(String namespaceURI) {
  +        if ((namespaceURI == null) || (namespaceURI.equals("")))
  +            return null;
  +
  +        namespaceURI = namespaceURI.intern();
  +        for (int cursor = iterator; cursor >= 0; cursor--) {
  +            if (URIStack[cursor] == namespaceURI)
  +                return prefixStack[cursor];
  +        }
  +        return null;
  +    }
  +
  +    /**
  +     * Return the prefix associated with the given namespace name by
  +     * looking thru all the namespace declarations that are in scope.
  +     * If the namespace declaration is not found, create one and
  +     * return the generated prefix.
  +     *
  +     * @param URI the namespace name for whom a declared prefix is desired
  +     * @return the prefix (will never return null)
  +     */
  +    public String getPrefixFromURI(String namespaceURI, Writer sink)
  +            throws IOException {
  +        String prefix = getPrefixFromURI(namespaceURI);
  +
  +        if (prefix == null) {
  +            prefix = addNSDeclaration(namespaceURI);
  +
  +            sink.write(" xmlns:");
  +            sink.write(prefix);
  +            sink.write("=\"");
  +            sink.write(namespaceURI);
  +            sink.write('\"');
  +        }
  +
  +        return prefix;
  +    }
  +
  +    /**
  +     * Given a prefix, return the associated namespace (if any).
  +     */
  +    public String getURIFromPrefix(String prefix) {
  +        if (prefix == null)
  +            prefix = "";
  +        prefix = prefix.intern();
  +        for (int cursor = iterator; cursor >= 0; cursor--) {
  +                if (prefixStack[cursor] ==  prefix)
  +                    return URIStack[cursor];
  +        }
  +
  +        return null;
  +    }
  +
  +    public void dump() {
  +        int end = iterator;
  +        int start = 0;
  +        for (int cursor = top; cursor >= 0; cursor--, end = start - 1) {
  +            start = scope[cursor] + 1;
  +
  +            System.out.println("Level: " + cursor);
  +
  +            for (int j = start; j <= end; j++) {
  +                System.out.println("    Map:" + URIStack[cursor] + " -> " +prefixStack[cursor]);
  +            }
  +        }
  +    }
   }