incubator-sling-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From conflue...@apache.org
Subject [CONF] Apache Sling > Add ResourceResolverFactory Service Interface
Date Sat, 02 Jan 2010 15:48:00 GMT
<html>
<head>
    <base href="http://cwiki.apache.org/confluence">
            <link rel="stylesheet" href="/confluence/s/1519/1/1/_/styles/combined.css?spaceKey=SLING&amp;forWysiwyg=true"
type="text/css">
    </head>
<body style="background-color: white" bgcolor="white">
<div id="pageContent">
<div id="notificationFormat">
<div class="wiki-content">
<div class="email">
     <h2><a href="http://cwiki.apache.org/confluence/display/SLING/Add+ResourceResolverFactory+Service+Interface">Add
ResourceResolverFactory Service Interface</a></h2>
     <h4>Page <b>edited</b> by             <a href="http://cwiki.apache.org/confluence/display/~fmeschbe">Felix
Meschberger</a>
    </h4>
     
          <br/>
     <div class="notificationGreySide">
         <h1><a name="AddResourceResolverFactoryServiceInterface-APIEnhancement%3AAddResourceResolverFactory"></a>API
Enhancement: Add ResourceResolverFactory</h1>



<p>Status: DRAFT<br/>
Created: 9. November 2008<br/>
Author: fmeschbe<br/>
JIRA: <a href="https://issues.apache.org/jira/browse/SLING-1262" rel="nofollow">SLING-1262</a><br/>
Prototype: <a href="http://svn.apache.org/repos/asf/sling/whiteboard/fmeschbe/resource"
rel="nofollow">http://svn.apache.org/repos/asf/sling/whiteboard/fmeschbe/resource</a><br/>
Updated: 17. November 2008, fmeschbe, Added Section 5.2</p>

<div>
<ul>
    <li><a href='#AddResourceResolverFactoryServiceInterface-1CurrentState'>1
Current State</a></li>
    <li><a href='#AddResourceResolverFactoryServiceInterface-2ExtensionsataGlance'>2
Extensions at a Glance</a></li>
    <li><a href='#AddResourceResolverFactoryServiceInterface-3ResourceResolverFactory'>3
ResourceResolverFactory</a></li>
    <li><a href='#AddResourceResolverFactoryServiceInterface-4ResourceResolver'>4
ResourceResolver</a></li>
    <li><a href='#AddResourceResolverFactoryServiceInterface-5ResourceProviderFactory'>5
ResourceProviderFactory</a></li>
<ul>
    <li><a href='#AddResourceResolverFactoryServiceInterface-5.1Credentials'>5.1
Credentials</a></li>
    <li><a href='#AddResourceResolverFactoryServiceInterface-5.2SlingRepositoryandAbstractSlingRepository'>5.2
SlingRepository and AbstractSlingRepository</a></li>
</ul>
    <li><a href='#AddResourceResolverFactoryServiceInterface-6ResourceProvider'>6
ResourceProvider</a></li>
    <li><a href='#AddResourceResolverFactoryServiceInterface-7LoginException'>7
LoginException</a></li>
    <li><a href='#AddResourceResolverFactoryServiceInterface-8LoggingintotheSystem'>8
Logging into the System</a></li>
    <li><a href='#AddResourceResolverFactoryServiceInterface-9ChangesinSling'>9
Changes in Sling</a></li>
</ul></div>


<h2><a name="AddResourceResolverFactoryServiceInterface-1CurrentState"></a>1
Current State</h2>

<p>The Sling API currently only defines the <tt>ResourceResolver</tt> interface
but not how such a resolver is to be created/retrieved.</p>

<p>In addition the Sling implementation has:</p>
<ul>
	<li>[Sling] Repository providers, which just register one or more repository instances
as services</li>
	<li><tt>JcrResourceResolverFactory</tt> service which creates <tt>ResourceResolver</tt>
instances based on JCR Session objects</li>
	<li>The authenticator selects one of the Repository services to authenticate against
