Sunday, March 15, 2009

Task 6 - Create Tapestry 5 components library

One of the promises of Tapestry 5 is easy creation of components. The word component can trigger lots of different associations in people’s minds. I guess for the majority of web developers the component means a GUI thing. For someone from the middle management a component might as well be a forum system with all the bells and whistles. For old school guys the first impression when the word component is a word of discussion might mean an architectural thing.

To me, the term components, is quite a familiar for a number of years now. When I started with web application development I was a lucky man as Web Objects were my first contact in a jungle of languages and frameworks out there. You can imagine (I hope) the disappointment when I had to switch to JSP. Only now I got an opportunity to use similar technology again!

Until now, all my posts were talking about preparing the development environment and this one feels like I am jumping ahead of time. In a sense this is true, but I think creating a place to put the goodies you will create and reuse is a good start. Why would you create a component and later copy it to a library? Let’s do it right now.

The tools are: Eclipse Ganymede, m2eclipse 0.9.7, Maven 2.0.10 and Java 6.

In Eclipse click the New button
then type maven in the filter box and select Maven Project
Click Next and select Create a simple project.
Click Next and fill-in the configuration details.
All of the values I have filled-in do not have any special meaning. You can name your GroupId and ArtifactId anything you want.

Now we will skip the last step of the wizard (adding dependencies) and just press Finish. You should see a new project in the Project Explorer.
Now double click the pom.xml to open it in Maven POM Editor. The content should be something like:


4.0.0
bb.webcraft.tapestry
components-library
bbWebCraft Tapestry 5 components library
0.0.1-SNAPSHOT
A collection of Tapestry 5 components


We need to add some more elements in the pom for this project to become a Tapestry 5 components library. A bare minimum is:

4.0.0
bb.webcraft.tapestry
components-library
bbWebCraft Tapestry 5 components library
0.0.1-SNAPSHOT
A collection of Tapestry 5 components


org.apache.tapestry
tapestry-core
${tapestry-release-version}





org.apache.maven.plugins
maven-compiler-plugin

1.5
1.5
true



org.apache.maven.plugins
maven-jar-plugin



bb.webcraft.tapestry.library.services.LibraryModule







5.0.18



Please note that Tapestry-Module-Classes could as well be
com.acme.services.MyModule

but would be a bad practice. The java packages you will create in this library project will have the same root as the GroupId (bb.webcraft.tapestry).

Let’s create a package bb.webcraft.tapestry.library.services
and then a java class named LibraryModule.
This is now your library’s IoC module. In order for Tapestry to know where to search for your component’s classes you need to make a contribution to the ComponentClassResolver service configuration
package bb.webcraft.tapestry.library.services;

import org.apache.tapestry5.ioc.Configuration;
import org.apache.tapestry5.services.LibraryMapping;

public class LibraryModule {
public static void contributeComponentClassResolver(Configuration<LibraryMapping> configuration) {
configuration.add(new LibraryMapping("bbwcraft", "bb.webcraft.tapestry.library"));
}
}
The project is now ready. If it had any components, you would just put the jar on your web application’s class path and use it. You can create a jar by typing mvn package in the console or by right clicking on a project root (or pom.xml) and selecting Run As / Maven package.
A jar named components-library-0.0.1-SNAPSHOT.jar should be created in the target folder. As you may know a jar has to be installed (mvn install) in your local maven repository to be used by other mavenized projects. You can then use the library by referencing it in your application’s pom like this:

bb.webcraft.tapestry
components-library
0.0.1-SNAPSHOT


Now would be the time and place to mention how to use the component from the library in some T5 application, but since we haven’t actually created one, we will leave this for the next post.

Before we end, let’s add another section in the library’s pom (under the <project> element).



org.apache.tapestry
tapestry-component-report
${tapestry-release-version}

bb.webcraft.tapestry.library






This is very important, as you and Tapestry will create a good documentation about your components. I will also talk about how to write the documentation for the components in the next post where we will actually create a component – a date input component composed of three combo boxes (day, month, year) suitable for selecting dates far in the past or future.

