| <!-- $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. |
| --> |
| |
| <chapter id="beans"> |
| <title>JavaBeans and Properties</title> |
| <para> |
| The Tapestry framework is based upon the use of |
| <ulink url="http://java.sun.com/j2se/1.3/docs/api/java/beans/package-summary.html">JavaBeans</ulink> |
| and JavaBeans properties. This chapter is a short review |
| of these concepts. A more |
| involved discussion is available as part of the |
| <ulink url="http://java.sun.com/docs/books/tutorial/javabeans/index.html">Java Tutorial</ulink>. |
| </para> |
| <section id="beans.beans"> |
| <title>JavaBeans</title> |
| <para> |
| The JavaBeans framework is a way of manipulating Java objects when their exact type is not known. The |
| ability to make objects work together, when their exact type is not known, is very powerful. It's an example |
| of the kind of flexibility availble in a highly dynamic language like Java that is not possible in |
| lower-level languages such as C++. |
| </para> |
| <para> |
| The JavaBeans framework is the basis for a number of component-based frameworks, including Java's AWT and Swing GUI |
| libraries, as well as Tapestry. The idea is that, by following a few naming rules and coding |
| conventions, it is possible to "plug into" a framework with new classes, classes not even written yet |
| when the framework is created. In Tapestry terms, this is used to allow the creation of new Tapestry components. |
| </para> |
| <para> |
| Any Java object can act as a JavaBean; it just has to follow certain naming conventions (discussed in |
| <link linkend="beans.properties">the next section</link>). In cases where a framework needs to create new |
| instances of a class, such as when Tapestry creates a new instance of a component, |
| the Java class must implement a public, no arguments constructor (it may implement additional constructors as |
| well). |
| </para> |
| <para> |
| The <ulink url="http://java.sun.com/j2se/1.3/docs/api/java/lang/reflect/package-summary.html">Java Reflection API</ulink> allows Tapestry to access the methods, attributes and constructors of a class. |
| </para> |
| </section> |
| <section id="beans.properties"> |
| <title>JavaBeans Properties</title> |
| <para> |
| For Tapestry, the central concept for JavaBeans are properties. The JavaBeans framework allows Tapestry to |
| treat any object as a collection of named properties. Tapestry frequently reads, and occasionally writes, values |
| from or to these named properties. |
| </para> |
| <para> |
| A property is <emphasis>not</emphasis> the same as an <emphasis>attribute</emphasis> ... though, most often, each property is backed up by an attribute. |
| To Tapestry, and the Reflection API, a property is a set of public methods on the object. |
| Accessing a property involves invoking one of these methods. |
| </para> |
| <example> |
| <title>JavaBeans getter method</title> |
| <programlisting> |
| public <replaceable>type</replaceable> get<replaceable>Name</replaceable>() |
| { |
| ... |
| } |
| </programlisting> |
| </example> |
| <example> |
| <title>JavaBeans setter method</title> |
| <programlisting> |
| public void set<replaceable>Name</replaceable>(<replaceable>type</replaceable> value) |
| { |
| ... |
| } |
| </programlisting> |
| </example> |
| <para> |
| A property may be read-only or write-only (that is, it may implement just one of the |
| two methods). The <replaceable>type</replaceable> may be a scalar type (boolean, int, etc.) |
| or any Java class. |
| </para> |
| <para> |
| Note the naming; the first letter of the property name is capitalized after <literal>get</literal> |
| or <literal>set</literal>. JavaBeans properties are case sensitive with respect to the method names |
| and the property names. A special case exists when the name is an acronyn; this is recognized |
| by two or more upper-case letters in a row (after get or set); in this case, the property name |
| does <emphasis>not</emphasis> have the first letter convert to lower-case. |
| </para> |
| <para> |
| As a special case, a boolean property may use an alternate name for the getter method: |
| </para> |
| <example> |
| <title>JavaBeans getter method (boolean)</title> |
| <programlisting> |
| public boolean is<replaceable>Name</replaceable>() |
| { |
| ... |
| } |
| </programlisting> |
| </example> |
| <para> |
| Although the normal implementation is to get or set an instance variable, more complicated options are |
| possible. One pattern is <emphasis>lazy evaluation</emphasis>, where an expensive calculation is |
| put off until the actual value is needed, for example: |
| </para> |
| <example> |
| <title>Lazy evaulation of JavaBeans property</title> |
| <programlisting> |
| |
| public List userNames = null; |
| |
| /** |
| * Returns a List of user names obtained from the database. |
| * |
| **/ |
| |
| public List getUserNames() |
| { |
| if (userNames == null) |
| userNames = fetchUserNamesFromDatabase(); |
| |
| return userNames; |
| } |
| </programlisting> |
| </example> |
| <para> |
| Here, the first time the method is invoked, the expensive database fetch occurs. The value |
| returned from the database is then cached for later invocations. |
| </para> |
| <para id="beans.properties.synthesized"> |
| Another common pattern is a <emphasis>synthesized property</emphasis>. Here, there is no |
| real attribute at all, the value is always computed on the fly. A frequent use of this is to |
| avoid tripping over null pointers. |
| </para> |
| <example> |
| <title>Synthesized JavaBeans Property</title> |
| <programlisting> |
| /** |
| * Returns the name of the company's account representative, if |
| * if the company has one, or null otherwise. |
| * |
| **/ |
| |
| public String getAccountRepName() |
| { |
| AccountRep rep = company.getAccountRep(); |
| |
| if (rep == null) |
| return null; |
| |
| return rep.getName(); |
| } |
| </programlisting> |
| </example> |
| <para> |
| This example creates a synthetic property, <varname>accountRepName</varname>. |
| </para> |
| </section> |
| <section id="beans.property-path"> |
| <title>Property Paths</title> |
| <para> |
| The JavaBeans framework provides basic named properties for JavaBean objects. Tapestry |
| extends this from simple properties to <emphasis>property paths</emphasis>. |
| </para> |
| <para> |
| A property path is a series of property names, separated by periods. When reading a property path, each |
| property is read in series. |
| </para> |
| <para> |
| In the <link linkend="intro.ex">example from the introduction</link>, the property path <varname>visit.userName</varname> |
| was referenced. This path means that the <varname>visit</varname> property of the start object (a Tapestry page) should be accessed, then the <varname>userName</varname> property of the visit object should |
| be accessed. This is approximately the same as Java code |
| <literal>getVisit().getUserName()</literal> (except that property access is not typesafe). |
| </para> |
| <para> |
| In some cases, property paths are used to change a value, instead of reading it. When this occurs, all properties |
| but the last a read; only the last property is written. In other words, updating <varname>visit.userName</varname> |
| would be similar to the JavaCode <literal>getVisit().setUserName(<replaceable>value</replaceable>)</literal>. |
| </para> |
| <para> |
| Property paths can be of any length; however, they are just as susceptable to <classname>NullPointerException</classname>s |
| as any other JavaCode. Care must be taken that none of the properties in a property path, |
| except the final one, return null. This can often be accomplished |
| using <link linkend="beans.properties.synthesized">synthesized properties</link>. |
| </para> |
| |
| </section> <!-- beans.property-path --> |
| |
| <section id="beans.ognl"> |
| <title>Object Graph Navigation Library</title> |
| |
| <para> |
| Beyond even simple property paths are the powerful Object Graph |
| Navigation Library (OGNL) <emphasis>expressions</emphasis>. |
| OGNL expressions are modeled after Java expressions; they can |
| invoke methods, perform comparisons, do arithmetic ... even build collections on the fly. |
| </para> |
| |
| |
| |
| <para> |
| OGNL is a separate framework from Tapestry; further details about it |
| are available at |
| <ulink url="http://www.ognl.org">http://www.ognl.org</ulink>. |
| </para> |
| |
| |
| </section> <!-- beans.ognl --> |
| </chapter> |