| <!-- $Id$ --> |
| <!-- |
| Copyright 2004 The Apache Software Foundation |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| --> |
| |
| |
| <appendix id="faq"> |
| <title>Frequently Asked Questions</title> |
| <para> |
| This section contains a few Q's and A's gleemed from the Tapestry developer mailing list. |
| </para> |
| <qandaset defaultlabel="qanda"> |
| <qandaentry> |
| <question> |
| <para> |
| <classname>java.lang.NoSuchMethodError</classname> gets thrown |
| when I attempt to use Tapestry with Tomcat. How do I fix this? |
| </para> |
| </question> |
| <answer> |
| <para> |
| <ulink url="http://jakarta.apache.org/tomcat/index.html">Tomcat</ulink> ships with version 1.0 of the |
| <ulink url="http://java.sun.com/xml/xml_jaxp.html">JAXP (Java API for XML Processing)</ulink> |
| framework. Tapestry is coded against version 1.1. You must replace the |
| <filename>jaxp.jar</filename> in Tomcat with the |
| <filename>javax.xml.jaxp.jar</filename> from Tapestry. Simply delete the old file |
| and copy the new one into the Tomcat distribution. |
| </para> |
| <para> |
| In addition you must replace <filename>parser.jar</filename> (which contains |
| an XML parser) with |
| <filename>org.apache.crimson.jar</filename>, Sun's default XML parser. |
| </para> |
| </answer> |
| </qandaentry> |
| <qandaentry> |
| <question> |
| <para>Can Tapestry be used to create a Portal application?</para> |
| </question> |
| <answer> |
| <para> |
| Of course it can! |
| </para> |
| <para> |
| This question came up pretty frequently on the SourceForge forum, so |
| I put together a mini-portal application as one of the tutorials. This sounded |
| out some limitations in the framework: the <classname>Porlet</classname> component |
| dynamically combines components from multiple pages (using the &Block; and |
| &RenderBlock; components). |
| </para> |
| </answer> |
| </qandaentry> |
| |
| <qandaentry> |
| <question> |
| <para> |
| Is Jetty required to use Tapestry? |
| </para> |
| </question> |
| <answer> |
| <para> |
| For a brief period of time, Tapestry used some Jetty specific code |
| to process file uploads. This showed up in release 2.0.0 and was fixed (removing all Jetty |
| dependencies) in release 2.0.1. |
| </para> |
| <para> |
| Tapestry still includes Jetty since it so easy to embed Jetty |
| and use it for testing and development, but it is not required. Many users |
| have had great success using Tomcat or Resin with Tapestry. |
| </para> |
| </answer> |
| </qandaentry> |
| |
| <qandaentry> |
| <question> |
| <para> |
| Why do I get NoClassDefFoundError exceptions in my Tapestry application |
| deployed under WebLogic 6.1? |
| </para> |
| </question> |
| <answer> |
| <para> |
| WebLogic appears to have a bug when deploying WAR files that contain libraries. If the library name, |
| in this case &TapestryFrameworkJar; |
| contains any periods, then WebLogic fails to expand the JAR file into its temporary deployment |
| directory. The end result is that |
| the Tapestry classes aren't on the classpath. |
| </para> |
| |
| <para> |
| The solution is to rename the Tapestry JAR file to not have periods in the name. Simply renaming it to <filename>tapestry.jar</filename> |
| or <filename>tapestry<replaceable>123</replaceable>.jar</filename> |
| will do. |
| </para> |
| </answer> |
| </qandaentry> |
| |
| <qandaentry> |
| <question> |
| <para> |
| One more time. What's this business about rewinding things for forms? |
| </para> |
| </question> |
| <answer> |
| <para> |
| This is one of the big stumbling blocks for some users of Tapestry. |
| The way Tapestry deals with forms is very complex, with a reason: it allows |
| for incredibly dynamic pages. |
| </para> |
| <para> |
| In tradional web appllications, the developer is responsible for |
| naming each form element, as well as writing a servlet to |
| handle the request cycle when the form is submitted. That turns into |
| a lot of code to extract name parameters from the &HttpServletRequest;, |
| convert them from Strings to other datatypes, and push the values |
| into appropriate business objects. |
| </para> |
| <para> |
| This works fine as far as it goes ... but the developer has an advantage |
| that the Tapestry framework doesn't have: the exact name, type and number |
| of form elements is known during development. |
| </para> |
| <para> |
| By contrast, Tapestry has to figure this all out on the fly. In addition, |
| Tapestry forms can wrap around &Foreach; components ... that means the same |
| &TextField; component may be responsible for updating a property of |
| a whole slew of objects. On top of that, the use |
| of &Conditional;, &Block; and &RenderBlock; components |
| mean that the exact set of components involved may be determined dynamically. |
| </para> |
| <note> |
| <para> |
| An example of this is the |
| <link linkend="inspector.logging">Tapestry Inspector Logging View</link>. A single |
| &PropertySelection; is wrapped by a &ListEdit; which iterates throught |
| a list of the possible categories. |
| </para> |
| <para> |
| Categories may be added at any time (in fact, that's another function |
| of the page). |
| </para> |
| </note> |
| <para> |
| Now, it's natural to envision Tapestry dynamically walking through its components |
| and HTML templates to render the form seen in the user's web browser. The |
| mental leap required is that |
| the initial renderring process has to be <emphasis>run again</emphasis> in order to figure out |
| which components are involved in processing the submission, and how. That's |
| the <emphasis>rewind phase</emphasis>. |
| </para> |
| <para> |
| Just as with the initial render, Tapestry must work through |
| just the right set of components, in just the right order, taking into account |
| &Conditional; and &Foreach; components. You must also factor in that Tapestry is |
| assigning the names used for the HTML form elements, which must also be "rediscovered" |
| so that the right HTTP parameter can be combined with the correct component and |
| assigned to the appropriate business object property. |
| </para> |
| <para> |
| Sure, this is overkill when you have a simple form to enter the user's name. |
| But doesn't it give you a warm feeling to know that when you do create |
| your killer dynamic form, the <emphasis>very same code</emphasis> you've come to know |
| and trust will be waiting to handle it, just as easily? |
| </para> |
| </answer> |
| </qandaentry> |
| <qandaentry> |
| <question> |
| <para> |
| How do I specify the CSS class used for a Tapestry component? |
| </para> |
| </question> |
| <answer> |
| <para> |
| Most Tapestry components support |
| <link linkend="components.informal-parameters">informal parameters</link>. |
| These are used to specify |
| additional HTML attributes for the tag generated by the component. |
| </para> |
| <para> |
| You can set the value for such informal parameters |
| is bindings in the &spec.component; element, or |
| in the <link linkend="components.html-template">HTML template</link>. |
| </para> |
| </answer> |
| </qandaentry> |
| <qandaentry> |
| <question> |
| <para> |
| I get the StaleSession page when I submit a form on my home page. Why? |
| </para> |
| </question> |
| <answer> |
| <para> |
| Tapestry applications run in a <link linkend="engine.stateless">stateless</link> mode initially. That is, they |
| don't create a &HttpSession;. This continues until the application has |
| some specific server-side state, at which point the &HttpSession; is created. |
| </para> |
| <para> |
| By default, &Form;s (as well as &ActionLink;s) are stateful; they require that |
| an active &HttpSession; exists. If there isn't an active session, they |
| throw a <classname>StaleSessionException</classname>. However, you can bind |
| the <varname>stateful</varname> parameter of these components to |
| <classname>Boolean.FALSE</classname> to remove this check. |
| </para> |
| <para> |
| This check makes sense once there's server side state; it detects when |
| an &HttpSession; has expired from lack of use. It's better than seeing |
| an anomolous <classname>NullPointerException</classname>, which is quite likely |
| when all state is lost. |
| </para> |
| </answer> |
| </qandaentry> |
| <qandaentry> |
| <question> |
| <para>What happened to the &ILifecycle; interface?</para> |
| </question> |
| <answer> |
| <para> |
| Prior to release 1.0.5, there was an interface, &ILifecycle;, that could |
| optionally be implemented by components so that they could be informed about the lifecycle |
| of the page which contains them, especially knowing when the page was detached from the engine (so that |
| the components could reset their state accordingly). |
| </para> |
| <para> |
| By release 1.0.5, this has become somewhat awkward. Firstly, several non-component objects needed |
| similar notification and there wasn't a way to cleanly accomplish this. Secondly, a finer grained |
| approach was desired, as different objects had different notification requirements. |
| </para> |
| <para> |
| For release 1.0.5, the interface was replaced by a more standard approach; well defined JavaBeans events. |
| These are described in the <link linkend="pages.events">Page Events</link> section of this document. |
| </para> |
| <para> |
| The &ILifecycle; interface was removed in release 2.0.0. |
| </para> |
| </answer> |
| </qandaentry> |
| <qandaentry> |
| <question> |
| <para>Why do I need to subclass &ApplicationServlet;? |
| </para> |
| </question> |
| <answer> |
| <para> |
| Several folks have suggested that subclassing &ApplicationServlet; is unneccessary, |
| and it's primary job, identifying the application specification path, could be accomplished |
| using servlet initial parameters. |
| There are several reasons why a subclass is necessary, outlined in this |
| <link linkend="engine.servlet.subclass-note">note</link>. Primarily, it's |
| a class loader issue. |
| </para> |
| </answer> |
| </qandaentry> |
| <qandaentry> |
| <question> |
| <para>What happened to <classname>ValidatingTextField</classname>, |
| <classname>NumericField</classname>, |
| <classname>DateField</classname> |
| and <classname>IntegerField</classname>? |
| </para> |
| </question> |
| <answer> |
| <para> |
| In release 1.0.8, the entire suite of components related to validating |
| form input was rewritten. A single component, &ValidField;, now does the work |
| of all the others. In the earlier version, component subclasses were needed |
| to change the behavior: converting objects to strings, strings to objects and |
| validating. This is now encapsulated in the &IValidator; interface. In short, it is now |
| much easier to create new kinds of validations and just plug them into the |
| &ValidField;. |
| </para> |
| |
| <para>This was, regrettably, a completely non-backwards compatible change. However, |
| compatible versions of three of the 1.0.7 components |
| (<classname>ValidatingTextField</classname>, |
| <classname>NumericField</classname> and |
| <classname>DateField</classname>) are now part of the |
| &TapestryContribJar; library. |
| </para> |
| |
| <para> |
| In addition, the old components had big disclaimers: "Don't use these inside |
| any kind of loop (such as a &Foreach;)". By expanding the role of the |
| &IValidationDelegate;, this is no longer so, the delegate now does much more, |
| including the ability to track errors for fields even inside loops. |
| </para> |
| </answer> |
| </qandaentry> |
| <qandaentry> |
| <question> |
| <para>Why don't my &Upload; components work? I keep getting NullPointerExceptions. |
| </para> |
| </question> |
| <answer> |
| <para> |
| The &Upload; component creates an <sgmltag class="starttag">input type="file"</sgmltag> |
| HTML element. This requires that the containing <sgmltag class="starttag">form</sgmltag> element |
| use the encoding MIME type <literal>multipart/form-data</literal>. This is accomplished by |
| setting the informal parameter <property>enctype</property> of the containing &Form; component to |
| <literal>multipart/form-data</literal>. |
| </para> |
| </answer> |
| </qandaentry> |
| |
| |
| <qandaentry> |
| <question> |
| <para>Why isn't Tapestry a JSP taglib?</para> |
| </question> |
| <answer> |
| <para> |
| Simply put, Tapestry needs to run the whole show, from the point the request is receieved by |
| the servlet all the way through to the end of sending a response page back to the client. |
| All the benefits of Tapestry come from |
| features that JSPs just don't provide ... knowing the full component heirarchy for the page, |
| and tracking which components are wrapped inside which others, no matter how dynamic the |
| rendering process is. The way components can work together to generate different |
| portions of the page is both powerful and necessary -- |
| that's how Tapestry builds the URLs for links and forms. |
| </para> |
| |
| <para> |
| By comparison, something like |
| <ulink url="http://jakarta.apache.org/">Struts</ulink> |
| still relies on the developer to do most of the work, by defining Actions ... which are |
| little more than a dressed up version of a servlet. Although it has some rudimentary |
| forms support (that can also be leveraged to process query parameters from ordinary links), |
| it's still an awful lot of coding. |
| </para> |
| |
| </answer> |
| </qandaentry> |
| |
| |
| |
| |
| |
| <qandaentry> |
| <question> |
| <para> |
| I've fixed all my imports to use <filename>org.apache.tapestry</filename>, but |
| my &DirectLink; listener methods no longer work. How do I fix things? |
| </para> |
| </question> |
| <answer> |
| <para> |
| With the removal of the <classname>IDirectListener</classname> |
| interface, the corresponding listener method variation was removed. The following |
| method signature <emphasis>used to</emphasis> |
| be recognized as a listener method: |
| </para> |
| |
| <informalexample> |
| <programlisting> |
| public void <replaceable>my-method</replaceable>(String[] parameters, &IRequestCycle; cycle) |
| throws RequestCycleException |
| { |
| ... |
| } |
| </programlisting> |
| </informalexample> |
| |
| <para> |
| In the new, simpler, scheme, listener methods take exactly one parameter, |
| the &IRequestCycle;. |
| The service parameters are now available from the &IRequestCycle;: |
| </para> |
| |
| <informalexample> |
| <programlisting> |
| public void <replaceable>my-method</replaceable>(IRequestCycle cycle) |
| throws RequestCycleException |
| { |
| Object[] parameters = cycle.getServiceParameters(); |
| ... |
| } |
| </programlisting> |
| </informalexample> |
| |
| <para> |
| Starting in release 2.2, the type of each parameter is encoded with its |
| value in the URL (in release 2.1 and earlier, the parameters were always Strings, |
| and it was your responsibility to convert them). |
| You can cast from &Object; |
| to a particular type (say, &Integer; or &String;). |
| </para> |
| |
| </answer> |
| </qandaentry> |
| |
| |
| <qandaentry> |
| <question> |
| <para> |
| How do I duplicate a component several times in the same HTML template? |
| </para> |
| </question> |
| |
| <answer> |
| <para> |
| Simply put: you can't. Component ids must be unique in the template and |
| must match aganst component specification. Even when two components |
| are the same type and have identical bindings, they are still unique |
| instances and have instance-specific state ... such as the portion of |
| the HTML template they wrap (for components with bodies). |
| </para> |
| |
| <para> |
| A useful shortcut is to use |
| the <literal>copy-of</literal> |
| attribute of the |
| &spec.component; element. |
| </para> |
| </answer> |
| |
| </qandaentry> |
| |
| </qandaset> |
| </appendix> |