blob: 7b0aaadf044c9a808eeb9079f33c5eba5483e72b [file] [log] [blame]
<?xml version="1.0" encoding="UTF-8"?>
<document>
<properties>
<author email="akarasulu">akarasulu</author>
<title>ApacheDS - Interceptor Mechanism</title>
</properties>
<body>
<section heading="h2" name="What is it?">
<p>
The mechanism is a means for injecting and isolating orthogonal services into
calls against the nexus. The nexus is the hub used to route calls to partitions
to perform CRUD operations upon entries. By injecting these services at this
level, partition implementators need not duplicate fuctionality. Services such
as authentication, authorization, schema checking, normalization, operational
attribute maintenance and more are introduced using Interceptors. By using
interceptors partition implementors need not be concerned with these aspects and
can focus on raw CRUD operations against their backing stores what ever they may
be.</p>
</section>
<section heading="h2" name="How does it work?">
<p>
Before we talk more about interceptors we must quickly cover the JNDI provider
implementation since it is somewhat
related.</p>
<subsection heading="h3" name="JNDI Implementation">
<p>
The JNDI implementation is composed of a set of JNDI Context implementations, a
ContextFactory implementation and a set of helper
classes.</p>
<ul nesting="1">
<li>
DeadContext</li>
<li>
JavaLdapSupport</li>
<li>
ServerContext</li>
<li>
ServerDirContext</li>
<li>
ServerLdapContext</li>
<li>
AbstractContextFactory</li>
<li>
CoreContextFactory</li>
<li>
ServerDirObjectFactory</li>
<li>
ServerDirStateFactory</li>
</ul>
<p>
Every JNDI Context implementation in the provider holds a dedicated reference to
a nexus proxy object. This proxy contains all the operations that the nexus
contains. The proxy object is at the heart of the mechanism. We will disuss
it more after covering the rest of the JNDI
provider.</p>
<p>
Calls made against JNDI Contexts take relative names as arguments. These names
are relative to the distinguished name of the JNDI Context. Within the Context
implementations these relative names are transformed into absolute distinguished
names. The transformed names are used to make calls against the
proxy.</p>
<p>
Additional processing may occur before or after a call is made by a context on
its proxy to manage JNDI provider specific functions. One such example is the
handling of Java objects for serialization and the use of object and state
factories.</p>
</subsection>
<subsection heading="h3" name="The nexus proxy object">
<p>
As mentioned above, each Context that is created has a nexus proxy. The proxy
maintains a handle on the context as
well.</p>
<p>
The primary job of the proxy is to inject Interceptor based services. It does
so by invoking a chain of Interceptors managed by the system. Interceptors
mirror the methods that are intercepted on the nexus interface. When an
intercepted method is invoked on the proxy, the proxy pushes an Invocation
object on to the InvocationStack associated with the current executing Thread.
The proxy then calls the same method on a chain of Interceptors. The results of
the call are returned after the InvocationStack is
popped.</p>
<p>
The InvocationStack is used to track the calls being intercepted. Invocation
objects pushed onto the stack track the context making the call to the proxy,
the name of the intercepted call and its arguments. A stack is used because in
the case of Triggers, stored procedures may be invoked which operate against the
DIT using JNDI. These JNDI calls will also be intercepted. Their Invocation
object will be stacked on top of the Invocation which raised the Trigger. This
way identities and context of operations can be tracked and used by the Trigger
management system to prevent runnaway cascades or to limit the cascade depth.
There are other areas besides just triggers where this stack will serve a
purpose.</p>
<p>
The InterceptorChain is a container of Interceptors which has the same or
analogous methods as do Interceptors. These are for the interceptable methods.
A call against the chain invokes the first Interceptor which then usually
invokes the next interceptor in the chain. An Interceptor need not call the
next interceptor however. It can raise an exception before making the call to
the next interceptor or it can completely bypass the rest of the chain by just
returning before calling the next Interceptor. Interceptors can preprocess the
arguments, or perform other tasks before they invoke the next Interceptor. They
can also catch exceptions raised by other downstream interceptors and respond to
them to handle errors. Finally they can perform post processing operations on
the results of returned values from downstream
Interceptors.</p>
<p>
One might ask when is the call made against the actual nexus. This happens
using a special Interceptor which resides at the end of the chain. It actually
makes the call against the nexus and returns the
results.</p>
</subsection>
</section>
</body>
</document>