and creates the Session to get the <tt>ResourceResolver</tt> from the <tt>JcrResourceResolverFactory</tt></li>
</ul>


<p>This implementation has a series of drawbacks:</p>
<ul>
	<li>The authenticator decides which repository to access: Problem is, that the authenticator
is most probably not the right instance to decide on this issue.</li>
	<li>Getting a Resource resolver is tedious in that a Session is first to be created
and then a resolver can be retrieved from the factory</li>
	<li>Only a single workspace of a single repository may be accessed at a any time and
the authenticator actually defines which of those.</li>
	<li>All in all, this decouples the ResourceResolver<a href="/confluence/pages/createpage.action?spaceKey=SLING&amp;title=Provider&amp;linkCreation=true&amp;fromPageId=101317"
class="createlink">Provider</a> too much from the repository and gives the authenticator
too much "power"</li>
</ul>


<p>Therefore I propose the extension of the Sling API as presented herein.</p>


<h2><a name="AddResourceResolverFactoryServiceInterface-2ExtensionsataGlance"></a>2
Extensions at a Glance</h2>

<p>This is the list of additions, I propose for the Sling API. Please refer to then
following sections for more details, description and motivation.</p>

<ul>
	<li>Add <tt>ResourceResolverFactory</tt> service interface which provides
a <tt>ResourceResolver</tt> instances</li>
	<li>Add <tt>ResourceProviderFactory</tt> service interface to help <tt>ResourceResolverFactory</tt>
in creating <tt>ResourceResolver</tt> instances</li>
	<li>Add lifecyle support to the <tt>ResourceResolver</tt> and <tt>ResourceProvider</tt>
interfaces</li>
	<li>Add <tt>LoginException</tt> to support failure reporting in the <tt>ResourceResolverFactory</tt></li>
</ul>



<h2><a name="AddResourceResolverFactoryServiceInterface-3ResourceResolverFactory"></a>3
ResourceResolverFactory</h2>

<p>The <tt>ResourceResolverFactory</tt> is provided by the Sling framework
as a service. The factory provides a single method</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
ResourceResolver getResourceResolver(Map&lt;<span class="code-object">String</span>,
<span class="code-object">Object</span>&gt; credentials) <span class="code-keyword">throws</span>
LoginException;
</pre>
</div></div>

<p>This method uses the credentials object to authenticate the user and to create <tt>ResourceResolver</tt>
instances, which may then be used to access resources. If authentication fails, a <tt>LoginException</tt>
(see below) is thrown.</p>

<p>Authentication fails if at least one <tt>ResourceProviderFactory</tt>
service which is registered with the <tt>provider.required</tt> property set to
<tt>true</tt> throws a <tt>LoginExcdeption</tt>. This for example
allows multiple <tt>ResourceProviderFactory</tt> services to be registered to
access the JCR repository, each for a different location/workspace and one factory service
to be the one to decide, whether authentication succeeds or not. <tt>ResourceResovlerFactory</tt>
services not having the <tt>provider.required</tt> property set to true will just
be ignored if they cannot return a <tt>ResourceProvider</tt>.</p>



<h2><a name="AddResourceResolverFactoryServiceInterface-4ResourceResolver"></a>4
ResourceResolver</h2>

<p>The <tt>ResourceResolver</tt> interface is extended with a new method</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
void close();
</pre>
</div></div>

<p>which must be called when the resource resolver is no longer used. This allows for
any cleanup required in the <tt>ResourceProvider</tt> instances attached to the
resource resolver.</p>



<h2><a name="AddResourceResolverFactoryServiceInterface-5ResourceProviderFactory"></a>5
ResourceProviderFactory</h2>

<p>The <tt>ResourceResolverFactory</tt> will return a <tt>ResourceResolver</tt>
which behind the scenes makes use of <tt>ResourceProvider</tt> instances. This
interface already exists today and is implemented to access bundle or filesystem resources.
Actually repository access is internally also implemented as a <tt>ResourceProvider</tt>.</p>

