You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@tapestry.apache.org by Onno Scheffers <on...@piraya.nl> on 2009/05/29 00:02:15 UTC

My experiences upgrading from T5.0.18 to T5.1.0.5

I've just upgraded our application from T5.0.18 to 5.1.0.5. I thought I'd
list my experiences here because they might help others.

About the application:
The application has about 90 pages. Some public, some require login and some
even require specific roles (administrator/manager/editor/...). We're
currently running pilots with the application in some organisations and most
of the website is not yet publicly available.
We want to support multiple languages but editors need to be able to edit
the content, so we store the content in a database instead of using the
built-in Tapestry localization through property-files.

I started working through the migration-guide. The only thing in the
migration-guide that really affected me was the new way the @Secure
annotations was handled (not switching to SSL on development). So I had to
set tapestry.secure-enabled to true in order to use a self-signed
certificate.

Having upgraded the libraries and having worked through the migration guide,
I started the application only to find out that none of the pages were
working anymore. I got the error-message "Block parameters are only allowed
directly within component elements".
We want all of our pages to be previewable so web-designers can easily work
on them. Since the <t:content> tag was not yet supported in Tapestry 5.0.18,
we used a workaround: a Border component that accepted a block-parameter
from the page. That way we could still copy some static border-content into
the template for previewability without getting its content rendered twice.
Apparently that trick didn't work anymore on Tapestry 5.1.0.5. So I went
through all of my pages replacing the block-parameter with a <t:content> tag
and I updated the Border-components.

Now the pages would render. But none of my content was showing up. All of a
sudden it seemed instead of Dutch content, English content was being queried
from the database and since we haven't created any English content yet, the
pages were mostly empty.
We store the preferred language per user in the database and when the user
logs in, we set his/her locale using the PersistentLocale service. On all
pages/components that render out content we injected the currentLocale,
which was always Dutch on T5.0.18. On T5.1.0.5 the injected Locale was en_US
on my machine. This suprised me, since I explicitly told tapestry in the
AppModule to only allow Dutch (SymbolConstants.SUPPORTED_LOCALES = "nl").
It seems T5.1.0.5 no longer allows setting Locales that are not in the list
of officially supported languages. Therefore the Dutch Locale was not set
and the injected Locale was wrong.
I created a custom LocaleService for retrieving the currentLocale that
simply returns the Dutch locale for now. Next I replaced all
Locale-injections in the application with that new service so at least we
have all code in a single place and it will be easier to change things in
the future when we are going to support additional languages.

Most pages were ok now. But some Javascript was not working properly. We use
jQuery and have tapestry.script-at-top set to true. It seemed the ordering
of the included Javascript files was wrong. jQuery was being included after
the Javascript files that depends on it. This seemed to have been caused by
the fact the we included the Javascript from the Border template using
<script src="${asset:context:/js/jquery-1.3.2.min.js}"
type="text/javascript"></script>. Previously all other JavaScript libraries
were included after those lines. Now they are included before them.
I updated the border to use the @InsertJavaScriptLibrary-annotation instead.
This fixed the problem.

Some components that created links were failing since we were using the
LinkFactory. The LinkFactory was an internal Tapestry service and therefore
we can't complain when it stops working. We had already put all
link-creation code into a single service because of this. So we only needed
to change the code in one place. With a little Googling I found that there
is a new public Service to use: PageRenderLinkSource.

The emails that were being sent out by the application didn't have valid
links anymore. We were generating the emails and the links were created
using Link.toAbsoluteURI(). This now returned relative URLs instead of
abolute URLs. So I used the BaseURLSource for generating a base URL and used
them to manually create full URLs again. Later I found out that this new
behavior is configurable.

On some secure pages I was using modal dialogs, to open another secure
Tapestry page with a form for editing some values. When the target page was
opened in a normal browser-window everything worked fine, but when the page
opened in the modal dialog I got an exception:
"Forms require that the request method be POST and that the t:formdata query
parameter have values."
I couldn't explain it at first and eventually it turned out that it was
caused by the same issue that caused the email-links to stop working:
Tapestry 5.1.0.5 now tries to use relative URLs whenever possible. The
relative URLs didn't seem to work for actions of a form inside iframes.
Luckily the new behavior is configurable. So I set
tapestry.force-absolute-uris to true and everything worked again, although
the error-message still doesn't make sense to me.
I could now also roll-back the changes I made for generating full URLs in
emails.

After that I also replaced all usages of the deprecated @ApplicationState
annotation to the new @SessionState annotation and made some more
configuration-changes: I disabled rendering the generator meta tag and
disabled gzip compression. I plan on enabling this later, but I want to
measure the impact on CPU- and memory usage before doing so.