Reblog this post [with Zemanta]

Tuesday, March 10, 2009

Tapestry 5 Caffe

Have an idea? Write it down.

Have a Tapestry 5 related idea. Visit Tapestry 5 Caffe!

This site is purely a brainstorming place where you can post your ideas or comment and vote on other's. I feel it offers more structure than mailing list where ideas can easily get lost and is lighter and friendlier than JIRA, but by no means a replacement. It is a place where ideas can be shared and see the popularity for each suggestion anyone can contribute. It can be viewed as vox populi, so the creators and people more involved in Tapestry 5 development can adjust their bearings if needed.

Maybe your idea will be picked up by Howard and others - a fresh perspective is allways welcome.

The site has several categories:

  • Website/Documentation (suggestions to improve the documentation and web site in general)
  • Components (new components ideas, improvements on existing ones)
  • ArsMachina
  • JumpStart
  • ChenilleKit
  • Equanda
Go drink a cup of coffee.
Reblog this post [with Zemanta]

Saturday, February 7, 2009

Wishlist and survey for Tapestry 5 components

I was wondering what components people are looking for when developing with Tapestry 5. There are 50+ components baked in the framework's core and there are 39 at the http://www.chenillekit.org. 9 more at http://equanda.org/equanda-tapestry5/ and 1 at http://code.google.com/p/tapestry5-treegrid/.

Are there any other libraries out there?

Update on february 11th:
I left out http://lombok.demon.co.uk/tapestry5Demo with 9 more components.

I made a list of 36 additional UI components in the form of a survey. Please take this survey, maybe some of the components will be part of some library because of it. Maybe some of them will evolve and maybe some of them will be unique to any web framework out there.

You can follow the results by visiting Real-time Summary Report and comments.

online surveys

Thanks!

Reblog this post [with Zemanta]

Monday, February 2, 2009

Which IDE are you using for developing Tapestry 5 applications?

The poll is closed after 45 days and the results are:

  1. Eclipse (30 votes, 71%)
  2. IDEA (8 votes, 19%)
  3. NetBeans (6 votes, 14%)
Happy weaving to all.

Saturday, January 31, 2009

Task 5 - Customize Eclipse for Tapestry 5 code editing

When coding, sometimes we (at least me) forget to use all the help from an IDE we are coding in. One of techniques is context help.

I am sure you are all used to typing

so you quicker create a for loop.

To speed up developing web applications with Tapestry 5, I have created 4 templates just to show the principle. I will most likely create more as I learn the framework and find the patterns that are recurring more often.

Get the templates at http://sites.google.com/site/bbwebcraft/ and import them into the Eclipse.


After importing you should see 4 new templates in the list:


Let’s try them out one by one.

Open any Tapestry 5 project you have in your workspace – maybe you have the one we created in task 1.

Open some page class like Index.java, put the cursor in the class body, type t5 and press Ctrl+Space.

You can see the 4 templates we have imported. Just select the first one – ActionLink.

A lot of code gets inserted which is good for a complete Tapestry 5 newbie and not so good for others.


package org.driving.school.pages;

import java.util.Date;

import org.apache.tapestry5.PersistenceConstants;
import org.apache.tapestry5.annotations.Persist;

/**
* Start page of application school.
*/
public class Index {
public Date getCurrentTime() {
return new Date();
}

public String getMyDemoMessage() {
return "My Demo Message Changed";
}


/*
Component that triggers an action on the server with a subsequent full page refresh.

Put this into the Index.tml

<a t:type="actionlink" t:id="myAction" t:context="literal:FooBar" href="#">My ActionLink</a>
<div>${myMessageAfterPressingTheActionLink}</div>

See http://tapestry.apache.org/tapestry5/tapestry-core/ref/org/apache/tapestry5/corelib/components/ActionLink.html
for a full component description.
*/

// Only keep the message until it has been displayed once. You must persist it
// because ActionLink performs redirect after post. If you click refresh browser
// button the message is lost, because it is persisted just for one request.
@Persist(PersistenceConstants.FLASH)
private String myMessageAfterPressingTheActionLink;

void onActionFromMyAction(String contextParameter) {
myMessageAfterPressingTheActionLink = "You pressed an action link which had a literal string "
+ contextParameter + " in its context.";
}

public String getMyMessageAfterPressingTheActionLink() {
return myMessageAfterPressingTheActionLink;
}
}


