code: /*
   * Licensed to the Apache Software Foundation (ASF) under one
   * or more contributor license agreements. See the NOTICE file
   * distributed with this work for additional information
   * regarding copyright ownership. The ASF licenses this file
   * to you under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  /*
   * $Id$
   */
  package org.apache.xalan.extensions;
  
  import java.util.Vector;
  
  import org.apache.xalan.templates.Constants;
  
  /**
   * Used during assembly of a stylesheet to collect the information for each 
   * extension namespace that is required during the transformation process 
   * to generate an {@link ExtensionHandler}.
   * 
   */
  public class ExtensionNamespacesManager
  {
    /**
     * Vector of ExtensionNamespaceSupport objects to be used to generate ExtensionHandlers.
     */
    private Vector m_extensions = new Vector();
    /**
     * Vector of ExtensionNamespaceSupport objects for predefined ExtensionNamespaces. Elements
     * from this vector are added to the m_extensions vector when encountered in the stylesheet.
     */
    private Vector m_predefExtensions = new Vector(7);
    /**
     * Vector of extension namespaces for which sufficient information is not yet available to
     * complete the registration process.
     */
    private Vector m_unregisteredExtensions = new Vector();
    
    /**
     * An ExtensionNamespacesManager is instantiated the first time an extension function or
     * element is found in the stylesheet. During initialization, a vector of ExtensionNamespaceSupport
     * objects is created, one for each predefined extension namespace.
     */
    public ExtensionNamespacesManager()
    {
      setPredefinedNamespaces();
    }
    
    /**
     * If necessary, register the extension namespace found compiling a function or 
     * creating an extension element. 
     * 
     * If it is a predefined namespace, create a
     * support object to simplify the instantiate of an appropriate ExtensionHandler
     * during transformation runtime. Otherwise, add the namespace, if necessary,
     * to a vector of undefined extension namespaces, to be defined later.
     * 
     */
    public void registerExtension(String namespace)
    {
      if (namespaceIndex(namespace, m_extensions) == -1)
      {
        int predef = namespaceIndex(namespace, m_predefExtensions);
        if (predef !=-1)
          m_extensions.add(m_predefExtensions.get(predef));
        else if (!(m_unregisteredExtensions.contains(namespace)))
          m_unregisteredExtensions.add(namespace);       
      }
    }
    
    /**
     * Register the extension namespace for an ElemExtensionDecl or ElemFunction,
     * and prepare a support object to launch the appropriate ExtensionHandler at 
     * transformation runtime.
     */  
    public void registerExtension(ExtensionNamespaceSupport extNsSpt)
    {
      String namespace = extNsSpt.getNamespace();
      if (namespaceIndex(namespace, m_extensions) == -1)
      {
        m_extensions.add(extNsSpt);
        if (m_unregisteredExtensions.contains(namespace))
          m_unregisteredExtensions.remove(namespace);
      }
      
    }
    
    /**
     * Get the index for a namespace entry in the extension namespace Vector, -1 if
     * no such entry yet exists.
     */
    public int namespaceIndex(String namespace, Vector extensions)
    {
      for (int i = 0; i < extensions.size(); i++)
      {
        if (((ExtensionNamespaceSupport)extensions.get(i)).getNamespace().equals(namespace))
          return i;
      }
      return -1;
    }
    
      
    /**
     * Get the vector of extension namespaces. Used to provide
     * the extensions table access to a list of extension
     * namespaces encountered during composition of a stylesheet.
     */
    public Vector getExtensions()
    {
      return m_extensions;
    }
    
    /**
     * Attempt to register any unregistered extension namespaces.
     */
    public void registerUnregisteredNamespaces()
    {
      for (int i = 0; i < m_unregisteredExtensions.size(); i++)
      {
        String ns = (String)m_unregisteredExtensions.get(i);
        ExtensionNamespaceSupport extNsSpt = defineJavaNamespace(ns);
        if (extNsSpt != null)
          m_extensions.add(extNsSpt);
      }    
    }
    
      /**
     * For any extension namespace that is not either predefined or defined 
     * by a "component" declaration or exslt function declaration, attempt 
     * to create an ExtensionNamespaceSuport object for the appropriate 
     * Java class or Java package Extension Handler.
     * 
     * Called by StylesheetRoot.recompose(), after all ElemTemplate compose()
     * operations have taken place, in order to set up handlers for
     * the remaining extension namespaces.
     * 
     * @param ns The extension namespace URI.
     * @return   An ExtensionNamespaceSupport object for this namespace
     * (which defines the ExtensionHandler to be used), or null if such 
     * an object cannot be created. 
     *
     * @throws javax.xml.transform.TransformerException
     */
    public ExtensionNamespaceSupport defineJavaNamespace(String ns)
    {
      return defineJavaNamespace(ns, ns);
    }
    public ExtensionNamespaceSupport defineJavaNamespace(String ns, String classOrPackage)
    {
      if(null == ns || ns.trim().length() == 0) // defensive. I don't think it's needed.  -sb
        return null;
  
      // Prepare the name of the actual class or package, stripping
      // out any leading "class:".  Next, see if there is a /.  If so,
      // only look at the text to the right of the rightmost /.
      String className = classOrPackage;
      if (className.startsWith("class:"))
        className = className.substring(6);
  
      int lastSlash = className.lastIndexOf('/');
      if (-1 != lastSlash)
        className = className.substring(lastSlash + 1);
        
      // The className can be null here, and can cause an error in getClassForName
      // in JDK 1.8.
      if(null == className || className.trim().length() == 0) 
        return null;
      
      try
      {
        ExtensionHandler.getClassForName(className);
        return new ExtensionNamespaceSupport(
                             ns, 
                             "org.apache.xalan.extensions.ExtensionHandlerJavaClass",                                         
                             new Object[]{ns, "javaclass", className});
      }
      catch (ClassNotFoundException e)
      {
        return new ExtensionNamespaceSupport(
                              ns, 
                              "org.apache.xalan.extensions.ExtensionHandlerJavaPackage",
                              new Object[]{ns, "javapackage", className + "."});
      }
    }
    
  /*
    public ExtensionNamespaceSupport getSupport(int index, Vector extensions)
    {
      return (ExtensionNamespaceSupport)extensions.elementAt(index);
    }
  */
    
    
    /**
     * Set up a Vector for predefined extension namespaces.
     */
    private void setPredefinedNamespaces()
    {    
      String uri = Constants.S_EXTENSIONS_JAVA_URL;
      String handlerClassName = "org.apache.xalan.extensions.ExtensionHandlerJavaPackage";
      String lang = "javapackage";
      String lib = "";
      m_predefExtensions.add(new ExtensionNamespaceSupport(uri, handlerClassName,
                                               new Object[]{uri, lang, lib}));
     
      uri = Constants.S_EXTENSIONS_OLD_JAVA_URL;
      m_predefExtensions.add(new ExtensionNamespaceSupport(uri, handlerClassName,
                                               new Object[]{uri, lang, lib}));
      
      uri = Constants.S_EXTENSIONS_LOTUSXSL_JAVA_URL;
      m_predefExtensions.add(new ExtensionNamespaceSupport(uri, handlerClassName,
                                               new Object[]{uri, lang, lib}));
      
      uri = Constants.S_BUILTIN_EXTENSIONS_URL;
      handlerClassName = "org.apache.xalan.extensions.ExtensionHandlerJavaClass";
      lang = "javaclass"; // for remaining predefined extension namespaces.    
      lib = "org.apache.xalan.lib.Extensions";
      m_predefExtensions.add(new ExtensionNamespaceSupport(uri, handlerClassName,
                                               new Object[]{uri, lang, lib}));
      
      uri = Constants.S_BUILTIN_OLD_EXTENSIONS_URL;
      m_predefExtensions.add(new ExtensionNamespaceSupport(uri, handlerClassName,
                                               new Object[]{uri, lang, lib}));
      
      // Xalan extension namespaces (redirect, pipe and SQL).
      uri = Constants.S_EXTENSIONS_REDIRECT_URL;
      lib = "org.apache.xalan.lib.Redirect";
      m_predefExtensions.add(new ExtensionNamespaceSupport(uri, handlerClassName,
                                               new Object[]{uri, lang, lib}));
   
      uri = Constants.S_EXTENSIONS_PIPE_URL;
      lib = "org.apache.xalan.lib.PipeDocument";
      m_predefExtensions.add(new ExtensionNamespaceSupport(uri, handlerClassName,
                                               new Object[]{uri, lang, lib}));
   
      uri = Constants.S_EXTENSIONS_SQL_URL;
      lib = "org.apache.xalan.lib.sql.XConnection";
      m_predefExtensions.add(new ExtensionNamespaceSupport(uri, handlerClassName,
                                               new Object[]{uri, lang, lib}));
   
      
      //EXSLT namespaces (not including EXSLT function namespaces which are
      // registered by the associated ElemFunction.
      uri = Constants.S_EXSLT_COMMON_URL;
      lib = "org.apache.xalan.lib.ExsltCommon";
      m_predefExtensions.add(new ExtensionNamespaceSupport(uri, handlerClassName,
                                               new Object[]{uri, lang, lib}));
  
      uri = Constants.S_EXSLT_MATH_URL;
      lib = "org.apache.xalan.lib.ExsltMath";
      m_predefExtensions.add(new ExtensionNamespaceSupport(uri, handlerClassName,
                                               new Object[]{uri, lang, lib}));
      
      uri = Constants.S_EXSLT_SETS_URL;
      lib = "org.apache.xalan.lib.ExsltSets";
      m_predefExtensions.add(new ExtensionNamespaceSupport(uri, handlerClassName,
                                               new Object[]{uri, lang, lib}));
      
      uri = Constants.S_EXSLT_DATETIME_URL;
      lib = "org.apache.xalan.lib.ExsltDatetime";
      m_predefExtensions.add(new ExtensionNamespaceSupport(uri, handlerClassName,
                                               new Object[]{uri, lang, lib}));
                                               
      uri = Constants.S_EXSLT_DYNAMIC_URL;
      lib = "org.apache.xalan.lib.ExsltDynamic";
      m_predefExtensions.add(new ExtensionNamespaceSupport(uri, handlerClassName,
                                               new Object[]{uri, lang, lib}));
  
      uri = Constants.S_EXSLT_STRINGS_URL;
      lib = "org.apache.xalan.lib.ExsltStrings";
      m_predefExtensions.add(new ExtensionNamespaceSupport(uri, handlerClassName,
                                               new Object[]{uri, lang, lib}));                                             
    }    
    
  }
  