Top 20 Apache Tapestry Interview Questions You Must Prepare 19.Mar.2024

  • A component-based view framework.
  • Classes are written as POJOs and byte-code trformed at run time
  • Configured with annotations and naming conventions rather than XML
  • Compared to JSPs, enforces a clear separation of HTML markup and Java code.
  • HTML templates are directly previewable by web designers
  • Changed component classes are live-reloaded into running application for faster development.
  • Uses the Post/Redirect/Get navigation pattern for form submission.

Yes. Tapestry is open source and free. 

It is licensed under the Apache Software License, which allows it to be used even inside proprietary software.

Tapestry is not a JSP tag library; Tapestry builds on the servlet API, but doesn’t use JSPs in any way. It uses it own HTML template format and its own rendering engine. Starting with release 3.0, Tapestry includes a simple JSP tag library to allow JSP pages to create links to Tapestry pages.

Retrieving bound properties : When writting a component, you often require various properties to be supplied by the component user. At some point during rendering, you will want to use the value of this property.

You can do this by accessing the Binding. Assume we have a component with one property called ‘values’. Our component will use this list in its preRenderCommponent() method to setup some model, for use elsewhere.

.... if(getValues() == null) {
  IBinding binding = getBindings("values"); if(binding.getObject() == null) {
      throw new RequestCycleException("The value for 'values' cannot be null", this);
  } setValues((List)values.getObject());
}

The binding itself will ensure that the object value is the correct type (assuming of course, it’s been setup right).

Performing Lazy Instantiation of state based upon component properties : In some cases, the output of a component may be based upon the state of some other property of the same component. For example, imagine a form where the user can choose the type of product to view. When they choose a product, the form makes a query to the database for products matching this type, and reshows the list on the same page. (the list would be included outside of the form element itself).

Lets assume that the page object exposes it’s products via a getProductModel() – which is an instance of IPropertySelectionModel.

We will also assume that the remainder of the page has the other components necessary to render correct HTML, using the value supplied by the getProductModel() result.

Here, it is helpful to know when in the rendering process you can rely on the value of selectedProduct to be set correctly, so that you can instantiate a ProductModel based on the provided value, for use in the form rendering. The best place to setup state is in the preRenderComponent() method. This is called by Tapestry just before it renders any component, but AFTER it has set component properties. So, we might write:

protected void preRenderComponent() {
  String selected = getSelectedProduct();
  List products = getMatchingProducts(selectedProduct);
  productModel = new ProductModel(products);
  .. other initialization code ...
}

Use the contrib:PopupLink component.

The script framework is an effective me to bundle scripts in components. It provides scripts with the advantages of components. It can now be reused like a component and not have to worry about renaming field names or the wiring between the fields and the scripts. You just declare the component and you are good to go. It certainly is another layer of abstraction that one will have to learn but once you have learned it, it is very powerful. And honestly there is not much to it.

The script framework is mandated by the fact that form element/field names are automatically generated by the framework. And so you write your script in XML and use variables for these names and let the framework provide the correct names during runtime. Going further, you may also ask the framework to provide other objects that would help in creating your script. For example…

<input-symbol key="select"
    class="org.apache.tapestry.form.PropertySelection"
    required="yes"/>

This defines an input variable “select” of type “org.apache.tapestry.form.PropertySelection”. All such variables/symbols passed in to the script is stored in a symbol map. And now you can use the form select list name by using an ant style syntax like ${select.name}. The expression within “${}” is an OGNL expression and is evaluated with respect to the symbol map. You may also define your own symbols/variables using <let…> like…

<let key="formObj">
    document.${select.form.name}
</let>
<let key="selectObj">
    ${formObj}.${select.name}
</let>

These variables/symbols are stored in the symbol map also. So now if you want to set the value of the form select list all you do is say ${formObj}.${selectObj}.value = ‘whatever’; this would be equivalent to document.myForm.mySelect.value = ‘whatever’; where myForm is the form name and mySelect is the select list name.

<input-symbol...>s are like method parameters and <let...>s are like instance variables. Typically you would pass values to the <input-symbol...>s via the Script component like...

<component id="myScript" type="Script">
    <static-binding name="script" value="ScriptSpecificationName.script"/>
    <binding name="select" expression="components.somePropertySelection"/>
</component>

The actual scripts are defined in one of the two sections of the script specification, <body…> or <initialization…>, depending on when you want the script to execute. If you want the script to execute on load of the page, then you define it in the <initialization…>, if you want it to execute on any other event, define it in the <body…> section of the specification. For example…

 

  1. <body>
  2.     function onChangeList(listObj)
  3.     {
  4.         alert(listObj.value);
  5.     }
  6. </body>
  7. <initialization>
  8.     ${selectObj}.onchange = function(e)
  9.     {
  10.         onChangeList(${selectObj});
  11.     }
  12. </initialization>

As you can see in the rendered page all scripts are aggregated at the top of the page body, there are no more scripts all over the page. Even event handlers are attached to form objects in the initialization block.

One more thing to remember, scripts being components, and components by nature being independent of its environment, will render the script in the page once for every ocurrance of the component. If you want the body of the script to be rendered only once no matter how many times the component is used, just wrap the body in a <unique> tag like…

<body>
<unique>
    function onChangeList(listObj)
    {
        alert(listObj.value);
    }
</unique>
</body>

My own testing, documented in the Sept. 2001 issue of the Java Report, agrees with other testing (documented in the Tapestry discussion forums): Although straight JSPs have a slight edge in demo applications, in real applications with a database or application server backend, the performance curves for equivalent Tapestry and JSP applications are identical. Don’t think about the performance of Tapestry; think about the performance of your Java developers.