<p>To allow for authenticated <tt>ResourceProvider</tt> instances in addition
to unauthenticated ones, a new factory interface <tt>ResourceProviderFactory</tt>
is introduced which provides a single method:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
<span class="code-comment">// Creates a normal resource provider using credentials
</span><span class="code-comment">// to indicate the user to login as.
</span>ResourceProvider getResourceProvider(Map&lt;<span class="code-object">String</span>,
<span class="code-object">Object</span>&gt; credentials) <span class="code-keyword">throws</span>
LoginException;

<span class="code-comment">// Creates an administrative resource provider. Any user
</span><span class="code-comment">// credentials are ignored. The ResourceProvider
is assumed
</span><span class="code-comment">// to have administrative (aka root aka superuser)
rights
</span><span class="code-comment">// on the resources provided.
</span><span class="code-comment">// This method is targeted as background services
and not
</span><span class="code-comment">// intended <span class="code-keyword">for</span>
normal request processing.
</span>ResourceProvider getAdministrativeResourceProvider(Map&lt;<span class="code-object">String</span>,
<span class="code-object">Object</span>&gt; credentials) <span class="code-keyword">throws</span>
LoginException;

<span class="code-comment">// Creates an anonymous resource provider. Any user
</span><span class="code-comment">// credentials are ignored. The ResourceProvider
is assumed
</span><span class="code-comment">// to have restricted (read-only mostly) rights
on the
</span><span class="code-comment">// resources provided. This factory method may
be used to
</span><span class="code-comment">// implemented guest access to the system.
</span><span class="code-comment">// This method is targeted as background services.
It may
</span><span class="code-comment">// also be used by authenticators to support
anonymous access
</span><span class="code-comment">// to the system in a <span class="code-keyword">public</span>
site where authentication is
</span><span class="code-comment">// the exception rather than the rule.
</span>ResourceProvider getAnonymousResourceProvider(Map&lt;<span class="code-object">String</span>,
<span class="code-object">Object</span>&gt; credentials) <span class="code-keyword">throws</span>
LoginException;
</pre>
</div></div>

<p>This method returns a resource provider with the given credentials or throws a <tt>LoginException</tt>
if the credentials do not allow access to the resources provided by the <tt>ResourceProviderFactory</tt>.</p>

<p>The <tt>ResourceProviderFactory</tt> is a service interface and as such
the registered <tt>ResourceProviderFactory</tt> services have the following defined
service registration properties:</p>

<ul>
	<li><tt>provider.roots</tt> &#8211; Defines the root paths under which
the ResourceProvider is attached into Resource tree. This is the same property as for the
<tt>ResourceProvider</tt> service and applies to all <tt>ResourceProvider</tt>
instances created by the factory.</li>
	<li><tt>provider.required</tt> &#8211; Indicates whether the <tt>ResourceProvider</tt>
instances provided by the <tt>ResourceProviderFactory</tt> have to be assumed
as required. Failing to create as <tt>ResourceProvider</tt> with this factory,
will cause the <tt>ResourceResolverFactory.getResourceResolver()</tt> method to
fail if this property is set to the boolean value <tt>true</tt>.</li>
</ul>



<h3><a name="AddResourceResolverFactoryServiceInterface-5.1Credentials"></a>5.1
Credentials</h3>

<p>Since I cannot assume all real-world use cases right now and do not want to tie the
Sling API into any specific use case, I propse the credentials to simply be a <tt>Map&lt;String,
Object&gt;</tt> object. To simplify use, though, a few predfined entries are defined
in the <tt>ResourceResolverFactory</tt> interface:</p>

<ul>
	<li><tt>user.name</tt> (String) &#8211; The name of the user to connect
as to resource providers.</li>
	<li><tt>user.password</tt> (String) &#8211; The password supplied by