The inserted code is more like a cheat sheet as it tells you what to insert in the appropriate template file to have a working example of the ActionLink component. It also gives a tip on why the field must be persisted.

All the templates also import the necessary classes from the framework, so you don’t even have to bother pressing Ctrl+Shift+O (Organize Imports).

Now, delete the code which has been inserted and try the second template (t5-addScriptLink).


/*
The method addScriptLink adds a link to a script file, a JavaScript
library. A component can inject such a script and pass one or more of
assets to this method. Tapestry will ensure that the necessary <link>
elements are added to the top of the document (just inside the
element). The same can be achieved with the annotation

@IncludeJavaScriptLibrary("${tapestry.scriptaculous}/dragdrop.js")
on a page (Index) class.
*/
@Inject
@Path("${tapestry.scriptaculous}/dragdrop.js")
private Asset dragDropLibrary;

@Environmental
private RenderSupport renderSupport;

void setupRender() {
renderSupport.addScriptLink(dragDropLibrary);
}


One can now quickly modify the name of the JavaScript library that is to be added on this page. It also includes an alternative way of doing the same thing.

The third template is a real beast. It includes the code and instructions to have a working autocomplete example in minutes. Show this to your boss to demonstrate how quickly you can have this done in Tapestry 5. :-)


/*
The Autocomplete mixin exists to allow a text field to query the server for completions
for a partially entered phrase. It is often used in situations where the field exists to
select a single value from a large set, too large to succesfully download to the client
as a drop down list; for example, when the number of values to select from is numbered
in the thousands.

Autocomplete can be added to Index.tml with:

<form t:type="form">
<input t:id="cityName" t:type="TextField" t:mixins="autocomplete"/>
</form>

Create a service interface:

public interface CityNames {
List<String> getAll();
}

And the implementation:

public class CityNamesImpl implements CityNames {
private List<String> cityNames = new ArrayList<String>();

public CityNamesImpl() {
// top 7 cities by population
cityNames.add("Mumbai");
cityNames.add("Shanghai");
cityNames.add("Karachi");
cityNames.add("Istanbul");
cityNames.add("Delhi");
cityNames.add("Sao Paulo");
cityNames.add("Moscow");
}

public List<String> getAll() {
Collections.sort(cityNames);
return Collections.unmodifiableList(cityNames);
}
}

Then in the AppModule bind the service:

binder.bind(CityNames.class, CityNamesImpl.class);

Change the look of the autocomplete menu by overriding CSS classes
DIV.t-autocomplete-menu UL
DIV.t-autocomplete-menu LI
DIV.t-autocomplete-menu LI.selected
*/
@Inject
private CityNames cityNames;

@Property
private String cityName;

List<String> onProvideCompletionsFromCityName(String partial) {
List<String> matches = new ArrayList<String>();

for (String cityName : cityNames.getAll()) {
if (cityName.toLowerCase().startsWith(partial.toLowerCase())) {
matches.add(cityName);
}
}
return matches;
}


And the last one (t5-zone) which demonstrates the usage of AJAX in Tapestry 5.


/*
A Zone can be updated via an ActionLink component. ActionLink supports a zone parameter,
which is the id of the Zone's <div>. Clicking such a link will invoke an event handler
method on the server as normal ... except that the return value of the event handler method
is used to send a partial page response to the client, and the content of that response
is used to update the Zone's <div> in place.

Put this into the Index.tml,

<t:block t:id="myBlockToBeUpdated">
The current time is: ${time}
</t:block>
<t:zone t:id="myZone">
<t:delegate to="myBlockToBeUpdated"/>
</t:zone><br/>
<a t:type="actionlink" t:id="refreshZone" href="#" t:zone="myZone">Refresh time with AJAX request.</a>
*/
@Inject
@Property
private Block myBlockToBeUpdated;

