| ---- |
| Apache Tapestry 5 |
| ---- |
| |
| What is Apache Tapestry? |
| |
| Apache Tapestry is an open-source framework for creating dynamic, robust, highly scalable web applications in Java. |
| Tapestry complements and builds upon the standard Java Servlet API, and so it works in any servlet container or application server. |
| |
| Tapestry divides a web application into a set of pages, each constructed from components. This provides a consistent structure, |
| allowing the Tapestry framework to assume responsibility for key concerns such as URL construction and dispatch, persistent state |
| storage on the client or on the server, user input validation, localization/internationalization, and exception reporting. |
| Developing Tapestry applications involves creating HTML templates using plain HTML, and combining the templates with small amounts of |
| Java code. In Tapestry, you create your application in terms of objects, and the methods and properties of those |
| objects -- and specifically not in terms of URLs and query parameters. |
| Tapestry brings true object oriented development to Java web applications. |
| |
| Tapestry is specifically designed to make creating new components very easy, |
| as this is a routine approach when building applications. |
| |
| Tapestry is architected to scale from tiny, single-page applications all the way up to |
| massive applications consisting of hundreds of individual pages, developed by |
| large, diverse teams. Tapestry has significant Ajax features baked right in. On the server-side, Tapestry easily integrates with any kind of backend, including JEE, |
| Spring and Hibernate. |
| |
| It's more than what you <can> do with Tapestry ... it's also <how> you do it! Tapestry is a vastly productive environment. |
| Java developers love it because they can make <Java code> changes and see them immediately ... no redeploy, no restart! And it's blazingly fast to boot |
| (even when files change). Designers |
| love it because Tapestry templates are so close to ordinary HTML, without all the cruft and confusion seen in JavaServer Pages. Managers love it because |
| it makes it easy for large teams to work together, and because they know important features (including localization) are baked right in. Once you work |
| in Tapestry there's no going back! |
| |
| Tapestry is released under the Apache Software License 2.0. |
| |
| New And Of Note |
| |
| * New {{{apidocs/org/apache/tapestry5/annotations/QueryParameterMapped.html}QueryParameterMapped}} annotation to |
| automatically map fields of a page to query parameters. |
| |
| * Service <implementation> classes may now be {{{tapestry-ioc/reload.html}live reloaded}}, much like page and component classes. |
| |
| * New {{{apidocs/org/apache/tapestry5/annotations/QueryParameter.html}QueryParameter}} annotation for parameters to event handler methods. |
| |
| * Submit components can now be used to cancel a form (bypassing client-side validation). |
| |
| * Tapestry no longer uses a StAX parser to parse templates (it uses a standard SAX parser), meaning fewer dependencies and |
| better compatibility with Google App Engine. |
| |
| * A {{{guide/testing.html}guide to integration testing}} is now available. |
| |
| * The {{{guide/persist.html}@SessionAttribute}} annotation can be used on component fields to |
| read and update HttpSession attributes. |
| |
| * The {{{tapestry-beanvalidator}JSR-303 Bean Validation Integration Library}} is now available. |
| |
| [] |
| |
| Roadmap |
| |
| The goal is to produce new releases on a regular schedule, every 4 - 6 months. |
| |
| High priorities for 5.2 include Spring Web Flow integration, and support for developing Tapestry applications as Portlets. |
| |
| Third Party Libraries, Tutorials and Resources |
| |
| A number of Third Party Libraries, Tutorials and Resources are listed on |
| the {{{http://tapestry.apache.org/}Tapestry Home Page}}. |
| |
| Adaptive API |
| |
| A key feature of Tapestry 5 is <adaptive API>. |
| |
| In traditional Java frameworks, including Tapestry 4, user code is expected to |
| conform to the framework. You create classes that extend from framework-provided |
| base classes, or implement framework-provided interfaces. |
| |
| This works well until you upgrade to the next release of the framework: with |
| the new features of the upgrade, you will more often than not experience breaks |
| in backwards compatibility. Interfaces or base classes will have changed and your |
| existing code will need to be changed to match. |
| |
| In Tapestry 5, the framework <adapts to your code>. You have control over the |
| names of the methods, the parameters they take, and the value that is returned. This |
| is driven by annotations, which tell Tapestry under what circumstances your |
| methods are to be invoked. |
| |
| For example, you may have a login form and have a method that gets invoked |
| when the form is submitted: |
| |
| +----+ |
| public class Login |
| { |
| @Persist |
| @Property |
| private String userId; |
| |
| @Property |
| private String password; |
| |
| @Component |
| private Form form; |
| |
| @Inject |
| private LoginAuthenticator authenticator; |
| |
| void onValidateFromForm() |
| { |
| if (! authenticator.isValidLogin(userId, password)) |
| { |
| form.recordError("Invalid user name or password."); |
| } |
| } |
| |
| Object onSuccessFromForm() |
| { |
| return PostLogin.class; |
| } |
| |
| } |
| +----+ |
| |
| This short snippet demonstrates a bit about how Tapestry operates. Services |
| within the application are injected with the @Inject annotation. The method names, onValidateFromForm() |
| and onSuccessFromForm(), |
| inform Tapestry about when the method is to be invoked. The two events <validate> and <success> occur |
| when a form is submitted; "validate" is triggered to perform cross-field validations, and "success" is |
| only triggered when there are no validation errors. The onSuccess() method's |
| return value directs Tapestry on what to do next: jump to another page within the application |
| (here identified as the class for the page, but many other options exist). When there are exceptions, |
| the page will be redisplayed to the user. |
| |
| This also represents a distinct change from Tapestry 4. In earlier versions of Tapestry, |
| the Form component's listener parameter would be bound to the method to invoke, by name. Further, |
| the listener method had to be public. |
| This new approach not only supports multiple listeners, but provides an improved separation of |
| view concerns (inside the page's template) and logic concerns, inside the Java class. |
| |
| In many cases, additional information about the event is available, and can be passed |
| into the method by adding parameters to the method. Again, Tapestry will adapt |
| to your parameters. |
| |
| Tapestry also saves you effort: the @Property annotation marks a field as readable and writable; |
| Tapestry will provide the accessor methods automatically. This kind of meta-programming is common in Tapestry, |
| and easy to implement yourself. |
| |
| Finally, Tapestry 5 explicitly separates actions (requests that change things) and rendering (requests that |
| render pages into markup) into two separate requests. Performing an action, such as clicking a link or submitting a form, |
| results in a <client side redirect> to the new page. This is often called "redirect after post". This helps ensure |
| that URLs in the browser are book-markable ... but also requires that a bit more information be stored in the session |
| between requests (using the @Persist annotation). |
| |
| About Snapshots and Releases |
| |
| Tapestry is built using {{{http://maven.apache.org/}Maven}}, which makes it really easy to download the source and build it yourself, either the whole |
| project, or just one single module. |
| |
| Better yet, you can pull down Tapestry modules from the central Maven repository. |
| |
| The use of Maven has let us move with great speed, providing preview releases and <snapshots>. |
| |
| Snapshots are <intermediate versions> of releases. As I'm writing this, the most recent preview release is 5.2.0 and the current snapshots are |
| for 5.2.0-SNAPSHOT. Maven keys off the -SNAPSHOT suffix and handles the dependency specially. It knows that snapshot releases can change frequently, |
| so it will keep checking (at least once a day, maybe more often) to see if there's an updated version of the snapshot. |
| |
| A nightly build process on Tapestry's continuous integration server creates new snapshots <every night>. |
| |
| Snapshots don't go in the central Maven repository (that's reserved for full releases). Instead, they go into the Apache snapshots repository |
| at {{{http://http://repository.apache.org/snapshots}http://repository.apache.org/snapshots}}. |
| |
| To access this repository, you may add <<<-DremoteRepositories=http://repository.apache.org/snapshots>>> to the command line when |
| running Maven. |
| |
| Your best bet is to use the {{{quickstart/}quickstart Maven archetype}} to create your initial Tapestry project; it generates a full project |
| directory, including a POM that links to the Tapestry snapshots repository. |
| |
| <<Documentation on this site usually refers to the latest snapshot ... that is, it is usually ahead of the last official release. In some cases, |
| it is written as if the snapshot release is stable; if documentation refers to version 5.2.x and that doesn't work, try 5.2..x-SNAPSHOT.>> |
| |
| Principle 1 -- Static Structure, Dynamic Behavior |
| |
| Tapestry is designed to be extremely scalable in several dimensions: |
| |
| * Tapestry applications may contain large numbers of pages and many custom components. |
| |
| * Tapestry applications may contain very complex functionality. |
| |
| * Tapestry applications may be created by large, diverse teams. |
| |
| * Tapestry applications can service large numbers of concurrent users. |
| |
| One core architecture decision in Tapestry exists to service many of the above goals |
| (and others that are harder to describe). <<Static Structure, Dynamic Behavior>> |
| |
| In Tapestry, the structure of any particular page is <static>. This is necessary for |
| several reasons, most importantly because Tapestry pages are <pooled>. Creating a Tapestry page |
| is an involved process, because the page object is simply the root of a large tree of other |
| objects including user provided components, many kinds of structural objects, template objects, |
| and others. Creating a new page instance for each request is simply not <scalable>. |
| |
| Instead, Tapestry <pools> pages. Once created, a page instance will be stored in a pool for |
| that particular type of page, and reused |
| in later requests. An incoming request, the result of a user clicking a link or submitting a form, |
| will be processed by <some> server within a cluster, and will use <some> page instance within the |
| page pool. Because page instances are static and uniform across instances and servers, |
| Tapestry can use any available page instance, or create a new one as needed. |
| |
| Tapestry does not need to store page instances inside the HttpSession. At most, it stores a smattering |
| of <persistent field values> from the page, but not the entire page instance. This lean |
| use of the HttpSession is key to Tapestry's very high scalability, especially in a clustered |
| configuration. |
| |
| Tapestry also includes built-in mechanisms to store a limited amount of state, such as a persistent |
| object id, directly into the URL used to access a page. |
| |
| In some Tapestry-like frameworks, such as JavaServer Faces and Wicket, the page structure is more dynamic, at |
| the cost of storing much, much more data in the HttpSession. |
| |
| This static structure is not so limiting as you might think. With different kinds of conditional |
| and looping components, and the ability to "jump out of the flow" and render components in an arbitrary order, |
| you will not find Tapestry to be rigid ... anything but! |
| |
| Public vs. Internal |
| |
| An issue plaguing previous versions of Tapestry 4 (and earlier) was the lack of a clear delineator |
| between private, internal APIs and public, external APIs. The fact that your code would extend |
| from base objects but that many of the methods on those base objects were "off limits" |
| further confused the issue. This has been identified as a key factor in the |
| "steep learning curve of Tapestry" meme. |
| |
| With the clean slate of Tapestry 5, we are being much more ruthless about internal vs. external. |
| |
| First of all, anything inside the org.apache.tapestry5.internal package |
| is <<internal>>. It is part of the implementation of Tapestry. It is the man behind the curtain. |
| You should not ever need to directly use this code. It is a <<bad idea>> to do so, because |
| internal code may <<change from one release to the next>> without concern for backwards |
| compatibility. |
| |
| Backwards Compatibility |
| |
| Tapestry has been plagued by backwards compatibility problems with every major release. Tapestry 5 |
| does not even attempt to be backwards compatible to Tapestry 4. Instead, it lays the ground work for |
| true backwards compatibility going forwards. |
| |
| Tapestry 5's API is based almost entirely on naming conventions and <annotations>. You components are just |
| ordinary Java classes; you will annotate fields to allow Tapestry to maintain their state or to allow Tapestry |
| to inject resources, and you will name (or annotate) methods to tell Tapestry under what circumstances |
| a method should be invoked. |
| |
| Tapestry will adapt to your classes. It will call your methods, passing in values via method parameters. |
| Instead of the rigidness of a fixed interface to implement, Tapestry will simply adapt to your classes, using |
| the hints provided by annotations and simple naming conventions. |
| |
| Because of this, Tapestry will be able to change internally to a great degree without it affecting any |
| of the application code <you> write. This should finally crack the backwards compatibility nut, allowing you to have |
| great assurance that you can upgrade to future releases of Tapestry without breaking your existing applications. |
| |
| This is already evident in Tapestry 5.1, where many new features and improvements have occurred, but is still |
| 100% backwards compatible to Tapestry 5.0, as long as you've avoided the temptation to make use of |
| internal APIs. |
| |
| Tapestry 5.2 is continuing in this vein with improved performance and new features without sacrificing |
| backwards compatibility at all. |