the user to connect to resource providers.</li>
	<li><tt>user.workspace</tt> (String) &#8211; This convenience property
may be used to hint at a primary workspace to connect to.</li>
	<li><tt>user.session</tt> (javax.jcr.Session) &#8211; This property
is primarily present to implement backwards compatibility for the <tt>JcrResourceResolverFactory</tt>
interface. If this property is provided, <tt>ResourceProviderFactory</tt> services
may wish to ignore any other properties and just use the JCR Session.</li>
</ul>


<p>Other properties may of course be supplied and depend mainly on <tt>ResourceProviderFactory</tt>
services, which may require or use them. Generally, though, providing the <tt>user.name</tt>
and <tt>user.password</tt> properties should suffice it.</p>


<h3><a name="AddResourceResolverFactoryServiceInterface-5.2SlingRepositoryandAbstractSlingRepository"></a>5.2
SlingRepository and AbstractSlingRepository</h3>

<p>The <tt>SlingRepository</tt> interface and the <tt>AbstractSlingRepository</tt>
abstract class currently provide support for getting administrative and anonymous sessions
to the repository. Access details for such sessions is to be configured with the <tt>AbstractSlingRepository</tt>
implementation.</p>

<p>With the implementation of a <tt>ResourceResolverFactory</tt> and its
accessor methods for acquiring administrative and anonymous access, the respective <tt>SlingRepository</tt>
and <tt>AbstractSlingRepository</tt> methods become superfluous.</p>

<p>In addition the <tt>SlingRepository.getDefaultWorkspace()</tt> method
is probably also not required since, it is either the underlying actual JCR repository defining
the default workspace or any JCR based <tt>ResourceProvider</tt> which defines
which workspace to access.</p>

<p>As a consequence the <tt>SlingRepository</tt> interface and support for
administrative and anonymous access to a repository in the <tt>AbstractSlingRepository</tt>
may be phased out.</p>

<p>However, for some time, we might have to provide backwards compatibility:</p>

<ul>
	<li><tt>SlingRepository.getDefaultWorkspace()</tt> &#8211; Implemented
by <tt>AbstractSlingRepository</tt>; always returns <tt>null</tt></li>
	<li><tt>SlingRepository.loginAdministrative()</tt> &#8211; Implemented
by <tt>AbstractSlingRepository</tt>; calls <tt>ResourceResolverFactory.getAdministrativeResourceResolver()</tt>
and returns a <tt>Session</tt> which on logout also closes the <tt>ResourceResolver</tt></li>
	<li><tt>AbstractSlingRepository.login(null, workspace)</tt> &#8211;
Implemented by <tt>AbstractSlingRepository</tt>; calls <tt>ResourceResolverFactory.getAnonymousResourceResolver()</tt>
and returns a <tt>Session</tt> which on logout also closes the <tt>ResourceResolver</tt></li>
	<li>The <tt>jcr/jackrabbit-server</tt> and  <tt>jcr/jackrabbit-client</tt>
modules do not register <tt>SlingRepository</tt> instances anymore but the actual
<tt>Repository</tt> instance as a <tt>Repository</tt> Service.</li>
	<li>The <tt>SlingRepository</tt> service is registered by a backwards compatibility
class, probably related to the actual <tt>ResourceResolverFactory</tt>.</li>
</ul>



<p>Alternatively, it might also be decided to drop <tt>SlingRepository</tt>
altogether form Sling.</p>


<h2><a name="AddResourceResolverFactoryServiceInterface-6ResourceProvider"></a>6
ResourceProvider</h2>

<p>To allow for <tt>ResourceProvider</tt> instances returned by <tt>ResourceProviderFactory</tt>
services to be cleaned up when no longer used, a new method is added to the <tt>ResourceProvider</tt>
interface:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
void close():
</pre>
</div></div>

<p>This method must close the <tt>ResourceProvider</tt> and cleanup any
resources used. For example a JCR based <tt>ResourceProvider</tt> will logout
the underlying session upon close.</p>

