[stringtemplate-interest] Does StringTemplate support components?

Adam Bennett adamb at videx.com
Wed Dec 27 10:28:00 PST 2006


 
Thanks for answering my question, John.  Let me summarize what I heard:  
---  
StringTemplate does not support "componentization" if we define a single component as a combination of .java code and a .st template that is independent of the enclosing template that invoked it.  This lack of support is intentional because it creates a situation where the view is pulling data from the model which is an anti-pattern that StringTemplate wishes to prevent.  
---  
   
Fair enough.  Even so I still find the idea of componentization attractive.  I have this dreamy vision of programmers cranking out reusable components and web designers mixing and matching them.  But perhaps it is not a worthwhile goal.  Although I am not too complelled by the order of invocation argument, I can now see at least one short coming of this sort of componentization: exceptions.  If the web server begins to evaluate a template and stream it to the client what happens if there is an exception while evaluating a sub component?  At this point the response is committed so we can't redirect them to an error page.  If we had gotten all the data up front as StringTemplate requires this would not be a problem.  
   
Thanks enlightening me.  
- Adam Bennett  
 
      _____  

  From: John Snyders [mailto:jjsnyders at rcn.com]
To: Adam Bennett [mailto:adamb at videx.com], stringtemplate-interest at antlr.org
Sent: Sat, 23 Dec 2006 20:54:42 -0800
Subject: RE: [stringtemplate-interest]Does StringTemplate support components?

  
I'll try to answer.    
-----Original Message-----
From: stringtemplate-interest-bounces at antlr.org [mailto:stringtemplate-interest-bounces at antlr.org]On Behalf Of Adam Bennett
Sent: Saturday, December 23, 2006 2:49 AM
To: stringtemplate-interest at antlr.org
Subject: Re: [stringtemplate-interest]Does StringTemplate support components?

  
I really appreciate all the suggestions but I haven't heard the answer yet.  I'll try to reformulate my the question:  
   
Question 1) From my reading, it appears that StringTempate supports calling other templates as if it were a subroutine, right? 
[John Snyders] Correct  
  I infer this from the "Expressions" document where it is talking about "Template References":  
   
"the enclosing page template would automatically create an instance of the referenced template and insert it"  
   
What I am focusing on here is "automatically create an instance".  Beautiful.  Less coding.  
   
Question 2) The documentation goes on to describe 2 ways of getting the necessary attributes to the subroutine template.  
1) "Accessing Attributes Of Enclosing Template"
[John Snyders] In a group file the templates must declare all the attributes they use so this really applies to the non-group (do these have a name?) .st templates. Essentially the attributes defined by the controller are globally available to all templates (unless hidden by an argument explicitly passed to the template in the call).  
2) "Passing Parameters To Another Template"
[John Snyders] This can be done with templates in .st or .stg files  
   
Are there any other ways?  
[John Snyders] Not really  
 You see, what I am looking for is a way to help the web designers work independently of the programmers.  Here's a scenario to describe what I mean.  Let's say that our web application handles the URL "/OurWebApp/account/summary.page" with Java code like this:  
   
StringTemplate st = group.GetInstanceOf("account/summary.st");  
... do some database queries  
st.setAttribute("foo", queryResult1);  
  
st.setAttribute("bar", queryResult2);  
... render the template and send it to the client browser  
   
The above code is maintained by the programmers.  The web designers can tweak the template text to their hearts content.  Initially it looks like:  
<html>  
<body>
...  
$foo$  
$bar$  
...
</body>
</html>    
   
