1 5 package com.opensymphony.webwork.views.velocity; 6 7 import com.opensymphony.webwork.ServletActionContext; 8 import com.opensymphony.webwork.config.Configuration; 9 import com.opensymphony.webwork.views.jsp.ParamTag; 10 import com.opensymphony.xwork.ActionContext; 11 import com.opensymphony.xwork.util.OgnlUtil; 12 import com.opensymphony.xwork.util.OgnlValueStack; 13 import ognl.Ognl; 14 import org.apache.commons.logging.Log; 15 import org.apache.commons.logging.LogFactory; 16 import org.apache.velocity.app.event.EventCartridge; 17 import org.apache.velocity.context.Context; 18 import org.apache.velocity.context.InternalContextAdapter; 19 import org.apache.velocity.exception.MethodInvocationException; 20 import org.apache.velocity.exception.ParseErrorException; 21 import org.apache.velocity.exception.ResourceNotFoundException; 22 import org.apache.velocity.runtime.directive.Directive; 23 import org.apache.velocity.runtime.parser.node.Node; 24 import org.apache.velocity.runtime.resource.Resource; 25 import org.apache.velocity.util.introspection.IntrospectionCacheData; 26 27 import javax.servlet.jsp.JspException ; 28 import javax.servlet.jsp.PageContext ; 29 import javax.servlet.jsp.tagext.BodyContent ; 30 import javax.servlet.jsp.tagext.BodyTag ; 31 import javax.servlet.jsp.tagext.IterationTag ; 32 import javax.servlet.jsp.tagext.Tag ; 33 import java.io.IOException ; 34 import java.io.Writer ; 35 import java.util.*; 36 37 38 44 public abstract class AbstractTagDirective extends Directive { 45 protected static Log log = LogFactory.getLog(AbstractTagDirective.class); 46 47 public static final String VELOCITY_WRITER = "com.opensymphony.webwork.views.velocity.AbstractTagDirective.VELOCITY_WRITER"; 48 49 56 protected static Map tagclassMap = new HashMap(); 57 58 63 public boolean render(InternalContextAdapter contextAdapter, Writer writer, Node node) throws IOException , ResourceNotFoundException, ParseErrorException, MethodInvocationException { 64 if (node.jjtGetNumChildren() < 1) { 65 throw new ParseErrorException("no tag specified! to use the #tag directive, you must specify at least the name of the tag to use"); 66 } 67 68 Object object = this.createObject(node.jjtGetChild(0)); 70 71 75 Node bodyNode = null; 76 77 81 if (this.getType() == BLOCK) { 82 bodyNode = node.jjtGetChild(node.jjtGetNumChildren() - 1); 83 } 84 85 88 Object currentParent = contextAdapter.get(VelocityManager.PARENT); 89 Object currentTag = contextAdapter.get(VelocityManager.TAG); 90 91 try { 92 contextAdapter.put(VelocityManager.PARENT, currentTag); 94 contextAdapter.put(VelocityManager.TAG, object); 95 96 InternalContextAdapter subContextAdapter = new WrappedInternalContextAdapter(contextAdapter); 97 98 if (object instanceof ParamTag.Parametric) { 100 Map params = ((ParamTag.Parametric) object).getParameters(); 101 102 if (params != null) { 103 params.clear(); 104 } 105 } 106 107 applyAttributes(contextAdapter, node, object); 108 109 if (object instanceof Tag) { 110 PageContext pageContext = ServletActionContext.getPageContext(); 111 112 if (currentTag instanceof Tag) { 113 ((Tag) object).setParent((Tag) currentTag); 114 } 115 116 try { 117 ActionContext.getContext().put(VELOCITY_WRITER, writer); 118 return this.processTag(pageContext, (Tag) object, subContextAdapter, writer, node, bodyNode); 119 } catch (Exception e) { 120 log.error("Error processing tag: " + e, e); 121 122 return false; 123 } 124 } else { 125 return true; 126 } 127 } finally { 128 131 if (currentParent != null) { 132 contextAdapter.put(VelocityManager.PARENT, currentParent); 133 } else { 134 contextAdapter.remove(VelocityManager.PARENT); 135 } 136 137 if (currentTag != null) { 138 contextAdapter.put(VelocityManager.TAG, currentTag); 139 } else { 140 contextAdapter.remove(VelocityManager.TAG); 141 } 142 } 143 } 144 145 151 protected String [] getTagPath() throws ResourceNotFoundException { 152 List pathList = new ArrayList(); 153 154 pathList.add("com.opensymphony.webwork.views.jsp.ui"); 156 pathList.add("com.opensymphony.webwork.views.jsp"); 157 158 if (Configuration.isSet("webwork.velocity.tag.path")) { 160 StringTokenizer st = new StringTokenizer(Configuration.getString("webwork.velocity.tag.path"), ","); 161 162 while (st.hasMoreTokens()) { 163 String token = st.nextToken().trim(); 164 pathList.add(token); 165 } 166 } 167 168 pathList.add(""); 170 171 String [] path = new String [pathList.size()]; 172 pathList.toArray(path); 173 174 return path; 175 } 176 177 187 protected Object createObject(Node node) throws ResourceNotFoundException { 188 String tagname = node.getFirstToken().toString(); 189 190 196 if (tagname.startsWith("\"") && tagname.endsWith("\"")) { 197 tagname = tagname.substring(1, tagname.length() - 1); 198 } 199 200 201 Class clazz = (Class ) tagclassMap.get(tagname); 202 203 if (clazz == null) { 204 clazz = this.findTagInPath(tagname); 205 tagclassMap.put(tagname, clazz); 206 } 207 208 if (clazz == null) { 209 throw new ResourceNotFoundException("No tag, '" + tagname + "', found in tag path"); 210 } 211 212 try { 213 return clazz.newInstance(); 214 } catch (Exception e) { 215 throw new ResourceNotFoundException("unable to instantiate tag class, '" + clazz.getName() + "'"); 216 } 217 } 218 219 232 protected Map createPropertyMap(InternalContextAdapter contextAdapter, Node node) throws ParseErrorException, MethodInvocationException { 233 Map propertyMap = new HashMap(); 234 235 for (int index = 1, length = node.jjtGetNumChildren(); index < length; 236 index++) { 237 this.putProperty(propertyMap, contextAdapter, node.jjtGetChild(index)); 238 } 239 240 return propertyMap; 241 } 242 243 265 protected Class findTagInPath(String tagname) throws ResourceNotFoundException { 266 String [] tagpath = this.getTagPath(); 267 268 Class clazz = null; 269 270 for (int index = 0; (clazz == null) && (index < tagpath.length); 271 index++) { 272 try { 273 clazz = Class.forName(tagpath[index] + "." + tagname + "Tag"); 274 } catch (ClassNotFoundException e) { 275 } 276 277 if (clazz == null) { 278 try { 279 clazz = Class.forName(tagpath[index] + "." + tagname); 280 } catch (ClassNotFoundException e) { 281 } 282 } 283 } 284 285 return clazz; 286 } 287 288 291 protected boolean processTag(PageContext pageContext, Tag tag, InternalContextAdapter context, Writer writer, Node node, Node bodyNode) throws ParseErrorException, IOException , MethodInvocationException, ResourceNotFoundException { 292 tag.setPageContext(pageContext); 293 writer = pageContext.getOut(); 294 295 try { 296 Map paramMap = null; 297 ParamTag.Parametric parameterizedTag = null; 298 299 if (tag instanceof ParamTag.Parametric) { 300 parameterizedTag = (ParamTag.Parametric) tag; 301 paramMap = parameterizedTag.getParameters(); 302 } 303 304 int result = tag.doStartTag(); 305 306 if (paramMap != null) { 307 parameterizedTag.getParameters().putAll(paramMap); 308 } 309 310 if (result != Tag.SKIP_BODY) { 311 if (tag instanceof BodyTag ) { 312 BodyTag bodyTag = (BodyTag ) tag; 313 314 if (result == BodyTag.EVAL_BODY_BUFFERED) { 315 BodyContent bodyContent = pageContext.pushBody(); 316 writer = bodyContent.getEnclosingWriter(); 317 bodyTag.setBodyContent(bodyContent); 318 } 319 320 bodyTag.doInitBody(); 321 } 322 323 for (boolean done = false; !done;) { 324 if (bodyNode != null) { 326 bodyNode.render(context, writer); 327 } 328 329 if (tag instanceof IterationTag ) { 330 IterationTag iterationTag = (IterationTag ) tag; 331 done = (iterationTag.doAfterBody() == BodyTag.EVAL_BODY_AGAIN) ? false : true; 332 } else { 333 done = true; 334 } 335 } 336 337 if (tag instanceof BodyTag ) { 338 if (result == BodyTag.EVAL_BODY_BUFFERED) { 339 writer = pageContext.popBody(); 340 } else { 341 ((BodyTag ) tag).setBodyContent(null); 342 } 343 } 344 } 345 346 tag.doEndTag(); 347 } catch (JspException e) { 348 String gripe = "Fatal exception caught while processing tag, " + tag.getClass().getName(); 349 log.warn(gripe, e); 350 351 String methodName = "-"; 352 throw new MethodInvocationException(gripe, e, methodName); 353 } 354 355 return true; 356 } 357 358 365 protected void putProperty(Map propertyMap, InternalContextAdapter contextAdapter, Node node) throws ParseErrorException, MethodInvocationException { 366 String param = node.value(contextAdapter).toString(); 368 369 int idx = param.indexOf("="); 370 371 if (idx != -1) { 372 String property = param.substring(0, idx); 373 374 String value = param.substring(idx + 1); 375 propertyMap.put(property, value); 376 } else { 377 throw new ParseErrorException("#" + this.getName() + " arguments must include an assignment operator! For example #tag( Component \"template=mytemplate\" ). #tag( TextField \"mytemplate\" ) is illegal!"); 378 } 379 } 380 381 390 private void applyAttributes(InternalContextAdapter context, Node node, Object object) throws ParseErrorException, MethodInvocationException { 391 Map propertyMap = this.createPropertyMap(context, node); 392 393 if ((propertyMap == null) || (propertyMap.size() == 0)) { 395 return; 396 } 397 398 OgnlValueStack stack = ActionContext.getContext().getValueStack(); 399 Map ognlContext = Ognl.createDefaultContext(object); 400 401 for (Iterator iterator = propertyMap.entrySet().iterator(); 402 iterator.hasNext();) { 403 Map.Entry entry = (Map.Entry) iterator.next(); 404 String key = entry.getKey().toString(); 405 Object value = entry.getValue(); 406 407 if (object instanceof ParamTag.Parametric && key.startsWith("params.")) { 408 value = stack.findValue(value.toString()); 409 } 410 411 OgnlUtil.setProperty(key, value, object, ognlContext); 412 } 413 } 414 415 419 class WrappedInternalContextAdapter implements InternalContextAdapter { 420 private HashMap params = new HashMap(); 421 private InternalContextAdapter contextAdapter; 422 423 public WrappedInternalContextAdapter(InternalContextAdapter contextAdapter) { 424 this.contextAdapter = contextAdapter; 425 } 426 427 public InternalContextAdapter getBaseContext() { 428 return contextAdapter.getBaseContext(); 429 } 430 431 public void setCurrentResource(Resource resource) { 432 contextAdapter.setCurrentResource(resource); 433 } 434 435 public Resource getCurrentResource() { 436 return contextAdapter.getCurrentResource(); 437 } 438 439 public String getCurrentTemplateName() { 440 return contextAdapter.getCurrentTemplateName(); 441 } 442 443 public EventCartridge getEventCartridge() { 444 return contextAdapter.getEventCartridge(); 445 } 446 447 public Context getInternalUserContext() { 448 return contextAdapter.getInternalUserContext(); 449 } 450 451 public Object [] getKeys() { 452 Set keySet = params.keySet(); 453 454 if (keySet == null) { 455 return contextAdapter.getKeys(); 456 } 457 458 Object [] objects = new Object [keySet.size()]; 459 keySet.toArray(objects); 460 461 return objects; 462 } 463 464 public Object [] getTemplateNameStack() { 465 return contextAdapter.getTemplateNameStack(); 466 } 467 468 public EventCartridge attachEventCartridge(EventCartridge eventCartridge) { 469 return contextAdapter.attachEventCartridge(eventCartridge); 470 } 471 472 public boolean containsKey(Object o) { 473 if (params.containsKey(o)) { 474 return true; 475 } 476 477 return contextAdapter.containsKey(o); 478 } 479 480 public Object get(String s) { 481 Object obj = params.get(s); 482 483 if (obj == null) { 484 obj = contextAdapter.get(s); 485 } 486 487 return obj; 488 } 489 490 public IntrospectionCacheData icacheGet(Object o) { 491 return contextAdapter.icacheGet(o); 492 } 493 494 public void icachePut(Object o, IntrospectionCacheData introspectionCacheData) { 495 contextAdapter.icachePut(o, introspectionCacheData); 496 } 497 498 public void popCurrentTemplateName() { 499 contextAdapter.popCurrentTemplateName(); 500 } 501 502 public void pushCurrentTemplateName(String s) { 503 contextAdapter.pushCurrentTemplateName(s); 504 } 505 506 public Object put(String s, Object o) { 507 return params.put(s, o); 508 } 509 510 public Object remove(Object o) { 511 Object obj = params.remove(o); 512 513 if (obj == null) { 514 obj = contextAdapter.remove(o); 515 } 516 517 return obj; 518 } 519 } 520 } 521 | Popular Tags |