Up to this point, providers/collectionadapters have had to handle all of the details in constructing URIs for feeds and entries. The process was cumbersome and problematic for many reasons. As part of the server refactoring, today I checked in a new interface called TargetBuilder (I know the name sucks) whose job it is to construct urls on behalf of the collection adapter.

Provider implementations provide the TargetBuilder implementation, which is accessed by the CollectionAdapter via the RequestContext. There is currently one TargetBuilder implementation, TemplateTargetBuilder, which uses the URI Template code in the i18n module to construct URLs.

The DefaultProvider and BasicProvider each use their own internal TargetBuilder implementations. It is possible for developers to override those implementations but it's not likely that they will.

Custom provider implementations will need to provide their own Target Builder implementations,

For instance, if you look at /branches/server_refactor_all/server/src/test/java/org/apache/abdera/protocol/server/test/custom/CustomProvider.java, you will see:

    setTargetBuilder(
      new TemplateTargetBuilder()
        .setTemplate(TargetType.TYPE_SERVICE, "{target_base}/atom")
.setTemplate(TargetType.TYPE_COLLECTION, "{target_base}/atom/{collection}{-opt|?|q,c,s,p,l,i,o}{-join|&|q,c,s,p,l,i,o}") .setTemplate(TargetType.TYPE_CATEGORIES, "{target_base}/atom/{collection};categories") .setTemplate(TargetType.TYPE_ENTRY, "{target_base}/atom/{collection}/{entry}") .setTemplate(OpenSearchFilter.TYPE_OPENSEARCH_DESCRIPTION, "{target_base}/search")
    );

Then, in /branches/server_refactor_all/server/src/test/java/org/apache/abdera/protocol/server/test/custom/SimpleAdapter.java, you will see:

  private String getEntryLink(RequestContext request, String entryid) {
    Map<String,String> params = new HashMap<String,String>();
params.put("collection", request.getTarget().getParameter("collection"));
    params.put("entry", entryid);
    return request.resolveIri(TargetType.TYPE_ENTRY, params);
  }

Note that the collection adapter calls the RequestContext, which uses the target builder to construct the URI.

Because the target builder is using the URI Template implementation, the input parameter in getEntryLink(..) can be a Map<String,Object>, a org.apache.abdera.i18n.templates.Context implementation, or any java bean with public getters. For instance, this would work also:

  public class Foo {
    public String getCollection() {return "feed";}
  }
  private String getEntryLink(RequestContext request, String entryid) {
    return request.resolveIri(TargetType.TYPE_ENTRY, new Foo());
  }

The TemplateTargetBuilder provides a number of built-in variables that can be used within the URI Templates.

{request_context_path} = the servlet context path of the current request
{request_content_type} = the mime content type of the current request
{request_uri} = the request uri (relative) of the current request
{request_resolved_uri} = the absolute request uri of the current request
{request_language} = the value of the current requests Accept-Language
{request_charset} = the value of the current requests Accept-Charset
{request_user} = the name of the authenticated user
{target_identity} = the value of Target.getIdentity()
{target_path} = the subset of the request uri used to identify the
                target
{target_base} = the root of the target_path, usually the contextpath +
                the servlet path
{request_parameter_[name]} = the value of
                             requestContext.getParameter("[name]")
{request_attribute_[name]} = the value of
                             requestContext.getAttribute(Scope.REQUEST,
                                                         "[name]")
{session_attribute_[name]} = the value of
                             requestContext.getAttribute(Scope.SESSION,
                                                         "[name]")
{request_header_[name]} = the value of
                          requestContext.getHeader("[name]")
{target_parameter_[name]} = the value of Target.getParameter("[name]")

These variables can be used anywhere within any of the URI Templates defined on TemplateTargetBuilder.

DefaultProvider and BasicProvider both use the TemplateTargetBuilder internally, but define a number of default templates. To add your own templates (or to override the defaults), you need to subclass the provider..

  public class MyProvider extends DefaultProvider {
    public MyProvider() {
      TemplateTargetBuilder ttb =
        (TemplateTargetBuilder) getTargetBuilder(null);
      ttb.setTemplate("foo", "{target_base}/my/custom/template");
    }
  }

Then, in your CollectionAdapter, you can call...

  request.resolveIri("foo", null);

Anyway, the code is checked into the server_refactor_all branch. As always, comments/feedback are welcomed and requested.

- James

Reply via email to