Block onActionFromRefreshZone() {
// Return the zone we want rendered.
return myBlockToBeUpdated;
}

public Date getTime() {
return new Date();
}


Again, if you follow the comments in the template, you will have a working example in under a minute.

And this is all about – getting beginners on the track fast! Including me.

Thursday, January 15, 2009

Task 4 – Customize Eclipse for Tapestry 5 template editing

As there is no initiative, at least to my knowledge, for Tapestry 5 support in Eclipse, we will have to manage with some manual tweaking.

First bring up a preference dialog (Windows/Preferences). Then type cont in the filter area to narrow down preferences which we are looking for. Click on Content Types under the General node. On the right side of the dialog find Text/HTML node and select it. All file associations for HTML content type are listed in the area just bellow.

We have to add Tapestry’s templates to be associated with HTML content type, so click on Add button and type *.tml in the input field and click OK.

You should see another entry in the File associations list - *.tml. Now confirm the addition by clicking on an OK button.

From now on a HTML editor which comes with Eclipse WTP is the default editor for tml files. This editor unfortunately does not handle formatting of the source code (tml in our case) very well.

If you are a one man band and don’t care about indenting the tags by some rules then you can safely skip this screencast bellow.

For others, who might have questioned themselves if there is a way, I will show you how you can make your templates look better in the editor and most importantly – with fewer conflicts if two or more designers are working repeatedly/in sequence with the same set of templates checked-in in some source control system like subversion and using the same formatter.

The screencast is best viewed in full screen mode.


A link to the plugin http://eclipsetidy.sourceforge.net

Below are the tags that I was talking about in the screencast that should be copied into the Eclipse Tidy preferences. It is just a quick first proposition – like monkey sort (not at all tested)

inline tags:
t:actionlink, t:addrowlink, t:ajaxformloop, t:any, t:checkbox, t:datefield, t:delegate, t:eventlink, t:gridcell, t:label, t:output, t:passwordfield, t:outputraw, t:removerowlink

block level tags:
t:beandisplay, t:beaneditform, t:beaneditor, t:errors, t:exceptiondisplay, t:form, t:formfragment, t:forminjector, t:grid, t:gridcolumns, t:gridpager, t:gridrows, t:if, t:linksubmit, t:loop, t:pagelink, t:palette, t:propertydisplay, t:propertyeditor, t:radio, t:radiogroup, t:renderobject, t:select, t:submit, t:submitnotifier, t:textarea, t:textfield, t:textoutput, t:unless, t:zone

