[stringtemplate-interest] Does StringTemplate support components?

Bill Venners bv-svp at artima.com
Thu Dec 28 09:10:44 PST 2006


Hi Adam,

I think we're on the same wavelength, but let me clarify just to be  
sure.

On Dec 28, 2006, at 8:39 AM, Adam Bennett wrote:

> 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);
>
The Java programmers would never call render in their code, but I'm  
not sure if that's what you meant here. The template designers would  
never call it either, just mention the attribute name of the object  
that has the render method in their template. The template engine  
would call render if it discovers the object implements the  
appropriate interface, else it would call toString.

> 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().
>
That's pretty close. What I have is more like this:

public interface View {
     void render(Writer out);
}

public class AccountsPage implements View {

      private AccountBalanceBox accountBalanceBox;
      private Locale locale;
      ....

     public AccountsPage(Locale locale, ..., AccountBalanceBox  
accountBalanceBox, ...) {

         ....
         if (accountBalanceBox == null) {
             throw new NullPointerException("accountBalanceBox was  
null");
         }
         ....
         this.locale = locale;
         this.accountBalanceBox = accountBalanceBox;
         ....
     }

     public void render(Writer out) {

         StringTemplateGroup group = new StringTemplateGroup("st",  
ST_FILES_ROOT);
         StringTemplate dialog = group.getInstanceOf("dialog");
         dialog.setAttribute("headline", headline);
         dialog.setAttribute("logofilename", logofilename);
         ...
         dialog.setAttribute("accountBalanceBox", accountBalanceBox);
         ...

         try {

             dialog.write(new NoIndentWriter(out));
         }
         catch (IOException e) {
             throw new RuntimeException(e);
         }
     }
}

So people have to create an AccountBalanceBox to pass to the  
constructor of AccountPage. Can't create an AccountPage without one,  
and that AccountBalanceBox also implements View with a render method  
that does StringTemplate stuff. I would like to generate these View  
classes from a more concise DSL, so that render method would always  
do ST stuff. In practice it seems that it is just as safe to define a  
View or Renderable interface or something, and if an object passed to  
setAttribute implements that interface, call its render method rather  
than toString. Because as Terence points out in some of his papers,  
you could put anything into toString too, not just String generation.

Anyway, I can see there is some flexibility lost to template  
designers by pushing them towards a component approach like this, and  
I'm wondering if in practice that is a bad thing? Terence designed ST  
from real world experience, so if I went down this path I might just  
discover the same problems he already discovered.

The other thing I'm wondering, though, is why wouldn't I also want to  
have the option to suck in the relevant templates at build time and  
generate print statements in the render method instead of calling ST  
to do it dynamically (like how JSPs are compiled, but without all of  
the ST-like restrictions on what the template can do)?  I figured I  
could take each localized and themed version and make a separate  
private helper method in the class, and then have render call the  
appropriate one. Or have both options. If I do that, then I really  
reduce the flexibility. The template DSL becomes a static language  
not a dynamic one. But again I'm not sure if in practice that may not  
be better. I could still interpret it during development, or even  
during deployment if I want by checking every so often for updated  
template files. But I would be able to know at build time that every  
name used in the template is indeed a variable declared in the  
corresponding View class.

Bill

>
> 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
>



More information about the stringtemplate-interest mailing list