1 16 package org.apache.commons.jelly.impl; 17 18 import java.io.IOException ; 19 import java.lang.reflect.InvocationTargetException ; 20 import java.net.MalformedURLException ; 21 import java.net.URL ; 22 import java.util.Collections ; 23 import java.util.Hashtable ; 24 import java.util.Iterator ; 25 import java.util.Map ; 26 import java.util.WeakHashMap ; 27 28 import org.apache.commons.beanutils.ConvertingWrapDynaBean; 29 import org.apache.commons.beanutils.ConvertUtils; 30 import org.apache.commons.beanutils.DynaBean; 31 import org.apache.commons.beanutils.DynaProperty; 32 33 import org.apache.commons.jelly.CompilableTag; 34 import org.apache.commons.jelly.JellyContext; 35 import org.apache.commons.jelly.JellyException; 36 import org.apache.commons.jelly.JellyTagException; 37 import org.apache.commons.jelly.DynaTag; 38 import org.apache.commons.jelly.LocationAware; 39 import org.apache.commons.jelly.NamespaceAwareTag; 40 import org.apache.commons.jelly.Script; 41 import org.apache.commons.jelly.Tag; 42 import org.apache.commons.jelly.XMLOutput; 43 import org.apache.commons.jelly.expression.Expression; 44 45 import org.apache.commons.logging.Log; 46 import org.apache.commons.logging.LogFactory; 47 48 import org.xml.sax.Attributes ; 49 import org.xml.sax.Locator ; 50 import org.xml.sax.SAXException ; 51 52 61 public class TagScript implements Script { 62 63 64 private static final Log log = LogFactory.getLog(TagScript.class); 65 66 67 68 protected Map attributes = new Hashtable (); 69 70 71 private Map tagNamespacesMap; 72 73 78 private Map namespaceContext; 79 80 81 private String fileName; 82 83 84 private String elementName; 85 86 87 private String localName; 88 89 90 private int lineNumber = -1; 91 92 93 private int columnNumber = -1; 94 95 96 private TagFactory tagFactory; 97 98 99 private Script tagBody; 100 101 102 private TagScript parent; 103 104 105 private Attributes saxAttributes; 106 107 108 private URL scriptURL = null; 109 110 112 private Map threadLocalTagCache = Collections.synchronizedMap(new WeakHashMap ()); 113 114 118 public static TagScript newInstance(Class tagClass) { 119 TagFactory factory = new DefaultTagFactory(tagClass); 120 return new TagScript(factory); 121 } 122 123 public TagScript() { 124 } 125 126 public TagScript(TagFactory tagFactory) { 127 this.tagFactory = tagFactory; 128 } 129 130 public String toString() { 131 return super.toString() + "[tag=" + elementName + ";at=" + lineNumber + ":" + columnNumber + "]"; 132 } 133 134 137 public Script compile() throws JellyException { 138 if (tagBody != null) { 139 tagBody = tagBody.compile(); 140 } 141 return this; 142 } 143 144 148 public void setTagNamespacesMap(Map tagNamespacesMap) { 149 if ( ! (tagNamespacesMap instanceof Hashtable ) ) { 151 tagNamespacesMap = new Hashtable ( tagNamespacesMap ); 152 } 153 this.tagNamespacesMap = tagNamespacesMap; 154 } 155 156 160 public void setLocator(Locator locator) { 161 setLineNumber( locator.getLineNumber() ); 162 setColumnNumber( locator.getColumnNumber() ); 163 } 164 165 166 169 public void addAttribute(String name, Expression expression) { 170 if (log.isDebugEnabled()) { 171 log.debug("adding attribute name: " + name + " expression: " + expression); 172 } 173 attributes.put(name, new ExpressionAttribute(name,expression)); 174 } 175 176 179 public void addAttribute(String name, String prefix, String nsURI, Expression expression) { 180 if (log.isDebugEnabled()) { 181 log.debug("adding attribute name: " + name + " expression: " + expression); 182 } 183 if(name.indexOf(':')==-1) 184 name = prefix + ':' + name; 185 attributes.put(name, new ExpressionAttribute(name,prefix,nsURI,expression)); 186 } 187 188 192 private URL getJellyContextURL(URL url) throws MalformedURLException { 193 String text = url.toString(); 194 int idx = text.lastIndexOf('/'); 195 text = text.substring(0, idx + 1); 196 return new URL (text); 197 } 198 199 202 203 public void run(JellyContext context, XMLOutput output) throws JellyTagException { 204 URL rootURL = context.getRootURL(); 205 URL currentURL = context.getCurrentURL(); 206 if ( ! context.isCacheTags() ) { 207 clearTag(); 208 } 209 try { 210 Tag tag = getTag(context); 211 if ( tag == null ) { 212 return; 213 } 214 tag.setContext(context); 215 setContextURLs(context); 216 217 if ( tag instanceof DynaTag ) { 218 DynaTag dynaTag = (DynaTag) tag; 219 220 for (Iterator iter = attributes.entrySet().iterator(); iter.hasNext();) { 222 Map.Entry entry = (Map.Entry ) iter.next(); 223 String name = (String ) entry.getKey(); 224 Expression expression = ((ExpressionAttribute) entry.getValue()).exp; 225 226 Class type = dynaTag.getAttributeType(name); 227 Object value = null; 228 if (type != null && type.isAssignableFrom(Expression.class) && !type.isAssignableFrom(Object .class)) { 229 value = expression; 230 } 231 else { 232 value = expression.evaluateRecurse(context); 233 } 234 dynaTag.setAttribute(name, value); 235 } 236 } 237 else { 238 DynaBean dynaBean = new ConvertingWrapDynaBean( tag ); 240 for (Iterator iter = attributes.entrySet().iterator(); iter.hasNext();) { 241 Map.Entry entry = (Map.Entry ) iter.next(); 242 String name = (String ) entry.getKey(); 243 Expression expression = ((ExpressionAttribute) entry.getValue()).exp; 244 245 DynaProperty property = dynaBean.getDynaClass().getDynaProperty(name); 246 if (property == null) { 247 throw new JellyException("This tag does not understand the '" + name + "' attribute" ); 248 } 249 Class type = property.getType(); 250 251 Object value = null; 252 if (type.isAssignableFrom(Expression.class) && !type.isAssignableFrom(Object .class)) { 253 value = expression; 254 } 255 else { 256 value = expression.evaluateRecurse(context); 257 } 258 dynaBean.set(name, value); 259 } 260 } 261 262 tag.doTag(output); 263 if (output != null) { 264 output.flush(); 265 } 266 } 267 catch (JellyTagException e) { 268 handleException(e); 269 } catch (JellyException e) { 270 handleException(e); 271 } catch (IOException e) { 272 handleException(e); 273 } catch (RuntimeException e) { 274 handleException(e); 275 } 276 catch (Error e) { 277 282 handleException(e); 283 } finally { 284 context.setRootURL(rootURL); 285 context.setCurrentURL(currentURL); 286 } 287 288 } 289 290 295 protected void setContextURLs(JellyContext context) throws JellyTagException { 296 if ((context.getCurrentURL() == null || context.getRootURL() == null) && scriptURL != null) 297 { 298 if (context.getRootURL() == null) context.setRootURL(scriptURL); 299 if (context.getCurrentURL() == null) context.setCurrentURL(scriptURL); 300 } 301 } 302 303 306 309 public Tag getTag(JellyContext context) throws JellyException { 310 Thread t = Thread.currentThread(); 311 Tag tag = (Tag) threadLocalTagCache.get(t); 312 if ( tag == null ) { 313 tag = createTag(); 314 if ( tag != null ) { 315 threadLocalTagCache.put(t,tag); 316 configureTag(tag,context); 317 } 318 } 319 return tag; 320 } 321 322 326 public TagFactory getTagFactory() { 327 return tagFactory; 328 } 329 330 334 public void setTagFactory(TagFactory tagFactory) { 335 this.tagFactory = tagFactory; 336 } 337 338 342 public TagScript getParent() { 343 return parent; 344 } 345 346 350 public Script getTagBody() { 351 return tagBody; 352 } 353 354 358 public void setParent(TagScript parent) { 359 this.parent = parent; 360 } 361 362 366 public void setTagBody(Script tagBody) { 367 this.tagBody = tagBody; 368 } 369 370 373 public String getFileName() { 374 return fileName; 375 } 376 377 380 public void setFileName(String fileName) { 381 this.fileName = fileName; 382 try 383 { 384 this.scriptURL = getJellyContextURL(new URL (fileName)); 385 } catch (MalformedURLException e) { 386 log.debug("error setting script url", e); 387 } 388 } 389 390 391 394 public String getElementName() { 395 return elementName; 396 } 397 398 401 public void setElementName(String elementName) { 402 this.elementName = elementName; 403 } 404 407 public int getLineNumber() { 408 return lineNumber; 409 } 410 411 414 public void setLineNumber(int lineNumber) { 415 this.lineNumber = lineNumber; 416 } 417 418 421 public int getColumnNumber() { 422 return columnNumber; 423 } 424 425 428 public void setColumnNumber(int columnNumber) { 429 this.columnNumber = columnNumber; 430 } 431 432 436 public Attributes getSaxAttributes() { 437 return saxAttributes; 438 } 439 440 444 public void setSaxAttributes(Attributes saxAttributes) { 445 this.saxAttributes = saxAttributes; 446 } 447 448 452 public String getLocalName() { 453 return localName; 454 } 455 456 460 public void setLocalName(String localName) { 461 this.localName = localName; 462 } 463 464 465 473 public synchronized Map getNamespaceContext() { 474 if (namespaceContext == null) { 475 if (parent != null) { 476 namespaceContext = getParent().getNamespaceContext(); 477 if (tagNamespacesMap != null && !tagNamespacesMap.isEmpty()) { 478 Hashtable newContext = new Hashtable (namespaceContext.size()+1); 480 newContext.putAll(namespaceContext); 481 newContext.putAll(tagNamespacesMap); 482 namespaceContext = newContext; 483 } 484 } 485 else { 486 namespaceContext = tagNamespacesMap; 487 if (namespaceContext == null) { 488 namespaceContext = new Hashtable (); 489 } 490 } 491 } 492 return namespaceContext; 493 } 494 495 498 502 protected Tag createTag() throws JellyException { 503 if ( tagFactory != null) { 504 return tagFactory.createTag(localName, getSaxAttributes()); 505 } 506 return null; 507 } 508 509 510 513 protected void configureTag(Tag tag, JellyContext context) throws JellyException { 514 if (tag instanceof CompilableTag) { 515 ((CompilableTag) tag).compile(); 516 } 517 Tag parentTag = null; 518 if ( parent != null ) { 519 parentTag = parent.getTag(context); 520 } 521 tag.setParent( parentTag ); 522 tag.setBody( tagBody ); 523 524 if (tag instanceof NamespaceAwareTag) { 525 NamespaceAwareTag naTag = (NamespaceAwareTag) tag; 526 naTag.setNamespaceContext(getNamespaceContext()); 527 } 528 if (tag instanceof LocationAware) { 529 applyLocation((LocationAware) tag); 530 } 531 } 532 533 536 protected void clearTag() { 537 Thread t = Thread.currentThread(); 538 threadLocalTagCache.put(t,null); 539 } 540 541 545 protected void setTag(Tag tag, JellyContext context) { 546 Thread t = Thread.currentThread(); 547 threadLocalTagCache.put(t,tag); 548 } 549 550 553 protected void startNamespacePrefixes(XMLOutput output) throws SAXException { 554 if ( tagNamespacesMap != null ) { 555 for ( Iterator iter = tagNamespacesMap.entrySet().iterator(); iter.hasNext(); ) { 556 Map.Entry entry = (Map.Entry ) iter.next(); 557 String prefix = (String ) entry.getKey(); 558 String uri = (String ) entry.getValue(); 559 output.startPrefixMapping(prefix, uri); 560 } 561 } 562 } 563 564 567 protected void endNamespacePrefixes(XMLOutput output) throws SAXException { 568 if ( tagNamespacesMap != null ) { 569 for ( Iterator iter = tagNamespacesMap.keySet().iterator(); iter.hasNext(); ) { 570 String prefix = (String ) iter.next(); 571 output.endPrefixMapping(prefix); 572 } 573 } 574 } 575 576 582 protected Object convertType(Object value, Class requiredType) 583 throws JellyException { 584 if (requiredType.isInstance(value)) { 585 return value; 586 } 587 if (value instanceof String ) { 588 return ConvertUtils.convert((String ) value, requiredType); 589 } 590 return value; 591 } 592 593 596 protected JellyException createJellyException(String reason) { 597 return new JellyException( 598 reason, fileName, elementName, columnNumber, lineNumber 599 ); 600 } 601 602 605 protected JellyException createJellyException(String reason, Exception cause) { 606 if (cause instanceof JellyException) { 607 return (JellyException) cause; 608 } 609 610 if (cause instanceof InvocationTargetException ) { 611 return new JellyException( 612 reason, 613 ((InvocationTargetException ) cause).getTargetException(), 614 fileName, 615 elementName, 616 columnNumber, 617 lineNumber); 618 } 619 return new JellyException( 620 reason, cause, fileName, elementName, columnNumber, lineNumber 621 ); 622 } 623 624 629 protected void handleException(JellyTagException e) throws JellyTagException { 630 if (log.isTraceEnabled()) { 631 log.trace( "Caught exception: " + e, e ); 632 } 633 634 applyLocation(e); 635 636 throw e; 637 } 638 639 644 protected void handleException(JellyException e) throws JellyTagException { 645 if (log.isTraceEnabled()) { 646 log.trace( "Caught exception: " + e, e ); 647 } 648 649 applyLocation(e); 650 651 throw new JellyTagException(e); 652 } 653 654 protected void applyLocation(LocationAware locationAware) { 655 if (locationAware.getLineNumber() == -1) { 656 locationAware.setColumnNumber(columnNumber); 657 locationAware.setLineNumber(lineNumber); 658 } 659 if ( locationAware.getFileName() == null ) { 660 locationAware.setFileName( fileName ); 661 } 662 if ( locationAware.getElementName() == null ) { 663 locationAware.setElementName( elementName ); 664 } 665 } 666 667 672 protected void handleException(Exception e) throws JellyTagException { 673 if (log.isTraceEnabled()) { 674 log.trace( "Caught exception: " + e, e ); 675 } 676 677 if (e instanceof LocationAware) { 678 applyLocation((LocationAware) e); 679 } 680 681 if ( e instanceof JellyException ) { 682 e.fillInStackTrace(); 683 } 684 685 if ( e instanceof InvocationTargetException ) { 686 throw new JellyTagException( ((InvocationTargetException )e).getTargetException(), 687 fileName, 688 elementName, 689 columnNumber, 690 lineNumber ); 691 } 692 693 throw new JellyTagException(e, fileName, elementName, columnNumber, lineNumber); 694 } 695 696 703 protected void handleException(Error e) throws Error , JellyTagException { 704 if (log.isTraceEnabled()) { 705 log.trace( "Caught exception: " + e, e ); 706 } 707 708 if (e instanceof LocationAware) { 709 applyLocation((LocationAware) e); 710 } 711 712 throw new JellyTagException(e, fileName, elementName, columnNumber, lineNumber); 713 } 714 } 715 716 717 class ExpressionAttribute { 718 public ExpressionAttribute(String name, Expression exp) { 719 this(name,"","",exp); 720 } 721 public ExpressionAttribute(String name, String prefix, String nsURI, Expression exp) { 722 this.name = name; 723 this.prefix = prefix; 724 this.nsURI = nsURI; 725 this.exp = exp; 726 } 727 728 String name; 729 String prefix; 730 String nsURI; 731 Expression exp; 732 } | Popular Tags |