I was also talking about DOCTYPE. If you want to know more go here (http://www.w3.org/QA/Tips/Doctype).

In the screencast I made a template. Here it is for you to copy/paste if you want:

<?xml version="1.0" encoding="UTF-8" ?>
<!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>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>
Insert title here
</title>
<link rel="stylesheet" type="text/css" href="${asset:context:css/MY-STYLESHEET.css}" />
</head>
<body>

</body>
</html>

If you look at the source code in the browser of the school application (Index page), Firefox 3 shows:


We can modify AppModule.java (method contributeApplicationDefaults) in a way to tell Tapestry not to compress white spaces,

configuration.add(SymbolConstants.COMPRESS_WHITESPACE, "false");

so the output is more readable:

It is not perfect, but good enough to eye scan the sources.

One more quick tip. Maybe you have noticed, you have to press F5 (refresh) on a running project (jetty:run) for some changes you have made to take effect. There is an option in the Preferences which can save you from pressing the button again and again.

Next time we will learn how to create java code templates to speed up Tapestry 5 web application development.




Reblog this post [with Zemanta]

Sunday, January 4, 2009

Task 3 - Rapid turnaround in Tapestry 5

The goal of this task is to learn how Tapestry can boost your productivity by allowing you to modify (some) files and see the changes immediately. This does not mean we will be learning how to configure the servlet container of your choice to reload the context when some files were changed. Oh no, I will be talking and demonstrating live class reloading.

I will continue to work on a web application from Task 1. Seeing is believing, so click on a play button of the screencast below to witness live class reloading in action.



Alternate location to view this screencast.

If you have already read the documentation at the official site, you probably know that you cannot change just any class and expect to be reloaded by the framework. A change to any loaded class inside the controlled package is noticed by the framework and acted appropriately upon. In case of our demo application the controlled packages are:

  • org.driving.school.pages
  • org.driving.school.components
  • org.driving.school.mixins
  • org.driving.school.base
We will be experimenting and exploring live class & template reloading in tasks to come.

As I “promised” in previous post I will tell you how to prepare your development environment to pick up changes in any CSS files your application will have. How can I be writing about something so basic after you have just watched a state of the art framework capability to pick up changes in class files? Well, if you are developing in Windows and using Jetty as your servlet container, then you will probably spend some time googling for a solution. I was.

But first let’s show the problem. In Eclipse (on Windows) open our school project. Add a css folder under src/main/webapp and create a new file school.css inside.
body {
color: red;
}

Then, modify Index.tml to include a reference to this CSS file. The head section should look like
<head>
<title>school Start Page</title>
<link rel="stylesheet" type="text/css" href="${asset:context:css/school.css}" />
</head>

Now start the web app if it was not already started. You should see


That is ok, red color as expected. Now change the color to black for instance in school.css in Eclipse while the web app is still running and save the changes. You will get


Now go googling. Just kidding, read on.

Stop web app by clicking on a red square in the Console view.

You have to get a copy of webdefault.xml file. Where? The safest way is to extract it from the jetty jar you are running your application with. If you look at the pom.xml file of the school application you will see a maven-jetty-plugin
<!-- Run the application using "mvn jetty:run" -->
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>maven-jetty-plugin</artifactId>
<version>6.1.9</version>
<configuration>
<!-- Log to the console. -->
<requestLog implementation="org.mortbay.jetty.NCSARequestLog">
<!-- This doesn't do anything for Jetty, but is a workaround for a Maven bug
that prevents the requestLog from being set. -->
<append>true</append>
</requestLog>
</configuration>
</plugin>

Notice the version 6.1.9. Navigate to %HOMEPATH%/.m2/repository/org/mortbay/jetty/jetty/6.1.9. Open jetty-6.1.9.jar and extract webdefault.xml file to src/main/resources/org/mortbay/jetty/webapp/ of the school project. Open this file in Eclipse and locate the section
<init-param>
<param-name>useFileMappedBuffer</param-name>
<param-value>true</param-value>
</init-param>

Change the value to false.
Modify pom.xml to look like
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>maven-jetty-plugin</artifactId>
<version>6.1.9</version>
<configuration>
<webAppConfig>
<defaultsDescriptor>src/main/resources/org/mortbay/jetty/webapp/webdefault.xml</defaultsDescriptor>
</webAppConfig>
<requestLog implementation="org.mortbay.jetty.NCSARequestLog">
<filename>target/yyyy_mm_dd.request.log</filename>
<append>true</append>
</requestLog>
</configuration>
</plugin>

The important part is which tells Jetty where to locate our modified webdefault.xml file. The need for this change we have made is described at http://docs.codehaus.org/display/JETTY/Files+locked+on+Windows.

Start the school web app. You will most likely get an error:

[INFO] Starting jetty 6.1.9 ...
2009-01-05 00:40:28.779::INFO: jetty-6.1.9
2009-01-05 00:40:28.789::WARN: failed ContextHandlerCollection@1e903d5
java.lang.IllegalArgumentException: Illegal context spec:null

WTF?

Change the version of the plugin to
<version>6.1.14</version>

Start the school web app again. Jetty started! If not, write a dirty comment on this blog.

What a detour. Do you still remember what we are trying to do? Type http://localhost:8080/school in the browser. Do you see the text in the color you have specified in the CSS file? Now change the color, save the school.css (you should not get an error dialog this time) and refresh the browser. Finally.







Reblog this post [with Zemanta]