DO NOT REPLY TO THIS EMAIL, BUT PLEASE POST YOUR BUG RELATED COMMENTS THROUGH THE WEB INTERFACE AVAILABLE AT <http://nagoya.apache.org/bugzilla/show_bug.cgi?id=14094>. ANY REPLY MADE TO THIS MESSAGE WILL NOT BE COLLECTED AND INSERTED IN THE BUG DATABASE.
http://nagoya.apache.org/bugzilla/show_bug.cgi?id=14094 use of Attribute limits types of content, bloats code Summary: use of Attribute limits types of content, bloats code Product: Struts Version: 1.1 Beta 2 Platform: All OS/Version: All Status: NEW Severity: Enhancement Priority: Other Component: Tiles framework AssignedTo: [EMAIL PROTECTED] ReportedBy: [EMAIL PROTECTED] low low priority.... This came up because I was writing my own templating system, that groks dreamweaver templates, with custom bits done as jsps (this lets us track the work of the web designer more faithfully). The way I'd started writing it I had four distinct subsystems: a parser, a templating engine (with no custom taggery) in the middle, a servlet to render the templates, and some custom tags for customisation jsps (they put content into the templates prior to rendering). It occurred to me that I'd like to be able to use the tiles or template tags instead of my own, to increase the amount of documentation available to our jsp developers, and rely on many eyes for less bugs in the custom tags. The abstractions I'd used for the template engine were reasonable enough and I assumed this could be done; so, I read the code looking for an integration point. Bottom line is I couldnt do it, because there was no way to pass the knowledge that, for example 'this is an URL which needs the context path added' through tiles, without editing the code of tiles itself. The types of content it supports are hardcoded everywhere using 'instanceof'. Eg (from InsertTag): public TagHandler processTypedAttribute(AttributeDefinition value) throws JspException { if( value instanceof DirectStringAttribute ) return new DirectStringHandler( (String)value.getValue() ); else if( value instanceof DefinitionAttribute ) return processDefinition( (ComponentDefinition)value.getValue() ); else if( value instanceof DefinitionNameAttribute ) { return processDefinitionName( (String)value.getValue() ); } } ewwwww... this code would clearly make more sense (and be more extensible) refactored to: public TagHandler processTypedAttribute(AttributeDefinition value) throws JspException { return value.getTagHandler(); } ..., with appropriate getTagHandler() methods, and then removing the method entirely. Big switches are clearly useful creating Attribute objects, since you only have the string arguments of the Put tag as a guide, but it doesnt make sense to limit yourself at output time to only objects you can define via the Put tag. A concrete example: you can include content from Beans using tiles, but only by calling 'toString'. If you have a large chunk of text behind this (eg from a content management system) the bean may be more efficiently written if it can stream the content. I realise adding an abstraction like this may be a non-goal, especially for getting struts 1.1 out the door, but I'm just going to add some notes on the api I ended up with in case this proves useful later. I'm sure you'd have better ideas! My parse tree from the templates is built mainly from Content objects, like so: public interface Content { public void service(PageContext context,ContentMap[] stack) throws ServletException, IOException; // named (replaceable) content in a template is distinguished // from anonymous content simply by having a non-null name. public String getName(); } (nb the names of some of the classes here may resemble those in tiles/templates, but the apis are often different). The PageContext passed in is similar to the JSP page context, and for similar reasons - it gives Content access to beans in all the scopes. (I dropped a couple of methods from JSP's PageContext - the ones to do with the 'body'). This allows me to implement includes like so: public void service(PageContext context, ContentMap[] stack) throws ServletException, IOException { context.include(value); } The relevance to tiles would be having the Put tag create PathAttribute objects with this method, so they know how to render /themselves/. The ContentMap[] passed is the equivalent of ContentMapStack in the 'templates' library. The implementation of the service method of a Template, which uses this, looks like: public void service(PageContext context,ContentMap[] stack) throws ServletException, IOException { if (this.template!=null) { context.getPage().service(context,template); return; } Iterator iter=contentList.iterator(); Content content=null; String cname=null; while(iter.hasNext()) { content=(Content)iter.next(); cname=content.getName(); if (cname!=null) { Content replacement=null; for (int i=0; i<stack.length; i++) { replacement=stack[i].getContent(cname); if (replacement!=null) { content=replacement; break; } } } content.service(context,stack); } } Obviously this isnt quite so relevant to tiles as you're using jsp templates, but it demonstrates how replacement of bits of content kicks in in my stuff. finally, an implementation of BeanContent (going back to the 'concrete example' above where I had a bean from a CMS that knew how to stream its content): public void service(PageContext context,ContentMap[] stack) throws ServletException, IOException { // find the bean Object bean=context.getAttribute(beanName,beanScope); // code using BeanUtils to get the bean from a property elided if (bean instanceof Content) { // bean, render thyself... ((Content)bean).service(context,stack); } else { // ok the bean is dumb - so just use 'toString' value=bean.toString(); if (direct!=null) { // ok testing for null here is hackery. context.getOut().write(value); } else { context.include(value); } } } Code like the above would replace much of the ugly if/else if/else if stuff in InsertTag. -- To unsubscribe, e-mail: <mailto:struts-dev-unsubscribe@;jakarta.apache.org> For additional commands, e-mail: <mailto:struts-dev-help@;jakarta.apache.org>