[stringtemplate-interest] Does StringTemplate support components?

Adam Bennett adamb at videx.com
Thu Dec 28 08:39:48 PST 2006


So let me see if I understand you.  You would instantiate the root 
component object and call render like so:

new AccountsPage(...parameters..).render(outputstream);

And the render would look something like:
class AccountsPage implements STRenderable
{
    private AccountBalanceBox acb = new AccountBalanceBox(... 
parameters...);
...
public void render(Writer out)
{
    StringTemplate st = ... acounts template file
    st.setAttribute("balanceBox", acb);
    st.write(out);
}
...
}

Where AccountBalanceBox is a child component that has a similar 
render(Writer) method.  And you purpose that ST knows how to render such 
"STRenderable" objects using the output stream rather than toString().  
Is that it, Bill?  Sounds like a great efficiency over toString().


Bill Venners wrote:
> Hello,
>
> One more note on components. I'm aware I can call toString() on a  
> component object, and get the behavior I described. But that of  
> course means you build Strings in memory first and then write them to  
> the output stream. It would be nice if I could write it to the output  
> stream to begin with, which is why I want to be able to call render 
> (Writer out). (I believe this still holds to ST's philosophy of  
> separation of model and view, so long as <component>.render(Writer  
> out) only renders another template with data already assembled by  
> that component.) I did notice somewhere in the ST documentation that  
> this is possible with ST itself, but as far as I know, only if you  
> pass a tree of data-holders to an outermost ST template that then  
> runs the show, likely by invoking templates in a structure similar to  
> the data-holder tree's structure.
>
> And I meant Terence, not Terrence. Sorry.
>
> Bill
>
> On Dec 27, 2006, at 4:45 PM, Bill Venners wrote:
>
>   
>> Hello,
>>
>> I like the idea of components as well, but not the kind you described
>> originally whereby you call Java code to get attributes. I have a
>> notion of a view is that it is a tree of component objects, each of
>> which encapsulates data and the ability to render that data in
>> various themes and locales. So a component would be a Java class that
>> requires all data needed by its template(s) to be passed to its
>> constructor up front, and it would store that data in instance
>> variables. When someone calls its render(Writer out) method, it would
>> render the appropriate template with that instance data. Each
>> component would do the enforcement of the separation of model and
>> view that I really like about ST.
>>
>> What ST pushed me towards is having those components just be holders
>> of data. So the Java programmer would build up a tree of these data-
>> holding components. The template designers would create a conceptual
>> tree of templates in a way, by having templates refer to templates.
>> Often the template tree will have the same structure as the data-
>> holder objects tree.
>>
>> So why not let each component keep track of its own data and
>> templates, and do the rendering of itself. What I'd need in ST is a
>> way to call render() on components I suppose, and I don't believe I
>> have a way to do that in ST, because it would open up the possibility
>> of calling any arbitrary Java code.
>>
>> The other thing that bugs me a bit is that I can't know at compile
>> time if I'm using a parameter in a template that doesn't exist in the
>> data. I'm tempted towards the JSP approach of taking some template
>> and translating it into print statements that could be called by the
>> render method of component objects. These would not compile if there
>> were naming problems.
>>
>> I know that Terrence came to the design of ST while solving real
>> problems of web pages and code generation. Is there any reason why
>> doing such a component approach might be less useful in practice than
>> the ST approach?
>>
>> Thanks.
>>
>> Bill
>> ----
>> Bill Venners
>> President
>> Artima, Inc.
>> http://www.artima.com
>>
>>
>> On Dec 27, 2006, at 10:28 AM, Adam Bennett wrote:
>>
>>     
>>> 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
>>>
>>>
>>>
>>> _______________________________________________
>>> stringtemplate-interest mailing list
>>> stringtemplate-interest at antlr.org
>>> http://www.antlr.org:8080/mailman/listinfo/stringtemplate-interest
>>>       
>>
>>
>> _______________________________________________
>> stringtemplate-interest mailing list
>> stringtemplate-interest at antlr.org
>> http://www.antlr.org:8080/mailman/listinfo/stringtemplate-interest
>>
>>     
>
> _______________________________________________
> stringtemplate-interest mailing list
> stringtemplate-interest at antlr.org
> http://www.antlr.org:8080/mailman/listinfo/stringtemplate-interest
>   

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://www.antlr.org:8080/pipermail/stringtemplate-interest/attachments/20061228/6dc5df81/attachment-0001.html 


More information about the stringtemplate-interest mailing list