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 if (log.isDebugEnabled()) { 204 log.debug("getTldFiles( " + webApp.toString() + "," + webModule.getName() + " ): Entry"); 205 } 206 207 List<URL> tldURLs = new ArrayList<URL>(); 208 209 // 1. web.xml <taglib> entries 210 JspConfigType[] jspConfigs = webApp.getJspConfigArray(); 211 for (JspConfigType jspConfig : jspConfigs) { 212 TaglibType[] taglibs = jspConfig.getTaglibArray(); 213 for (TaglibType taglib : taglibs) { 214 String uri = taglib.getTaglibUri().getStringValue().trim(); 215 String location = taglib.getTaglibLocation().getStringValue().trim(); 216 if (!location.equals("")) { 217 if (location.startsWith("/")) { 218 location = location.substring(1); 219 } 220 try { 221 File targetFile = webModule.getEarContext().getTargetFile(createURI(location)); 222 if (targetFile!=null) { 223 tldURLs.add(targetFile.toURL()); 224 } 225 } 226 catch (MalformedURLException mfe) { 227 throw new DeploymentException("Could not locate TLD file specified in <taglib>: URI: " + uri + " Location: " + location + " " + mfe.getMessage(), mfe); 228 } 229 catch (URISyntaxException use) { 230 throw new DeploymentException("Could not locate TLD file specified in <taglib>: URI: " + uri + " Location: " + location + " " + use.getMessage(), use); 231 } 232 } 233 } 234 } 235 236 // 2. TLD(s) in JAR files in WEB-INF/lib 237 // 3. TLD(s) under WEB-INF 238 List<URL> tempURLs = scanModule(webModule); 239 for (URL webInfURL : tempURLs) { 240 tldURLs.add(webInfURL); 241 } 242 243 // 4. All TLD files in all META-INF(s) 244 tempURLs.clear(); 245 try { 246 Enumeration<URL> enumURLs = webModule.getEarContext().getClassLoader().getResources("META-INF"); 247 while (enumURLs.hasMoreElements()) { 248 URL enumURL = enumURLs.nextElement(); 249 tempURLs = scanDirectory(enumURL); 250 for (URL metaInfURL : tempURLs) { 251 tldURLs.add(metaInfURL); 252 } 253 tempURLs.clear(); 254 } 255 } 256 catch (IOException ioe) { 257 throw new DeploymentException("Could not locate TLD files located in META-INF(s) " + ioe.getMessage(), ioe); 258 } 259 260 log.debug("getTldFiles() Exit: URL[" + tldURLs.size() + "]: " + tldURLs.toString()); 261 return tldURLs; 262 } 263 264 265 /** 266 * scanModule(): Scan the module being deployed for JAR files or TLD files in the WEB-INF 267 * directory 268 * 269 * @param webModule module being deployed 270 * @return list of the URL(s) for the TLD files in the module 271 * @throws DeploymentException if module cannot be scanned 272 */ 273 private List<URL> scanModule(WebModule webModule) throws DeploymentException { 274 log.debug("scanModule( " + webModule.getName() + " ): Entry"); 275 276 List<URL> modURLs = new ArrayList<URL>(); 277 try { 278 Enumeration<JarEntry> entries = webModule.getModuleFile().entries(); 279 while (entries.hasMoreElements()) { 280 JarEntry jarEntry = entries.nextElement(); 281 if (jarEntry.getName().startsWith("WEB-INF/") && jarEntry.getName().endsWith(".tld")) { 282 File targetFile = webModule.getEarContext().getTargetFile(createURI(jarEntry.getName())); 283 if (targetFile!=null) { 284 modURLs.add(targetFile.toURL()); 285 } 286 } 287 if (jarEntry.getName().startsWith("WEB-INF/lib/") && jarEntry.getName().endsWith(".jar")) { 288 File targetFile = webModule.getEarContext().getTargetFile(createURI(jarEntry.getName())); 289 List<URL> jarUrls = scanJAR(new JarFile(targetFile), null); 290 for (URL jarURL : jarUrls) { 291 modURLs.add(jarURL); 292 } 293 } 294 } 295 } 296 catch (IOException ioe) { 297 throw new DeploymentException("Could not scan module for TLD files: " + webModule.getName() + " " + ioe.getMessage(), ioe); 298 } 299 catch (Exception e) { 300 throw new DeploymentException("Could not scan module for TLD files: " + webModule.getName() + " " + e.getMessage(), e); 301 } 302 303 log.debug("scanModule() Exit: URL[" + modURLs.size() + "]: " + modURLs.toString()); 304 return modURLs; 305 } 306 307 308 /** 309 * scanJAR(): Scan a JAR files looking for all TLD 310 * 311 * @param jarFile jar file to scan 312 * @param prefix Optional prefix to limit the search to a specific subdirectory in the JAR file 313 * @return list of the URL(s) for the TLD files in the JAR file 314 * @throws DeploymentException if jar file cannot be scanned 315 */ 316 private List<URL> scanJAR(JarFile jarFile, String prefix) throws DeploymentException { 317 log.debug("scanJAR( " + jarFile.getName() + " ): Entry"); 318 319 List<URL> jarURLs = new ArrayList<URL>(); 320 try { 321 Enumeration<JarEntry> entries = jarFile.entries(); 322 while (entries.hasMoreElements()) { 323 JarEntry jarEntry = entries.nextElement(); 324 URL tempURL = null; 325 if (prefix != null) { 326 if (jarEntry.getName().endsWith(".tld") && jarEntry.getName().startsWith(prefix)) { 327 tempURL = new URL("jar:file:" + jarFile.getName() + "!/" + jarEntry.getName()); 328 } 329 } else { 330 if (jarEntry.getName().endsWith(".tld")) { 331 tempURL = new URL("jar:file:" + jarFile.getName() + "!/" + jarEntry.getName()); 332 } 333 } 334 if (tempURL != null) { 335 jarURLs.add(tempURL); 336 } 337 } 338 } 339 catch (MalformedURLException mfe) { 340 throw new DeploymentException("Could not scan JAR file for TLD files: " + jarFile.getName() + " " + mfe.getMessage(), mfe); 341 } 342 catch (Exception e) { 343 throw new DeploymentException("Could not scan JAR file for TLD files: " + jarFile.getName() + " " + e.getMessage(), e); 344 } 345 346 log.debug("scanJAR() Exit: URL[" + jarURLs.size() + "]: " + jarURLs.toString()); 347 return jarURLs; 348 } 349 350 351 /** 352 * scanDirectory(): Scan a directory for all TLD files 353 * 354 * @param url URL for the directory to be scanned 355 * @return list of the URL(s) for the TLD files in the directory 356 * @throws DeploymentException if directory cannot be scanned 357 */ 358 private List<URL> scanDirectory(URL url) throws DeploymentException { 359 log.debug("scanDirectory( " + url.toString() + " ): Entry"); 360 361 List<URL> dirURLs = new ArrayList<URL>(); 362 File directory; 363 if (url != null) { 364 if (url.toString().startsWith("jar:file:")) { 365 try { 366 JarURLConnection jarConnection = (JarURLConnection) url.openConnection(); 367 URL urlJC = jarConnection.getJarFileURL(); 368 URI baseURI = createURI(urlJC.toString()); 369 directory = new File(baseURI); 370 if (directory.isDirectory()) { 371 if (directory.canRead()) { 372 JarFile temp = new JarFile(directory); 373 List<URL> tempURLs = scanJAR(temp, "META-INF"); 374 for (URL jarURL : tempURLs) { 375 dirURLs.add(jarURL); 376 } 377 } else { 378 log.warn("Cannot read JAR file: " + url.toString()); 379 } 380 } 381 } 382 catch (Exception e) { 383 throw new DeploymentException("Could not scan directory for TLD files: " + url.toString() + " " + e.getMessage(), e); 384 } 385 } else if (url.toString().startsWith("file:")) { 386 try { 387 URI baseURI = createURI(url.toString()); 388 directory = new File(baseURI); 389 if (directory.isDirectory() && directory.canRead()) { 390 File[] children = directory.listFiles(); 391 for (File child : children) { 392 if (child.getName().endsWith(".tld")) { 393 dirURLs.add(child.toURL()); 394 } 395 } 396 } else { 397 log.warn("Cannot read directory: " + url.toString()); 398 } 399 } 400 catch (Exception e) { 401 throw new DeploymentException("Could not scan directory for TLD files: " + url.toString() + " " + e.getMessage(), e); 402 } 403 } else if (url.toString().startsWith("jar:")) { 404 log.warn("URL type not accounted for: " + url.toString()); 405 } 406 } 407 408 log.debug("scanDirectory() Exit: URL[" + dirURLs.size() + "]: " + dirURLs.toString()); 409 return dirURLs; 410 } 411 412 413 private List<Class> getListenerClasses(WebAppType webApp, WebModule webModule, List<URL> urls, Set<String> listenerNames) throws DeploymentException { 414 if (log.isDebugEnabled()) { 415 log.debug("getListenerClasses( " + webApp.toString() + "," + '\n' + 416 webModule.getName() + " ): Entry"); 417 } 418 419 // Get the classloader from the module's EARContext 420 ClassLoader classLoader = webModule.getEarContext().getClassLoader(); 421 List<Class> classes = new ArrayList<Class>(); 422 423 for (URL url : urls) { 424 parseTldFile(url, classLoader, classes, listenerNames); 425 } 426 427 if (log.isDebugEnabled()) { 428 log.debug("getListenerClasses() Exit: Classes[" + classes.size() + "]: " + classes.toString()); 429 } 430 return classes; 431 } 432 433 434 private void parseTldFile(URL url, ClassLoader classLoader, List<Class> classes, Set<String> listenerNames) throws DeploymentException { 435 log.debug("parseTLDFile( " + url.toString() + " ): Entry"); 436 437 try { 438 XmlObject xml = XmlBeansUtil.parse(url, null); 439 TaglibDocument tld = convertToTaglibSchema(xml); 440 TldTaglibType tl = tld.getTaglib(); 441 442 // Get all the listeners from the TLD file 443 ListenerType[] listeners = tl.getListenerArray(); 444 for (ListenerType listener : listeners) { 445 FullyQualifiedClassType cls = listener.getListenerClass(); 446 String className = cls.getStringValue().trim(); 447 listenerNames.add(className); 448 try { 449 Class clas = classLoader.loadClass(className); 450 classes.add(clas); 451 } 452 catch (ClassNotFoundException e) { 453 log.warn("JspModuleBuilderExtension: Could not load listener class: " + className + " mentioned in TLD file at " + url.toString()); 454 } 455 } 456 457 // Get all the tags from the TLD file 458 TagType[] tags = tl.getTagArray(); 459 for (TagType tag : tags) { 460 FullyQualifiedClassType cls = tag.getTagClass(); 461 String className = cls.getStringValue().trim(); 462 try { 463 Class clas = classLoader.loadClass(className); 464 classes.add(clas); 465 } 466 catch (ClassNotFoundException e) { 467 log.warn("JspModuleBuilderExtension: Could not load tag class: " + className + " mentioned in TLD file at " + url.toString()); 468 } 469 } 470 } 471 catch (XmlException xmle) { 472 throw new DeploymentException("Could not parse TLD file at " + url.toString(), xmle); 473 } 474 catch (IOException ioe) { 475 throw new DeploymentException("Could not find TLD file at " + url.toString(), ioe); 476 } 477 478 log.debug("parseTLDFile(): Exit"); 479 } 480 481 482 /** 483 * convertToTaglibSchema(): Convert older TLD files based on the 1.1 and 1.2 DTD or the 2.0 XSD 484 * schemas 485 * 486 * <p><strong>Note(s):</strong> 487 * <ul> 488 * <li>Those tags from the 1.1 and 1.2 DTD that are no longer valid (e.g., jsp-version) are 489 * removed 490 * <li>Valid tags from the 1.1 and 1.2 DTD are converted (e.g., tlibversion to 491 * tlib-version) 492 * <li>The <taglib> root and the <tag> root elements are reordered as necessary (i.e., 493 * description, display-name) 494 * <li>The <rtexprvalue> tag is inserted in the <attribute> tag if necessary since it was 495 * not required to preceed <type> in 2.0 schema. Default value of false is used. 496 * </ul> 497 * 498 * @param xmlObject possibly old-style tag lib document 499 * @return converted TagLibDocument in the new shiny schema 500 * @throws XmlException if something goes horribly wrong 501 */ 502 protected static TaglibDocument convertToTaglibSchema(XmlObject xmlObject) throws XmlException { 503 if (log.isDebugEnabled()) { 504 log.debug("convertToTaglibSchema( " + xmlObject.toString() + " ): Entry"); 505 } 506 507 XmlCursor cursor = xmlObject.newCursor(); 508 XmlCursor moveable = xmlObject.newCursor(); 509 try { 510 cursor.toStartDoc(); 511 cursor.toFirstChild(); 512 if (SchemaConversionUtils.JAVAEE_NAMESPACE.equals(cursor.getName().getNamespaceURI())) { 513 log.debug("Nothing to do"); 514 } 515 else if (SchemaConversionUtils.J2EE_NAMESPACE.equals(cursor.getName().getNamespaceURI())) { 516 log.debug("Converting XSD 2.0 to 2.1 schema"); 517 SchemaConversionUtils.convertSchemaVersion(cursor, SchemaConversionUtils.JAVAEE_NAMESPACE, SCHEMA_LOCATION_URL, VERSION); 518 cursor.toStartDoc(); 519 cursor.toChild(SchemaConversionUtils.JAVAEE_NAMESPACE, "taglib"); 520 cursor.toFirstChild(); 521 do { 522 String name = cursor.getName().getLocalPart(); 523 if ("tag".equals(name)) { 524 cursor.push(); 525 cursor.toFirstChild(); 526 SchemaConversionUtils.convertToDescriptionGroup(SchemaConversionUtils.JAVAEE_NAMESPACE, cursor, moveable); 527 do { 528 name = cursor.getName().getLocalPart(); 529 boolean rtexprvalueFound = false; 530 boolean typeFound = false; 531 if ("attribute".equals(name)) { 532 cursor.push(); 533 cursor.toFirstChild(); 534 do { 535 name = cursor.getName().getLocalPart(); 536 if ("rtexprvalue".equals(name)) { 537 rtexprvalueFound = true; 538 } 539 if ("type".equals(name)) { 540 typeFound = true; 541 } 542 } while (cursor.toNextSibling()); 543 cursor.pop(); 544 if (typeFound && !rtexprvalueFound) { 545 //-------------------------------------------------------------- 546 // Handle the case where the <type> tag must now be preceded by 547 // the <rtexprvalue> tag in the 2.1 schema. Cases are: 548 // 1: Only type found: 549 // We are currently positioned directly after the attribute 550 // tag (via the pop) so just insert the rtexprvalue tag 551 // with the default value. The tags will be properly 552 // ordered below. 553 // 2: Both type and rtexprvalue found: 554 // The tags will be properly ordered below with the 555 // convertToAttributeGroup() call, so nothing to do 556 // 3: Only rtexprvalue found: 557 // Nothing to do 558 // 4: Neither found: 559 // Nothing to do 560 //-------------------------------------------------------------- 561 cursor.push(); 562 cursor.toFirstChild(); 563 cursor.insertElementWithText("rtexprvalue", SchemaConversionUtils.JAVAEE_NAMESPACE, "false"); 564 cursor.pop(); 565 } 566 cursor.push(); 567 cursor.toFirstChild(); 568 SchemaConversionUtils.convertToTldAttribute(SchemaConversionUtils.JAVAEE_NAMESPACE, cursor, moveable); 569 cursor.pop(); 570 } 571 } while (cursor.toNextSibling()); 572 cursor.pop(); 573 // Do this conversion last after the other tags have been converted 574 SchemaConversionUtils.convertToTldTag(SchemaConversionUtils.JAVAEE_NAMESPACE, cursor, moveable); 575 } 576 } while (cursor.toNextSibling()); 577 } 578 else { 579 log.debug("Converting DTD to 2.1 schema"); 580 SchemaConversionUtils.convertToSchema(cursor, SchemaConversionUtils.JAVAEE_NAMESPACE, SCHEMA_LOCATION_URL, VERSION); 581 cursor.toStartDoc(); 582 cursor.toChild(SchemaConversionUtils.JAVAEE_NAMESPACE, "taglib"); 583 cursor.toFirstChild(); 584 SchemaConversionUtils.convertToDescriptionGroup(SchemaConversionUtils.JAVAEE_NAMESPACE, cursor, moveable); 585 do { 586 String name = cursor.getName().getLocalPart(); 587 if ("jsp-version".equals(name) || 588 "jspversion".equals(name) || 589 "info".equals(name)) { 590 cursor.removeXmlContents(); 591 cursor.removeXml(); 592 } 593 if ("tlibversion".equals(name)) { 594 cursor.setName(TLIB_VERSION); 595 } 596 if ("tlibversion".equals(name)) { 597 cursor.setName(TLIB_VERSION); 598 } 599 if ("shortname".equals(name)) { 600 cursor.setName(SHORT_NAME); 601 } 602 if ("tag".equals(name)) { 603 cursor.push(); 604 cursor.toFirstChild(); 605 SchemaConversionUtils.convertToDescriptionGroup(SchemaConversionUtils.JAVAEE_NAMESPACE, cursor, moveable); 606 boolean bodyContentFound = false; 607 do { 608 name = cursor.getName().getLocalPart(); 609 if ("tagclass".equals(name)) { 610 cursor.setName(TAG_CLASS); 611 } 612 if ("teiclass".equals(name)) { 613 cursor.setName(TEI_CLASS); 614 } 615 if ("bodycontent".equals(name)) { 616 cursor.setName(BODY_CONTENT); 617 bodyContentFound = true; 618 } 619 if ("body-content".equals(name)) { 620 bodyContentFound = true; 621 } 622 if ("attribute".equals(name)) { 623 cursor.push(); 624 cursor.toFirstChild(); 625 SchemaConversionUtils.convertToTldAttribute(SchemaConversionUtils.JAVAEE_NAMESPACE, cursor, moveable); 626 cursor.pop(); 627 } 628 if ("variable".equals(name)) { 629 cursor.push(); 630 cursor.toFirstChild(); 631 SchemaConversionUtils.convertToTldVariable(SchemaConversionUtils.JAVAEE_NAMESPACE, cursor, moveable); 632 cursor.pop(); 633 } 634 if ("info".equals(name)) { 635 cursor.removeXmlContents(); 636 cursor.removeXml(); 637 } 638 } while (cursor.toNextSibling()); 639 cursor.pop(); 640 if (!bodyContentFound) { 641 //-------------------------------------------------------------- 642 // Handle the case where the <body-content> tag is missing. We 643 // are currently positioned directly after the <tag> attribute 644 // (via the pop) so just insert the <body-content> tag with the 645 // default value. The tags will be properly ordered below. 646 //-------------------------------------------------------------- 647 cursor.push(); 648 cursor.toFirstChild(); 649 cursor.insertElementWithText("body-content", SchemaConversionUtils.JAVAEE_NAMESPACE, "scriptless"); 650 cursor.pop(); 651 } 652 // Do this conversion last after the other tags have been converted 653 cursor.push(); 654 cursor.toFirstChild(); 655 SchemaConversionUtils.convertToTldTag(SchemaConversionUtils.JAVAEE_NAMESPACE, cursor, moveable); 656 cursor.pop(); 657 } 658 if ("validator".equals(name)) { 659 cursor.push(); 660 cursor.toFirstChild(); 661 SchemaConversionUtils.convertToTldValidator(SchemaConversionUtils.JAVAEE_NAMESPACE, cursor, moveable); 662 cursor.pop(); 663 } 664 } while (cursor.toNextSibling()); 665 } 666 } 667 finally { 668 cursor.dispose(); 669 moveable.dispose(); 670 } 671 XmlObject result = xmlObject.changeType(TaglibDocument.type); 672 if (result != null) { 673 try { 674 XmlBeansUtil.validateDD(result); 675 } catch (XmlException e) { 676 log.warn("Invalid transformed taglib", e); 677 } 678 if (log.isDebugEnabled()) { 679 log.debug("convertToTaglibSchema( " + result.toString() + " ): Exit 1"); 680 } 681 return (TaglibDocument) result; 682 } 683 try { 684 XmlBeansUtil.validateDD(xmlObject); 685 } catch (XmlException e) { 686 log.warn("Invalid transformed taglib", e); 687 } 688 if (log.isDebugEnabled()) { 689 log.debug("convertToTaglibSchema( " + xmlObject.toString() + " ): Exit 2"); 690 } 691 return (TaglibDocument) xmlObject; 692 } 693 694 695 private URI createURI(String path) throws URISyntaxException { 696 path = path.replaceAll(" ", "%20"); 697 return new URI(path); 698 } 699 700 public static final GBeanInfo GBEAN_INFO; 701 702 static { 703 GBeanInfoBuilder infoBuilder = GBeanInfoBuilder.createStatic(JspModuleBuilderExtension.class, NameFactory.MODULE_BUILDER); 704 infoBuilder.addAttribute("defaultEnvironment", Environment.class, true, true); 705 infoBuilder.addReference("NamingBuilders", NamingBuilder.class, NameFactory.MODULE_BUILDER); 706 707 infoBuilder.setConstructor(new String[]{ 708 "defaultEnvironment", 709 "NamingBuilders"}); 710 GBEAN_INFO = infoBuilder.getBeanInfo(); 711 } 712 713 public static GBeanInfo getGBeanInfo() { 714 return GBEAN_INFO; 715 } 716 }