<p>This method will have no effect if called on a <tt>ResourceProvider</tt>
which is registered as a service. For example the <tt>BundleResourceProvider</tt>
will implement an empty <tt>close()</tt> method.</p>

<p>The <tt>close()</tt> method is not expected to throw any exception at
all. If some error occurrs while processing cleanup, the method is expected to implement error
processing, which might be logging a message or just to ignore the situation.</p>


<h2><a name="AddResourceResolverFactoryServiceInterface-7LoginException"></a>7
LoginException</h2>

<p>The <tt>LoginException</tt> extends the existing <tt>SlingException</tt>
and therefore is an unchecked <tt>RuntimeException</tt>. This exception may be
thrown by the <tt>ResourceProviderFactory.getResourceProvider()</tt> and <tt>ResourceResolverFactory.getResourceResolver()</tt>
methods to indicate failure to connect to any resources. The exception should provide a descriptive
message as well as any cause which led to the <tt>LoginException</tt>.</p>


<h2><a name="AddResourceResolverFactoryServiceInterface-8LoggingintotheSystem"></a>8
Logging into the System</h2>

<p>To log into the system, the authenticator will extract the credentials from the HTTP
request  and call the <tt>ResourceResolverFactory.getResourceResolver</tt> method
with the credentials. If the <tt>ResourceResolverFactory</tt> throws a <tt>LoginException</tt>,
authentication fails.</p>


<h2><a name="AddResourceResolverFactoryServiceInterface-9ChangesinSling"></a>9
Changes in Sling</h2>

<ul>
	<li>The existing <tt>JcrResourceResolverFactory</tt> interface is deprecated</li>
	<li>The <tt>JcrResourceResolverFactoryImpl</tt> class is turned in to a
<tt>ResourceProviderFactory</tt>, which accepts JCR Session instances in the credentials
as the base for creating a <tt>ResourceProvider</tt> instance.</li>
	<li>A new implementation of the <tt>JcrResourceResolverFactory</tt> interface
is created, which just relates to the <tt>ResourceResolverFactory.getResourceResolver()</tt>
method providing the JCR Session as the only credentials entry.</li>
	<li>The jcr/resource module is split into two modules:
	<ul>
		<li>The <tt>JcrResourceResolverFactoryImpl</tt> and <tt>JcrResourceResolver</tt>
classes are moved to a new module implementing the <tt>ResourceResolverFactory</tt>
interface</li>
		<li>The jcr/resource module keeps the exported classes and interfaces in the <tt>o.a.s.jcr.resource</tt>
package as well as the internal implementations of the JCR support for the Sling Resource
API</li>
	</ul>
	</li>
</ul>


<p>Existing code may still use the <tt>JcrResourceResolverFactory</tt> service
to get a <tt>ResourceResolver</tt>. Still it is expected and proposed for this
existing code to migrate to the new API over time. Existing code in the Sling project will
be migrated to the new API as soon as it is available. New code should use the new <tt>ResourceResolverFactory</tt>
interface.</p>
     </div>
     <div id="commentsSection" class="wiki-content pageSection">
       <div style="float: right;">
            <a href="http://cwiki.apache.org/confluence/users/viewnotifications.action"
class="grey">Change Notification Preferences</a>
       </div>

       <a href="http://cwiki.apache.org/confluence/display/SLING/Add+ResourceResolverFactory+Service+Interface">View
Online</a>
       |
       <a href="http://cwiki.apache.org/confluence/pages/diffpagesbyversion.action?pageId=101317&revisedVersion=6&originalVersion=5">View
Change</a>
              |
       <a href="http://cwiki.apache.org/confluence/display/SLING/Add+ResourceResolverFactory+Service+Interface?showComments=true&amp;showCommentArea=true#addcomment">Add
Comment</a>
            </div>
</div>
</div>
</div>
</div>
</body>
</html>

Mime
View raw message