jackrabbit-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Apache Wiki <wikidi...@apache.org>
Subject [Jackrabbit Wiki] Update of "ApacheSling/ComponentAPI" by FelixMeschberger
Date Wed, 04 Jul 2007 09:53:58 GMT
Dear Wiki user,

You have subscribed to a wiki page or wiki category on "Jackrabbit Wiki" for change notification.

The following page has been changed by FelixMeschberger:

The comment on the change is:

New page:
= The Component API =


== Introduction ==

The Component API defines a presentation framework to build Web Applications. As such the
Component API builds upon the Servlet API but extends the latter with new functionality:

   * A web page may be built from many different pieces. This aggregation of different pieces
is comparable to the functionality provided by the Portlet API. In contrast to the latter,
though, the pieces may themselves be aggregates of yet more pieces. So a single web page response
may consist of a tree of pieces.
   * Just like the Servlet API and the Portlet API the Component API just defines a Java based
framework. Implementing the rendering of pieces in some scripting language is left to the
implementation of the Component API.
   * In contrast to the Servlet API and the Portlet API, the Component API is content centric.
That is, the request URL does not address a servlet or a portlet but a piece of content represented
by an instance of the {{{com.day.components.Content}}} interface. From this content object,
the Component framework will derive the {{{com.day.components.Component}}} instance, which
is used to perform any actions and render the response.

An implementation of the presentation framework defined by the Component API is called a _Component

=== Going Content Centric ===

Traditional web applications are built around the notion of a traditional application which
is converted into an application which may be used using a Web Browser. Web applications consist
of a series of servlets and JSP scripts, which are called based on configuration in the web
application deployment descriptor. Such applications are generally based on some internal
database or some static filesystem content.

The Component API on the other hand looks more like a traditional web server from the outside,
which delivers more or less static content. Thus, while the traditional web application uses
the request URL to select a piece of code to execute, the Component API uses the URL to select
a piece of content to be delivered. 

Apart from using the URLs to address content resources, the Component API abstracts away from
a concrete persistence store implementation by defining ''content'' to be an instance of a
class which implements the {{{Content}}} interface. Instantiation and management of content
is left to the Component Framework.

=== Comparsion to the Servlet API ===

The Component API builds upon the Servlet API. Generally a Component Framework will run inside
a Servlet Container and be manifested towards the Servlet Container as a single Servlet, which
dispatches requests to the Components depending on the request URLs.

Response rendering may itself be a multi-step operation. Depending on the Component implementation,
the rendering may include dispatching for child (or even foreign) Content.

=== Comparision to the Portlet API ===

Unlike the Portlet API, which defines one single level of portlet hierarchy - portlets are
just pieces residing besides each other - the Component API allows for hierarchic structuring
of Content and hence Compoent renderings. To support this structuring, the Component Framework
does not control the rendering process of all elements on the page like the Portlet Container
does for the portlets. Instead only the Content object addressed by the request URL is processed
and it is left to the Component rendering that Content to dispatch other Content/Component
tupels to add more data to the response. 

=== To Iterator or To Enumerate ===

With the advent of the Java Collection framework in Java 2, the {{{Enumeration}}} has been
superceded by the {{{Iterator}}}. So the natural choice for the Component API for methods
to return enumeratable collection of objects would have be to declare the use of {{{Iterator}}}
instances. But because the Servlet API defines to use {{{Enumeration}}} instances, the Component
API will also declare the use of {{{Enumeration}}} instances for consistency with the Servlet
API extended by the Component API.

== Request Processing ==

Unlike traditional Servlet API request processing, a Component API request is processed by
the Component Framework in four basic steps:

 Content Resolution:: The Component Framework derives a Content instance from the client request
