struts-sandbox/struts2/apps/mailreader-bang/src/main/webapp/pages/tour.html [1764:1910]: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Now look back at the code used to generate this block.

Notice anything nifty?

How about that the markup between the iterator tag is actually simpler than the markup that we would use to render one row of the table?

Instead of using a qualified reference like "value=user.subscription[0].host", we use the simplest possible reference: "value=host". We didn't have to define a local variable, and reference that local in the loop code. The reference to each item in the list is automatically resolved, no fuss, no muss.

Nice trick!

The secret to this magic is the value stack. Next to Interceptors, the value stack is probably the coolest thing there is about the framework. To explain the value stack, let's step back and start from the beginning.

Merging dynamic data into static web pages is a primary reason we create web applications. The Java API has a mechanism that allows you to place objects in a servlet scope (page, request, session, or application), and then retrieve them using a JSP scriplet. If the object is placed directly in one of the scopes, a JSP tag or scriptlet can find that object by searching page scope and then request scope, and session scope, and finally application scope.

The value stack works much the same way, only better. When you push an object on the value stack, the public properties of that object become first-class properties of the stack. The object's properties become the stack's properties. If another object on the stack has properties of the same name, the last object pushed onto the stack wins. (Last-In, First-Out.)

When the iterator tag loops through a collection, it pushes each item in the collection onto the stack. The item's properties become the stack's property. In the case of the Subscriptions, if the Subscription has a public Host property, then during that iteration, the stack can access the same property.

Of course, at the end of each iteration, the tag "pops" the item off the stack. If we were to try and access the Host property later in the page, it won't be there.

When an Action is invoked, the Action class is pushed onto the value stack. Since the Action is on the value stack, our tags can access any property of the Action as if it were an implicit property of the page. The tags don't access the Action directly. If a textfield tag is told to render the "Username" property, the tag asks the value stack for the value of "Username", and the value stack returns the first property it finds by that name.

The Validators also use the stack. When validation fails on a field, the value for the field is pushed onto the value stack. As a result, if the client enters text into an Integer field, the framework can still redisplay whatever was entered. An invalid input value is not stored in the field (even if it could be). The invalid input is pushed onto the stack for the scope of the request.

The Subscription list uses another new tag: the param tag. As tags go, "param" takes very few parameters of its own: just "name" and "value", and neither is required. Although simple, "param" is one of the most powerful tags the framework provides. Not so much because of what it does, but because of what "param" allows the other tags to do.

Essentially, the "param" tag provides parameters to other tags. A tag like "text" might be retrieving a message template with several replaceable parameters. No matter how many parameters are in the template, and no matter what they are named, you can use the "param" tag to pass in whatever you need.

pager.legend = Displaying {current} of {count} items matching {criteria}.
...
<s:text name="pager.legend">
    <s:param name="current" value="42" />
    <s:param name="count" value="314" />
    <s:param name="criteria" value="Life, the Universe, and Everything" />
</s:text>

In the case of an "url" tag, we can use "param" to create the query string. A statement like this:


  <s:url action="Subscription!edit"><s:param name="host" value="host"/></s:url>">

can render a hyperlink like this:


  <a href="/struts2-mailreader/Subscription!edit.do?host=mail.yahoo.com">Edit</a>

If a hyperlink needs more parameters, you can use "param" to add as many parameters as needed.

Subscription

If we follow one of the "Edit" subscription links on the Registration page, we come to the Subscriptions page, which displays the details of our description in a data-entry form. Let's have a look a the Subscription configuration in "struts.xml" and follow the bouncing ball from page to action to page. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - struts-sandbox/struts2/apps/mailreader-wildone/src/main/webapp/pages/tour.jsp [1766:1916]: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Now look back at the code used to generate this block.

Notice anything nifty?

How about that the markup between the iterator tag is actually simpler than the markup that we would use to render one row of the table?

Instead of using a qualified reference like "value=user.subscription[0].host", we use the simplest possible reference: "value=host". We didn't have to define a local variable, and reference that local in the loop code. The reference to each item in the list is automatically resolved, no fuss, no muss.

Nice trick!

The secret to this magic is the value stack. Next to Interceptors, the value stack is probably the coolest thing there is about the framework. To explain the value stack, let's step back and start from the beginning.

Merging dynamic data into static web pages is a primary reason we create web applications. The Java API has a mechanism that allows you to place objects in a servlet scope (page, request, session, or application), and then retrieve them using a JSP scriplet. If the object is placed directly in one of the scopes, a JSP tag or scriptlet can find that object by searching page scope and then request scope, and session scope, and finally application scope.

The value stack works much the same way, only better. When you push an object on the value stack, the public properties of that object become first-class properties of the stack. The object's properties become the stack's properties. If another object on the stack has properties of the same name, the last object pushed onto the stack wins. (Last-In, First-Out.)

When the iterator tag loops through a collection, it pushes each item in the collection onto the stack. The item's properties become the stack's property. In the case of the Subscriptions, if the Subscription has a public Host property, then during that iteration, the stack can access the same property.

Of course, at the end of each iteration, the tag "pops" the item off the stack. If we were to try and access the Host property later in the page, it won't be there.

When an Action is invoked, the Action class is pushed onto the value stack. Since the Action is on the value stack, our tags can access any property of the Action as if it were an implicit property of the page. The tags don't access the Action directly. If a textfield tag is told to render the "Username" property, the tag asks the value stack for the value of "Username", and the value stack returns the first property it finds by that name.

The Validators also use the stack. When validation fails on a field, the value for the field is pushed onto the value stack. As a result, if the client enters text into an Integer field, the framework can still redisplay whatever was entered. An invalid input value is not stored in the field (even if it could be). The invalid input is pushed onto the stack for the scope of the request.

The Subscription list uses another new tag: the param tag. As tags go, "param" takes very few parameters of its own: just "name" and "value", and neither is required. Although simple, "param" is one of the most powerful tags the framework provides. Not so much because of what it does, but because of what "param" allows the other tags to do.

Essentially, the "param" tag provides parameters to other tags. A tag like "text" might be retrieving a message template with several replaceable parameters. No matter how many parameters are in the template, and no matter what they are named, you can use the "param" tag to pass in whatever you need.

pager.legend = Displaying {current} of {count} items matching {criteria}.
    ...
    <s:text name="pager.legend">
    <s:param name="current" value="42" />
    <s:param name="count" value="314" />
    <s:param name="criteria" value="Life, the Universe, and Everything" />
    </s:text>

In the case of an "url" tag, we can use "param" to create the query string. A statement like this:


    <s:url action="Subscription!edit"><s:param name="host" value="host"/></s:url>">

can render a hyperlink like this:


    <a href="/struts2-mailreader/Subscription!edit.do?host=mail.yahoo.com">Edit</a>

If a hyperlink needs more parameters, you can use "param" to add as many parameters as needed.

Subscription

If we follow one of the "Edit" subscription links on the Registration page, we come to the Subscriptions page, which displays the details of our description in a data-entry form. Let's have a look a the Subscription configuration in "struts.xml" and follow the bouncing ball from page to action to page. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -