[jira] Commented: (TAP5-627) Allow injection of named spring beans

2010-06-16 Thread Baptiste Autin (JIRA)

[ 
https://issues.apache.org/jira/browse/TAP5-627?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanelfocusedCommentId=12879292#action_12879292
 ] 

Baptiste Autin commented on TAP5-627:
-

+1
Several beans of the same type in the same container is a frequent situation 
(for instance when you have a DAO class that inherits from another one)

IMHO, injecting the ApplicationContext and calling getBean() is not a 
reasonable option. For good reasons, Spring users dislike injecting the 
ApplicationContext, and so supporting named spring beans would be *really* 
great.

(and instead of inventing a new annotation to do this, why not supporting the 
JSR 250 @Resource ?)

 Allow injection of named spring beans
 -

 Key: TAP5-627
 URL: https://issues.apache.org/jira/browse/TAP5-627
 Project: Tapestry 5
  Issue Type: New Feature
  Components: tapestry-spring
Affects Versions: 5.1.0.2
Reporter: Paul Field

 Since 5.1 now handles Spring beans through the master object provider, it is 
 (I think) impossible to specify spring beans by name, which is a pain when 
 you have multiple spring beans implementing the same interface.
 Could the Spring Object Provider take notice of an annotation that specifies 
 the bean name, please?  (e.g. @Service or @Id)
 It would be particularly nice if the same annotation specified the names of 
 Tapestry IOC services *and* spring beans, so that if we decide to move 
 services from Spring into Tapestry IOC we don't need to change any other code.

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.



[CONF] Apache Tapestry Content Type and Markup

2010-06-16 Thread confluence







Content Type and Markup
Page  added by Ulrich Stärk

 

 Content Type and Markup Output