All in all the upgrade took me about 2 days, which is quite a bit for a
minor upgrade of a framework which is supposed to be backward-compatible. On
the other hand, most of the time was actually spent re-testing existing
functionality which would have happened anyway, even if everything worked
straight away. Which reminds me yet again that we should finally free up
some time to setup automatic regression-tests :o)

I'm happy we're on 5.1 now though. A lot of improvements have been made that
make life much easier. I already fell in love with the NotEmpty mixin that
makes it much easier to keep the page XHTML strict compliant even if a tag
has no content to render.


- Onno

Re: My experiences upgrading from T5.0.18 to T5.1.0.5

Posted by "Thiago H. de Paula Figueiredo" <th...@gmail.com>.
Em Thu, 28 May 2009 21:38:50 -0300, Onno Scheffers <on...@piraya.nl>  
escreveu:

> This looks like a nice solution, but will it also work if you want to  
> have the page render a smaller portion that the entire HTML body? I  
> think it gets more complex if you want the Border component to also  
> render most of the
> page structure.

In my projects, my Layout component (Border sounds to T4-ish for me,  
hehehe) does render everything that is shared between pages (header, menu,  
footer, etc).

> In our case, left- and right menu's etc. are all rendered by specific  
> components that are included by the Border component.

I don't see any probleme doing that in a Layout (Border) component. In  
pages, to preview shared parts, I would use the Remove component again on  
them. Or I could use T5's <t:remove>.

> If you were to put the JustBody component on the content-div instead of  
> the HTML body,

That's what I do.

> there is no way of using the Remove component for removing the
> outer divs since they are closed only after the dynamic area is closed  
> and you need to keep the XML-structure intact.

But I can use Remove inside the outer divs, surrounding their content.

> Anyway. I'm glad we don't have to resort to work-around anymore. We now  
> have <t:content> :o)

:)

-- 
Thiago H. de Paula Figueiredo
Independent Java consultant, developer, and instructor
http://www.arsmachina.com.br/thiago

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


Re: My experiences upgrading from T5.0.18 to T5.1.0.5

Posted by Onno Scheffers <on...@piraya.nl>.
>
> I use another approach: I wrote a JustBody and a Remove component. JustBody
> only renders its body, not the HTML element it's declared in. Remove renders
> nothing. They're included in Tapestry CRUD (
> www.arsmachina.com.br/project/tapestrycrud).
> So my page templates always start like this:


This looks like a nice solution, but will it also work if you want to have
the page render a smaller portion that the entire HTML body? I think it gets
more complex if you want the Border component to also render most of the
page structure. In our case, left- and right menu's etc. are all rendered by
specific components that are included by the Border component.

So let's say I have this structure:
<body>
   <div class="outer">
      <div class="inner">
         <div class="content">
           [CONTENT]
         </div>
      </div>
   </div>
</body>

The page must have the same structure to be previewable (CSS depends on it).
If the Border component renders the structure already and the page were to
render its complete body I would get the structure in my page twice if I'm
not mistaken.
If you were to put the JustBody component on the content-div instead of the
HTML body, there is no way of using the Remove component for removing the
outer divs since they are closed only after the dynamic area is closed and
you need to keep the XML-structure intact.

Anyway. I'm glad we don't have to resort to work-around anymore. We now have
<t:content> :o)


regards,

Onno

Re: My experiences upgrading from T5.0.18 to T5.1.0.5

Posted by "Thiago H. de Paula Figueiredo" <th...@gmail.com>.
Em Thu, 28 May 2009 19:02:15 -0300, Onno Scheffers <on...@piraya.nl>  
escreveu:

> we used a workaround: a Border component that accepted a block-parameter
> from the page. That way we could still copy some static border-content  
> into the template for previewability without getting its content  
> rendered twice.

I use another approach: I wrote a JustBody and a Remove component.  
JustBody only renders its body, not the HTML element it's declared in.  
Remove renders nothing. They're included in Tapestry CRUD  
(www.arsmachina.com.br/project/tapestrycrud).
So my page templates always start like this:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"  
"http://www.w3.org/TR/html4/strict.dtd">
<html t:type="Layout"  
xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
	<!-- For previewability, as this tag will not appear in generated pages  
-->
	<head t:type="crud/Remove">
		<title>Welcome!</title>
		<link href="css/main.css" rel="stylesheet" type="text/css" />
	</head>
	<!-- The body tag will not appear in the generated page, just its  
contents. -->
	<body t:type="crud/JustBody">
	...
	</body>
</html>

My Layout component is absolutely normal, without block parameters, just  
ordinary ones.

