Summary
Definitions
Overview
Illustration 1
Illustration 2
Illustration 3
-The Framework - a flyby-
Conclusion
Biography
Resources
|
The framework - a flyby
In the above illustrations, we saw how we can utilize the services
provided by the framework to build our applications elegantly and
effortlessly. Here, we will skim the framework and unveil some of the
key objects and their mechanics, that provide these services.
In the servlet world, every user request goes through a cycle of being
sent to the server, mapped to a servlet, processed in the servlet using
the query string, Request and Session objects, responded by the servlet
by manually building the markup and finally rendered in the browser.
This cycle entails a lot of convoluted, shoddy coding that frustrates
developers and maintainers. Tapestry framework is a rich API that
deconvolutes this coding and shields the developer from the shoddiness.
The API, built on top of the servlet API, provides the developer with
all the servlet functionality, and a lot more, in a much friendly way,
in the form of objects that forms the framework.
We saw in our illustrations that Pages are made of three parts - the
template, the specification and the component class, and that a Page
may be composed of other components recursively that are in turn each
made of the three parts. This means, when a request is made for a
particular page, the framework has to build a single HTML page from the
three parts of the Page component and recursively from the parts of its
contained components. This build task entails resolving, parsing and
loading the XML specification, instantiating the component class and
resolving, parsing and loading the template. The "loading"
step is where the bulk of the work happens that involves building all
contained components recursively. This build step for each contained
component entails the same steps as the build task of the Page. At the
end of the build task, we have an object, Page object, of type
org.apache.tapestry.IPage that represents the entire Page.
BasePage that we saw earlier is an object of this type.
The analagous object that you will have at the end of building a JWC
will be of type org.apache.tapestry.IComponent . The making
of these objects, as we have just learned, is quite an involved,
time-consuming process, and it would be a huge performance impact to
discard it after one use. This gives rise to the concept of caching.
When a request is made for a particular page, the framework goes to a
Source object, org.apache.tapestry.engine.IPageSource , to
get an instance of the requested Page. The Page Source object maintains
a pool of Page objects previously built and pops one out for each
request. If the pool is empty, it is responsibility of the Page Source
object to build the Page object and provide it to the framework. Once
the request is processed, the Page is returned back to the Source and
put in the pool for future use. In addition to
IPageSource , the framework has a few other Source objects that
is used in obtaining other resources -
org.apache.tapestry.engine.ISpecificationSource and
org.apache.tapestry.engine.ITemplateSource are a couple of them.
Each of these Source objects caches the objects they provide in a pool
just like the Page Source. Ok, we now know that the framework goes to
the Source object to retrieve the Page, but how does the framework know
which Page was requested in the first place? Well, to answer that, we
need a bit of understanding of the wiring in a Page.
When the framework renders a Page, contained components encode
framework specific information including the Page name into the Page.
Later when the Page is submitted, this information, in the form of
request parameters, is read by the framework and parsed to retrieve the
Page name and other information used by the framework for request
processing. This responsibility of encoding and parsing of request
parameters is entrusted with the framework Service object -
org.apache.tapestry.engine.IEngineService . All components go to
the Service object to encode or parse request parameters. The framework
comes with a predefined set of Services for different types of user
requests - enter a Tapestry application
(org.apache.tapestry.engine.HomeService ), navigate to a
Page (org.apache.tapestry.engine.PageService ), submit a
form (org.apache.tapestry.engine.DirectService or
org.apache.tapestry.engine.ActionService ) just to name a few.
When components encode the component-specific request parameters, they
also encode the type of Service object they used to encode their
request parameters. This enables the framework to go to the right
Service object to parse the various components' request parameters.
The other responsibility of the Service object is to manage the request
processing (includes loading the Page and executing the listeners of
the component class) and response rendering (includes setting the
correct content type and rendering the Page) tasks. In addition to the
framework provided Services, the developer is empowered with the
framework API to implement any number of custom Services that one may
need. These custom Services are specified in the application
specification via the <service> element.
The framework provides support for many other aspects of a Tapestry
application viz. localization, application state management, bytecode
enhancement and script support to name a few. All these, and other,
different aspects of the web application is managed by an aptly named
pivotal framework object, the engine -
org.apache.tapestry.IEngine . The Engine object is responsible
for instantiating and initializing most of the objects needed for
processing the request including the Service objects, Source objects,
object pools and others. These objects that the Engine initializes are
common to all instances of the application and so are held in the
ServletContext . Application data common to all instances
of the application is stored in a developer provided
Plain-Old-Java-Object called the Global. The Global object, like other
request-processing objects, is also managed by the Engine and stored in
the ServletContext . The developer specifies the Global
object via the application specification property
org.apache.tapestry.global-class . Data specific to a single
instance (user session data) will be stored in a special object called
the "Visit". The Visit is also a developer provided
Plain-Old-Java-Object that is managed by the Engine. The Engine creates
the Visit when necessary and stores it in HTTPSession . The
developer specifies the Visit object via the application specification
property org.apache.tapestry.visit-class .
A user request mapped to a Tapestry servlet is delegated to the Engine
for processing. The Engine handles the controller aspect and delegates
it further to the Engine Service. This chain-of-responsibility requires
that the objects needed for request processing be passed around to
every single object that has any processing responsibility. Passing
around a bunch of objects can and will be unmaintainable. To solve this
problem, the framework wraps all objects required for request
processing in a single object of type
org.apache.tapestry.IRequestCycle . Request Cycle wraps the
HTTPServletRequest , HTTPServletResponse ,
Engine, Engine Service and the current Page among other objects. With
all this wrapped information, the Request Cycle acts as a facade to the
request processing event.
|