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/SlingGuideDefaultMappings" by FelixMeschberger
Date Mon, 09 Jul 2007 14:36:25 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:
http://wiki.apache.org/jackrabbit/ApacheSling/SlingGuideDefaultMappings

New page:
= Default Content Mapping and Request Rendering =

One of the big obstacles in quick adoption of Sling might arguably be the requirement for
multiple developments, such as...

   1. Creating a {{{Content}}} implementation (or decide on reusing an existing implementation)
   1. Defining the mapping descriptor to map the repository contents to the {{{Content}}}
object and vice versa
   1. Optionally create a node type defintion file in ''CND'' format
   1. Creating a {{{Component}}} implementation (or decide on reusing an existing implementation)
   1. Package this all up into an OSGi Bundle for deployment

While these steps make sense in an ideal world we all know does not exist (with the exception
of Utopia, but there are no computers in Utopia), helpers for rapid development are needed.
These helpers come in the form of usefull defaults on various levels.



== Default Content Mapping ==

When a request is processed by Sling, one step is to resolve the request URL into a {{{Content}}}
object. This works by checking the request URL for the longest match with an existing JCR
repository node. The path of this node is then used to load the {{{Content}}} object through
the {{{ContentManager.load(String)}}} method. If no mapping exists for the given node, an
exception is thrown and the request fails.

In such a case of missing content mapping, a default {{{Content}}} mapping is defined in the
form of the {{{org.apache.sling.content.jcr.DefaultContent}}} class. This mapping has the
following features:

   * The {{{DefaultContent}}} class is a {{{java.util.Map}}}. Thus all properties may be accessed
using the familiar {{{Map}}} API.
   * All non-protected properties of the node are loaded. Single value properties become scalar
objects, while multi value properties become {{java.util.List}}} objects.
   * The types of the repository values are mapped according to the JCR specification for
mapping between Property types and Java types.
   * A few properties have special significance. See below.
   * Creating new instances of this class and inserting these into the repository creates
nodes of type {{{nt:unstructured}}}. When loading instances of this class the actual primary
type of the node does not matter.


|| '''Property''' || '''Type''' || '''Description''' ||
|| {{{path}}} || String || The path of the node from which the content was loaded. This must
not be modified by application programs, unless you are prepared for unexpected behaviour
when storing the object. ||
|| {{{primaryType}}} || String || The primary node type of the (existing) node. This property
is purely informational and will never be used when inserting new content or writing back
content. ||
|| {{{mixinTypes}}} || List of String | The mixin node types of the (existing) node. This
property is purely informational and will never be used when inserting new content or writing
back content. If the node has no mixin node types, this property does not exist. ||
|| {{{sling:componentId}}} || String || The component ID of the component used to handle requests
to this content. This property may be modified by application programs (though you should
be aware of the consequences) and is used as the result of the {{{Content.getComponentId()}}}
method. ||



== Default Component Selection ==

After having mapped the JCR repository node into the {{{Content}}} object the {{{Component}}}
to actually handle the request must be resolved. This is done by calling the {{{Content.getComponentId()}}}
method and looking up this component ID in an internal table. If either the {{{Content.getComponentId()}}}
method returns {{{null}}} or no component is registered with the requested component ID a
default resolution processing takes place as follows:

   1. Let {{{cid}}} be the result of calling {{{Content.getComponentId()}}}
   1. If {{{cid}}} is {{{null}}}, let {{{cid}}} be the result of calling =Content.getPath()}}}
(this is never {{{null}}})
   1. Check for a component with the given {{{cid}}} and use it if existing
   1. Otherwise, remove any leading slash from {{{cid}}} and replace slashes by dots and check
for a component with this modified {{{cid}}} and use it if existing
   1. Otherwise, let {{{cid}}} be the fully qualified name of the {{{Content}}} object class
and check for a component with this modified {{{cid}}} and use it if existing
   1. Otherwise and if {{{cid}}} ends with the string ''Content'', remove that suffix and
check for a component with this modified {{{cid}}} and use it if existing
   1. Otherwise, append {{{Component}}} to the end of {{{cid}}} and and check for a component
with this modified {{{cid}}} and use it if existing
   1. Otherwise, let {{{cid}}} be the value of the {{{org.apache.sling.components.DefaultComponent.ID}}}
field and check for a component with this modified {{{cid}}} and use it if existing
   1. Finally, fail without having found a component to use - this is highly unlikely, though,
because the default component is part of the Sling Core bundle and should always be available.


=== DefaultComponent ===

The default component first checks whether the request is sent with parameters and will update
the {{{Content}}} object with the parameters as follows:

   * If the {{{Content}}} object is a {{{java.util.Map}}} (such as is the case for the {{{DefaultContent}}})
the properties will directly accessed through the {{{Map}}}} API. Otherwise, the {{{Content}}}
object is wrapped inside a {{{org.apache.commons.collections.BeanMap}}} to access the fields
through the {{{Map}}} API.
   * Any properties listed in the {{{_delete}}} parameter are removed. The {{{_delete}}} parameter
may contain a comma-separated list of property names and may occurr multiple times.
   * All other parameters are used to set property values, where any existing properties will
be replaced and all properties not listed in the parameters remain unmodified. If a parameter
occurrs only once a single value property is set, if  parameter occurrs multiple times, a
multi value property is set as a list of strings. Note, that any data type conversion may
happen only by the =BeanMap= as required and thus lead to failure to update a single proeperty.

After the optional update phase, the fields of the {{{Content}}} object are written back.
Again, the {{{Content}}} object is either accessed as a {{{Map}}} directly if it is a {{{Map}}}
or packed in a {{{BeanMap}}} otherwise. The format of the output is deduced from the request
URL's extension as returned by the {{{ComponentRequest.getExtension()}}} method:

|| '''Extension''' || '''Format''' ||
|| {{{html}}}, {{{htm}}} || HTML, UTF-8 encoded ||
|| {{{xml}}} || XML, UTF-8 encoded ||
|| {{{txt}}} || Plain text, UTF-8 encoded ||
|| {{{properties}}} || Java Properties file format suitable for a normal properties file ||
|| {{{json}}} || JSON, UTF-8 encoded  ||


=== Default Script ===

The easiest way to develop and deploy a component is to create a scripted component in the
repository by just creating a node of type {{{sling:scriptedComponent}}} and creating a single
JSP script at {{{jsp/start.jsp}}} below the component node. After that you can refer to that
component by the path of the component node and get the {{{start.jsp}}} script called.

For more more elaborate script selection you may of course create more scripts and refer to
them below the {{{sling:scripts}}} node of the component node.


== Rapid Development Primer ==

To summarize, for rapid development you will have to execute the following steps:

   1. Create a {{{sling:scriptedComponent}}} node, for example at {{{/some/sample/component}}}
   1. Create a JSP script file at {{{jsp/start.jsp}}} below that node; that would be {{{/some/sample/component/jsp/start.jsp}}}
in the example
   1. Create one or more nodes of any type, for example {{{nt:unstructured}}}, which have
a single value string property named {{{sling:componentId}}} referring to the component via
its path
   1. Request the node by typing its path in your browser's address field

Mime
View raw message