The Abdera trunk now includes an implementation of the URI Template specification. The implementation has been extended to support the concept of "IRI Templates" capable of generating both URI's and IRI's.

See also: http://www.ibm.com/developerworks/web/library/wa-uri/


import org.apache.abdera.i18n.templates.Template;

private static final Template template = 
  new Template(
    "{scheme}://{-append|.|host}example.org{-opt|/|path}{-listjoin|/|path}{-prefix|/|page}{-opt|?|a,b}{-join|&|a,b}");

Template objects are immutable and threadsafe. Static, constant instances can be declared and reused as many times as necessary.

There are three basic ways of expanding a Template into a URI/IRI:

You can use a java.util.Map:

Map<String,Object> map = new HashMap<String,Object>();
map.put("scheme","http");
map.put("host", "www");
map.put("path", new String[] {"foo","bar","baz"});
map.put("page", "index.html");
map.put("a", "term");
map.put("b", 10);
    
System.out.println(template.expand(map));

> http://www.example.org/foo/bar/baz/index.html?a=term&b=10

You can use a custom Context implementation:

import org.apache.abdera.i18n.templates.CachingContext;
import org.apache.abdera.i18n.templates.Context;

Context context = new CachingContext() {
  protected <T> T resolveActual(String var) {
    return (T)(var.equals("scheme") ? "http" :
           var.equals("host")   ? "www"  :
           var.equals("path")   ? new String[] {"foo","bar","baz"} :
           var.equals("page")   ? "index.html" :
           var.equals("a")      ? "term" :
           var.equals("b")      ? 10 : 
           null);
  }
  public Iterator<String> iterator() {
    return template.iterator();
  }      
};
   
System.out.println(template.expand(context));

Or, you can use the public fields and getters of a Java object:

  public static class MyObject {
    
    public static String scheme = "http";
    
    public String getHost() {
      return "www";
    }
    public String[] getPath() {
      return new String[] {"foo","bar","baz"};
    }
    public String getPage() {
      return "index.html";
    }
    public String getA() {
      return "term";
    }
    public int getB() {
      return 12;
    }
  }

  System.out.println(template.expand(new MyObject()));

When using a Java object, there are times when the name of the template variable and the name of the method or field do not match up. For that, a VarName annotation (JDK 1.5+) is provided:

import org.apache.abdera.i18n.templates.VarName;

public static class MyObject {
  // ...    

  @VarName("b") public int getCount() {
    return 12;
  }
}

If a particular Java object is intended primarily to provide the expansion values for a Template, an Annotation has been provided to associate a template directly with the object.

import org.apache.abdera.i18n.templates.URITemplate;

@URITemplate("{scheme}://{-append|.|host}example.org{-opt|/|path}{-listjoin|/|path}{-prefix|/|page}{-opt|?|a,b}{-join|&|a,b}")
public static class MyObject {
 
  // ...    

}

You can then expand the object into a URI without having to create a Template object instance:

System.out.println(Template.expandAnnotated(new MyObject()));

The URI Template implementation has a built in "explain" mechanism that can be used to explain the template for debugging and documentation purposes.

private static final Template template = 
  new Template(
    "{scheme}://{-append|.|host}example.org{-opt|/|path}{-listjoin|/|path}{-prefix|/|page}{-opt|?|a,b}{-join|&|a,b}");

template.explain(System.out);

Will produce:

Template:
	?{scheme}://{-append|.|host}example.org{-opt|/|path}{-listjoin|/|path}{-prefix|/|page}{-opt|?|a,b}{-join|&|a,b}?

 Variables:
	scheme
	host
	path
	page
	a
	b

 Tokens:
	{scheme} 
		 Replaced with the value of 'scheme'
	{-append|.|host} 
		 If 'host' is defined then append '.' to the value of 'host'
	{-opt|/|path} 
		 If ['path'] is defined and a string, or a list with one or more members, then insert '/'
	{-listjoin|/|path} 
		 Join the members of the list 'path' together with '/'
	{-prefix|/|page} 
		 If 'page' is defined then prefix the value of 'page' with '/'
	{-opt|?|a,b} 
		 If ['a','b'] is defined and a string, or a list with one or more members, then insert '?'
	{-join|&|a,b} 
		 Join 'var=value' with '&' for each variable in ['a','b']

 Example:
	scheme = foo
	host = foo
	path = foo
	page = foo
	a = foo
	b = foo

	foo://foo.example.org/foo/foo?a=foo&b=foo

	scheme = null
	host = foo
	path = null
	page = foo
	a = null
	b = foo

	://foo.example.org/foo?b=foo

	scheme = foo
	host = null
	path = foo
	page = null
	a = foo
	b = null

	foo://example.org/foo?a=foo
  • No labels