In web.xml:

add an additional servlet mapping for your tapestry application to /admin, and add the following:

  1. <security-constraint>
  2.  <web-resource-collection>
  3.   <url-pattern>/admin/*</url-pattern>
  4.  </web-resource-collection>
  5.  <auth-constraint>
  6.    <role-name>ADMIN</role-name>
  7.  </auth-constraint>
  8. </security-constraint>

In your base class for protected pages:

public void validate(IRequestCycle cycle) throws RequestCycleException {
  boolean isAdmin = getRequestCycle().getRequestContext().getRequest().isUserInRole("ADMIN");
  if (!isAdmin) {
    // not in right role
    throw new PageRedirectException.......
  }

}

you can have a number of mappings for the same app-servlet to different URIs, that way you can rely a bit more on the declarative security.

Tapestry is very much unlike most other frameworks in that it doesn’t use code generation; instead it uses a true component object model based on JavaBe properties and strong specifications. This gives Tapestry a huge amount of flexibility and enables dynamic runtime inspection of the application with the Tapestry Inspector (a mini-application that can be built into any Tapestry application).

Usage page properties:

Page1.page
<page-specification class="Welcome.Action">
        <property name="success" value="Home" />
        <property name="error" value="Error" />
</page-specification>

Page2.page
<page-specification class="Welcome.Action">
        <property name="success" value="Home2" />
        <property name="error" value="Error2" />
</page-specification>

Welcome.Action.java
public void submitListener(IRequestCycle cycle)
{
    if (success)
        cycle.activate(getSpecification().getProperty("success"));
    if (error)
        cycle.activate(getSpecification().getProperty("error"));
}

So on success, it will be redirected to Home2 and on error it will be redirected to Error2 page.

Start your servlet container with the JVM system parameter org.apache.tapestry.disable-caching set to true, i.e., -Dorg.apache.tapestry.disable-caching=true. 

Tapestry will discard cached specifications and templates after each request. You application will run a bit slower, but changes to templates and specifications will show up immediately. This also tests that you are persistent server-side state correctly. 

Of course! JBoss is free and convienient for the turn-key demonstrations. You can download Tapestry and JBoss and have a real J2EE application running in about a minute! The scripts that configure JBoss are sensitive to the particular release of JBoss, it must be release 3.0.@However, Tapestry applications are 100% container agnostic ... Tapestry doesn’t care what servlet container it is used with and does not even require an EJB container.

No – but you can copy the definition of a component pretty easily.

<component id="valueInsert" type="Insert" >
   <binding name="value" expression="getValueAt( rowIndex, columnIndex )" />
</component>

<component id="valueInsert1" copy-of="valueInsert"/>
<component id="valueInsert2" copy-of="valueInsert"/>
<component id="valueInsert3" copy-of="valueInsert"/>
<component id="valueInsert4" copy-of="valueInsert"/>

You would need to throw a RedirectException with the new URL; this sends an HTTP redirect to the client.

Make a method like the following a a listener, such as from a DirectLink or whatever.

(The Document is just a class that holds the file information you want to send to the user.)

  1. public void downloadAction(IRequestCycle cycle)
  2. {
  3.     try
  4.     {
  5.         HttpServletResponse response =
  6.         cycle.getRequestContext().getResponse();
  7.         byte[] data = new byte[1024];
  8.         FileInputStream in = document.getFileInputstream();
  9.         response.setHeader("Content-disposition",
  10.           "inline; filename=" +
  11.            document.getFileName());
  12.         response.setContentType(document.getMimeType());
  13.         response.setContentLength(new Long(document.getSize()).intValue());
  14.         ServletOutputStream out = response.getOutputStream();
  15.         while (in.read(data) > -1)
  16.         {
  17.             out.write(data);
  18.         }
  19.         in.close();
  20.         response.flushBuffer();
  21.     }
  22.     catch (IOException e)
  23.     {
  24.         e.printStackTrace();
  25.     }
  26. }

Make a method like the following a a listener, such as from a DirectLink or whatever.

(The Document is just a class that holds the file information you want to send to the user.)

public void downloadAction(IRequestCycle cycle)
{
    try
    {
        HttpServletResponse response =
        cycle.getRequestContext().getResponse();


        byte[] data = new byte[1024];
        FileInputStream in = document.getFileInputstream();


        response.setHeader("Content-disposition",
          "inline; filename=" +
           document.getFileName());
        response.setContentType(document.getMimeType());
        response.setContentLength(new Long(document.getSize()).intValue());
        ServletOutputStream out = response.getOutputStream();

        while (in.read(data) > -1)
        {
            out.write(data);
        }
        in.close();
        response.flushBuffer();
    }
    catch (IOException e)
    {
        e.printStackTrace();
    }
}

The button’s listener should get invoked when the form encounters your button during the rewind. the form’s submitListener should get invoked after the form has completed its rewind, and thus after all other listeners have been invoked. note - this can mean that the listener for a button can be invoked BEFORE the form has ’submitted’ all its values - it depends where your input fields are relative to your button.

  • No. Tapestry does not use JSP Tag library.
  • Tapestry builds on the Servlet API, but does not use JSP anyway.
  • It uses it own HTML template format and its own rendering engine.

Tapestry is open source and free. It is licensed under the Apache Software License, which allows it to be used even inside proprietary software.

Currently, no WYSIWYG editor is available for Tapestry; however, the design of Tapestry allows existing editors to work reasonably well (Tapestry additions to the HTML markup are virtually invisible to a WYSIWYG editor).Spindle is a Tapestry plugin for the excellent open-source Eclipse IDE. It adds wizards and editors for creating Tapestry applications, pages and components.