-- 
Thiago H. de Paula Figueiredo
Independent Java consultant, developer, and instructor
http://www.arsmachina.com.br/thiago

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


Re: My experiences upgrading from T5.0.18 to T5.1.0.5

Posted by Onno Scheffers <on...@piraya.nl>.
>
> Thanks for sharing the experience.


You're welcome.



> 1) Can you illustrate the structure of your pages that were using your
> t:content workaround? Based on your description, and the error message, I
> can't envision a scenario where this worked in 5.0.18 but not in 5.1.0, so
> I'm curious to see what you were doing.


It was a solution that was posted on this list a long time ago. I didn't
look into the exact reaon why it doesn't work anymore since this work-around
was always marked in our code as a TODO that needed fixing as soon as
Tapestry supported some sort of $content$ directive. It does now, so I was
happy to start using it.

- Template for Border component:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "
http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:t="
http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
   <head>
      <title>${title}</title>
      [...]
      <script src="${asset:context:/js/jquery-1.3.2.min.js}"
type="text/javascript"></script>
      <script src="${asset:context:/js/jquery-ui-1.7.1.min.js}"
type="text/javascript"></script>
      <script type="text/javascript"
src="${asset:context:/js/global.js}"></script>
   </head>
   <body>
      <div id="container">
         [...]
         <div class="outer">
            <div class="inner">
               <t:if test="protectedPage">
                  <t:delegate to="content" />
                  <t:parameter name="else">
                     <div class="float-wrap">
                        <div id="content">
                           <t:delegate to="content" />
                        </div>
                        [...]
                     </div>
                     [...]
                  </t:parameter>
               </t:if>
            </div>
         </div>
      </div>
      [...]
   </body>
</html>

- Java code for Border component:
public class Border {
   // TODO: This Block-trick is a work-around to be able to use previewable
html pages. As soon as
   // TODO: the $content$ directive makes it into Tapestry 5, we should
remove this.
   /**
    * The input-block, as provided by the page, that should be rendered.
    */
   @Parameter
   @Property
   private Block content;

   [...]
}

- Template for page (note the inclusion of the Border component in the html
tag)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "
http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:t="
http://tapestry.apache.org/schema/tapestry_5_0_0.xsd"
t:type="border/Border">
   <head>
      [...]
   </head>
   <body>
      <div id="container">
         [...]
         <div class="outer">
            <div class="inner">
               <div class="float-wrap">
                  <div id="content">
                  <!--*************************************** CONTENT BLOCK
*****************************************
                      * Everything outside of the content block is rendered
by the Border component. The only       *
                      * reason for including the other content is to get
properly previewabilty of the html. This   *
                      * makes it easier for the webdesigners to work
with.                                          *

***********************************************************************************************-->
                     <t:parameter name="content">
                        <h1 t:id="contentTitle">[TITLE]</h1>
                        <div t:id="contentText">[TEXT]</div>
                        [...]
                     </t:parameter>
                  <!--*************************************** /CONTENT BLOCK
****************************************-->
                  </div>
                  [...]
               </div>
               [...]
            </div>
         </div>
      </div>
      [...]
   </body>
</html>



> 2) Could decorating or advising the PersistentLocale service have
> accomplished what you needed?  For example, you could have checked the set
> locale after the method returned (eg: using advise), and set it to the dutch
> locale as needed.  This would have saved you the pain of creating a new
> service and having to change your injections everywhere.



It probably could have. There are usually a lot of ways to fix a single
problem. For me, creating a new service was quick and easy and a
project-wide search/replace is also pretty easy to do.
On top of that I found a description in a Tapestry bug-fix that stated
unsupported Locales could no longer be set. So apparently it caused problem
when you were able to set unsupported Locales and the behavior was changed
on purpose. Therefore I figured it would be bad practice to still rely on
the Tapestry mechanism while it is not supposed to work the way we used it.
Therefore it made sense to me to have a separate service for it.

regards,

Onno

Re: My experiences upgrading from T5.0.18 to T5.1.0.5

Posted by Robert Zeigler <ro...@scazdl.org>.
Thanks for sharing the experience.
A couple of questions:
1) Can you illustrate the structure of your pages that were using your  
t:content workaround? Based on your description, and the error  
message, I can't envision a scenario where this worked in 5.0.18 but  
not in 5.1.0, so I'm curious to see what you were doing.

2) Could decorating or advising the PersistentLocale service have  
accomplished what you needed?  For example, you could have checked the  
set locale after the method returned (eg: using advise), and set it to  
the dutch locale as needed.  This would have saved you the pain of  
creating a new service and having to change your injections everywhere.

Robert

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org