001    /**
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *     http://www.apache.org/licenses/LICENSE-2.0
010     *
011     *  Unless required by applicable law or agreed to in writing, software
012     *  distributed under the License is distributed on an "AS IS" BASIS,
013     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     *  See the License for the specific language governing permissions and
015     *  limitations under the License.
016     */
017    
018    package org.apache.geronimo.jasper.deployment;
019    
020    import java.io.File;
021    import java.io.IOException;
022    import java.net.JarURLConnection;
023    import java.net.MalformedURLException;
024    import java.net.URI;
025    import java.net.URISyntaxException;
026    import java.net.URL;
027    import java.util.ArrayList;
028    import java.util.Collection;
029    import java.util.Enumeration;
030    import java.util.HashMap;
031    import java.util.HashSet;
032    import java.util.List;
033    import java.util.Map;
034    import java.util.Set;
035    import java.util.jar.JarEntry;
036    import java.util.jar.JarFile;
037    
038    import javax.xml.namespace.QName;
039    
040    import org.apache.commons.logging.Log;
041    import org.apache.commons.logging.LogFactory;
042    import org.apache.geronimo.common.DeploymentException;
043    import org.apache.geronimo.deployment.ModuleIDBuilder;
044    import org.apache.geronimo.deployment.service.EnvironmentBuilder;
045    import org.apache.geronimo.deployment.xmlbeans.XmlBeansUtil;
046    import org.apache.geronimo.gbean.AbstractName;
047    import org.apache.geronimo.gbean.GBeanData;
048    import org.apache.geronimo.gbean.GBeanInfo;
049    import org.apache.geronimo.gbean.GBeanInfoBuilder;
050    import org.apache.geronimo.j2ee.annotation.Holder;
051    import org.apache.geronimo.j2ee.deployment.EARContext;
052    import org.apache.geronimo.j2ee.deployment.Module;
053    import org.apache.geronimo.j2ee.deployment.ModuleBuilderExtension;
054    import org.apache.geronimo.j2ee.deployment.NamingBuilder;
055    import org.apache.geronimo.j2ee.deployment.WebModule;
056    import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory;
057    import org.apache.geronimo.jasper.JasperServletContextCustomizer;
058    import org.apache.geronimo.kernel.GBeanAlreadyExistsException;
059    import org.apache.geronimo.kernel.Naming;
060    import org.apache.geronimo.kernel.config.Configuration;
061    import org.apache.geronimo.kernel.config.ConfigurationStore;
062    import org.apache.geronimo.kernel.repository.Environment;
063    import org.apache.geronimo.schema.SchemaConversionUtils;
064    import org.apache.geronimo.xbeans.javaee.FullyQualifiedClassType;
065    import org.apache.geronimo.xbeans.javaee.JspConfigType;
066    import org.apache.geronimo.xbeans.javaee.ListenerType;
067    import org.apache.geronimo.xbeans.javaee.TagType;
068    import org.apache.geronimo.xbeans.javaee.TaglibDocument;
069    import org.apache.geronimo.xbeans.javaee.TaglibType;
070    import org.apache.geronimo.xbeans.javaee.TldTaglibType;
071    import org.apache.geronimo.xbeans.javaee.WebAppType;
072    import org.apache.xbean.finder.ClassFinder;
073    import org.apache.xmlbeans.XmlCursor;
074    import org.apache.xmlbeans.XmlException;
075    import org.apache.xmlbeans.XmlObject;
076    
077    /**
078     * This JSP module builder extension is meant to find all the TLD descriptor files associated with a
079     * deployable artifact, search those TLD files for listeners, search those listeners for
080     * annotations, and ultimately create a ClassFinder using those annoated classes (for later
081     * processing by the various naming builders)
082     *
083     * @version $Rev $Date
084     */
085    public class JspModuleBuilderExtension implements ModuleBuilderExtension {
086    
087        private static final Log log = LogFactory.getLog(JspModuleBuilderExtension.class);
088    
089        private final Environment defaultEnvironment;
090        private final NamingBuilder namingBuilders;
091    
092        private static final QName TLIB_VERSION = new QName(SchemaConversionUtils.JAVAEE_NAMESPACE, "tlib-version");
093        private static final QName SHORT_NAME = new QName(SchemaConversionUtils.JAVAEE_NAMESPACE, "short-name");
094        private static final QName TAG_CLASS = new QName(SchemaConversionUtils.JAVAEE_NAMESPACE, "tag-class");
095        private static final QName TEI_CLASS = new QName(SchemaConversionUtils.JAVAEE_NAMESPACE, "tei-class");
096        private static final QName BODY_CONTENT = new QName(SchemaConversionUtils.JAVAEE_NAMESPACE, "body-content");
097    
098        private static final String SCHEMA_LOCATION_URL = "http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd";
099        private static final String VERSION = "2.1";
100    
101        public JspModuleBuilderExtension(Environment defaultEnvironment, NamingBuilder namingBuilders) {
102            this.defaultEnvironment = defaultEnvironment;
103            this.namingBuilders = namingBuilders;
104        }
105    
106        public void createModule(Module module, Object plan, JarFile moduleFile, String targetPath, URL specDDUrl, Environment environment, Object moduleContextInfo, AbstractName earName, Naming naming, ModuleIDBuilder idBuilder) throws DeploymentException {
107        }
108    
109        public void installModule(JarFile earFile, EARContext earContext, Module module, Collection configurationStores, ConfigurationStore targetConfigurationStore, Collection repository) throws DeploymentException {
110        }
111    
112        public void initContext(EARContext earContext, Module module, ClassLoader cl) throws DeploymentException {
113        }
114    
115        public void addGBeans(EARContext earContext, Module module, ClassLoader cl, Collection repository) throws DeploymentException {
116            if (!(module instanceof WebModule)) {
117                //not a web module, nothing to do
118                return;
119            }
120            //TODO Only merge if we detect jsps???
121            EnvironmentBuilder.mergeEnvironments(module.getEnvironment(), defaultEnvironment);
122    
123            WebModule webModule = (WebModule) module;
124            WebAppType webApp = (WebAppType) webModule.getSpecDD();
125    
126            EARContext moduleContext = module.getEarContext();
127            Map sharedContext = module.getSharedContext();
128    
129            GBeanData webAppData = (GBeanData) sharedContext.get(WebModule.WEB_APP_DATA);
130    
131            AbstractName moduleName = moduleContext.getModuleName();
132            Map<NamingBuilder.Key, Object> buildingContext = new HashMap<NamingBuilder.Key, Object>();
133            buildingContext.put(NamingBuilder.GBEAN_NAME_KEY, moduleName);
134    
135            //use the same jndi context as the web app
136            Map compContext = NamingBuilder.JNDI_KEY.get(sharedContext);
137            buildingContext.put(NamingBuilder.JNDI_KEY, compContext);
138    
139            //use the same holder object as the web app.
140            Holder holder = NamingBuilder.INJECTION_KEY.get(sharedContext);
141            buildingContext.put(NamingBuilder.INJECTION_KEY, holder);
142    
143            XmlObject jettyWebApp = webModule.getVendorDD();
144    
145            Configuration earConfiguration = earContext.getConfiguration();
146    
147            Set<String> listenerNames = new HashSet<String>();
148    
149            ClassFinder classFinder = createJspClassFinder(webApp, webModule, listenerNames);
150            webModule.setClassFinder(classFinder);
151    
152            namingBuilders.buildNaming(webApp, jettyWebApp, webModule, buildingContext);
153    
154            //only try to install it if reference will work.
155            //Some users (tomcat?) may have back doors into jasper that make adding this gbean unnecessary.
156            GBeanInfo webAppGBeanInfo = webAppData.getGBeanInfo();
157            if (webAppGBeanInfo.getReference("ContextCustomizer") != null) {
158                AbstractName jspLifecycleName = moduleContext.getNaming().createChildName(moduleName, "jspLifecycleProvider", NameFactory.GERONIMO_SERVICE);
159                GBeanData gbeanData = new GBeanData(jspLifecycleName, JasperServletContextCustomizer.GBEAN_INFO);
160                gbeanData.setAttribute("holder", holder);
161    
162                try {
163                    moduleContext.addGBean(gbeanData);
164                } catch (GBeanAlreadyExistsException e) {
165                    throw new DeploymentException("Duplicate jspLifecycleProvider", e);
166                }
167    
168                webAppData.setReferencePattern("ContextCustomizer", jspLifecycleName);
169            }
170            //add listeners if possible
171            //we may need to add them in another way for tomcat
172            Object value = webAppData.getAttribute("listenerClassNames");
173            if (value instanceof Collection) {
174                ((Collection<String>) value).addAll(listenerNames);
175            }
176        }
177    
178        protected ClassFinder createJspClassFinder(WebAppType webApp, WebModule webModule, Set<String> listenerNames) throws DeploymentException {
179            List<URL> urls = getTldFiles(webApp, webModule);
180            List<Class> classes = getListenerClasses(webApp, webModule, urls, listenerNames);
181            return new ClassFinder(classes);
182        }
183    
184    
185        /**
186         * getTldFiles(): Find all the TLD files in the web module being deployed
187         *
188         * <p>Locations to search for these TLD file(s) (matches the precedence search order for TLD
189         * files per the JSP specs):
190         * <ol>
191         *      <li>web.xml <taglib> entries
192         *      <li>TLD(s) in JAR files in WEB-INF/lib
193         *      <li>TLD(s) under WEB-INF
194         *      <li>All TLD files in all META-INF(s)
195         * </ol>
196         *
197         * @param webApp    spec DD for module
198         * @param webModule module being deployed
199         * @return list of the URL(s) for the TLD files
200         * @throws DeploymentException if there's a problem finding a tld file
201         */
202        private List<URL> getTldFiles(WebAppType webApp, WebModule webModule) throws DeploymentException {
203            log.debug("getTldFiles( " + webApp.toString() + "," + webModule.getName() + " ): Entry");
204    
205            List<URL> tldURLs = new ArrayList<URL>();
206    
207            // 1. web.xml <taglib> entries
208            JspConfigType[] jspConfigs = webApp.getJspConfigArray();
209            for (JspConfigType jspConfig : jspConfigs) {
210                TaglibType[] taglibs = jspConfig.getTaglibArray();
211                for (TaglibType taglib : taglibs) {
212                    String uri = taglib.getTaglibUri().getStringValue().trim();
213                    String location = taglib.getTaglibLocation().getStringValue().trim();
214                    if (!location.equals("")) {
215                        if (location.startsWith("/")) {
216                            location = location.substring(1);
217                        }
218                        try {
219                            File targetFile = webModule.getEarContext().getTargetFile(new URI(location));
220                            if (targetFile!=null) {
221                                tldURLs.add(targetFile.toURL());
222                            }
223                        }
224                        catch (MalformedURLException mfe) {
225                            throw new DeploymentException("Could not locate TLD file specified in <taglib>: URI: " + uri + " Location: " + location + " " + mfe.getMessage(), mfe);
226                        }
227                        catch (URISyntaxException use) {
228                            throw new DeploymentException("Could not locate TLD file specified in <taglib>: URI: " + uri + " Location: " + location + " " + use.getMessage(), use);
229                        }
230                    }
231                }
232            }
233    
234            // 2. TLD(s) in JAR files in WEB-INF/lib
235            // 3. TLD(s) under WEB-INF
236            List<URL> tempURLs = scanModule(webModule);
237            for (URL webInfURL : tempURLs) {
238                tldURLs.add(webInfURL);
239            }
240    
241            // 4. All TLD files in all META-INF(s)
242            tempURLs.clear();
243            try {
244                Enumeration<URL> enumURLs = webModule.getEarContext().getClassLoader().getResources("META-INF");
245                while (enumURLs.hasMoreElements()) {
246                    URL enumURL = enumURLs.nextElement();
247                    tempURLs = scanDirectory(enumURL);
248                    for (URL metaInfURL : tempURLs) {
249                        tldURLs.add(metaInfURL);
250                    }
251                    tempURLs.clear();
252                }
253            }
254            catch (IOException ioe) {
255                throw new DeploymentException("Could not locate TLD files located in META-INF(s) " + ioe.getMessage(), ioe);
256            }
257    
258            log.debug("getTldFiles() Exit: URL[" + tldURLs.size() + "]: " + tldURLs.toString());
259            return tldURLs;
260        }
261    
262    
263        /**
264         * scanModule(): Scan the module being deployed for JAR files or TLD files in the WEB-INF
265         * directory
266         *
267         * @param webModule module being deployed
268         * @return list of the URL(s) for the TLD files in the module
269         * @throws DeploymentException if module cannot be scanned
270         */
271        private List<URL> scanModule(WebModule webModule) throws DeploymentException {
272            log.debug("scanModule( " + webModule.getName() + " ): Entry");
273    
274            List<URL> modURLs = new ArrayList<URL>();
275            try {
276                Enumeration<JarEntry> entries = webModule.getModuleFile().entries();
277                while (entries.hasMoreElements()) {
278                    JarEntry jarEntry = entries.nextElement();
279                    if (jarEntry.getName().startsWith("WEB-INF/") && jarEntry.getName().endsWith(".tld")) {
280                        File targetFile = webModule.getEarContext().getTargetFile(new URI(jarEntry.getName()));
281                        if (targetFile!=null) {
282                            modURLs.add(targetFile.toURL());
283                        }
284                    }
285                    if (jarEntry.getName().startsWith("WEB-INF/lib/") && jarEntry.getName().endsWith(".jar")) {
286                        File targetFile = webModule.getEarContext().getTargetFile(new URI(jarEntry.getName()));
287                        List<URL> jarUrls = scanJAR(new JarFile(targetFile), null);
288                        for (URL jarURL : jarUrls) {
289                            modURLs.add(jarURL);
290                        }
291                    }
292                }
293            }
294            catch (IOException ioe) {
295                throw new DeploymentException("Could not scan module for TLD files: " + webModule.getName() + " " + ioe.getMessage(), ioe);
296            }
297            catch (Exception e) {
298                throw new DeploymentException("Could not scan module for TLD files: " + webModule.getName() + " " + e.getMessage(), e);
299            }
300    
301            log.debug("scanModule() Exit: URL[" + modURLs.size() + "]: " + modURLs.toString());
302            return modURLs;
303        }
304    
305    
306        /**
307         * scanJAR(): Scan a JAR files looking for all TLD
308         *
309         * @param jarFile jar file to scan
310         * @param prefix  Optional prefix to limit the search to a specific subdirectory in the JAR file
311         * @return list of the URL(s) for the TLD files in the JAR file
312         * @throws DeploymentException if jar file cannot be scanned
313         */
314        private List<URL> scanJAR(JarFile jarFile, String prefix) throws DeploymentException {
315            log.debug("scanJAR( " + jarFile.getName() + " ): Entry");
316    
317            List<URL> jarURLs = new ArrayList<URL>();
318            try {
319                Enumeration<JarEntry> entries = jarFile.entries();
320                while (entries.hasMoreElements()) {
321                    JarEntry jarEntry = entries.nextElement();
322                    URL tempURL = null;
323                    if (prefix != null) {
324                        if (jarEntry.getName().endsWith(".tld") && jarEntry.getName().startsWith(prefix)) {
325                            tempURL = new URL("jar:file:" + jarFile.getName() + "!/" + jarEntry.getName());
326                        }
327                    } else {
328                        if (jarEntry.getName().endsWith(".tld")) {
329                            tempURL = new URL("jar:file:" + jarFile.getName() + "!/" + jarEntry.getName());
330                        }
331                    }
332                    if (tempURL != null) {
333                        jarURLs.add(tempURL);
334                    }
335                }
336            }
337            catch (MalformedURLException mfe) {
338                throw new DeploymentException("Could not scan JAR file for TLD files: " + jarFile.getName() + " " + mfe.getMessage(), mfe);
339            }
340            catch (Exception e) {
341                throw new DeploymentException("Could not scan JAR file for TLD files: " + jarFile.getName() + " " + e.getMessage(), e);
342            }
343    
344            log.debug("scanJAR() Exit: URL[" + jarURLs.size() + "]: " + jarURLs.toString());
345            return jarURLs;
346        }
347    
348    
349        /**
350         * scanDirectory(): Scan a directory for all TLD files
351         *
352         * @param url URL for the directory to be scanned
353         * @return list of the URL(s) for the TLD files in the directory
354         * @throws DeploymentException if directory cannot be scanned
355         */
356        private List<URL> scanDirectory(URL url) throws DeploymentException {
357            log.debug("scanDirectory( " + url.toString() + " ): Entry");
358    
359            List<URL> dirURLs = new ArrayList<URL>();
360            File directory;
361            if (url != null) {
362                if (url.toString().startsWith("jar:file:")) {
363                    try {
364                        JarURLConnection jarConnection = (JarURLConnection) url.openConnection();
365                        URL urlJC = jarConnection.getJarFileURL();
366                        URI baseURI = new URI(urlJC.toString().replaceAll(" ", "%20"));
367                        directory = new File(baseURI);
368                        if (directory.isDirectory()) {
369                            if (directory.canRead()) {
370                                JarFile temp = new JarFile(directory);
371                                List<URL> tempURLs = scanJAR(temp, "META-INF");
372                                for (URL jarURL : tempURLs) {
373                                    dirURLs.add(jarURL);
374                                }
375                            } else {
376                                log.warn("Cannot read JAR file: " + url.toString());
377                            }
378                        }
379                    }
380                    catch (Exception e) {
381                        throw new DeploymentException("Could not scan directory for TLD files: " + url.toString() + " " + e.getMessage(), e);
382                    }
383                } else if (url.toString().startsWith("file:")) {
384                    try {
385                        URI baseURI = new URI(url.toString().replaceAll(" ", "%20"));
386                        directory = new File(baseURI);
387                        if (directory.isDirectory() && directory.canRead()) {
388                            File[] children = directory.listFiles();
389                            for (File child : children) {
390                                if (child.getName().endsWith(".tld")) {
391                                    dirURLs.add(child.toURL());
392                                }
393                            }
394                        } else {
395                            log.warn("Cannot read directory: " + url.toString());
396                        }
397                    }
398                    catch (Exception e) {
399                        throw new DeploymentException("Could not scan directory for TLD files: " + url.toString() + " " + e.getMessage(), e);
400                    }
401                } else if (url.toString().startsWith("jar:")) {
402                    log.warn("URL type not accounted for: " + url.toString());
403                }
404            }
405    
406            log.debug("scanDirectory() Exit: URL[" + dirURLs.size() + "]: " + dirURLs.toString());
407            return dirURLs;
408        }
409    
410    
411        private List<Class> getListenerClasses(WebAppType webApp, WebModule webModule, List<URL> urls, Set<String> listenerNames) throws DeploymentException {
412            log.debug("getListenerClasses( " + webApp.toString() + "," + '\n' +
413                    webModule.getName() + " ): Entry");
414    
415            // Get the classloader from the module's EARContext
416            ClassLoader classLoader = webModule.getEarContext().getClassLoader();
417            List<Class> classes = new ArrayList<Class>();
418    
419            for (URL url : urls) {
420                parseTldFile(url, classLoader, classes, listenerNames);
421            }
422    
423            log.debug("getListenerClasses() Exit: Classes[" + classes.size() + "]: " + classes.toString());
424            return classes;
425        }
426    
427    
428        private void parseTldFile(URL url, ClassLoader classLoader, List<Class> classes, Set<String> listenerNames) throws DeploymentException {
429            log.debug("parseTLDFile( " + url.toString() + " ): Entry");
430    
431            try {
432                XmlObject xml = XmlBeansUtil.parse(url, null);
433                TaglibDocument tld = convertToTaglibSchema(xml);
434                TldTaglibType tl = tld.getTaglib();
435    
436                // Get all the listeners from the TLD file
437                ListenerType[] listeners = tl.getListenerArray();
438                for (ListenerType listener : listeners) {
439                    FullyQualifiedClassType cls = listener.getListenerClass();
440                    String className = cls.getStringValue().trim();
441                    listenerNames.add(className);
442                    try {
443                        Class clas = classLoader.loadClass(className);
444                        classes.add(clas);
445                    }
446                    catch (ClassNotFoundException e) {
447                        log.warn("JspModuleBuilderExtension: Could not load listener class: " + className + " mentioned in TLD file at " + url.toString());
448                    }
449                }
450    
451                // Get all the tags from the TLD file
452                TagType[] tags = tl.getTagArray();
453                for (TagType tag : tags) {
454                    FullyQualifiedClassType cls = tag.getTagClass();
455                    String className = cls.getStringValue().trim();
456                    try {
457                        Class clas = classLoader.loadClass(className);
458                        classes.add(clas);
459                    }
460                    catch (ClassNotFoundException e) {
461                        log.warn("JspModuleBuilderExtension: Could not load tag class: " + className + " mentioned in TLD file at " + url.toString());
462                    }
463                }
464            }
465            catch (XmlException xmle) {
466                throw new DeploymentException("Could not parse TLD file at " + url.toString(), xmle);
467            }
468            catch (IOException ioe) {
469                throw new DeploymentException("Could not find TLD file at " + url.toString(), ioe);
470            }
471    
472            log.debug("parseTLDFile(): Exit");
473        }
474    
475    
476        /**
477         * convertToTaglibSchema(): Convert older TLD files based on the 1.1 and 1.2 DTD or the 2.0 XSD
478         * schemas
479         *
480         * <p><strong>Note(s):</strong>
481         * <ul>
482         *      <li>Those tags from the 1.1 and 1.2 DTD that are no longer valid (e.g., jsp-version) are
483         *      removed
484         *      <li>Valid  tags from the 1.1 and 1.2 DTD are converted (e.g., tlibversion to
485         *      tlib-version)
486         *      <li>The <taglib> root and the <tag> root elements are reordered as necessary (i.e.,
487         *      description, display-name)
488         *      <li>The <rtexprvalue> tag is inserted in the &lt;attribute> tag if necessary since it was
489         *      not required to preceed <type> in 2.0 schema. Default value of false is used.
490         * </ul>
491         *
492         * @param xmlObject possibly old-style tag lib document
493         * @return converted TagLibDocument in the new shiny schema
494         * @throws XmlException if something goes horribly wrong
495         */
496        protected static TaglibDocument convertToTaglibSchema(XmlObject xmlObject) throws XmlException {
497            log.debug("convertToTaglibSchema( " + xmlObject.toString() + " ): Entry");
498    
499            XmlCursor cursor = xmlObject.newCursor();
500            XmlCursor moveable = xmlObject.newCursor();
501            try {
502                cursor.toStartDoc();
503                cursor.toFirstChild();
504                if (SchemaConversionUtils.JAVAEE_NAMESPACE.equals(cursor.getName().getNamespaceURI())) {
505                    log.debug("Nothing to do");
506                }
507                else if (SchemaConversionUtils.J2EE_NAMESPACE.equals(cursor.getName().getNamespaceURI())) {
508                    log.debug("Converting XSD 2.0 to 2.1 schema");
509                    SchemaConversionUtils.convertSchemaVersion(cursor, SchemaConversionUtils.JAVAEE_NAMESPACE, SCHEMA_LOCATION_URL, VERSION);
510                    cursor.toStartDoc();
511                    cursor.toChild(SchemaConversionUtils.JAVAEE_NAMESPACE, "taglib");
512                    cursor.toFirstChild();
513                    do {
514                        String name = cursor.getName().getLocalPart();
515                        if ("tag".equals(name)) {
516                            cursor.push();
517                            cursor.toFirstChild();
518                            SchemaConversionUtils.convertToDescriptionGroup(SchemaConversionUtils.JAVAEE_NAMESPACE, cursor, moveable);
519                            do {
520                                name = cursor.getName().getLocalPart();
521                                boolean rtexprvalueFound = false;
522                                boolean typeFound = false;
523                                if ("attribute".equals(name)) {
524                                    cursor.push();
525                                    cursor.toFirstChild();
526                                    do {
527                                        name = cursor.getName().getLocalPart();
528                                        if ("rtexprvalue".equals(name)) {
529                                            rtexprvalueFound = true;
530                                        }
531                                        if ("type".equals(name)) {
532                                            typeFound = true;
533                                        }
534                                    } while (cursor.toNextSibling());
535                                    cursor.pop();
536                                    if (typeFound && !rtexprvalueFound) {
537                                        //--------------------------------------------------------------
538                                        // Handle the case where the <type> tag must now be preceded by
539                                        // the <rtexprvalue> tag in the 2.1 schema. Cases are:
540                                        // 1: Only type found:
541                                        //      We are currently positioned directly after the attribute
542                                        //      tag (via the pop) so just insert the rtexprvalue tag
543                                        //      with the default value. The tags will be properly
544                                        //      ordered below.
545                                        // 2: Both type and rtexprvalue found:
546                                        //      The tags will be properly ordered below with the
547                                        //      convertToAttributeGroup() call, so nothing to do
548                                        // 3: Only rtexprvalue found:
549                                        //      Nothing to do
550                                        // 4: Neither found:
551                                        //      Nothing to do
552                                        //--------------------------------------------------------------
553                                        cursor.push();
554                                        cursor.toFirstChild();
555                                        cursor.insertElementWithText("rtexprvalue", SchemaConversionUtils.JAVAEE_NAMESPACE, "false");
556                                        cursor.pop();
557                                    }
558                                    cursor.push();
559                                    cursor.toFirstChild();
560                                    SchemaConversionUtils.convertToTldAttribute(SchemaConversionUtils.JAVAEE_NAMESPACE, cursor, moveable);
561                                    cursor.pop();
562                                }
563                            } while (cursor.toNextSibling());
564                            cursor.pop();
565                            // Do this conversion last after the other tags have been converted
566                            SchemaConversionUtils.convertToTldTag(SchemaConversionUtils.JAVAEE_NAMESPACE, cursor, moveable);
567                        }
568                    } while (cursor.toNextSibling());
569                }
570                else {
571                    log.debug("Converting DTD to 2.1 schema");
572                    SchemaConversionUtils.convertToSchema(cursor, SchemaConversionUtils.JAVAEE_NAMESPACE, SCHEMA_LOCATION_URL, VERSION);
573                    cursor.toStartDoc();
574                    cursor.toChild(SchemaConversionUtils.JAVAEE_NAMESPACE, "taglib");
575                    cursor.toFirstChild();
576                    SchemaConversionUtils.convertToDescriptionGroup(SchemaConversionUtils.JAVAEE_NAMESPACE, cursor, moveable);
577                    do {
578                        String name = cursor.getName().getLocalPart();
579                        if ("jsp-version".equals(name) ||
580                            "jspversion".equals(name) ||
581                            "info".equals(name)) {
582                            cursor.removeXmlContents();
583                            cursor.removeXml();
584                        }
585                        if ("tlibversion".equals(name)) {
586                            cursor.setName(TLIB_VERSION);
587                        }
588                        if ("tlibversion".equals(name)) {
589                            cursor.setName(TLIB_VERSION);
590                        }
591                        if ("shortname".equals(name)) {
592                            cursor.setName(SHORT_NAME);
593                        }
594                        if ("tag".equals(name)) {
595                            cursor.push();
596                            cursor.toFirstChild();
597                            SchemaConversionUtils.convertToDescriptionGroup(SchemaConversionUtils.JAVAEE_NAMESPACE, cursor, moveable);
598                            boolean bodyContentFound = false;
599                            do {
600                                name = cursor.getName().getLocalPart();
601                                if ("tagclass".equals(name)) {
602                                    cursor.setName(TAG_CLASS);
603                                }
604                                if ("teiclass".equals(name)) {
605                                    cursor.setName(TEI_CLASS);
606                                }
607                                if ("bodycontent".equals(name)) {
608                                    cursor.setName(BODY_CONTENT);
609                                    bodyContentFound = true;
610                                }
611                                if ("body-content".equals(name)) {
612                                    bodyContentFound = true;
613                                }
614                                if ("attribute".equals(name)) {
615                                    cursor.push();
616                                    cursor.toFirstChild();
617                                    SchemaConversionUtils.convertToTldAttribute(SchemaConversionUtils.JAVAEE_NAMESPACE, cursor, moveable);
618                                    cursor.pop();
619                                }
620                                if ("variable".equals(name)) {
621                                    cursor.push();
622                                    cursor.toFirstChild();
623                                    SchemaConversionUtils.convertToTldVariable(SchemaConversionUtils.JAVAEE_NAMESPACE, cursor, moveable);
624                                    cursor.pop();
625                                }
626                                if ("info".equals(name)) {
627                                    cursor.removeXmlContents();
628                                    cursor.removeXml();
629                                }
630                            } while (cursor.toNextSibling());
631                            cursor.pop();
632                            if (!bodyContentFound) {
633                                //--------------------------------------------------------------
634                                // Handle the case where the <body-content> tag is missing. We
635                                // are currently positioned directly after the <tag> attribute
636                                // (via the pop) so just insert the <body-content> tag with the
637                                // default value. The tags will be properly ordered below.
638                                //--------------------------------------------------------------
639                                cursor.push();
640                                cursor.toFirstChild();
641                                cursor.insertElementWithText("body-content", SchemaConversionUtils.JAVAEE_NAMESPACE, "scriptless");
642                                cursor.pop();
643                            }
644                            // Do this conversion last after the other tags have been converted
645                            cursor.push();
646                            cursor.toFirstChild();
647                            SchemaConversionUtils.convertToTldTag(SchemaConversionUtils.JAVAEE_NAMESPACE, cursor, moveable);
648                            cursor.pop();
649                        }
650                        if ("validator".equals(name)) {
651                            cursor.push();
652                            cursor.toFirstChild();
653                            SchemaConversionUtils.convertToTldValidator(SchemaConversionUtils.JAVAEE_NAMESPACE, cursor, moveable);
654                            do {
655                                name = cursor.getName().getLocalPart();
656                                if ("init-param".equals(name)) {
657                                    cursor.push();
658                                    cursor.toFirstChild();
659                                    SchemaConversionUtils.convertToTldInitParam(SchemaConversionUtils.JAVAEE_NAMESPACE, cursor, moveable);
660                                    cursor.pop();
661                                }
662                            } while (cursor.toNextSibling());
663                            cursor.pop();
664                        }
665                    } while (cursor.toNextSibling());
666                }
667            }
668            finally {
669                cursor.dispose();
670                moveable.dispose();
671            }
672            XmlObject result = xmlObject.changeType(TaglibDocument.type);
673            if (result != null) {
674                try {
675                    XmlBeansUtil.validateDD(result);
676                } catch (XmlException e) {
677                    log.warn("Invalid transformed taglib", e);
678                }
679                log.debug("convertToTaglibSchema( " + result.toString() + " ): Exit 1");
680                return (TaglibDocument) result;
681            }
682            try {
683                XmlBeansUtil.validateDD(xmlObject);
684            } catch (XmlException e) {
685                log.warn("Invalid transformed taglib", e);
686            }
687            log.debug("convertToTaglibSchema( " + xmlObject.toString() + " ): Exit 2");
688            return (TaglibDocument) xmlObject;
689        }
690    
691    
692        public static final GBeanInfo GBEAN_INFO;
693    
694        static {
695            GBeanInfoBuilder infoBuilder = GBeanInfoBuilder.createStatic(JspModuleBuilderExtension.class, NameFactory.MODULE_BUILDER);
696            infoBuilder.addAttribute("defaultEnvironment", Environment.class, true, true);
697            infoBuilder.addReference("NamingBuilders", NamingBuilder.class, NameFactory.MODULE_BUILDER);
698    
699            infoBuilder.setConstructor(new String[]{
700                    "defaultEnvironment",
701                    "NamingBuilders"});
702            GBEAN_INFO = infoBuilder.getBeanInfo();
703        }
704    
705        public static GBeanInfo getGBeanInfo() {
706            return GBEAN_INFO;
707        }
708    }