1 33 34 package com.icesoft.faces.webapp.parser; 35 36 import com.icesoft.jasper.JasperException; 37 import com.icesoft.jasper.compiler.TldLocationsCache; 38 import com.icesoft.jasper.xmlparser.ParserUtils; 39 import com.icesoft.jasper.xmlparser.TreeNode; 40 import org.apache.commons.logging.Log; 41 import org.apache.commons.logging.LogFactory; 42 43 import javax.faces.context.ExternalContext; 44 import javax.faces.context.FacesContext; 45 import java.io.File ; 46 import java.io.FileReader ; 47 import java.io.IOException ; 48 import java.io.InputStream ; 49 import java.io.InputStreamReader ; 50 import java.io.Reader ; 51 import java.io.StringBufferInputStream ; 52 import java.io.StringReader ; 53 import java.io.StringWriter ; 54 import java.net.JarURLConnection ; 55 import java.net.URL ; 56 import java.net.URLConnection ; 57 import java.util.Arrays ; 58 import java.util.Enumeration ; 59 import java.util.Hashtable ; 60 import java.util.Iterator ; 61 import java.util.jar.JarEntry ; 62 import java.util.jar.JarFile ; 63 import java.util.regex.Matcher ; 64 import java.util.regex.Pattern ; 65 import java.util.zip.ZipEntry ; 66 67 public class JspPageToDocument { 68 static String JSP_TAGLIB_PATTERN = "<%@\\s*taglib\\s+(.*?)%>"; 69 static String URI_PATTERN = "uri=\"(.*?)\""; 70 static String PREFIX_PATTERN = "prefix=\"(.*?)\""; 71 static String JSP_DECL_PATTERN = "<%.*?%>"; 72 static String STATIC_INCLUDE_PATTERN = 73 "<%@\\s*include\\s+file=\"([^\"]*)\".*?%>"; 74 static String STATIC_INCLUDE_DIRECTIVE_PATTERN = 75 "<\\s*jsp:directive.include\\s+file=\"([^\"]*)\".*?/>"; 76 static String OPEN_TAG_PATTERN = "<\\s*(\\w*\\:*\\w+)([^>]*)>"; 77 static String GENERIC_TAG_PATTERN = "(<\\s*)(/*)(\\w+)([^:])"; 78 static String ATTRIBUTE_PATTERN = "\\s*([^=]*)\\s*=\\s*\"([^\"]*)\""; 79 static String HTML_TAG_PATTERN = "<\\s*html"; 80 static String P_TAG_PATTERN = "<\\s*/*(p)([^>]*?)/*>"; 81 static String IMG_TAG_PATTERN = "<\\s*(img)([^>]*?)/*>"; 82 static String JSP_INCLUDE_PATTERN = "<\\s*jsp:include([^>]*?)/>"; 83 static String BR_TAG_PATTERN = "<\\s*br\\s*>"; 84 static String HR_TAG_PATTERN = "<\\s*hr\\s*>"; 85 static String LINK_TAG_PATTERN = "<\\s*(link)([^>]*?)/*>"; 86 static String META_TAG_PATTERN = "<\\s*(meta)([^>]*?)/*>"; 87 static String INPUT_TAG_PATTERN = "<\\s*(input)([^>]*?)/*>"; 88 static String NBSP_ENTITY_PATTERN = " "; 89 static String COPY_ENTITY_PATTERN = "©"; 90 static String DOC_DECL_PATTERN = "<!DOCTYPE [^>]*>"; 91 static String XML_DECL_PATTERN = "<\\?xml [^>]*\\?>"; 92 93 static String MYFACES_TAG_CLASS = 94 "org/apache/myfaces/taglib/core/ViewTag.class"; 95 static String SUN_TAG_CLASS = "com/sun/faces/taglib/jsf_core/ViewTag.class"; 96 97 private static final Log log = LogFactory.getLog(JspPageToDocument.class); 98 99 public static void main(String [] args) { 100 try { 101 getInputAsString(transform(new FileReader (args[0]))); 102 } catch (Exception e) { 103 e.printStackTrace(); 104 } 105 106 } 107 108 112 public static String transform(String input) { 113 String result = input; 114 115 Pattern jspDeclarationPattern = 116 Pattern.compile(JSP_DECL_PATTERN, Pattern.DOTALL); 117 Matcher jspDeclarationMatcher = jspDeclarationPattern.matcher(result); 118 if (!jspDeclarationMatcher.find()) { 119 return (preprocessJspDocument(result)); 121 } 122 123 result = performStaticInclude(STATIC_INCLUDE_PATTERN, input); 124 125 result = toLowerHTML(result); 126 127 Pattern jspTaglibPattern = 128 Pattern.compile(JSP_TAGLIB_PATTERN, Pattern.DOTALL); 129 Pattern openTagPattern = 130 Pattern.compile(OPEN_TAG_PATTERN, Pattern.DOTALL); 131 Pattern attributePattern = 132 Pattern.compile(ATTRIBUTE_PATTERN, Pattern.DOTALL); 133 Pattern prefixPattern = Pattern.compile(PREFIX_PATTERN, Pattern.DOTALL); 134 Pattern uriPattern = Pattern.compile(URI_PATTERN, Pattern.DOTALL); 135 136 Hashtable declarationsTable = new Hashtable (); 137 Matcher jspTaglibMatcher = jspTaglibPattern.matcher(result); 138 declarationsTable.put("xmlns:jsp", "jsp"); 139 declarationsTable 140 .put("xmlns:icefaces", "http://www.icesoft.com/icefaces"); 141 142 while (jspTaglibMatcher.find()) { 143 String attributes = jspTaglibMatcher.group(1); 144 Matcher prefixMatcher = prefixPattern.matcher(attributes); 145 Matcher uriMatcher = uriPattern.matcher(attributes); 146 prefixMatcher.find(); 147 uriMatcher.find(); 148 String prefix = prefixMatcher.group(1); 149 String url = uriMatcher.group(1); 150 declarationsTable.put("xmlns:" + prefix, url); 151 } 152 153 Matcher openTagMatcher = openTagPattern.matcher(result); 154 openTagMatcher.find(); 155 String tag = openTagMatcher.group(1); 156 String attributes = openTagMatcher.group(2); 157 158 Matcher attributeMatcher = attributePattern.matcher(attributes); 159 while (attributeMatcher.find()) { 160 String name = attributeMatcher.group(1); 161 String value = attributeMatcher.group(2); 162 declarationsTable.put(name, value); 163 } 164 165 Enumeration declarations = declarationsTable.keys(); 166 String namespaceDeclarations = ""; 167 while (declarations.hasMoreElements()) { 168 String prefix = (String ) declarations.nextElement(); 169 String url = (String ) declarationsTable.get(prefix); 170 namespaceDeclarations += prefix + "=\"" + url + "\" "; 171 } 172 173 jspDeclarationMatcher = jspDeclarationPattern.matcher(result); 174 result = jspDeclarationMatcher.replaceAll(""); 175 176 result = "<icefaces:root " + namespaceDeclarations + ">" + 178 result + 179 "</icefaces:root>"; 180 181 Pattern jspIncludePattern = Pattern.compile(JSP_INCLUDE_PATTERN); 182 Matcher jspIncludeMatcher = jspIncludePattern.matcher(result); 183 StringBuffer jspIncludeBuf = new StringBuffer (); 184 while (jspIncludeMatcher.find()) { 185 String args = jspIncludeMatcher.group(1); 186 jspIncludeMatcher.appendReplacement(jspIncludeBuf, 187 "<icefaces:include" + args + 188 " isDynamic=\"#{true}\" />"); 189 } 190 jspIncludeMatcher.appendTail(jspIncludeBuf); 191 result = jspIncludeBuf.toString(); 192 193 result = toSingletonTag(P_TAG_PATTERN, result); 195 result = toSingletonTag(LINK_TAG_PATTERN, result); 196 result = toSingletonTag(META_TAG_PATTERN, result); 197 result = toSingletonTag(IMG_TAG_PATTERN, result); 198 result = toSingletonTag(INPUT_TAG_PATTERN, result); 199 200 Pattern brTagPattern = Pattern.compile(BR_TAG_PATTERN); 201 Matcher brTagMatcher = brTagPattern.matcher(result); 202 result = brTagMatcher.replaceAll("<br/>"); 203 204 Pattern hrTagPattern = Pattern.compile(HR_TAG_PATTERN); 205 Matcher hrTagMatcher = hrTagPattern.matcher(result); 206 result = hrTagMatcher.replaceAll("<hr/>"); 207 208 Pattern nbspEntityPattern = Pattern.compile(NBSP_ENTITY_PATTERN); 209 Matcher nbspEntityMatcher = nbspEntityPattern.matcher(result); 210 result = nbspEntityMatcher.replaceAll("&nbsp"); 212 213 Pattern copyEntityPattern = Pattern.compile(COPY_ENTITY_PATTERN); 214 Matcher copyEntityMatcher = copyEntityPattern.matcher(result); 215 result = copyEntityMatcher.replaceAll("©"); 216 217 Pattern docDeclPattern = Pattern.compile(DOC_DECL_PATTERN); 218 Matcher docDeclMatcher = docDeclPattern.matcher(result); 219 result = docDeclMatcher.replaceAll(""); 220 221 result = unescapeBackslash(result); 222 223 return result; 224 } 225 226 static String preprocessJspDocument(String input) { 227 String result = input; 228 result = performStaticInclude(STATIC_INCLUDE_DIRECTIVE_PATTERN, input); 229 return result; 230 } 231 232 236 public static Reader preprocessJspDocument(Reader input) { 237 String inputString = getInputAsString(input); 238 String outputString = preprocessJspDocument(inputString); 239 return new StringReader (outputString); 240 } 241 242 static String performStaticInclude(String includePatternString, 243 String input) { 244 String result = input; 245 boolean matchFound = true; 246 247 Pattern staticIncludePattern = Pattern.compile(includePatternString); 248 StringBuffer staticIncludeBuf; 249 250 while (matchFound) { 251 matchFound = false; 252 staticIncludeBuf = new StringBuffer (); 253 Matcher staticIncludeMatcher = staticIncludePattern.matcher(result); 254 while (staticIncludeMatcher.find()) { 255 matchFound = true; 256 String args = staticIncludeMatcher.group(1); 257 try { 258 if (!args.startsWith("/")) { 259 String servletPath = FacesContext.getCurrentInstance() 260 .getExternalContext().getRequestServletPath(); 261 String workingDir = servletPath.substring( 0, 262 servletPath.lastIndexOf("/") ); 263 args = workingDir + "/" + args; 264 } 265 String includeString = getInputAsString( 266 new InputStreamReader ( 267 FacesContext.getCurrentInstance() 268 .getExternalContext() 269 .getResource(args) 270 .openConnection() 271 .getInputStream())); 272 Pattern xmlDeclPattern = Pattern.compile(XML_DECL_PATTERN); 274 Matcher xmlDeclMatcher = 275 xmlDeclPattern.matcher(includeString); 276 includeString = xmlDeclMatcher.replaceAll(""); 277 278 staticIncludeMatcher.appendReplacement(staticIncludeBuf, 279 escapeBackreference( 280 includeString)); 281 } catch (Exception e) { 282 staticIncludeMatcher.appendReplacement( 284 staticIncludeBuf, ""); 285 if (log.isErrorEnabled()) { 286 log.error("static include failed to include " + args, 287 e); 288 } 289 } 290 } 291 staticIncludeMatcher.appendTail(staticIncludeBuf); 292 result = staticIncludeBuf.toString(); 293 } 294 return result; 295 } 296 297 static String toSingletonTag(String pattern, String input) { 298 Pattern tagPattern = Pattern.compile(pattern, Pattern.DOTALL); 299 Matcher tagMatcher = tagPattern.matcher(input); 300 StringBuffer tagBuf = new StringBuffer (); 301 while (tagMatcher.find()) { 302 String tagName = tagMatcher.group(1); 303 String attributes = tagMatcher.group(2); 304 tagMatcher.appendReplacement(tagBuf, 305 escapeBackreference("<" + tagName + 306 attributes + 307 "/>")); 308 } 309 tagMatcher.appendTail(tagBuf); 310 return tagBuf.toString(); 311 } 312 313 317 public static String toLowerHTML(String input) { 318 Pattern genericPattern = 319 Pattern.compile(GENERIC_TAG_PATTERN); 320 Matcher genericMatcher = genericPattern.matcher(input); 321 StringBuffer inputBuffer = new StringBuffer (); 322 323 while (genericMatcher.find()) { 324 String openBracket = genericMatcher.group(1); 325 String slash = genericMatcher.group(2); 326 String tagName = genericMatcher.group(3); 327 String trailing = genericMatcher.group(4); 328 if (!"HTML".equals(tagName)) { 329 tagName = tagName.toLowerCase(); 330 } 331 genericMatcher.appendReplacement(inputBuffer, 332 escapeBackreference(openBracket + 333 slash + tagName 334 + trailing)); 335 } 336 genericMatcher.appendTail(inputBuffer); 337 338 return inputBuffer.toString(); 339 } 340 341 345 public static String escapeBackreference(String input) { 346 String result = input; 347 348 Pattern slashPattern = 349 Pattern.compile("\\\\"); 350 Matcher slashMatcher = slashPattern.matcher(result); 351 result = slashMatcher.replaceAll("\\\\\\\\"); 352 353 Pattern dollarPattern = 354 Pattern.compile("\\$"); 355 Matcher dollarMatcher = dollarPattern.matcher(result); 356 result = dollarMatcher.replaceAll("\\\\\\$"); 357 358 return result; 359 } 360 361 365 public static String unescapeBackslash(String input) { 366 String result = input; 367 368 Pattern slashPattern = 369 Pattern.compile("\\\\\\\\"); 370 Matcher slashMatcher = slashPattern.matcher(result); 371 result = slashMatcher.replaceAll("\\\\"); 372 373 return result; 374 375 } 376 377 381 public static Reader transform(Reader input) { 382 String inputString = getInputAsString(input); 383 String outputString = transform(inputString); 384 385 if (log.isTraceEnabled()) { 386 log.trace(outputString); 387 } 388 389 return new StringReader (outputString); 390 } 391 392 398 public static InputStream getTldInputStream( 399 ExternalContext context, String namespaceURL) 400 throws IOException { 401 402 JarFile jarFile = null; 404 String [] location = null; 405 406 namespaceURL = String.valueOf(namespaceURL); 407 408 411 if ("jsp".equals(namespaceURL)) { 412 return null; 413 } 414 415 if ("http://java.sun.com/JSP/Page".equals(namespaceURL)) { 416 return null; 417 } 418 419 TldLocationsCache tldCache = new TldLocationsCache(context); 421 try { 422 location = tldCache.getLocation(namespaceURL); 423 } catch (Exception e) { 424 if (log.isDebugEnabled()) { 425 log.debug(e.getMessage(), e); 426 } 427 } 428 429 if (null == location) { 430 if ( namespaceURL.startsWith("/") && 431 namespaceURL.endsWith(".tld") ) { 432 location = new String [] {namespaceURL}; 433 } 434 } 435 436 if (null == location) { 437 location = scanJars(context, namespaceURL); 438 } 439 440 if (null == location) { 441 URL tagURL = JspPageToDocument.class.getClassLoader() 443 .getResource(MYFACES_TAG_CLASS); 444 if (null != tagURL) { 445 location = scanJar((JarURLConnection ) tagURL.openConnection(), 446 namespaceURL); 447 } 448 } 449 450 if (null == location) { 451 URL tagURL = JspPageToDocument.class.getClassLoader() 453 .getResource(SUN_TAG_CLASS); 454 if (null != tagURL) { 455 456 URLConnection conn = tagURL.openConnection(); 460 if (conn instanceof JarURLConnection ) { 461 location = scanJar((JarURLConnection ) conn, namespaceURL); 462 } 463 } 464 } 465 466 if (null == location) { 467 try { 468 String separator = System.getProperty("path.separator"); 470 String wsDirs = System.getProperty("ws.ext.dirs"); 471 472 String [] dirs = null; 473 if (null != wsDirs) { 474 dirs = wsDirs.split(separator); 475 } else { 476 dirs = new String []{}; 477 } 478 Iterator theDirs = Arrays.asList(dirs).iterator(); 479 while (theDirs.hasNext()) { 480 String dir = (String ) theDirs.next(); 481 try { 482 location = scanJars(dir, namespaceURL); 483 } catch (Exception e) { 484 } 487 if (null != location) { 488 break; 489 } 490 } 491 } catch (Exception e) { 492 if (log.isDebugEnabled()) { 493 log.debug(e.getMessage(), e); 494 } 495 } 496 } 497 498 if (null == location) { 499 String msg = "Can't find TLD for location [" + namespaceURL + 500 "]. JAR containing the TLD may not be in the classpath"; 501 log.error(msg); 502 return null; 503 } else { 504 if (log.isTraceEnabled()) { 505 for (int i = 0; i < location.length; i++) { 506 log.trace("Found TLD location for " + namespaceURL + " = " + 507 location[i]); 508 } 509 } 510 } 511 512 if (!location[0].endsWith("jar")) { 513 return context.getResourceAsStream(location[0]); 514 } else { 515 URL jarFileUrl = new URL ("jar:" + location[0] + "!/"); 517 JarURLConnection conn = (JarURLConnection ) jarFileUrl 518 .openConnection(); 519 conn.setUseCaches(false); 520 conn.connect(); 521 jarFile = conn.getJarFile(); 522 ZipEntry jarEntry = jarFile.getEntry(location[1]); 523 return jarFile.getInputStream(jarEntry); 524 } 525 526 } 527 528 532 public static InputStream stripDoctype(InputStream source) { 533 String result = getInputAsString(new InputStreamReader (source)); 534 535 Pattern docDeclPattern = Pattern.compile(DOC_DECL_PATTERN); 536 Matcher docDeclMatcher = docDeclPattern.matcher(result); 537 result = docDeclMatcher.replaceAll(""); 538 539 return new StringBufferInputStream (result); 540 } 541 542 static String getInputAsString(Reader in) { 543 char[] buf = new char[1024]; 544 StringWriter out = new StringWriter (); 545 546 try { 547 int l = 1; 548 while (l > 0) { 549 l = in.read(buf); 550 if (l > 0) { 551 out.write(buf, 0, l); 552 } 553 } 554 } catch (IOException e) { 555 if (log.isWarnEnabled()) { 556 log.warn(e.getMessage(), e); 557 } 558 } 559 return out.toString(); 560 561 } 562 563 566 static String [] scanJars(ExternalContext context, String namespaceURL) { 567 try { 568 String [] location = null; 569 Iterator paths = 570 context.getResourcePaths("/WEB-INF/lib/").iterator(); 571 while (paths.hasNext()) { 572 String path = (String ) paths.next(); 573 if (!path.endsWith(".jar")) { 574 continue; 575 } 576 path = context.getResource(path).toString(); 577 578 JarURLConnection connection = (JarURLConnection ) 579 new URL ("jar:" + path + "!/").openConnection(); 580 location = scanJar(connection, namespaceURL); 581 if (null != location) { 582 return location; 583 } 584 } 585 } catch (Exception e) { 586 if (log.isWarnEnabled()) { 587 log.warn("Jar scanning under /WEB_INF/lib failed " 588 + e.getMessage(), e); 589 } 590 } 591 592 return null; 593 } 594 595 598 static String [] scanJars(String dir, String namespaceURL) 599 throws IOException { 600 String [] location = null; 601 Iterator paths = Arrays.asList(new File (dir).listFiles()).iterator(); 602 while (paths.hasNext()) { 603 String path = ((File ) paths.next()).getCanonicalPath(); 604 if (!path.endsWith(".jar")) { 605 continue; 606 } 607 608 URL url = new URL ("jar:file:" + path + "!/"); 609 JarURLConnection connection = 610 (JarURLConnection ) url.openConnection(); 611 location = scanJar(connection, namespaceURL); 612 if (null != location) { 613 return location; 614 } 615 } 616 617 return null; 618 } 619 620 static String [] scanJar(JarURLConnection conn, String namespaceURL) 621 throws IOException { 622 JarFile jarFile = null; 623 String resourcePath = conn.getJarFileURL().toString(); 624 625 if (log.isTraceEnabled()) { 626 log.trace("Fallback Scanning Jar " + resourcePath); 627 } 628 629 jarFile = conn.getJarFile(); 630 Enumeration entries = jarFile.entries(); 631 while (entries.hasMoreElements()) { 632 try { 633 JarEntry entry = (JarEntry ) entries.nextElement(); 634 String name = entry.getName(); 635 if (!name.startsWith("META-INF/")) { 636 continue; 637 } 638 if (!name.endsWith(".tld")) { 639 continue; 640 } 641 InputStream stream = jarFile.getInputStream(entry); 642 try { 643 String uri = getUriFromTld(resourcePath, stream); 644 if ((uri != null) && (uri.equals(namespaceURL))) { 645 return (new String []{resourcePath, name}); 646 } 647 } catch (JasperException jpe) { 648 if (log.isDebugEnabled()) { 649 log.debug(jpe.getMessage(), jpe); 650 } 651 } finally { 652 if (stream != null) { 653 stream.close(); 654 } 655 } 656 } catch (Throwable t) { 657 if (log.isDebugEnabled()) { 658 log.debug(t.getMessage(), t); 659 } 660 } 661 } 662 663 return null; 664 } 665 666 667 671 static String getUriFromTld(String resourcePath, InputStream in) 672 throws JasperException { 673 674 TreeNode tld = new ParserUtils().parseXMLDocument(resourcePath, in); 676 TreeNode uri = tld.findChild("uri"); 677 if (uri != null) { 678 String body = uri.getBody(); 679 if (body != null) { 680 return body; 681 } 682 } 683 684 return null; 685 } 686 687 } 688 | Popular Tags |