URL. The details of how to resolve the Content data and how to instantiate and populate the
object is outside the scope of this document. One possible solution would be to map the request
URL to a [http://www.jcp.org/en/jsr/detail?id=170 Java Content Repository] Node and to use
an object content mapping tool (e.g. [http://incubator.apache.org/graffito/jcr-mapping/index.html
Jackrabbit Object Content Mapping]) to instantiate such an object.
 Component Resolution:: From the Content object created in the first step, the Component object
is resolved from the Component ID retrieved from the Content object. The Component ID is a
simple string, whose semantics is defined by the Component Framework. One possible definition
could be for the Component ID to the fully qualified name of a class implementing the {{{Component}}}
 Input Processing and Response Generation:: After getting the Content and the Component, the
=Component.service()= method is called to process any user supplied input and send the response
to the client. To structure the rendered response page, this method is responsible to include
other content. See [[#Dispatching_Requests][Dispatching Requests]] for details. See [[#Error_Handling][Error
Handling]] below for a discussion how exceptions and HTTP stati are handled.

=== URL decomposition ===

During the ''Content Resolution'' step, the client request URL is decomposed into the following

 Content Path:: The longest substring of the request URL resolving to a Content object such
that the content path is either the complete request URL or the next character in the request
URL after the content path is either a dot ({{{.}}}) or a slash ({{{/}}}).
 Selectors:: If the first character in the request URL after the content path is a dot, the
string after the dot upto but not including the last dot before the next slash character or
the end of the request URL. If the content path spans the complete request URL or if a slash
follows the content path in the request URL, no seletors exist. If only one dot follows the
content path before the end of the request URL or the next slash, no selectors exist.
 Extension:: The string after the last dot after the content path in the request URL but before
the end of the request URL or the next slash after the content path in the request URL. If
a slash follows the content path in the request URL, the extension is empty.
 Suffix Path:: If the request URL contains a slash character after the content path and optional
selectors and extension, the path starting with the slash upto the end of the request URL
is the suffix path. Otherwise, the suffix path is empty.

'''Examples''': Assume there is Content at {{{/a/b}}}, which has no child content.

|| '''URI''' || '''Content Path''' || '''Selectors''' || '''Extension''' || '''Suffix''' ||
|| /a/b                      || /a/b || ""    || ""   || ""         ||
|| /a/b.html                 || /a/b || ""    || html || ""         ||
|| /a/b.s1.html              || /a/b || s1    || html || ""         ||
|| /a/b.s1.s2.html           || /a/b || s1.s2 || html || ""         ||
|| /a/b/c/d                  || /a/b || ""    || ""   || /c/d       ||
|| /a/b.html/c/d             || /a/b || ""    || html || /c/d       ||
|| /a/b.s1.html/c/d          || /a/b || s1    || html || /c/d       ||
|| /a/b.s1.s2.html/c/d       || /a/b || s1.s2 || html || /c/d       ||
|| /a/b/c/d.s.txt            || /a/b || ""    || ""   || /c/d.s.txt ||
|| /a/b.html/c/d.s.txt       || /a/b || ""    || html || /c/d.s.txt ||
|| /a/b.s1.html/c/d.s.txt    || /a/b || s1    || html || /c/d.s.txt ||
|| /a/b.s1.s2.html/c/d.s.txt || /a/b || s1.s2 || html || /c/d.s.txt ||

== The ComponentRequest ==

The {{{org.apache.sling.component.ComponentRequest}}} interface defines the basic data available
from the client request to both action processing and response rendering. The ComponentRequest
extends the ==javax.servlet.http.HTTPServletRequest==.

This section describes the data available from the ComponentRequest. For a complete and normative
description of the methods, refer to the Component API JavaDoc. The following information
is represented for reference. In the case of differences between the following descriptions
and the Component API JavaDoc, the latter takes precedence.

 Content access:: Content may be accessed from the ComponentRequest object through the following
methods: {{{getChildren(Content parent)}}}, {{{getContent()}}}, {{{getContent(String path)}}}.
 Request URL information:: In addition to the standard HttpServletRequest information the
ComponentRequest provides the following methods: {{{getExtension()}}}, {{{getSelector(int
index)}}}, {{{getSelectors()}}}, {{{getSelectorString()}}}, {{{getSuffix()}}}. Note that the
content path is not directly available form the ComponentRequest object. Instead it is available
through the {{{Content.getPath()}}} method of the Content object retrieved through {{{ComponentRequest.getContent()}}}.
 Request Parameters:: To support user input submitted as {{{multipart/form-data}}} encoded
POST parameters, the Component API intrduces the {{{RequestParameter}}} interface allowing
file uploads. Request parameters represented as {{{RequestParameter}}} objects are returned
by the following methods: {{{getRequestParameter(String name)}}}, {{{getRequestParameterMap()}}},
{{{getRequestParameters(String name)}}}.
 Request Dispatching:: In addition to standard Serlvet API request dispatching, the Component
API supports dispatching requests to render different Content using {{{ComponentRequestDispatcher}}}
objects returned by this method: {{{getRequestDispatcher(Content content)}}}.
 Miscellaneous:: Finally the ComponentRequest interface provides the following methods: {{{getCookie(String
name)}}}, {{{getResponseContentType()}}}, {{{getResponseContentTypes()}}}, {{{getResourceBundle(Locale

The ComponentRequest objects are only valid during the time of executing the =performAction=
or =render= methods. Implementations of these methods must not keep references for later use.
As such, the ComponentRequest interface and its extensions are defined to not be thread safe.

''A note on HTTP Sessions'': The ComponentRequest extends the HttpSerlvetRequest and thus
supports standard HTTP sessions. Be aware, though that Sessions are server side sessions and
hence violate the sessionless principle of REST and therefore should be used with care. It
is almost always possible to not use sessions.

== The ComponentResponse ==

The {{{com.day.components.ComponentResponse}}} interface extends the {{{javax.servet.http.HttpServletResponse}}}
interface with just the following methods: {{{getContentType()}}}, {{{getNamespace()}}}.

== The Content ==

The {{{org.apache.sling.component.Content}}} interface defines the general contract required
by Content objects handled by the Component framework. Implementations may provide any means
to implement and/or extend this interface. The interface defines the following methods:

 getComponentId():: Returns the identifier of the Component used to handle the action and
render the response for the client request underlying the Content object.
 getPath():: Returns the path derived from the client request URL which lead to the creation
of the Content object. See the [#URL_decomposition URL decomposition] section above for more
information. It is not required, that the Content object path be a part of the original client
request URL. The request URL may also have been mapped to some internal path.

== The Component ==

The {{{org.apache.sling.component.Component}}} interface defines the API implemented to actually
handle requests. As such the Component interface is comparable to the =javax.servlet.Servlet=
interface. Like those other interfaces, the Component interface provides methods for life
cycle management: {{{init(ComponentContext context)}}}, {{{destroy()}}}.

=== Processing the Request ===

The Component Framework calls the {{{service(ComponentRequest request, ComponentResponse response)}}}
method of the Component to have the component process the request optionally processing user
input, rendering the response and optionally dispatch to other Content/Component tuples to
provide more response data.

=== Content and its Component ===

The Content object and a Component form a pair, in which the Content object takes the passive
part of providing data to the Component and the Component takes the active part of acting
upon the Content object. As a consequence, there always exists a link between a given implementation
of the Content interface and a given implementation of the Component interface.

This link is manifested by the Component identifier available from the Content object through
the {{{Content.getComponentId()}}} method on the one hand. On the other hand, the link is
manifested by the {{{getContentClassName()}}} and {{{createContentInstance()}}} methods of
the Component interface.

=== Component Lifecylce ===

When a Component instance is created and added to the Component framework, the {{{init(ComponentContext)}}}
method is called to prepare and initialize the Component. If this method terminates abnormally
by throwing an exception, the Component is not used. The Component Framework implementation
may try at a later time to recreate the Component, intialize it and use it. If the Component
Framework tries to recreate the Component a new instance of the Component must be created
to be initialized and used.

When the Component has successfully been initialized, it may be referred to by Content objects.
When a client request is to be processed, the Content object is resolved and the {{{service}}}
method on the Component to which the Content object refers is called. The {{{service}}} method
may - and generally will - be called simultaneously to handle different requests in different
threads. As such, implementations of these methods must be thread safe.

When the Component Framework decides to take a Component out of service, the {{{destroy()}}}
method is called to give the Component a chance to cleanup any held resources. The destroy
method must only be called by the Component Framework when no more request processing is using
the Component, that is no thread may be in the {{{service}}} method of a Component to be destroyed.
Irrespective of whether the destroy method terminated normally or abnormally, the Component
will not be used again.

The addition and removal of Components is at the discretion of the Component Framework. A
Component may be loaded at framework start time or on demand and my be removed at any time.
But only one single Component instance with the same Component identifier may be active at
the same time within a single Component Framework instance.

=== The ComponentExtension ===

To enhance the core functionality of Components, each Component may have zero, one ore more
Component Extensions attached. A Component Extensions is a Java object implementing the {{{org.apache.sling.component.ComponentExtension}}}
interface. This interface just defines a {{{getName()}}} method to identify extensions.

The concrete implementation as well as instantiation and management of Component Extensions
is left to the Component Framework implementation with one restriction though: The extensions
must be available to the Component at the time the {{{init(ComponentContext)}}} method is
called may only be dropped after the {{{destroy()}}} method terminates.

The Component interface defines two methods to access Extensions: The {{{getExtensions()}}}
method returns a {{{java.util.Enumeration}}} of all ComponentExtension objects attached to
the component. If no Component Extension are attached to the Component, an empty enumeration
is returned. The {{{getExtension(String name)}}} returns the named Component Extension attached
to the Component or {{{null}}} if no such Component Extension is attached to the Component.

Component Frameworks are allowed to share Component Extension instances of the same name between
different Component instances. Regardless of whether Component Extensions are shared or not,
they must be thread safe, as any Component Extension may be used within the {{{service}}}
method, which themselves may be called concurrently.

== Dispatching Requests ==

To include renderings of child Content objects, a {{{org.apache.sling.component.ComponentRequestDispatcher}}}
object may be retrieved from the ComponentContext with which the Component has been initialized
or from the ComponentRequest provided to the service method. Using this dispatcher the reponse
of rendering the Content may be included by calling the {{{ComponentRequestDispatcher.include(ComponentRequest,
ComponentResponse)}}} method.

This method is comparable to the {{{RequestDispatcher.include(ServletRequest, ServletResponse}}}
method of the Servlet API but dispatching by the {{{ComponentRequestDispatcher}}} does not
go through the servlet container and stays within the Component Framework.

The {{{service}}} method of included Components are called with an instance of the {{{ComponentRequest}}}
interface whose {{{getContent()}}} returns the Content object for the included Content.

When a Component is included by another component the following request attributes are set:

|| '''Request Attributes''' || '''Type''' || '''Description''' ||
|| {{{org.apache.sling.component.request.content}}} || String || The {{{Content}}} instance
to which the client URL resolved. This attribute is set when included Components are being
rendered and it is not set for the Component directly addressed by the client request. ||
|| {{{org.apache.sling.component.request.component}}} || String || The {{{Component}}} instance
for the {{{Content}}} object to which the client URL resolved. This attribute is set when
included Components are being rendered and it is not set for the Component directly addressed
by the client request. ||

=== Error Handling ===

While processing requests, the {{{service}}} methods called may have problems. Components
have multiple options of reporting issues during processing to the client:

 * Set the status of the HTTP response calling the {{{ComponentResponse.setStatus}}} method
 * Send an error page calling the {{{ComponentResponse.sendError}}} method
 * Throw an exception

If such an exception is thrown, the Component Framework must act upon the exception in one
of the following ways:

   * If the request is processed through Servlet API request inclusion, the exception must
be given back to the servlet container. A {{{ComponentException}}} is just forwarded as a
{{{ServletException}}}. This is a requirement of the Servlet API specification which states
for included requests:

|| '''SRV.8.5 Error Handling''' [[BR]]If the servlet that is the target of a request dispatcher
throws a runtime exception or a checked exception of type ServletException or IOException,
it should be propagated to the calling servlet. All other exceptions should be wrapped as
ServletExceptions and the root cause of the exception set to the original exception, as it
should not be propagated. ||

   * Otherwise, the Component Framework may handle the error itself in a manner similar to
the error handling approach defined the Servlet API specification (Section SRV 9.9 Error Handling
of the Java Servlet Specification 2.4). Specifically the request attributes defined by the
Servlet API specification must be set for the error handler:

|| '''Request Attributes''' || '''Type''' || '''Description''' ||
|| {{{javax.servlet.error.status_code}}} || {{{java.lang.Integer}}} || The status code of
the response. In the case of an exception thrown from the {{{service}}}, the code is defined
by the Component Framework. ||
|| {{{javax.servlet.error.exception_type}}} || {{{java.lang.Class}}} || The fully qualified
name of the exception class thrown. This attribute does not exist, if error handling does
not result from an exception. This attribute is maintained for backwards compatibility according
to the Servlet API Specification. ||
|| {{{javax.servlet.error.message}}} || {{{java.lang.String}}} || The message of the exception
thrown. This attribute does not exist, if error handling does not result from an exception.
This attribute is maintained for backwards compatibility according to the Servlet API Specification.
|| {{{javax.servlet.error.exception}}} || {{{java.lang.Throwable}}} || The exception thrown.
This attribute does not exist, if error handling does not result from an exception. ||
|| {{{javax.servlet.error.request_uri}}} || {{{java.lang.String}}} || The request URL whose
processing resulted in the error. ||
|| {{{javax.servlet.error.servlet_name}}} || {{{java.lang.String}}} || The name of the servlet
which yielded the error. The servlet name will generally not have any significance inside
the Component Framework. ||
|| {{{com.day.components.error.componentId}}} || {{{java.lang.String}}} || The identifier
of the Component whose {{{service}}} method has caused the error. This attribute does not
exist, if the Component Framework itself caused the error processing. ||

   * If the Component Framework decides to not handle the error itself, the exception must
be forwarded to the servlet container as a {{{ComponentException}}} wrapping the original
exception as its root cause.

This specification does not define, how error handlers are configured and used if the Component
Framework provides error handling support. Likewise the Component Framework may or may not
implement support to handle calls to the {{{ComponentResponse.sendError}}} method. The Component
Framework may also use its own error handling also for errors resulting from request processing
failures, for example if authentication is required or if the request URL cannot be resolved
to a Content object.

View raw message