blob: 7206a99ac88ecbacb52a489aabbf5862759a28bd [file] [log] [blame]
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. The ASF licenses this file to You
under the Apache License, Version 2.0 (the "License"); you may not
use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. For additional information regarding
copyright in this work, please see the NOTICE file in the top level
directory of this distribution. -->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Apache Abdera</title>
<meta name="generator" content="DocBook XSL Stylesheets V1.70.1"/>
</head>
<body>
<!-- Header -->
<div id="banner">
<h1><a href="http://incubator.apache.org/abdera">Apache Abdera</a></h1>
<p>Version 0.4.0-incubating-SNAPSHOT</p>
<hr/>
</div>
<div id="divider"></div>
<h1>Implementing A Server</h1>
<div class="article" lang="en">
<div class="titlepage">
<div><div class="author">
<h3 class="author">Contributed by: <span class="firstname">Adam</span> <span class="surname">Constabaris</span></h3>
</div>
</div>
</div>
</div>
<div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="section"><a href="#intro">Introduction</a></span></dt><dt><span class="section"><a href="#providers">Implementing <code class="classname">Provider</code></a></span></dt><dt><span class="section"><a href="#app_assembly">Putting it all together</a></span></dt></dl></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="intro"/>Introduction</h2></div></div></div><p>The framework for implementing an APP server in Abdera is, as shipped, incomplete, but
armed with a knowledge of how APP works, you shouldn't have too much trouble enabling
APP access to an (appropriate!) domain model. In order to effectively use the classes in
the framework, you'll have to know how to configure them and what you need to implement
yourself. The first part of the document describes (loosely) how Abdera is configured,
while the second part concerns notes about implementing some of the more important
classes. I assume throughout that you are familiar with the Atom format, APP basics, and
Abdera's general model for representing the Atom format. </p><p> Abdera is designed to use a controller servlet, and ships with a basic implementation
that is be suitable for a range of situations. Changing your Abdera server configuration
is largely achieved by setting properties of the form
<code class="literal">some.abdera.framework.Interface=my.domain.abdera.InterfaceImplementation</code>;
that is, the property's name is the fully qualified name of the interface whose
implementation you want to specify, and the value is the fully-qualified name of a class
that implements that interface. Swapping out Abdera's default parser factory for a
SAX-based one, for example, would be done by setting
<span class="property">org.apache.abdera.parser.ParserFactory</span> to (say)
<span class="property">net.my.domain.MyParserFactory</span>. </p><p> Properties can be specified in a number of places; first, most of the crucial bits of
core Abdera are specified in <code class="classname">org.apache.abdera.util.Constants</code>.
You can also use the Java standard <a href="http://java.sun.com/j2se/1.5.0/docs/guide/jar/jar.html#Service%20Provider" target="_top">service provider</a> mechanism, or a file named
<code class="filename">abdera.properties</code> on the classpath (generally, values are looked up
in this order, with later values overriding ones set by earlier mechanisms). While
Abdera core ships with settings that allow you to parse or create feed documents without
any special configuration, server implementations are more variable and so require more
work. </p><p>As you might expect, this form of configuration makes heavy use of reflection, and
default or well-known constructors. In general, if you don't need to supply a lot of
helper classes or are happy using (e.g) JNDI lookup mechanisms to look up such things as
database connections, you can use these mechanisms without too much fuss. It's also not
much more work to use a dependency injection framework (such as Spring) for your server
configuration. </p><p> The interfaces you need to implement in order to create an APP server are listed in
<code class="classname">org.apache.abdera.protocol.server.util.ServerConstants</code>: </p><div class="variablelist"><dl><dt><span class="term">
<code class="classname">org.apache.abdera.protocol.server.servlet.RequestHandlerManager</code>
</span></dt><dd><p>Factory for objects that control the request processing.</p></dd><dt><span class="term">
<code class="classname">org.apache.abdera.protocol.server.auth.SubjectResolver</code>
</span></dt><dd><p>Factory for objects that determine the identity of calling
clients.</p></dd><dt><span class="term">
<code class="classname">org.apache.abdera.protocol.server.provider.TargetResolver</code>
</span></dt><dd><p>Factory for objects that determine the type of APP entity involved
in the request (e.g. entry, collection, media, service, categories)</p></dd><dt><span class="term">
<code class="classname">org.apache.abdera.protocol.server.ServiceContext</code>
</span></dt><dd><p>Controller: coordinates all of the other factory classes.</p></dd><dt><span class="term">
<code class="classname">org.apache.abdera.protocol.server.provider.ProviderManager</code>
</span></dt><dd><p>Factory for <code class="classname">Provider</code> implementations that
implement the CRUD operations of the APP server.</p></dd></dl></div><p>
</p><p> The <code class="classname">org.apache.abdera.protocol.server.provider.Provider</code>
interface defines all of the CRUD operations involved in the Atom protocol: this is
where you put the code that gets entries, collections, service documents,and handles
updates and deletions; most of the rest of these classes are involved in making sure an
HTTP request is routed to the right method on the <code class="classname">Provider</code>. Since
the <code class="classname">ProviderManager</code> class is responsible for instantiating and
configuring your <code class="classname">Provider</code> objects, it has an important role to
play. Concrete default implementations for most of the other interfaces are provided,
but you will have to provide implementations for both
<code class="classname">ProviderManager</code> and <code class="classname">Provider</code>. </p><p> An absolutely minimal APP server will also have to configure a target resolver, i.e. provide
a way to determine which kind of APP entity is being operated on (i.e. it answers questions of
the form "is this a request for a service document?"). In all likelihood, a subclass of
<code class="classname">org.apache.abdera.protocol.server.util.RegexTargetResolver</code>
will suffice here, since it maps request URIs that match a particular regular expression
to entity types. Your subclass can supply the actual mapping that you're going to use
(see <code class="classname">SimpleTargetResolver</code> in the server example). Additionally, since the
<code class="classname">ServiceContext</code> is responsible for getting references to all these other
classes and configuring them (most importantly the <code class="classname">ProviderManager</code>), you'll
probably want to subclass it as well.
</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="providers"/>Implementing <code class="classname">Provider</code></h2></div></div></div><p>While the specifics are going to be largely determined by the type of information your
server is processing and how it's stored (e.g. on a file system vs. rows in a database),
there are a few things to look out for that apply to any <code class="classname">Provider</code>
implementation. One thing you'll definitely need is need a system for turning objects in
your domain model into Abdera's model objects, and vice-versa. This part has to be left
as an exercise for the reader. </p><p>Most of the methods in the <span class="interface">Provider</span> interface are fairly well
described by their names: <code class="methodname">getEntry</code>, for example, is called when
the client has called <code class="literal">GET</code> on an entry URI. One exception here is the
<code class="methodname">getInfo</code> method, which serves mainly to enable support for
HTTP's <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.3" target="_top">conditional GET</a> [ <a href="http://fishbowl.pastiche.org/2002/10/21/http_conditional_get_for_rss_hackers" target="_top">see also</a> ]. </p><p> You'll notice that the various <code class="methodname">getXXX</code> methods return a
<code class="classname">ResponseInfo</code> object, which encompasses the HTTP response,
including the headers and response body. In addition to the
<code class="classname">RequestContext</code> argument, these methods also accept a
<code class="literal">boolean</code> argument that determines whether the method is evaluating
the request for cacheability<sup>[<a id="d0e180" href="#ftn.d0e180">1</a>]</sup> or whether it should actually generate a response body. Let's refer to the
first mode (where the boolean parameter is <code class="literal">false</code>) as "header mode"
and the second as "full response mode". When the method is called in header mode, it
<span class="emphasis"><em>may</em></span> check the <code class="literal">ETag</code> or
<code class="literal">If-Modified-Since</code> HTTP headers submitted by the APP client
against the entry's current tag or modification time. </p><p>So, if you're implementing conditional GET in your <code class="classname">Provider</code>,
the <code class="methodname">getInfo</code> method can delegate to the appropriate
<code class="methodname">getXXX</code> method in header mode. Even if your provider
<span class="emphasis"><em>doesn't</em></span> support conditional GET, you'll probably want to
support different header and full response modes, to avoid having to generate a
potentially "expensive" document twice. A relatively straightforward way to do this is
to have your methods return an <code class="classname">EmptyResponseContext</code> with a status
code of 200 (or 404, if the user's requested an entry that doesn't exist) when they're
called in header mode. The default request processing pipeline ensures that the method
will be called again in full response mode.</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="app_assembly"/>Putting it all together</h2></div></div></div><p>The default <code class="classname">AbderaServlet</code> class can be used as your servlet controller, but
it is somewhat limited in how much "help" it can provide by way of making servlet or EJB container resources such as
database connection pools available to your protocol implementation. <code class="classname">AbderaServlet</code>
uses the property-resolution mechanisms described above<sup>[<a id="d0e224" href="#ftn.d0e224">2</a>]</sup>. The basic
steps it uses to process a request are:
</p><div class="procedure"><ol type="1"><li><p>Obtain a reference to a <code class="classname">ServiceContext</code> (via reflection).</p></li><li><p>Use the service context to get a reference to a <code class="classname">RequestHandlerManager</code>.</p></li><li><p>Use the request handler manager to obtain a <code class="classname">RequestHandler</code>.</p></li><li><p>Call <code class="methodname">process()</code> on the request handler.</p></li></ol></div><p>
If your <code class="classname">ServiceContext</code> implementation can get references to
appropriately configured target resolvers and provider managers, then all you need to do
is map the AbderaServlet to the desired URI and set the <span class="property">org.apache.abdera.protocol.server.ServiceContext</span>
property to the name of your service context implementation.
</p><p>
If you require greater control over how the <code class="classname">ServiceContext</code> is instantiated or
configured, you should create your own servlet whose <code class="methodname">service</code> method executes
this basic process.
</p></div><div class="footnotes"><br/><hr width="100" align="left"/><div class="footnote"><p><sup>[<a id="ftn.d0e180" href="#d0e180">1</a>] </sup>They can also check that certain preconditions are satisfied,
e.g. the "lost update" mechanism for a PUT (update) request, which checks
whether the ETag supplied by the client matches the current ETag for the
associated entry, but I'll leave that part out.</p></div><div class="footnote"><p><sup>[<a id="ftn.d0e224" href="#d0e224">2</a>] </sup>With one twist: it also lets you specify your
implementation classes via the servlet's initialization parameters.</p></div></div></div></body></html>