But wait!  The web designer is changes her [artistic] mind and decides to take the summary page the next level.  She wants to show the users account balance so she makes a call to the accountBalanceBox template.
  
  
<html>  
<body>
...  
$foo$  
$bar$  
$accountBalanceBox()$  
...
</body>
</html> 
[John Snyders]  But this is not a presentation change! The web designer is responsible for presentation. The content of the page (the foo and bar and account balance) are the responsibility of the product owner which may be the customer and it is up to the web designer and programmer together to implement. In other words this is a change to the data model available to the page(s).  
   
   
But accountBalanceBox needs a $dollars$ attribute.  This can only be determined by getting the user ID from the HttpSession and then querying the database for it.  But that's the job of the programmer.  If we have support for true componentization then the Java code that handles summary.page should NOT need to set the $dollars$ attribute.  The general principle here is separation of concerns (http://en.wikipedia.org/wiki/Separation_of_concerns).  If accountBalanceBox is made to be a logical component, which includes both a template as well as some Java code, it gives web designers full freedom to mix and match the components that have been provided by the programmers.
[John Snyders] but from the HTML/HTTP point of view summary.page is monolithic and this is what ST must generate. You can have one template for the overall page and another seperate template for the accountBalanceBox. You can have component code for getting foo and bar and a seperate component for getting the account balance but there is just one HTTP request for the summary page and one HTML reply that includes both information.   
   
I think one of the suggestions was to have the controller call the account balance component which would invoke its own ST template with its own model and return a string. That string would then be passed as an attribute to the overall page template. I don't like doing it this way because I think that the page should be generated with one call to string template.   
   
My feeling is that the controller needs to know about all the model data that a given page needs. It may not know the details of what is in the model but it knows which components to call to get it. So it calls one component to get the foo and bar then calls another to get the account balance. These components contribute to the model in the form of attributes. I have been using ST for generating the presentation of a web app and this is more or less how I do it. I started with the non-group templates but quickly moved to the group format.   

A concern may be a large number of arguments to pass around. There are 2 things that can help here. One is that when calling a template you can use ... to have attributes pass through to called templates. The other is that attributes can reference arbitrarily deeply nested object structure. So you could have your top level template with a single argument called model and have that object (or Map) contain all the different parts of the model as children   
Ex:  
$model.foo$  
$model.bar$  
$accountBalanceBox(balance=model.balance,...)$  
   
Some other options (I have not tried these yet) to reduce interaction between components:  
   
If using AJAX the request for the foo and bar data may be totally different from the accountBalanceBox. With AJAX much of the controller moves to the client. In the extreme the dynamic part of the web app is just serving data and there is no need for ST or any template engine.  
   
If you don't like the controler knowing what parts of the model is needed for a given page that information could be configured in an external data file (like a struts tiles def) which the controler reads. Then if the controler knows what to call to get model parts a, b, and c the page designer can decide that the account summary page needs a and b and the orders page needs b and c.  
   
So I think the mechanism I am after is some sort of hook.  As StringTemplate encounters accountBalanceBox it calls my Java function which gives me a chance to provide the necessary attributes.  Such a hook might look like this:  
   
void templatePreprocess(StringTemplate st, StringTemplateContext context)  
{  
  if (st.getName().equals("accountBalanceBox"))  
  {  
    HttpSession session = context.getAttribute("session");  
    int userID = session.getAttirbute("userID");  
    st.setAttribute("dollars", database.getBalance(userID));  
    return;  
  }  
  ...  
}  
   
Does such a mechanism exist?
[John Snyders] No,  All model data must be given to the template before it is invoked with toString (or write)   

Section 7.1 of Enforcing Strict ModelView Separation in Template Engines describes why pulling data from the template breaks separation.  
   
Once you have more than one hook being called there can be order dependent interactions that can cause problems. For ages hook1 is called before hook2 and all is well. Then one day the page designer moves things around and now hook2 is called before hook1 and the code breaks. Perhaps you are now trying to get something out of the session before it is there. In many case there are no order dependencies but in general it is not possible for the developer to defensively code so that the code can be called in any order.  
   
   
Thanks much.  
- Adam  
   
I have been using ST for a few months now for generating HTML. It takes some getting used to but I like it better than what I had done in the past which includes JSP and JSP/Struts.  
   
-John  
       
   
 
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://www.antlr.org:8080/pipermail/stringtemplate-interest/attachments/20061227/dc8c5ca0/attachment-0001.html 


More information about the stringtemplate-interest mailing list