001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one
003     * or more contributor license agreements. See the NOTICE file
004     * distributed with this work for additional information
005     * regarding copyright ownership. The ASF licenses this file
006     * to you under the Apache License, Version 2.0 (the  "License");
007     * you may not use this file except in compliance with the License.
008     * You may obtain a copy of the License at
009     *
010     *     http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing, software
013     * distributed under the License is distributed on an "AS IS" BASIS,
014     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     */
018    /*
019     * $Id: ExtensionNamespacesManager.java 1225575 2011-12-29 15:50:25Z mrglavas $
020     */
021    package org.apache.xalan.extensions;
022    
023    import java.util.Vector;
024    
025    import org.apache.xalan.templates.Constants;
026    
027    /**
028     * Used during assembly of a stylesheet to collect the information for each 
029     * extension namespace that is required during the transformation process 
030     * to generate an {@link ExtensionHandler}.
031     * 
032     */
033    public class ExtensionNamespacesManager
034    {
035      /**
036       * Vector of ExtensionNamespaceSupport objects to be used to generate ExtensionHandlers.
037       */
038      private Vector m_extensions = new Vector();
039      /**
040       * Vector of ExtensionNamespaceSupport objects for predefined ExtensionNamespaces. Elements
041       * from this vector are added to the m_extensions vector when encountered in the stylesheet.
042       */
043      private Vector m_predefExtensions = new Vector(7);
044      /**
045       * Vector of extension namespaces for which sufficient information is not yet available to
046       * complete the registration process.
047       */
048      private Vector m_unregisteredExtensions = new Vector();
049      
050      /**
051       * An ExtensionNamespacesManager is instantiated the first time an extension function or
052       * element is found in the stylesheet. During initialization, a vector of ExtensionNamespaceSupport
053       * objects is created, one for each predefined extension namespace.
054       */
055      public ExtensionNamespacesManager()
056      {
057        setPredefinedNamespaces();
058      }
059      
060      /**
061       * If necessary, register the extension namespace found compiling a function or 
062       * creating an extension element. 
063       * 
064       * If it is a predefined namespace, create a
065       * support object to simplify the instantiate of an appropriate ExtensionHandler
066       * during transformation runtime. Otherwise, add the namespace, if necessary,
067       * to a vector of undefined extension namespaces, to be defined later.
068       * 
069       */
070      public void registerExtension(String namespace)
071      {
072        if (namespaceIndex(namespace, m_extensions) == -1)
073        {
074          int predef = namespaceIndex(namespace, m_predefExtensions);
075          if (predef !=-1)
076            m_extensions.add(m_predefExtensions.get(predef));
077          else if (!(m_unregisteredExtensions.contains(namespace)))
078            m_unregisteredExtensions.add(namespace);       
079        }
080      }
081      
082      /**
083       * Register the extension namespace for an ElemExtensionDecl or ElemFunction,
084       * and prepare a support object to launch the appropriate ExtensionHandler at 
085       * transformation runtime.
086       */  
087      public void registerExtension(ExtensionNamespaceSupport extNsSpt)
088      {
089        String namespace = extNsSpt.getNamespace();
090        if (namespaceIndex(namespace, m_extensions) == -1)
091        {
092          m_extensions.add(extNsSpt);
093          if (m_unregisteredExtensions.contains(namespace))
094            m_unregisteredExtensions.remove(namespace);
095        }
096        
097      }
098      
099      /**
100       * Get the index for a namespace entry in the extension namespace Vector, -1 if
101       * no such entry yet exists.
102       */
103      public int namespaceIndex(String namespace, Vector extensions)
104      {
105        for (int i = 0; i < extensions.size(); i++)
106        {
107          if (((ExtensionNamespaceSupport)extensions.get(i)).getNamespace().equals(namespace))
108            return i;
109        }
110        return -1;
111      }
112      
113        
114      /**
115       * Get the vector of extension namespaces. Used to provide
116       * the extensions table access to a list of extension
117       * namespaces encountered during composition of a stylesheet.
118       */
119      public Vector getExtensions()
120      {
121        return m_extensions;
122      }
123      
124      /**
125       * Attempt to register any unregistered extension namespaces.
126       */
127      public void registerUnregisteredNamespaces()
128      {
129        for (int i = 0; i < m_unregisteredExtensions.size(); i++)
130        {
131          String ns = (String)m_unregisteredExtensions.get(i);
132          ExtensionNamespaceSupport extNsSpt = defineJavaNamespace(ns);
133          if (extNsSpt != null)
134            m_extensions.add(extNsSpt);
135        }    
136      }
137      
138        /**
139       * For any extension namespace that is not either predefined or defined 
140       * by a "component" declaration or exslt function declaration, attempt 
141       * to create an ExtensionNamespaceSuport object for the appropriate 
142       * Java class or Java package Extension Handler.
143       * 
144       * Called by StylesheetRoot.recompose(), after all ElemTemplate compose()
145       * operations have taken place, in order to set up handlers for
146       * the remaining extension namespaces.
147       * 
148       * @param ns The extension namespace URI.
149       * @return   An ExtensionNamespaceSupport object for this namespace
150       * (which defines the ExtensionHandler to be used), or null if such 
151       * an object cannot be created. 
152       *
153       * @throws javax.xml.transform.TransformerException
154       */
155      public ExtensionNamespaceSupport defineJavaNamespace(String ns)
156      {
157        return defineJavaNamespace(ns, ns);
158      }
159      public ExtensionNamespaceSupport defineJavaNamespace(String ns, String classOrPackage)
160      {
161        if(null == ns || ns.trim().length() == 0) // defensive. I don't think it's needed.  -sb
162          return null;
163    
164        // Prepare the name of the actual class or package, stripping
165        // out any leading "class:".  Next, see if there is a /.  If so,
166        // only look at the text to the right of the rightmost /.
167        String className = classOrPackage;
168        if (className.startsWith("class:"))
169          className = className.substring(6);
170    
171        int lastSlash = className.lastIndexOf('/');
172        if (-1 != lastSlash)
173          className = className.substring(lastSlash + 1);
174          
175        // The className can be null here, and can cause an error in getClassForName
176        // in JDK 1.8.
177        if(null == className || className.trim().length() == 0) 
178          return null;
179        
180        try
181        {
182          ExtensionHandler.getClassForName(className);
183          return new ExtensionNamespaceSupport(
184                               ns, 
185                               "org.apache.xalan.extensions.ExtensionHandlerJavaClass",                                         
186                               new Object[]{ns, "javaclass", className});
187        }
188        catch (ClassNotFoundException e)
189        {
190          return new ExtensionNamespaceSupport(
191                                ns, 
192                                "org.apache.xalan.extensions.ExtensionHandlerJavaPackage",
193                                new Object[]{ns, "javapackage", className + "."});
194        }
195      }
196      
197    /*
198      public ExtensionNamespaceSupport getSupport(int index, Vector extensions)
199      {
200        return (ExtensionNamespaceSupport)extensions.elementAt(index);
201      }
202    */
203      
204      
205      /**
206       * Set up a Vector for predefined extension namespaces.
207       */
208      private void setPredefinedNamespaces()
209      {    
210        String uri = Constants.S_EXTENSIONS_JAVA_URL;
211        String handlerClassName = "org.apache.xalan.extensions.ExtensionHandlerJavaPackage";
212        String lang = "javapackage";
213        String lib = "";
214        m_predefExtensions.add(new ExtensionNamespaceSupport(uri, handlerClassName,
215                                                 new Object[]{uri, lang, lib}));
216       
217        uri = Constants.S_EXTENSIONS_OLD_JAVA_URL;
218        m_predefExtensions.add(new ExtensionNamespaceSupport(uri, handlerClassName,
219                                                 new Object[]{uri, lang, lib}));
220        
221        uri = Constants.S_EXTENSIONS_LOTUSXSL_JAVA_URL;
222        m_predefExtensions.add(new ExtensionNamespaceSupport(uri, handlerClassName,
223                                                 new Object[]{uri, lang, lib}));
224        
225        uri = Constants.S_BUILTIN_EXTENSIONS_URL;
226        handlerClassName = "org.apache.xalan.extensions.ExtensionHandlerJavaClass";
227        lang = "javaclass"; // for remaining predefined extension namespaces.    
228        lib = "org.apache.xalan.lib.Extensions";
229        m_predefExtensions.add(new ExtensionNamespaceSupport(uri, handlerClassName,
230                                                 new Object[]{uri, lang, lib}));
231        
232        uri = Constants.S_BUILTIN_OLD_EXTENSIONS_URL;
233        m_predefExtensions.add(new ExtensionNamespaceSupport(uri, handlerClassName,
234                                                 new Object[]{uri, lang, lib}));
235        
236        // Xalan extension namespaces (redirect, pipe and SQL).
237        uri = Constants.S_EXTENSIONS_REDIRECT_URL;
238        lib = "org.apache.xalan.lib.Redirect";
239        m_predefExtensions.add(new ExtensionNamespaceSupport(uri, handlerClassName,
240                                                 new Object[]{uri, lang, lib}));
241     
242        uri = Constants.S_EXTENSIONS_PIPE_URL;
243        lib = "org.apache.xalan.lib.PipeDocument";
244        m_predefExtensions.add(new ExtensionNamespaceSupport(uri, handlerClassName,
245                                                 new Object[]{uri, lang, lib}));
246     
247        uri = Constants.S_EXTENSIONS_SQL_URL;
248        lib = "org.apache.xalan.lib.sql.XConnection";
249        m_predefExtensions.add(new ExtensionNamespaceSupport(uri, handlerClassName,
250                                                 new Object[]{uri, lang, lib}));
251     
252        
253        //EXSLT namespaces (not including EXSLT function namespaces which are
254        // registered by the associated ElemFunction.
255        uri = Constants.S_EXSLT_COMMON_URL;
256        lib = "org.apache.xalan.lib.ExsltCommon";
257        m_predefExtensions.add(new ExtensionNamespaceSupport(uri, handlerClassName,
258                                                 new Object[]{uri, lang, lib}));
259    
260        uri = Constants.S_EXSLT_MATH_URL;
261        lib = "org.apache.xalan.lib.ExsltMath";
262        m_predefExtensions.add(new ExtensionNamespaceSupport(uri, handlerClassName,
263                                                 new Object[]{uri, lang, lib}));
264        
265        uri = Constants.S_EXSLT_SETS_URL;
266        lib = "org.apache.xalan.lib.ExsltSets";
267        m_predefExtensions.add(new ExtensionNamespaceSupport(uri, handlerClassName,
268                                                 new Object[]{uri, lang, lib}));
269        
270        uri = Constants.S_EXSLT_DATETIME_URL;
271        lib = "org.apache.xalan.lib.ExsltDatetime";
272        m_predefExtensions.add(new ExtensionNamespaceSupport(uri, handlerClassName,
273                                                 new Object[]{uri, lang, lib}));
274                                                 
275        uri = Constants.S_EXSLT_DYNAMIC_URL;
276        lib = "org.apache.xalan.lib.ExsltDynamic";
277        m_predefExtensions.add(new ExtensionNamespaceSupport(uri, handlerClassName,
278                                                 new Object[]{uri, lang, lib}));
279    
280        uri = Constants.S_EXSLT_STRINGS_URL;
281        lib = "org.apache.xalan.lib.ExsltStrings";
282        m_predefExtensions.add(new ExtensionNamespaceSupport(uri, handlerClassName,
283                                                 new Object[]{uri, lang, lib}));                                             
284      }    
285      
286    }