Tapestry reads well-formed XML template files and renders its output as XML, with minor caveats:


	The ?xml? XML declaration is omitted.
	Most element render with an open and close tag, even if empty.
	Certain elements will be abbreviated to just the open tag, if empty:
	
		br
		hr
		img
	
	
	![CDATA[] sections are not used
This is all to ensure that the markup stream, while (almost) well formed, is still properly understood by browsers expecting ordinary HTML.



In fact, Tapestry may decide to render a purely XML document; it depends on the content type of the response. The default content type for pages is "text/html" ... this triggers specialized XML rendering.

A page may declare its content type using the ContentType|../apidocs/org/apache/tapestry5/annotations/ContentType.html class annotation. Content types other than "text/html" will render as well-formed XML documents, including the XML declaration, and more standard behavior for empty elements.

Input/Output Character Set

The character set (aka character encoding) used when writing output and when parsing requests is normally "utf-8". All pages use the same encoding, which can be set using the tapestry.charset configuration setting.



   
Change Notification Preferences
   
   View Online
   








[CONF] Apache Tapestry CSS

2010-06-16 Thread confluence







CSS
Page  added by Ulrich Stärk

 

 Tapestry CSS Support

Cascading Style Sheets (CSS) is an important technology, even with Tapestry. Tapestry works best when the rendered HTML is simple and semantic  semantic meaning HTML that goes back to its roots, simple, straightforward, with tags used for structure and, as much as possible, details about font, color and layout delegated to CSS.

Default CSS Stylesheet

Tapestry includes a built-in stylesheet, default.css, is all HTML documents (documents that have an outer html element and a nested head element). The default.css stylesheet is always ordered first ... any additional stylesheets will come after. This allows Tapestry's default styles to be overridden.

All the styles in the default stylesheet are prefixed with "t-" (for Tapestry).

Adding your own CSS

A page or component that is rendering the head tag can add a stylesheet directly in the markup.



head
  link href="" class="code-quote">"/css/myapp.css" rel="stylesheet" type="text/css"/
  . . .



If you want to leverage Tapestry's localization support, you may want to make use of an expansion and the asset: binding prefix:



head
  link href="" class="code-quote">"${context:css/myapp.css}" rel="stylesheet" type="text/css"/
  . . .



The "context:" prefix means that the remainder of the expansion is a path to a context asset, a resource in the web application root (src/main/webapp in your workspace).

Using the IncludeStylesheet Annotation

Another approach to adding a stylesheet is to include an IncludeStylesheet|../apidocs/org/apache/tapestry5/annotations/IncludeStylesheet.html annotation on your component class:



@IncludeStylesheet("context:css/myapp.css")
public class MyComponent
{

}



As with included _javascript_ libraries, each stylesheet will only be added once, regardless of the number of components that include it via the annotation.



   
Change Notification Preferences
   
   View Online
   








[CONF] Apache Tapestry Environmental Services

2010-06-16 Thread confluence







Environmental Services
Page  added by Ulrich Stärk

 

 Environmental Services

Environmental services represent yet another, distinct form of injection.

Unlike service injection (injection via a service implementation's constructor) or normal component injection (directly into component fields, via the @Inject annotation) where the injected value is always the same, with environmental services, the injected value is very late bound and dynamic.

Environmental services are often a conduit of communication between an outer component and the components it encloses.

An example of this is form support; the Form|../tapestry-core/ref/org/apache/tapestry5/corelib/components/Form.html component creates an environmental of type FormSupport|../apidocs/org/apache/tapestry5/services/FormSupport.html. The FormSupport interface allows enclosed components to participate in both the rendering of the Form and the Form's eventual submission. This is how control names and client-side ids are determined, how fields register callbacks so that they can process their part of the submission, and how fields hook themselves to client-side validation.

Using the @Environmental annotation

The Environmental|../apidocs/org/apache/tapestry5/annotations/Environmental.html annotation is used to dynamically connect to a Environmental service provided by an enclosing component.

A very common Environmental is RenderSupport|../apidocs/org/apache/tapestry5/RenderSupport.html, used when generating client-side _javascript_.




  @Inject @Path("${tapestry.scriptaculous}/dragdrop.js")
  private Asset dragDropLibrary;

  @Environmental
  private RenderSupport renderSupport;

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




Environmental services are, by their nature, per-thread (and therefore per-request).

Accessing an environmental field causes a lookup, by type, against the Environment|../apidocs/org/apache/tapestry5/services/Environment.html service.

Normally, an environmental of the specified type must be available in the Environment, or an exception is thrown when accessing the field.

If the value of the Environmental annotation is false, then the environmental value is optional.

Placing a value in the environment

The Environment service has push() and pop() methods to put a value in the Environment, and discard it.

For example, say you were building a tab-based menu system and you needed to allow an outer TabGroup component to communicate with inner Tab components, to control various aspects of presentation.

The relevant information could be exposed as an interface, TabModel.



public class TabGroup
{
  @Inject
  private Environment environment;

  void beginRender()
  {
 environment.push(TabModel.class, new TabModelImpl(...));
  }

  void afterRender()
  {
environment.pop(TabModel.class);
  }
}

public class Tab
{
  @Environmental
  private TabModel model;

  void beginRender(MarkupWriter writer)
  {
...
  }
}



Notice that when pushing a value into the Environment, you identify its type as well as the instance. Environment maintains a number of stacks, one for each type. Thus, pushing a TabModel into the environment won't disturb the RenderSupport or other environmentals already there.

What's important here is that the code that pushes a environmental onto a stack should also pop it off.

The enclosed class, Tab, has full access to whatever object was pushed onto the stack by the TabGroup.

The reason why Environment is a stack is so that a component can, when it makes sense, easily replace or intercept access to an Environmental.

Fundamental Environmentals

Not all environmentals are pushed into the Environment by components.

A number of environmentals are initialized as part of page rendering, even before the first component starts to render. This initialization is accomplished with MarkupRendererFilter|../apidocs/org/apache/tapestry5/services/MarkupRendererFilter.html contributions to the MarkupRenderer|../apidocs/org/apache/tapestry5/service/MarkupRenderer.html service.

Accessing Environmentals in Services

The Environmenal annotation only works inside components.

To access an Environmental inside a service implementation, you must inject the Environment service and obtain values from it using the peek() method.

If this is something that will occur frequently, it is possible to create a service implementation that is "backed" by the Environment. For example, RenderSupport is accessible as a normal injection, because a service is built for it in TapestryModule:



  public RenderSupport buildRenderSupport(EnvironmentalShadowBuilder builder)
  {
return builder.build(RenderSupport.class);
  }



The EnvironmentShadowBuilder service creates a service implementation that delegates to the proper instance in the environment. The same technique can be used for your own services and environmentals.



   
 

[CONF] Apache Tapestry DOM

2010-06-16 Thread confluence







DOM
Page  added by Ulrich Stärk

 

 Document Object Model

Tapestry 5 takes a very different approach to markup generation than Tapestry 4, or most other frameworks.

Tapestry 4 Approach

In Tapestry 4, markup generation was based on generating a character stream. At the lowest level, the fact that the output was in a markup format such as HTML, XHTML or WML was not known. Higher levels, such as the IMarkupWriter interface (and its implementations) provide the concept of markup generation: elements, attributes, start tags and end tags.

Often, components would work together to generate markup. A common example would be a Form component and the many form control components it contains (such as TextField, Checkbox, etc.). The Form could not fully render until all such enclosed components had rendered first.

IMarkupWriter supported nested writers. Nested writers are a way to buffer output until needed. A Form component would render its body using a nested writer, then write out its form and input type="hidden" elements, as well as the nested, buffered body.

This technique breaks down when two elements are peers, and not in a parent/child relationship. For example, the rendering of a FieldLabel component is affected by its companion TextField component. Handling these cases in Tapestry 4 required a number of kludges and special cases.

Tapestry 5 Approach

Tapestry 5 components render out a DOM, a Document Object Model. This is a tree of nodes representing elements, attributes and text within a document.

The DOM may ultimately be operated upon in a random access manner, rather than the serial (or buffered) approach used in Tapestry 4.

A new MarkupWriter|../apidocs/org/apache/tapestry5/MarkupWriter.html interface allows the majority of code to treat the generation of output as a stream. In fact, MarkupWriter is more like a cursor into the DOM tree.

Once all rendering is complete, the DOM tree is streamed to the client.

DOM Classes

The implementation of this DOM is part of Tapestry, despite the fact that several third-party alternatives exist. This represents a desire to limit dependencies for the framework, but also the Tapestry DOM is streamlined for initial creation, and a limited amount of subsequent modification. Most DOM implemenations are more sophisticated, with greater support for querying (often using XPath) and manipulation.

Once the Document object is created, you don't directly create new DOM objects; instead, each DOM object includes methods that create new sub-objects. This primarily applies to the Element class, which can be a container of text, comments and other elements.

Document|../apidocs/org/apache/tapestry5/dom/Document.html

The Document object represents the an entire document, which is to say, an entire response to be sent to the client.

Documents will have a single root element. The newRootElement() method is used to create the root element for the document.

TODO: Support for doctypes, content type, processing instructions, and top-level comments.

Element|../apidocs/org/apache/tapestry5/dom/Element.html

An element of the document. Elements may have attributes, and they may themselves contain other elements, as well as text and comments.

The addAttribute() method adds a new attribute/value pair to the Element. If an existing attribute with the specified name already exists, then then the new value is ignored. This has implications when different pieces of code try to add attributes to an Element ... the first to add an attribute will "win"

Not yet implemented are some basic methods for manipulating the DOM after it is built. Plans are to add a few methods for re-parenting DOM nodes into new elements. In addition, some searching methods may be added.

MarkupWriter|../apidocs/org/apache/tapestry5/MarkupWriter.html

The MarkupWriter interface allows the structure of the document to be built while maintaining a streaming metaphor.

element() and end()

Calls to element() create a new element within the tree, and may provide attributes for the new element as well. Calls to write(), writeln() and writef() write text nodes within the current element. Every call to element() should be matched with a call to end(), which is used to move the current node up one level.




  writer.element("img", "src", "icon.png", "width", 20, "height", 20, alt, "*");
  writer.end();



Note that end() must be called here, even though the img element is empty (has no body). If the call to end() is omitted, then later elements created by calls to element() will be nested inside the img element, which is not desired.

Again, every call to element() must be matched with a call to end():



  writer.element("select", "name", "choice");
  
  for (String name : optionsNames)
  {
writer.element("option");
writer.write(name);
writer.end();
  }
  
  writer.end();



attributes()

Adds additional name/value pairs to the current element.

When a 

[CONF] Apache Tapestry HTTPS

2010-06-16 Thread confluence







HTTPS
Page  added by Ulrich Stärk

 

 Securing your application with HTTPS

Tapestry assumes your application will be primarily deployed as a standard web application, using HTTP (not HTTPS) as the transport mechanism.

However, many applications will need to have some of their pages secured: only accessible via HTTPS. This could be a login page, or a product ordering wizard, or administrative pages.

All that is necessary to mark a page as secure is to add the Secure|../apidocs/org/apache/tapestry5/annotations/Secure.html annotation to the page class:


@Secure
public class ProcessOrder
{
  . . .
}



When a page is marked as secure, Tapestry will ensure that access to that page uses HTTPS. All links to the page will use the "https" protocol.

If an attempt is made to access a secure page using a non-secure request (a normal HTTP request), Tapestry will send an HTTPS redirect to the client.

Links to non-secure pages from a secure page will do the reverse: a complete URL with an "http" protocol will be used. In other words, Tapestry manages the transition from insecure to secure and back again.

Links to other (secure) pages and to assets will be based on relative URLs and, therefore, secure.

The rationale behind using secure links to assets from secure pages is that it prevents the client web browser from reporting a mixed security level.

Securing Multiple Pages

Rather than placing an @Secure annotation on individual pages, it is possible to enable security for folders of pages. All pages in or beneath the folder will be secured.

This is accomplished by making a contribution to the MetaDataLocator|../apidocs/org/apache/tapestry5/services/MetaDataLocator.html service configuration. For example, to secure all pages in the "admin" folder:


public void contributeMetaDataLocator(MappedConfigurationString,String configuration)
{
configuration.add("admin:" + MetaDataConstants.SECURE_PAGE, "true");
}



Here "admin" is the folder name, and the colon is a separator between the folder name and the the meta data key. SECURE_PAGE is a public constant for value "tapestry.secure-page";

When Tapestry is determining if a page is secure or not, it starts by checking for the @Secure annotation, then it consults the MetaDataLocator service.

If you want to make your entire application secure:


public void contributeMetaDataLocator(MappedConfigurationString,String configuration)
{
configuration.add(MetaDataConstants.SECURE_PAGE, "true");
}



With no colon, the meta data applies to the entire application (including any component libraries used in the application).

Base URL Support

When Tapestry switches back and forth between secure and unsecure mode, it must create a full URL (rather than a relative URL) that identifies the protocol, server host name and perhaps even a port number.

That can be a stumbling point, especially the server host name. In a cluster, behind a fire wall, the server host name available to Tapestry, via the HttpServletRequest.getServerName() method, is often not the server name the client web browser sees ... instead it is the name of the internal server behind the firewall. The firewall server has the correct name from the web browser's point of view.

Because of this, Tapestry includes a hook to allow you to override how these default URLs are created: the BaseURLSource|../apidocs/org/apache/tapestry5/services/BaseURLSource.html service.

The default implementation is based on just the getServerName() method; it's often not the correct choice even for development.

Fortunately, it is very easy to override this implementation. Here's an example of an override that uses the default port numbers that the Jetty servlet container uses for normal HTTP (port 8080) and for secure HTTPS (port 8443):


public static void contributeAlias(ConfigurationAliasContribution configuration)
{
BaseURLSource source = new BaseURLSource()
{
public String getBaseURL(boolean secure)
{
String protocol = secure ? "https" : "http";

int port = secure ? 8443 : 8080;

return String.format("%s://localhost:%d", protocol, port);
}
};

configuration.add(AliasContribution.create(BaseURLSource.class, source));
}



This override is hardcoded to generate URLs for localhost; as such you might use it for development but certainly not in production.

The Alias service exists just for these kinds of overrides; it allows a late-binding to a customized implementation of the BaseURLSource service that hides the built-in Tapestry implementation.

Development Mode

When working in development mode, the Secure annotation is ignored. This is controlled by the tapestry.secure-enabled configuration symbol.

Application Server Configuration

Setting up HTTPS support varies from application server to application server.


	Jetty:
	
		Jetty 6
	
	
	Tomcat:
	

[CONF] Apache Tapestry Input Validation

2010-06-16 Thread confluence







Input Validation
Page  added by Ulrich Stärk

 

 Form Input and Validation

The life's blood of any application is form input; this is the most effective way to gather significant information from the user. Whether it's a search form, a login screen or a multi-page registration wizard, forms are how the user really expresses themselves to the application.

Tapestry excels at creating forms and validating input. Input validation is declarative, meaning you simply tell Tapestry what validations to apply to a given field, and it takes care of it on the server and (once implemented) on the client as well.

Finally, Tapestry is able to not only present the errors back to the user, but to decorate the fields and the labels for the fields, marking them as containing errors (primarily, using CSS effects).

Form component

The core of Tapestry's form support is the Form|../tapestry-core/ref/org/apache/tapestry5/corelib/components/Form.html component. The Form component encloses (wraps around) all the other field components such as TextField|../tapestry-core/ref/org/apache/tapestry5/corelib/components/TextField.html, TextArea|../tapestry-core/ref/org/apache/tapestry5/corelib/components/TextArea.html, Checkbox|../tapestry-core/ref/org/apache/tapestry5/corelib/components/Checkbox.html, etc.

The Form component generates a number of component events that you may provide event handler methods for.

When rendering, the Form component emits two notifications: first, "prepareForRender", then "prepare". These allow the Form's container to setup any fields or properties that will be referenced in the form. For example, this is a good chance to create a temporary entity object to be rendered, or to load an entity from a database to be editted.

When user submits the form on the client, a series of steps occur on the server.

First, the Form emits a "prepareForSubmit" notification, then a "prepare" notification. These allow the container to ensure that objects are set up and ready to receive information from the form submission.

Next, all the fields inside the form are activated to pull values out of the incoming request, validate them and (if valid) store the changes.

_For Tapestry 4 Users: _ Tapestry 5 does not use the fragile "form rewind" approach from Tapestry 4. Instead, a hidden field generated during the render stores the information needed to process the form submission.

After the fields have done their processing, the Form emits a "validateForm" event. This is a chance to perform cross-form validation that can't be described declaratively.

Next, the Form determines if there have been any validation errors. If there have been, then the submission is considered a failure, and a "failure" event is emitted. If there have been no validation errors, then a "success" event is emitted.

Last, the Form emits a "submit" event (for logic that doesn't care about success or failure).

Tracking Validation Errors

Associated with the Form is an ValidationTracker|../apidocs/org/apache/tapestry5/ValidationTracker.html that tracks all the provided user input and validation errors for every field in the form. The tracker can be provided to the Form via the Form's tracker parameter, but this is rarely necessary.

The Form includes methods isValid() and getHasErrors(), which are used to see if the Form's validation tracker contains any errors.

In your own logic, it is possible to record your own errors. Form includes two different versions of method recordError(), one of which specifies a Field|../apidocs/org/apache/tapestry5/Field.html (an interface implemented by all form element components), and one of which is for "global" errors, unassociated with any particular field.

Storing Data Between Requests

As with other action requests, the result of a form submission is to send a redirect to the client which re-renders the page. The ValidationTracker must be stored persistently between requests, or all the validation information will be lost (the default ValidationTracker provided by the Form is persistent).

Likewise, the individual fields updated by the components should also be persistent.

For example, a Login page, which collects a user name and a password, might look like:



public class Login
{
@Persist
private String userName;

private String password;

@Inject
private UserAuthenticator authenticator;

@Component(id = "password")
private PasswordField passwordField;

@Component
private Form form;

String onSuccess()
{
if (!authenticator.isValid(userName, password))
{
form.recordError(passwordField, "Invalid user name or password.");
return null;
}

return "PostLogin";
}

public String getPassword()
{
return password;
}

public void setPassword(String password)
{
password = password;
}

public String getUserName()
{

[CONF] Apache Tapestry Layout Component

2010-06-16 Thread confluence







Layout Component
Page  added by Ulrich Stärk

 

 Layout Component

You may see frequent reference to a Layout Component, but you won't find it in the component reference|../tapestry-core/ref/index.html. Layout isn't a component, it's a component pattern.

A Layout component exists to provide common content across all pages in your application. In traditional servlet development, you may be familiar with the use of a JSP include to include a banner across the top of your page and a copyright message across the bottom.

Tapestry doesn't have a mechanism for such includes, nor does it have the need.

Instead, you can create a component that acts like a template for your pages.

Layout.tml


html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd"
head
titleMy Nifty Web Application/title
/head
body
div class="nav-top"
Nifty Web Application
/div

t:body/

div class="nav-bottom"
(C) 2008 NiftyWebCo, Inc.
/div
/body
/html



Layout is a standard component, with a standard component template. Like all component templates, it will be stored on the classpath (i.e., under src/main/resources).

The magic is in the t:body/ element in the center; this will be replaced by the page's content, whatever that is.

The two div elements above and below the t:body are, in this example, placeholders for the typical content you'll see in a web application: banners (and banner ads!), menus, login forms and so forth.

Often these get very complex ... in fact, in most applications, the Layout component grows to be more complex than almost any page in the application.

Remember that if you include a link to a resource such as an image or a stylesheet, you must use an absolute URL. The same component will be used for pages in many different folders, or with many different activation contexts, meaning that relative URLs are not only different for different pages, but may shift unexpectedly.

Layout.java


@IncludeStylesheet("context:css/site.css")
public class Layout
{
}



Components must always have a Java class. In this trivial example, the Layout component does not have much logic. We can save ourselves some typing using the @IncludeStylesheet|../apidocs/org/apache/tapestry5/annotations/IncludeStylesheet.html annotation (as opposed to directly adding the link element to the template.

Index.tml


html t:type="layout" xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd"

   h1Welcome to the Nifty Web Application!/h1

   p
Would you like to t:pagelink page="login"Log In/t:pagelink?
   /p
/html



This is an example of using the Layout component. To keep our Index.tml template relatively previewable, we are using an html element and the t:type attribute to specify that it is a component.

The html tag will be removed, and replaced with the content from the Layout.tml template (which convieniently starts with an html element). The t:body in Layout.tml will be replaced with the page specific content here: the h1 and p tags.

Any page in the application that follows this pattern, using the Layout component, will have the same look and feel.

You may find that your application has more than one look and feel: perhaps user registration pages have one look, while administrative pages have another. This can be accomplished by having multiple Layout components and using different layout types for different pages.



   
Change Notification Preferences
   
   View Online
   








[CONF] Apache Tapestry Logging

2010-06-16 Thread confluence







Logging
Page  added by Ulrich Stärk

 

 Logging of Tapestry Components and Pages

Tapestry makes extensive use of SLF4J to log details about the creation and operation of your page and component classes.

The default configuration for logging uses Log4J as the logging toolkit, though this can be changed|../../tapestry-ioc/logging.html.

Class to Logger

The logger name for a page or component matches the fully qualified class name. You can configure this in log4j.properties:


log4j.category.org.apache.tapestry5.integration.app1.pages.MerryChristmas=trace



Injecting Loggers

You may mark a field of type Logger with the @Inject annotation. The proper Logger for your page or component will be injected.


public class MyPage
{
  @Inject
  private Logger logger;
  
  . . .



@Log annotation

You may mark any component method with the Log|../apidocs/org/apache/tapestry5/annotations/Log.html annotation. Method entry, exit (and any thrown exceptions) will be logged at DEBUG level, along with parameter values and the method's return value. This is very convienient for debugging, especially when placed on event handler methods.

Component Transformation Debugging

Tapestry performs a transformation on your classes as they are loaded, often you want to gain insight into what it has done. Tapestry uses a secondary logger, consisting of the class name with the prefix "tapestry.transformer.", to log (at debug level) the results of transforming the class.

Example:


[DEBUG] MerryChristmas Finished class transformation: InternalClassTransformation[
public org.apache.tapestry5.integration.app1.pages.MerryChristmas extends java.lang.Object
  implements org.apache.tapestry5.runtime.Component, org.apache.tapestry5.runtime.RenderCommand

add default method: public void postRenderCleanup()
default

add default method: public void setupRender(org.apache.tapestry5.MarkupWriter $1, org.apache.tapestry5.runtime.Event $2)
default

add default method: public void beginRender(org.apache.tapestry5.MarkupWriter $1, org.apache.tapestry5.runtime.Event $2)
default

add default method: public void beforeRenderTemplate(org.apache.tapestry5.MarkupWriter $1, org.apache.tapestry5.runtime.Event $2)
default

add default method: public void afterRenderTemplate(org.apache.tapestry5.MarkupWriter $1, org.apache.tapestry5.runtime.Event $2)
default

add default method: public void beforeRenderBody(org.apache.tapestry5.MarkupWriter $1, org.apache.tapestry5.runtime.Event $2)
default

add default method: public void afterRenderBody(org.apache.tapestry5.MarkupWriter $1, org.apache.tapestry5.runtime.Event $2)
default

add default method: public void afterRender(org.apache.tapestry5.MarkupWriter $1, org.apache.tapestry5.runtime.Event $2)
default

add default method: public void cleanupRender(org.apache.tapestry5.MarkupWriter $1, org.apache.tapestry5.runtime.Event $2)
default

add default method: public boolean handleComponentEvent(org.apache.tapestry5.runtime.ComponentEvent $1)
default

add default method: public org.apache.tapestry5.ComponentResources getComponentResources()
default

add default method: public void containingPageDidLoad()
default

add default method: public void containingPageDidDetach()
default

add default method: public void containingPageDidAttach()
default

add field: protected final org.apache.tapestry5.internal.InternalComponentResources _$resources;

replace method: public final org.apache.tapestry5.ComponentResources getComponentResources()
return _$resources;

add default method: public void render(org.apache.tapestry5.MarkupWriter $1, org.apache.tapestry5.runtime.RenderQueue $2)
default

replace method: public void render(org.apache.tapestry5.MarkupWriter $1, org.apache.tapestry5.runtime.RenderQueue $2)
_$resources.queueRender($2);

convert default constructor: initializer();

add constructor: org.apache.tapestry5.integration.app1.pages.MerryChristmas(org.apache.tapestry5.internal.InternalComponentResources $1)
{
  _$resources = $1;
  initializer();

}

]



Is this helpful? Probably only if you are developing your own code that integrates into the component class transformation chain; for example, to support your own field and method annotations.

Component Event Debugging

Tapestry can also debug component event logic. The component's logger, with a "tapestry.events." prefix, is used at debug level. The debugging output identifies the event name and event source, and identifies any methods that are invoked.

Note that events that are not handled by a component will bubble up to the component's container; further logging for the same event will occur using the logger associated with the container. The page containing the initial component is the final step when logging.

Examples:


[DEBUG] ActionLink Dispatch event: ComponentEvent[action from (self)]
[DEBUG] ActionDemo Dispatch event: ComponentEvent[action from actionlink]
[DEBUG] ActionDemo Invoking: 

[CONF] Apache Tapestry Page Lifecycle

2010-06-16 Thread confluence







Page Lifecycle
Page  added by Ulrich Stärk

 

 Page Lifecycle

In Tapestry, you are free to develop your presentation objects, page and components classes, as ordinary objects, complete with instance variables and so forth.

This is somewhat revolutionary in terms of web development in Java. Using servlets, or Struts, your presentation objects (Servlets, or Struts Actions, or the equivalent in other frameworks) are stateless singletons. That is, a single instance is created, and all incoming requests are threaded through that single instance.

Because multiple requests are handled by many different threads, this means that the single instance's variable are useless ... any value written into an instance variable would immediately be overwritten by a different thread. Thus, it is necessary to use the Servlet API's HttpServletRequest object to store per-request data, and the HttpSession object to store data between requests.

Tapestry takes a very different approach.

In Tapestry, you will have many different instances of any particular page, each either in use for a single request (on a single thread), or waiting in a page pool to be used.

By reserving page instances to particular threads, all the difficult, ugly issues related to multi-threading go by the wayside. Instead, familiar, simple coding practices (using ordinary methods and fields) can be used.

However, there's a risk: it would be a disaster if data could "bleed" from one request to another. Imagine the outcome in a banking application if the first user's account number and password became the default for the second user to reach the application!

Tapestry takes special care to purge all instance variables back to their default value at the end of each request.

The end result is that all pages in the pool are entirely equivalent to each other; it doesn't matter which instance is used for processing any particular request.

Remember that the page instance is just the tip of the iceberg: a page instance encompasses the page component, its templates, all of its parameter bindings, tokens read from its template and (recursively) the same thing for all components inside the page. It adds up.

A page instance will be "checked out" of the pool for a short period of time: a few milliseconds to service a typical request. Because of this, it is generally the case that Tapestry can handle a large number of end users with a relatively small pool of page instances.

Comparison to JavaServer Pages

JSPs also use a caching mechanism; the JSP itself is compiled into a Java servlet class, and acts as a singleton.

However, the individual JSP tags are pooled.

This is one of the areas where Tapestry can significantly outperform JSPs. Much of the code inside a compiled JSP class concerns getting tags from a tag pool, configuring the properties of the tag instance, using the tag instance, then cleaning up the tag instance and putting it back in the pool.

The operations Tapestry does once per request are instead executed dozens or potentially hundreds of times (dependending the complexity of the page, and if any nested loops occur).

Pooling JSP tags is simply the wrong granularity.

Tapestry can also take advantage of its more coarse grained caching to optimize how data moves, via parameters, between components. This means that Tapestry pages will actually speed up after they render the first time.

Page Pool Configuration

Tapestry's page pool is used to store page instances. The pool is "keyed" on the name of the page (such as "start") and the locale for the page (such as "en" or "fr").

Within each key, Tapestry tracks the number of page instances that have been created, as well as the number that are in use (currently attached to a request).

When a page is first accessed in a request, it is taken from the pool. Tapestry has some configuration values that control the details of how and when page instances are created.


	If a free page instance is available, the page is marked in use and attached to the request.
	If there are fewer page instances than the soft limit, then a new page instance is simply created and attached to the request.
	If the soft limit has been reached, Tapestry will wait for a short period of time for a page instance to become available before creating a new page instance.
	If the hard limit has been reached, Tapestry will throw an exception rather than create a new page instance.
	Otherwise, Tapestry will create a new page instance.
Thus a busy application will initially create pages up-to the soft limit (which defaults to five page instances). If the application continues to be pounded with requests, it will slow its request processing, using the soft wait time in an attempt to reuse an existing page instance.



A truly busy application will continue to create new page instances as needed until the hard limit is reached.

Remember that all these configuration values are per key: 

[CONF] Apache Tapestry Page Navigation

2010-06-16 Thread confluence







Page Navigation
Page  added by Ulrich Stärk

 

 Page Navigation

In essense, a Tapestry application is a number of related pages, working together. To some degree, each page is like an application unto itself.

Any individual request will be targetted at a single page. Requests come in two forms:


	component event requests target a specific component on a specific page, triggering an event within that component
	render requests target a specific page, and stream the HTML markup for that page back to the client
This dictomy between component event requests and render requests is new in Tapestry 5. It is in some ways based on ideas from the Portlet specification and differentiating the two types of requests alleviates a number of problems in traditional web applications related to the browser back button, or to the user hitting the refresh button in their browser.



Component Event Requests

Component event requests may take the form of hyperlinks (ActionLink|../ref/org/apache/tapestry5/corelib/components/ActionLink.html) or form submissions (Form|../ref/org/apache/tapestry5/corelib/components/Form.html).

In both cases, the value returned from an event handler method controls the response sent to the client web browser.

The URL for a component event request identifies the name of the page, the nested id of the component, and the name of the event to trigger on the component (this is usually "action"). Further, a component event request may contain additional context information, which will be provided to the event handler method.

These URLs expose a bit of the internal structure of the application. Over time, as an application grows and is maintained, the ids of components may change. This means that component event request URLs should not be bookmarked. Fortunately, users will rarely have the chance to do so (see below).

Null response

If the event handler method returns no value, or returns null, then the current page (the page containing the component) will render the response.

A page render link for the current page is created and sent to the client as a client side redirect. The client browser will automatically submit a new request to generate the page.

The user will see the newly generated content in their browser. In addition, the URL in the browser's address bar will be a render request URL. Render request URLs are shorter and contain less application structure (for instance, they don't include component ids or event types). Render requests URLs are what your users will bookmark. The component event request URLs are transitory, meaningful only while the application is actively engaged, and not meant to be used in later sessions.

String response

When a string is returned, it is expected to be the logical name of a page (as opposed to the page's fully qualified class name). As elsewhere, the name of the page is case insensitive.

Again, a render request URL will be constructed and sent to the client as a redirect.

Class response

When a class is returned, it is expected to be a page class. Returning a page class from an event handler is safer for refactoring than returning a page name.

As with other response types, a render request URL will be constructed and sent to the client as a redirect.

Page response

You may also return an instance of a page, rather than the name or class of a page.

A page may be injected via the InjectPage|../apidocs/org/apache/tapestry5/annotations/InjectPage.html annotation.

Often, you will configure the page in some way before returning the page (examples below).

You can also return a component within the page, but this will generate a runtime warning.

Link response

An event handler method may return a Link|../apidocs/org/apache/tapestry5/Link.html instance directly. The Link is converted into a URL and a client redirect to that URL is sent to the client.

The ComponentResources|../apidocs/org/apache/tapestry5/ComponentResources.html object that is injected into your pages (and components) has methods for creating component event and page render links.

Stream response

An event handler can also return a StreamResponse|../apidocs/org/apache/tapestry5/StreamResponse.html object, which encapsulates a stream to be sent directly to the client browser. This is useful for compnents that want to, say, generate an image or PDF and provide it to the client.

URL response

A URL is handled as a client redirect to an external URL.

Object response

Any other type of object returned from an event handler method is an error.

Page Render Requests

Render requests are simpler in structure and behavior than component event requests. In the simplest case, the URL is simply the logical name of the page.

Pages may have an activation context. The activation context represents persistent information about the state of the page. In practical terms, the activation context is usually the id of some database-persistent object.

[CONF] Apache Tapestry Persistent Page Data

2010-06-16 Thread confluence







Persistent Page Data
Page  added by Ulrich Stärk

 

 Persistent Page Data

Most instance variables in Tapestry are automatically cleared at the end of each request.

This is important, as it pertains to how Tapestry pages are pooled and shared, over time, by many users.

However, you often want to store some persistent data on a single page, and have access to it in later requests. Long term storage of data should go in a database of some form, but server-side state for the duration of the as user's interaction with the application should go in the HttpSession (though Tapestry provides a few other options as well).

Note: To store values that may be accessed across multiple pages, uses a session state object.

Making a field persistent is accomplished with the Persist annotation|../apidocs/org/apache/tapestry5/annotations/Persist.html. Again, this does not refer to database persistence, it refers to session persistance.

This annotation is applied to private instance fields of components.



  @Persist
  private int value;



Annotated fields will store their state between requests. Generally, speaking, this means that the value is stored into the session (but other approaches are possible).

Whenever you make a change to a persistent field, its value is stored.

On later requests, the value for such persistent fields is reloaded from storage.

Persistence Strategies

The value for each field is the strategy used to store the field between requests.

session strategy

The session strategy stores field changes into the session; the session is created as necessary.

A suitably long session attribute name is used; it incorporates the name of the page, the nested component id, and the name of the field.

Session strategy is the default strategy used unless otherwise overridden.

flash strategy

The flash strategy stores information in the session as well, just for not very long. Values are stored into the session, but then deleted from the session as they are first used to restore a page's state.

The flash is typically used to store temporary messages that should only be displayed to the user once.

client strategy

The field is persisted onto the client; you will see an additional query parameter in each URL (or an extra hidden field in each form).

Client persistence is somewhat expensive. It can bloat the size of the rendered pages by adding hundreds of characters to each link. There is extra processing on each request to de-serialize the values encoded into the query parameter.

Client persistence does not scale very well; as more information is stored into the query parameter, its length can become problematic. In many cases, web browsers, firewalls or other servers may silently truncate the URL which will break the application.

Use client persistence with care, and store a minimal amount of data. Try to store the identity (that is, primary key) of an object, rather than the object itself.

Persistence Search

By default the value for the Persist annotation is the empty string. When this is true, then the actual strategy to be used is determined by a search up the component hiearchy.

For each component, the meta-data property tapestry.persistence-strategy is checked. This can be specified using the Meta|../apidocs/org/apache/tapestry5/annotations/Meta.html annotation.

If the value is non-blank, then that strategy is used. This allows a component to control the persistence strategy used inside any sub-components (that don't explicitly use a different strategy).

In any case, if no component provides the meta data, then the ultimate default, "session", is used.

Default Values

Fields marked with @Persist may not have default values (whether set inline, or inside a constructor).

Clearing Persistent Fields

If you reach a point where you know that all data for a page can be discarded, you can do exactly that.

The method discardPersistentFieldChanges() of ComponentResources will discard all persistent fields for the page, regardless of which strategy is used to store the property. This will not affect the page in memory, but takes effect for subsequent requests.

Clustering Issues

The Servlet API was designed with the intention that there would be only a modest amount of server-side state, and that the stored values would be individual numbers and strings, and thus, immutable.

Many web frameworks do not use the HttpSession this way, and store large and mutable objects in the session.

This is not an issue for single servers, but in a cluster, anything stored in the session must be serialized to a bytestream and distributed to other servers within the cluster, and restored there.

Most application servers perform the serialization and distribution as part of HttpSession.setAttribute().

This creates a problem for mutable objects, because if you read a mutable session object, change its state, but don't invoke setAttribute(), the changes will be 

[CONF] Apache Tapestry Persistent State

2010-06-16 Thread confluence







Persistent State
Page  added by Ulrich Stärk

 

 Persistent State

Often, you will have a situation where you have a bit of data that is needed across multiple pages. Perhaps you are creating a multi-page wizard, or perhaps you have an object that tracks the user's identify once logged in.

Ordinary persistent page data is not appropriate, since persistent fields apply to a specific page and aren't shared across pages.

Instead, you want to use a Session State Object (an SSO).

With an SSO, the value is automatically stored outside the page; with the default storage strategy, it is stored in the session. Such a value is global to all pages for the same user, but is stored seperately for different users.

A field holding an SSO is marked with the SessionState|../apidocs/org/apache/tapestry5/annotations/SessionState.html annotation.

Example:



public class MyPage
{
  @SessionState
  private MyState myState;
  
  . . .
}



Any other component or page that declares a field of the same type, regardless of name, and marks it with the SessionState annotation will share the same value. It's that simple.

For Tapestry 4 Users: a big change here is that you don't need to provide any configuration for the SSO before using it, nor do you provide a logical name. Tapestry 5 uses the class name to identify the SSO, so there's no need for a logical name.

The first time you access an SSO, it is created automatically. Typically, the SSO will have a public no-args constructor ... but you may inject dependencies into the SSO via its constructor, as you can with a Tapestry IoC service implementation.

Assigning a value to an SSO field will store that value. Assigning null to an SSO field will remove the SSO (reading the field subsequently will force a new SSO instance to be created).

Check for Creation

Scalable web applications do not create the server-side session needlessly. If you can avoid creating the session, especially on first access to your web application, you will be able to handle an order of magnitude more users. So, if you can avoid creating the SSO, you should do so.

But how to avoid creating it? Simply checking ("myState != null") will force the creation of the SSO and the session to store it in.

Instead, create a second field:



  private boolean myStateExists;



This companion field is used to see if the SSO already exists. It is not annotated; it is located by name ("Exists" is appended to the name of the field storing the SSO). It must be type boolean and must be a private instance variable.

Alternately, you may allow for the state being null:



  @SessionState(create=false)
  private MyState myState;



In this case, the myState field will be null if the MyState SSO does not exist, but will be non-null if it has been created (either by assigning a value to the field, or by a different SSO field where create is true).

Persistence Strategies

Each SSO is managed according to a persistence strategy. The default persistence strategy, "session", stores the SSOs inside the session. The session is created as needed.

Clustering Issues

The clustering strategy for Application State Objects in release 5.0 now applies to all session-persisted objects. See the persistent page data notes for more details.

Configuring SSOs

Generally, you will configure an SSO if you need to change it from the default persistence strategy. Right now there's only one built in strategy, but more will be coming in the future.

Alternately, you will configure an SSO so that you can control how it is instantiated. You may need to inject some values into the SSO when it is first created, or otherwise initialize it. In this second case, you may provide an ApplicationStateCreator|../apidocs/org/apache/tapestry5/services/ApplicationStateCreator.html object, which will be called upon to create the SSO as necessary. This is also the technique to use when you want your SSO to be represented by an interface rather than a class: you need to provide a creator that knows about the class that implements the interface.

Contributions to the ApplicationStateManager service are used to configure an SSO. From your application's module:



  public void contributeApplicationStateManager(MappedConfigurationClass, ApplicationStateContribution configuration)
  {
ApplicationStateCreatorMyState creator = new ApplicationStateCreatorMyState()
{
  public MyState create()
  {
return new MyState(new Date());
  }
};
  
configuration.add(MyState.class, new ApplicationStateContribution("session", creator));
  }



Here, we have an SSO type of MyState, and we're providing a creator for it. We've dolled the creator up with some generic types, but that isn't essential.

Our creator creates a new MyState instance using an alternate constructor that takes the current date and time. Again, just an example.

Finally, we create an 

[CONF] Apache Tapestry Project Layout

2010-06-16 Thread confluence







Project Layout
Page  added by Ulrich Stärk

 

 Project Layout

This is the suggested layout for your Tapestry project; it is the layout of folders and files created by the Tapestry Quickstart Archetype|../../quickstart/. If you are creating your own build using Ant, you may use whatever conventions work for you ... as long as everything gets packaged up into the right place in the target WAR.

Parts of this project layout mimics the format of an exploded WAR (a WAR file unpackaged onto the file system). This will often enable you to run your application directly from your workspace, without any special build or packaging process, while developing. Each of the major IDEs has plugins to allow you to accomplish this task ... and its one of the factors (combined with live class reloading) that makes working with Tapestry a breeze.

Below is a sample project, whose root package is com.example.myapp:


!../images/projectlayout.png!Project Layouth2. Main source files

Main Java source files, the files that will be compiled into the WAR file, are in src/main/java. This is only Java source files. You can see the Index.java source file inside the pages subpackage, and the Layout.java source file inside the components subpackage. The package names demonstrated here are required, dictated by the rules for component classes.

Compiled Java classes will ultimately be packaged in the WAR inside the WEB-INF/classes folder.

Classpath Resources

Resource files are under src/main/resources. This includes the message catalog for the Index page (Index.properties), as well as the message catalog and component template for the Layout component (Layout.tml). These files will also be packaged into the WEB-INF/classes folder of the WAR.

Component templates will always be stored in the resources folder. Templates for pages may be packaged in the WAR proper instead.

Context Resources

The WAR is built primarily from the src/main/webapp folder; this is where ordinary files are stored (such as images and stylesheets). Page templates may also be stored here (Index.tml). The file src/main/webapp/WEB-INF/web.xml is the servlet container deployment descriptor, which has a very specific configuration for Tapestry.

The build tool (usually Maven) will be responsible for putting compiled classes and resources into the WEB-INF/classes folder of the WAR, and for putting the Tapestry library, and its dependencies (as well as any additional libraries defined by your application) into the WEB-INF/lib folder.

Testing

The folders src/test/java and src/test/resources are used when compiling and executing tests. Files in these folders are not packaged into the final WAR.



   
Change Notification Preferences
   
   View Online
   








[CONF] Apache Tapestry Project Layout

2010-06-16 Thread confluence







Project Layout
Page edited by Ulrich Stärk


 Changes (3)
 



...
  
!../images/projectlayout.png!Project Layouth2. Main source files 
!../images/projectlayout.png!Project Layout 
 
h2. Main source files  
Main Java source files, the files that will be compiled into the WAR file, are in {{src/main/java}}. This is _only_ Java source files. You can see the {{Index.java}} source file inside the {{pages}} subpackage, and the {{Layout.java}} source file inside the {{components}} subpackage. The package names demonstrated here are required, dictated by the rules for [component classes|#component-classes.html].  
...

Full Content

Project Layout

This is the suggested layout for your Tapestry project; it is the layout of folders and files created by the Tapestry Quickstart Archetype|../../quickstart/. If you are creating your own build using Ant, you may use whatever conventions work for you ... as long as everything gets packaged up into the right place in the target WAR.

Parts of this project layout mimics the format of an exploded WAR (a WAR file unpackaged onto the file system). This will often enable you to run your application directly from your workspace, without any special build or packaging process, while developing. Each of the major IDEs has plugins to allow you to accomplish this task ... and its one of the factors (combined with live class reloading) that makes working with Tapestry a breeze.

Below is a sample project, whose root package is com.example.myapp:


!../images/projectlayout.png!Project Layout

Main source files

Main Java source files, the files that will be compiled into the WAR file, are in src/main/java. This is only Java source files. You can see the Index.java source file inside the pages subpackage, and the Layout.java source file inside the components subpackage. The package names demonstrated here are required, dictated by the rules for component classes.

Compiled Java classes will ultimately be packaged in the WAR inside the WEB-INF/classes folder.

Classpath Resources

Resource files are under src/main/resources. This includes the message catalog for the Index page (Index.properties), as well as the message catalog and component template for the Layout component (Layout.tml). These files will also be packaged into the WEB-INF/classes folder of the WAR.

Component templates will always be stored in the resources folder. Templates for pages may be packaged in the WAR proper instead.

Context Resources

The WAR is built primarily from the src/main/webapp folder; this is where ordinary files are stored (such as images and stylesheets). Page templates may also be stored here (Index.tml). The file src/main/webapp/WEB-INF/web.xml is the servlet container deployment descriptor, which has a very specific configuration for Tapestry.

The build tool (usually Maven) will be responsible for putting compiled classes and resources into the WEB-INF/classes folder of the WAR, and for putting the Tapestry library, and its dependencies (as well as any additional libraries defined by your application) into the WEB-INF/lib folder.

Testing

The folders src/test/java and src/test/resources are used when compiling and executing tests. Files in these folders are not packaged into the final WAR.




Change Notification Preferences

View Online
|
View Changes









[CONF] Apache Tapestry Project Layout

2010-06-16 Thread confluence







Project Layout
File attached by  Ulrich Stärk




projectlayout.png
(50 kB image/png)



   
Change Notification Preferences
   
   View Attachments









[CONF] Apache Tapestry Project Layout

2010-06-16 Thread confluence







Project Layout
Page edited by Ulrich Stärk


 Changes (2)
 



...
  
!../images/projectlayout.png!Project Layout 
!projectlayout.png|title=Project Layout! 
 h2. Main source files 
...

Full Content

Project Layout

This is the suggested layout for your Tapestry project; it is the layout of folders and files created by the Tapestry Quickstart Archetype|../../quickstart/. If you are creating your own build using Ant, you may use whatever conventions work for you ... as long as everything gets packaged up into the right place in the target WAR.

Parts of this project layout mimics the format of an exploded WAR (a WAR file unpackaged onto the file system). This will often enable you to run your application directly from your workspace, without any special build or packaging process, while developing. Each of the major IDEs has plugins to allow you to accomplish this task ... and its one of the factors (combined with live class reloading) that makes working with Tapestry a breeze.

Below is a sample project, whose root package is com.example.myapp:




Main source files

Main Java source files, the files that will be compiled into the WAR file, are in src/main/java. This is only Java source files. You can see the Index.java source file inside the pages subpackage, and the Layout.java source file inside the components subpackage. The package names demonstrated here are required, dictated by the rules for component classes.

Compiled Java classes will ultimately be packaged in the WAR inside the WEB-INF/classes folder.

Classpath Resources

Resource files are under src/main/resources. This includes the message catalog for the Index page (Index.properties), as well as the message catalog and component template for the Layout component (Layout.tml). These files will also be packaged into the WEB-INF/classes folder of the WAR.

Component templates will always be stored in the resources folder. Templates for pages may be packaged in the WAR proper instead.

Context Resources

The WAR is built primarily from the src/main/webapp folder; this is where ordinary files are stored (such as images and stylesheets). Page templates may also be stored here (Index.tml). The file src/main/webapp/WEB-INF/web.xml is the servlet container deployment descriptor, which has a very specific configuration for Tapestry.

The build tool (usually Maven) will be responsible for putting compiled classes and resources into the WEB-INF/classes folder of the WAR, and for putting the Tapestry library, and its dependencies (as well as any additional libraries defined by your application) into the WEB-INF/lib folder.

Testing

The folders src/test/java and src/test/resources are used when compiling and executing tests. Files in these folders are not packaged into the final WAR.




Change Notification Preferences

View Online
|
View Changes









[CONF] Apache Tapestry Request Processing

2010-06-16 Thread confluence







Request Processing
Page  added by Ulrich Stärk

 

 Request Processing

Understanding the request processing pipeline is very important, as it is one of the chief extension points for Tapestry.

Much of the early stages of processing are in the form of extensible pipelines|../tapestry-ioc/pipeline.html.

Tapestry Filter

All incoming requests originate with the TapestryFilter, which is configured inside the application's web.xml.

The TapestryFilter is responsible for a number of startup and initialization functions.

When it receives a request, the TapestryFilter obtains the HttpServletRequestHandler|../apidocs/org/apache/tapestry5/services/HttpServletRequestHandler.html service, and invokes its service() method.

HttpServletRequestHandler Pipeline

This pipeline performs initial processing of the request. It can be extended by contributing a HttpServletRequestFilter|../apidocs/org/apache/tapestry5/services/HttpServletRequestFilter.html into the HttpServletRequestHandler service's configuration.'

Tapestry does not contribute any filters into this pipeline of its own

The terminator for the pipeline does two things:


	It stores the request and response into the RequestGlobals|../apidocs/org/apache/tapestry5/services/RequestGlobals.html service. This is a threaded service that stores per-thread/per-request information.
	It wraps the request and response as a Request|../apidocs/org/apache/tapestry5/services/Request.html and Response|../apidocs/org/apache/tapestry5/services/Response.html, and passes them into the RequestHandler|../apidocs/org/apache/tapestry5/services/RequestHandler.html pipeline.
Primarily, this exists to bridge from the Servlet API objects to the corresponding Tapestry objects. This is the basis for the planned portlet integration for Tapestry.



RequestHandler Pipeline

This pipeline is where most extensions related to requests take place. Request represents an abstraction on top of HttpServletRequest; this is necessary to support non-servlet applications, such as portlet applications. Where other code and services within Tapestry require access to information in the request, such as query parameters, that information is obtained from the Request (or Response) objects.

The pipeline includes a number of built-in filters:


	CheckForUpdates is responsible for class and template reloading.
	Localization identifies the locale for the user.
	StaticFiles checks for URLs that are for static files (files that exist inside the web context) and aborts the request, so that the servlet container can handle the reuest normally.
	ErrorFilter catches uncaught exceptions from the lower levels of Tapestry and presents the exception report page. This involves the RequestExceptionHandler|../apidocs/org/apache/tapestry5/services/RequestExceptionHandler.html service, which is responsible for initializing and rendering the core/ExceptionReport|../apidocs/org/apache/tapestry5/corelib/pages/ExceptionReport.html page.
The terminator for this pipeline stores the Request and the Response into RequestGlobals, then requests that the MasterDispatcher|../apidocs/org/apache/tapestry5/services/Dispatcher.html service figure out how to handle the request (if it is, indeed, a Tapestry request).



Master Dispatcher Service

The MasterDispatcher service is a chain-of-command, aggregating together (in a specific order), several Dispatcher objects. Each Dispatcher is built to recognize and process a particular kind of URL.

RootPath

As discussed elsewhere, requests for the context root will instead be treated like render requests for the "start" page.

Asset

Requests that being with "/assets/" are references to asset resources that are stored on the classpath, inside the Tapestry JARs (or perhaps inside the JAR for a component library). The contents of the file will be pumped down to the client browser.

PageRender

Page render requests are requests to render a particular page. Such requests may include additional elements on the path, which will be treated as activation context (generally speaking, the primary key of some related entity object), allowing the page to reconstruct the state it will need to succesfully render itself.

The event handler method for the activate event may return a value; this is treated the same as the return value from a component action request; typically this will result in a redirect to another page. In this way, the activate event can perform simple validation at the page level ("can the user see this page?").

Page render URLs consist of the logical name of the page plus additional path elements for the activation context. The dispatcher here strips terms off of the path until it finds a known page name. Thus, "/mypage/27" would look first for a page whose name was "mypage/27", then look for a page name "mypage". Assuming the second search was succesful, the page would be activated with the context "27". If no logical page name can be 

[CONF] Apache Tapestry Response Compression

2010-06-16 Thread confluence







Response Compression
Page  added by Ulrich Stärk

 

 Response Compression

Starting in Tapestry 5.1, the framework automatically GZIP compresses content streamed to the client. This can signifcantly reduce the amount of network traffic for a Tapestry application, at the cost of extra processing time on the server to compress the response stream.

This directly applies to both rendered pages and streamed assets from the classpath.

Context assets will also be compressed ... but this requires referencing such assets using the "context:" binding prefix, so that generated URL is handled by Tapestry and not the servlet container.

Compression Configuration

Small streams generally do not benefit from being compressed; there is overhead when using compression, not just the CPU time to compress the bytes, but a lot of overhead. For small responses, Tapestry does not attempt to compress the output stream.

The configuration symbol tapestry.min-gzip-size allows the cutoff to be set; it defaults to 100 bytes.

In addition, some file types are already compressed and should not be recompressed (they actually get larger, not smaller!). The service ResponseCompressionAnalyzer|../apidocs/org/apache/tapestry5/services/ResponseCompressionAnalyzer.html's configuration is an unordered collection of content type strings that should not be compressed. The default content types are "image/jpeg".

The mapping from file type (by extension) to content type is typically done as part of your servlet-containers configuration. Alternately, you can contribute to the ResourceStreamer service's configuration. This is a mapped configuration; it maps file extensions (such as "css" or "js") to content types ("text/css" or "text/_javascript_") respectively.

StreamResponse

When returning a StreamResponse|../apidocs/org/apache/tapestry5/StreamResponse.html from a component event method, the stream is totally under your control; it will not be compressed. You should use the ResponseCompressionAnalyzer service to determine if the client supports compression, and add a java.util.zip.GZIPOutputStream to your stream stack if compression is desired.



   
Change Notification Preferences
   
   View Online
   








[CONF] Apache Tapestry Service Status

2010-06-16 Thread confluence







Service Status
Page  added by Ulrich Stärk

 

 IoC Services Status

Using Tapestry there will often be a large number of services defined in the registry; a mix of the builtin services provided by the framework and your own.

Built in to every Tapestry application is a page, ServiceStatus, that can present this information to you.

The page "ServiceStatus" presents the list of services within the appication's Registry.


Unable to render embedded object: File (servicestatus.png) not found.

PageServices may be builtin, defined, virtual or real.

Builtin only applies to a few special services that are part of Tapestry IoC.

Defined services are defined in some module, but have not yet been referenced in any way.

Virtual services have been referenced and have gotten as far as creating a service proxy.

Real services have had methods invoked, this forces the realization of the service which includes instantiating the service, injecting dependencies, and decorating with any applicable interceptors.

The Service Status page does not display service information when the application is in production mode.



   
Change Notification Preferences
   
   View Online
   








[CONF] Apache Tapestry Service Status

2010-06-16 Thread confluence







Service Status
File attached by  Ulrich Stärk




servicestatus.png
(142 kB image/png)



   
Change Notification Preferences
   
   View Attachments









[CONF] Apache Tapestry Type Coercion

2010-06-16 Thread confluence







Type Coercion
Page  added by Ulrich Stärk

 

 Parameter Type Coercions

Tapestry automatically handles type coercions for parameters.

Type coercions occur when a value passed into a parameter (as bound in template or in an annoation) does not match the type of the parameter.

For example, consider the Count component:



public class Count
{
@Parameter
private int start = 1;

@Parameter(required = true)
private int end;

@Parameter
private int value;

. . .



Here, the type of all three parameters is int.

However, it is likely that the component will be used as so:



  Merry Christmas: t:count end="3" Ho! /t:count



A bare whole number is interpreted by the prop binding prefix as a long. So this is the long value 3.

Tapestry will automatically coerce the bound value, a long, to the parameter's type, int. This may be a lossy coercion (if the long represents a number larger than can be stored in an int).

TypeCoercer Service

The TypeCoercer service is responsible for this type coercion. This service is part of the tapestry-ioc module, and is documented there|../tapestry-ioc/coerce.html. The service is quite extensible, allowing for new types and coercions to be added easily. The TapestryModule contributes a few additional coercions into the TypeCoercer service.



   
Change Notification Preferences
   
   View Online
   








[CONF] Apache Tapestry Unit testing pages or components

2010-06-16 Thread confluence







Unit testing pages or components
Page  added by Ulrich Stärk

 

 Unit testing pages or components

You can easily unit test a certain page or a component. Follow the simple tasks below.

Setting up a driving environment

In order to unit test a page, you'll need to create an instance of PageTester|../apidocs/org/apache/tapestry5/test/pagelevel/PageTester.html. It acts as both the browser and the servlet container so that you can use it to drive your page. As it is not a real servlet container, you need to tell it the same information as you would in web.xml:
1. Your application package.
1. Your filter name. This is used to load your Tapestry IoC module only. If you have none, you can pass an empty string or anything to it.
1. The folder acting as your context root. This is used to locate your templates (if they're put there).Here is an example (using TestNG, but you're free to use JUnit or anything else):



public class MyTest extends Assert
{
@Test
public void test1()
{
String appPackage = "org.example.app";
String appName = "App1"; // App1Module.java has configured some services.
PageTester tester = new PageTester(appPackage, appName, "src/main/webapp");
}
}


Testing the rendering of a page

To test if a page renders properly (optionally with context), you can tell the PageTester to render it and then assert against the DOM Document|../apidocs/org/apache/tapestry5/dom/Document.html returned.

Here is an example. Let's assuming the page being tested is named "MyPage" and it should return a page containing an HTML element whose id is "id1" and whose text content should be "hello":



public class MyTest extends Assert
{
@Test
public void test1()
{
String appPackage = "org.example.app";
String appName = "LocaleApp";
PageTester tester = new PageTester(appPackage, appName, "src/main/webapp");
Document doc = tester.renderPage("MyPage");
assertEquals(doc.getElementById("id1").getChildText(), "hello");
}
}



If the page requires a context, you can pass it this way:



public class MyTest extends Assert
{
@Test
public void test1()
{
String appPackage = "org.example.app";
String appName = "LocaleApp";
PageTester tester = new PageTester(appPackage, appName, "src/main/webapp");
Object[] context = new Object[]{ "abc", 123 };
Document doc = tester.invoke(new ComponentInvocation(new PageLinkTarget("MyPage"), context));
assertEquals(doc.getElementById("id1").getChildText(), "hello");
}
}



Testing an action link

After rendering a page, you may want to "click" on an action link and then assert against the resulting page. You can do it this way:



public class MyTest extends Assert
{
@Test
public void test1()
{
String appPackage = "org.example.app";
String appName = "LocaleApp";
PageTester tester = new PageTester(appPackage, appName, "src/main/webapp");
Document doc = tester.renderPage("MyPage");
Element link = doc.getElementById("link1");
doc = tester.clickLink(link);
assertTrue(doc.toString().contains("abc"));
}
}



Testing a form submission

After rendering a page, you may want to fill out a form, submit it and then inspect the resulting page. You can do it this way:



public class MyTest extends Assert
{
@Test
public void test1()
{
String appPackage = "org.example.app";
String appName = "LocaleApp";
PageTester tester = new PageTester(appPackage, appName, "src/main/webapp");
Document doc = tester.renderPage("MyPage");
Element form = doc.getElementById("form1");
MapString, String fieldValues = new HashMapString, String();
fieldValues.put("field1", "hello");
fieldValues.put("field2", "100");
doc = tester.submitForm(form, fieldValues);
assertTrue(doc.toString().contains("abc"));
}
}



To submit a form by clicking a submit button, call the clickSubmit()|../apidocs/org/apache/tapestry5/test/pagelevel/PageTester.html#clickSubmitorg.apache.tapestry5.dom.Element_java.util.Map method instead.

Unit testing a component

To unit test a component, just create a test page containing that component. Then unit test that page.



   
Change Notification Preferences
   
   View Online
   








[CONF] Apache Tapestry URL rewriting

2010-06-16 Thread confluence







URL rewriting
Page  added by Ulrich Stärk

 

 Tapestry URL Rewriting Support

Since 5.1.0.1, Tapestry has basic support for URL rewriting. Incoming requests and links generated by Tapestry can be rewritten using exactly the same API. It is based on a chain of URLRewriterRule interfaces. These rules are executed before all other Tapestry request handling, so it does not even know that the received request is not the original one.

Each URL rewriter rule, in its Request process, can choose between returning another Request, effectively rewriting it, or returning the received request unchanged, meaning that this rule does not apply to that request.

To create facilitate Request creation, Tapestry provides the SimpleRequestWrapper class. It wraps an Request, delegating all methods except getPath() and getServerName(). More request wrappers may be added in the future on demand.

Configuration

Tapestry's URL rewriting support is configured by Tapestry-Ioc through contribution of URLRewriterRule}}s to the {{URLRewriter service. The following example is part of the Tapestry's tests.

Simple example of rule chaining

This example just rewrites all incoming requests to /struts to /tapestry. In your AppModule or any other Tapestry-IoC module class:




public static void contributeURLRewriter(OrderedConfigurationURLRewriterRule configuration)
{

URLRewriterRule rule = new URLRewriterRule() 
{

public Request process(Request request, URLRewriteContext context)
{
final String path = request.getPath();
if (path.equals("/struts"))
{
request = new SimpleRequestWrapper(request, "/tapestry");
}

return request;

}

public RewriteRuleApplicability applicability()
{
return RewriteRuleApplicability.INBOUND;
}

};

configuration.add("myrule", rule);
}




Example of rule chaining

In your AppModule or any other Tapestry-IoC module class.




public static void contributeURLRewriter(OrderedConfigurationURLRewriterRule configuration)
{

URLRewriterRule rule1 = new URLRewriterRule()
{

public Request process(Request request, URLRewriteContext context)
{
final String path = request.getPath();
if (path.equals("/struts")) 
{
request = new SimpleRequestWrapper(request, "/jsf");
}

return request;

}

public RewriteRuleApplicability applicability()
{
return RewriteRuleApplicability.INBOUND;
} 

};

URLRewriterRule rule2 = new URLRewriterRule()
{

public Request process(Request request, URLRewriteContext context)
{
final String path = request.getPath();
if (path.equals("/jsf")) 
{
request = new SimpleRequestWrapper(request, "/tapestry");
}
return request;

}

public RewriteRuleApplicability applicability()
{
return RewriteRuleApplicability.INBOUND;
}

};

URLRewriterRule rule3 = new URLRewriterRule()
{

public Request process(Request request, URLRewriteContext context)
{
String path = request.getPath();
if (path.equals("/tapestry")) 
{
path = "/urlrewritesuccess";
request = new SimpleRequestWrapper(request, path);
}
return request;

}

public RewriteRuleApplicability applicability()
{
return RewriteRuleApplicability.INBOUND;
}

};

URLRewriterRule rule4 = new URLRewriterRule()
{

public Request process(Request request, URLRewriteContext context)
{
String serverName = request.getServerName();
String path = request.getPath();
final String pathToRewrite = "/urlrewritesuccess/login";
if (serverName.equals("localhost")  path.equalsIgnoreCase(pathToRewrite)) 
{
request = new SimpleRequestWrapper(request, "http://login.domain.com", "/");
}
return request;

}

public RewriteRuleApplicability applicability()
{
return RewriteRuleApplicability.OUTBOUND;
}


};

configuration.add("rule1", rule1);
configuration.add("rule2", rule2, "after:rule1");
configuration.add("rule3", rule3, "after:rule2");
configuration.add("rule4", rule4);

}




This examples shows the URL rewriting chaining: the first rule rewrites requests to /struts and rewrites them to /jsf and leaves requests to other URLs unchanged. The second rewrites /jsf to /tapestry and the third rewrites 

[CONF] Apache Tapestry Input Validation

2010-06-16 Thread confluence







Input Validation
File attached by  Ulrich Stärk




validation_errors.png
(33 kB image/png)



   
Change Notification Preferences
   
   View Attachments









[CONF] Apache Tapestry Input Validation

2010-06-16 Thread confluence







Input Validation
File attached by  Ulrich Stärk




validation_initial.png
(25 kB image/png)



   
Change Notification Preferences
   
   View Attachments









[CONF] Apache Tapestry Input Validation

2010-06-16 Thread confluence







Input Validation
File attached by  Ulrich Stärk




validation_minlength.png
(32 kB image/png)



   
Change Notification Preferences
   
   View Attachments









[CONF] Apache Tapestry Input Validation

2010-06-16 Thread confluence







Input Validation
File attached by  Ulrich Stärk




validation_password.png
(31 kB image/png)



   
Change Notification Preferences
   
   View Attachments









[CONF] Apache Tapestry Input Validation

2010-06-16 Thread confluence







Input Validation
Page edited by Ulrich Stärk


 Changes (12)
 



...
Next, all the fields inside the form are activated to pull values out of the incoming request, validate them and (if valid) store the changes.  
_For Tapestry 4 Users: _ Tapestry 5 does not use the fragile form rewind approach from Tapestry 4. Instead, a hidden field generated during the render stores the information needed to process the form submission. 
 After the fields have done their processing, the Form emits a validateForm event. This is a chance to perform cross-form validation that cant be described declaratively. 
...
  
!../images/validation_initial.png!Initial form presentationNotice how the Label components are displaying the textual names for the fields. Given that we have not done any explicit configuration, whats happened is that the components ids (userName and password) have been converted to User Name and Password. 
!validation_initial.png|title=Initial form presentation! 
 
Notice how the Label components are displaying the textual names for the fields. Given that we have not done any explicit configuration, whats happened is that the components ids (userName and password) have been converted to User Name and Password.  
If you just submit the form as is, the fields will violate the required constraint and the page will be redisplayed to present those errors to the user:  
!validation_errors.png|title=Errors and decorations! 
 
!../images/validation_errors.png!Errors and decorationsTheres a couple of subtle things going on here. First, Tapestry tracks _all_ the errors for _all_ the fields. The Errors component has displayed them at the top of the form. Further, the _default validation decorator_ has added decorations to the labels and the fields, adding t-error to the CSS class for the fields and labels. Tapestry provides a default CSS stylesheet that combines with the t-error class to make things turn red. 
 Next, well fill in the user name but not provide enough characters for password.   
!../images/validation_minlength.png!Minlength error messageThe user name field is OK, but theres an error on just the password field. The PasswordField component always displays a blank value by default, otherwise wed see the partial password displayed inside. 
!validation_minlength.png|title=Minlength error message! 
 
The user name field is OK, but theres an error on just the password field. The PasswordField component always displays a blank value by default, otherwise wed see the partial password displayed inside.  
If you type in enough characters and submit, we see how the logic inside the Login page can attach errors to fields:   
!../images/validation_password.png!Application supplied errorsThis is nice and seamless; the same look and feel and behavior for both the built-in validators, and for errors generated based on application logic. 
!validation_password.png|title=Application supplied errors! 
 
This is nice and seamless; the same look and feel and behavior for both the built-in validators, and for errors generated based on application logic.  
h1. Centralizing Validation with @Validate  
...

Full Content

Form Input and Validation

The life's blood of any application is form input; this is the most effective way to gather significant information from the user. Whether it's a search form, a login screen or a multi-page registration wizard, forms are how the user really expresses themselves to the application.

Tapestry excels at creating forms and validating input. Input validation is declarative, meaning you simply tell Tapestry what validations to apply to a given field, and it takes care of it on the server and (once implemented) on the client as well.

Finally, Tapestry is able to not only present the errors back to the user, but to decorate the fields and the labels for the fields, marking them as containing errors (primarily, using CSS effects).

Form component

The core of Tapestry's form support is the Form|../tapestry-core/ref/org/apache/tapestry5/corelib/components/Form.html component. The Form component encloses (wraps around) all the other field components such as TextField|../tapestry-core/ref/org/apache/tapestry5/corelib/components/TextField.html, TextArea|../tapestry-core/ref/org/apache/tapestry5/corelib/components/TextArea.html, Checkbox|../tapestry-core/ref/org/apache/tapestry5/corelib/components/Checkbox.html, etc.

The Form component generates a number of component events that you may provide event handler methods for.

[jira] Created: (TAP5-1189) Invoke JavaScript with LinkSubmit

2010-06-16 Thread sakshi (JIRA)
Invoke JavaScript with LinkSubmit
-

 Key: TAP5-1189
 URL: https://issues.apache.org/jira/browse/TAP5-1189
 Project: Tapestry 5
  Issue Type: Question
  Components: tapestry-component-report
Affects Versions: 5.1.0.5
Reporter: sakshi


Hi,

I am using Tapestry5.

I have tried multiple options to invoke javascript on clicking linkSubmit, but 
none works, although they all work with Submit component of tapestry.
a) Invoking javascript from tml page as follows:
 script
  function extraStep() {
alert(ENTER extraStep);  
  }
/script
 t:loop source=photoDetails value=each -${each.title}  br /
t:form t:id=formId id=formIdp
t:label for=reportedCategory/  t:select t:id=reportedCategory 
t:label=Reported Category//p
[t:actionlink t:id=approvePhotosApprove/t:actionlink]
  input type=hidden id=photoObject value=${each} /
t:linksubmit t:id=disapprovePhoto value=Disapprove Photo  
onclick=extraStep();/t:linksubmit
  /t:form  
/t:loop
** This works with Submit but not with linkSubmit
b) tried using mixins, but didnt work with LinkSubmit
c) tried using JSON, but that also didnt work with LinkSubmit. afterRender() 
does not get invoked.
onSuccess(),onSelectedFromDisapprovePhoto() methods are not invoked from 
Linksubmit.

Can someone please advise how can I use LinkSubmit in order to invoke 
javascript.
Looking forward for an early response.

regards
sakshi

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.



[jira] Created: (TAP5-1190) New page-level events to decorate component event and page render links

2010-06-16 Thread Howard M. Lewis Ship (JIRA)
New page-level events to decorate component event and page render links
-

 Key: TAP5-1190
 URL: https://issues.apache.org/jira/browse/TAP5-1190
 Project: Tapestry 5
  Issue Type: New Feature
  Components: tapestry-core
Affects Versions: 5.2.0
Reporter: Howard M. Lewis Ship
Priority: Minor


This is based on some customer work.

Customer really wanted URLs to include a series of (optional) values as query 
parameters, not path info ... which makes sense, because you'd have a category 
filter sometimes, a name filter sometimes, etc.

Anyway, this worked fine in most cases ... there's a method on the page to act 
like the passivate event handler, but return a Link with the query parameters 
added.  The active event handler would extract the query parameters and store 
them inside fields.

Got trickier handling event links; had to modify some low-level components to 
fire a decorateLink event so that the page's event handler could add the 
query parameters to the link.

It would be nice if these concepts were inside Tapestry; that after generating 
a Link via the passivate event (or by building a Link using a supplied page 
activation context) that an optional event (perhaps called decorateLink) 
would be triggered to add these extra query parameters.

Ideally, there would be two events, decoratePageRenderLink and 
decorateComponentEventLink.  The first parameter would be the Link to 
decorate. The second would be the PageRenderRequestParameters or 
ComponentEventRequestParameters, as appropriate.  This would give the event 
handler method enough information to decide whether to decorate the link, and 
what information to put into it.

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.