abdera-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jmsn...@apache.org
Subject svn commit: r1173209 [15/49] - in /abdera/abdera2: ./ .settings/ activities/ activities/src/ activities/src/main/ activities/src/main/java/ activities/src/main/java/org/ activities/src/main/java/org/apache/ activities/src/main/java/org/apache/abdera2/ ...
Date Tue, 20 Sep 2011 15:57:20 GMT
Added: abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/AnnotationContext.java
URL: http://svn.apache.org/viewvc/abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/AnnotationContext.java?rev=1173209&view=auto
==============================================================================
--- abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/AnnotationContext.java (added)
+++ abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/AnnotationContext.java Tue Sep 20 15:56:46 2011
@@ -0,0 +1,38 @@
+package org.apache.abdera2.common.templates;
+
+import org.apache.abdera2.common.anno.Param;
+
+public class AnnotationContext extends MapContext {
+
+  private static final long serialVersionUID = 3092158634973274492L;
+  
+  private void process(org.apache.abdera2.common.anno.Context context) {
+    for (Param param : context.value())
+      put(param.name().toLowerCase(),param.value());
+  }
+  
+  public AnnotationContext(org.apache.abdera2.common.anno.Context context) {
+    process(context);
+  }
+  
+  public AnnotationContext(Object object) {
+    org.apache.abdera2.common.anno.Context context = getContext(object);
+    if (object == null)
+      throw new IllegalArgumentException();
+    else process(context);
+  }
+  
+  public static org.apache.abdera2.common.anno.Context getContext(Object object) {
+    if (object == null) 
+      throw new IllegalArgumentException();
+    Class<?> _class = 
+      object instanceof Class<?> ? 
+          (Class<?>)object : object.getClass();
+    if (_class.isAnnotationPresent(org.apache.abdera2.common.anno.Context.class)) {
+      return
+        _class.getAnnotation(org.apache.abdera2.common.anno.Context.class);
+    }
+    return null;
+  }
+  
+}

Propchange: abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/AnnotationContext.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/CachingContext.java
URL: http://svn.apache.org/viewvc/abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/CachingContext.java?rev=1173209&view=auto
==============================================================================
--- abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/CachingContext.java (added)
+++ abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/CachingContext.java Tue Sep 20 15:56:46 2011
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+package org.apache.abdera2.common.templates;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.abdera2.common.templates.AbstractContext;
+
+/**
+ * Abstract Context implementation that caches resolved values so that do not have to be resolved again
+ */
+@SuppressWarnings("unchecked")
+public abstract class CachingContext extends AbstractContext {
+
+    private static final long serialVersionUID = 8912954163958644811L;
+    
+    private Map<String, Object> cache = new HashMap<String, Object>();
+
+    public <T> T resolve(String var) {
+        T t = (T)cache.get(var);
+        if (t == null) {
+            t = (T)resolveActual(var);
+            if (t != null)
+                cache.put(var, t);
+        }
+        return t;
+    }
+
+    protected abstract <T> T resolveActual(String var);
+
+    public void clear() {
+        cache.clear();
+    }
+}

Propchange: abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/CachingContext.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/Context.java
URL: http://svn.apache.org/viewvc/abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/Context.java?rev=1173209&view=auto
==============================================================================
--- abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/Context.java (added)
+++ abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/Context.java Tue Sep 20 15:56:46 2011
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+package org.apache.abdera2.common.templates;
+
+import java.io.Serializable;
+
+/**
+ * Used to resolve values for template variables
+ */
+public interface Context extends Serializable, Iterable<String> {
+
+    /**
+     * Resolve a value for the specified variable. The method can return either a String, an Array or a Collection.
+     */
+    <T> T resolve(String var);
+
+    /**
+     * True if IRI expansion is enabled
+     */
+    boolean isIri();
+
+    /**
+     * True if IRI expansion is to be enabled
+     */
+    void setIri(boolean isiri);
+
+    /**
+     * Clear this context
+     */
+    void clear();
+
+    boolean contains(String var);
+}

Propchange: abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/Context.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/DefaultingContext.java
URL: http://svn.apache.org/viewvc/abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/DefaultingContext.java?rev=1173209&view=auto
==============================================================================
--- abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/DefaultingContext.java (added)
+++ abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/DefaultingContext.java Tue Sep 20 15:56:46 2011
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+package org.apache.abdera2.common.templates;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+@SuppressWarnings("unchecked")
+public class DefaultingContext 
+  extends DelegatingContext {
+
+  private static final long serialVersionUID = 3395776996994628136L;
+  private final Context defaults;
+  
+  public DefaultingContext(Context main, Context defaults) {
+    super(main);
+    if (defaults == null)
+      throw new IllegalArgumentException();
+    this.defaults = defaults;
+  }
+
+  public <T> T resolve(String var) {
+    T t = (T)super.resolve(var);
+    return t != null ? t : (T)defaults.resolve(var);
+  }
+
+  public Iterator<String> iterator() {
+    Set<String> set = new HashSet<String>();
+    for (String name : subcontext)
+      set.add(name);
+    for (String name : defaults)
+      set.add(name);
+    return set.iterator();
+  }
+  
+  public boolean contains(String var) {
+    boolean a = subcontext.contains(var);
+    return a ? a : defaults.contains(var);
+  }
+  
+  public String toString() {
+    StringBuilder buf = new StringBuilder();
+    buf.append("Subcontext: " + subcontext);
+    buf.append("\n");
+    buf.append("Default Context: " + defaults);
+    return buf.toString();
+  }
+}

Propchange: abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/DefaultingContext.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/DelegatingContext.java
URL: http://svn.apache.org/viewvc/abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/DelegatingContext.java?rev=1173209&view=auto
==============================================================================
--- abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/DelegatingContext.java (added)
+++ abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/DelegatingContext.java Tue Sep 20 15:56:46 2011
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+package org.apache.abdera2.common.templates;
+
+import java.util.Iterator;
+
+@SuppressWarnings("unchecked")
+public abstract class DelegatingContext extends AbstractContext {
+
+  private static final long serialVersionUID = 5513709111934286216L;
+    protected final Context subcontext;
+
+    protected DelegatingContext(Context subcontext) {
+        this.subcontext = subcontext;
+    }
+
+    protected <T> T resolveActual(String var) {
+        return (T)this.subcontext.resolve(var);
+    }
+
+    public Iterator<String> iterator() {
+        return this.subcontext.iterator();
+    }
+
+    public boolean isIri() {
+      return this.subcontext.isIri();
+    }
+    
+    public void setIri(boolean isiri) {
+      this.subcontext.setIri(isiri);
+    }
+    
+    public boolean contains(String var) {
+      return this.subcontext.contains(var);
+    }
+
+    public <T> T resolve(String var) {
+      return this.subcontext.resolve(var);
+    }
+
+    public void clear() {
+      this.subcontext.clear();
+    }
+}

Propchange: abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/DelegatingContext.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/Expression.java
URL: http://svn.apache.org/viewvc/abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/Expression.java?rev=1173209&view=auto
==============================================================================
--- abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/Expression.java (added)
+++ abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/Expression.java Tue Sep 20 15:56:46 2011
@@ -0,0 +1,196 @@
+/*
+ * 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.
+ */
+package org.apache.abdera2.common.templates;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.abdera2.common.templates.Context;
+import org.apache.abdera2.common.templates.Expression;
+import org.apache.abdera2.common.templates.Operation;
+
+public class Expression 
+  implements Iterable<Expression.VarSpec>, Serializable {
+  
+  private static final long serialVersionUID = 1457650843240079628L;
+  private static final Pattern EXPRESSION = Pattern.compile("([\\+\\#\\.\\/\\;\\?\\&\\=\\,\\!\\@\\|\\$\\(\\)])?(.*){1}");
+  private static final Pattern VARSPEC = Pattern.compile("([^(?:\\:\\d+)\\*\\^]+)([(?:\\:\\d+)\\*\\^]+)?");
+  private static final Pattern LENGTH = Pattern.compile("\\:(\\d+)");
+  
+  private final String EXP;
+  private Operation op;
+  private List<VarSpec> varspecs = 
+    new ArrayList<VarSpec>();
+  
+  public Expression(String exp) {
+    this.EXP = exp;
+    parse();
+  }
+  
+  public String toString() {
+    return EXP;
+  }
+  
+  @Override
+  public int hashCode() {
+    final int prime = 31;
+    int result = 1;
+    result = prime * result + ((EXP == null) ? 0 : EXP.hashCode());
+    result = prime * result + ((op == null) ? 0 : op.hashCode());
+    result = prime * result + ((varspecs == null) ? 0 : varspecs.hashCode());
+    return result;
+  }
+
+  @Override
+  public boolean equals(Object obj) {
+    if (this == obj)
+      return true;
+    if (obj == null)
+      return false;
+    if (getClass() != obj.getClass())
+      return false;
+    Expression other = (Expression) obj;
+    if (EXP == null) {
+      if (other.EXP != null)
+        return false;
+    } else if (!EXP.equals(other.EXP))
+      return false;
+    if (op == null) {
+      if (other.op != null)
+        return false;
+    } else if (!op.equals(other.op))
+      return false;
+    if (varspecs == null) {
+      if (other.varspecs != null)
+        return false;
+    } else if (!varspecs.equals(other.varspecs))
+      return false;
+    return true;
+  }
+
+  public Operation getOperation() {
+    return op;
+  }
+  
+  public String evaluate(Context context) {
+    return getOperation().evaluate(this, context);
+  }
+  
+  public Iterator<Expression.VarSpec> iterator() {
+    return varspecs.iterator();
+  }
+
+  private void parse() {
+    Matcher mt = EXPRESSION.matcher(EXP);
+    if (mt.find()) {
+      this.op = Operation.get(mt.group(1)); // grab the operation
+      String varlist = mt.group(2);
+      if (varlist == null)
+          throw new IllegalArgumentException(
+              "Invalid Expression: No variables");
+      String[] vars = 
+        varlist.split("\\s*,\\s*");
+      for (String var : vars) {
+        Matcher vt = VARSPEC.matcher(var);
+        if (vt.find()) {
+          VarSpec spec = new VarSpec(vt.group(1),vt.group(2));
+          varspecs.add(spec);
+        } else {
+          throw new IllegalArgumentException(
+            "Invalid Expression: Invalid variable spec");
+        }
+      }
+    } else {
+      throw new IllegalArgumentException("Invalid Expression");
+    }
+  }
+  
+  
+  public static class VarSpec {
+    private final String name;
+    private final int length;
+    private final boolean explode;
+    private final boolean noval;
+    public VarSpec(String name, String modifier) {
+      this.name = name;
+      this.length = getLength(modifier);
+      this.explode = isExplode(modifier);
+      this.noval = isNoval(modifier);
+    }
+    private int getLength(String modifier) {
+      if (modifier == null || "".equals(modifier)) 
+        return -1;
+      Matcher m = LENGTH.matcher(modifier);
+      if (m.find()) {
+          return Integer.parseInt(m.group(1));
+      } else return -1;
+    }
+    private boolean isNoval(String modifier) {
+      return "^".equals(modifier);
+    }
+    private boolean isExplode(String modifier) {
+      return "*".equals(modifier);
+    }
+    public String getName() {
+      return name;
+    }
+    public int getLength() {
+      return length;
+    }
+    public boolean isNoval() {
+      return noval;
+    }
+    public boolean isExplode() {
+      return explode;
+    }
+    @Override
+    public int hashCode() {
+      final int prime = 31;
+      int result = 1;
+      result = prime * result + (explode ? 1231 : 1237);
+      result = prime * result + length;
+      result = prime * result + ((name == null) ? 0 : name.hashCode());
+      return result;
+    }
+    @Override
+    public boolean equals(Object obj) {
+      if (this == obj)
+        return true;
+      if (obj == null)
+        return false;
+      if (getClass() != obj.getClass())
+        return false;
+      VarSpec other = (VarSpec) obj;
+      if (explode != other.explode)
+        return false;
+      if (length != other.length)
+        return false;
+      if (name == null) {
+        if (other.name != null)
+          return false;
+      } else if (!name.equals(other.name))
+        return false;
+      return true;
+    }
+  }
+
+}

Propchange: abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/Expression.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/MapContext.java
URL: http://svn.apache.org/viewvc/abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/MapContext.java?rev=1173209&view=auto
==============================================================================
--- abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/MapContext.java (added)
+++ abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/MapContext.java Tue Sep 20 15:56:46 2011
@@ -0,0 +1,99 @@
+/*
+ * 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.
+ */
+package org.apache.abdera2.common.templates;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.apache.abdera2.common.templates.Context;
+import org.apache.abdera2.common.templates.MapContext;
+
+/**
+ * Context implementation based on a HashMap
+ */
+@SuppressWarnings("unchecked")
+public class MapContext extends HashMap<String, Object> implements Context {
+
+    private static final long serialVersionUID = 2206000974505975049L;
+
+    private boolean isiri = false;
+
+    public MapContext() {
+    }
+
+    public MapContext(boolean isiri) {
+      this.isiri = isiri;
+    }
+    
+    public MapContext(Map<String, Object> map) {
+        super(map);
+    }
+
+    public MapContext(Map<String, Object> map, boolean isiri) {
+        super(map);
+        this.isiri = isiri;
+    }
+    
+    public MapContext(Context context) {
+      for (String name : context)
+        put(name, context.resolve(name));
+    }
+
+    public <T> T resolve(String var) {
+        return (T)get(var);
+    }
+
+    public boolean isIri() {
+        return isiri;
+    }
+
+    public void setIri(boolean isiri) {
+        this.isiri = isiri;
+    }
+
+    public Iterator<String> iterator() {
+        return keySet().iterator();
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = super.hashCode();
+        result = prime * result + (isiri ? 1231 : 1237);
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (!super.equals(obj))
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        final MapContext other = (MapContext)obj;
+        if (isiri != other.isiri)
+            return false;
+        return true;
+    }
+
+    public boolean contains(String var) {
+      return containsKey(var);
+    }
+}

Propchange: abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/MapContext.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/MultiContext.java
URL: http://svn.apache.org/viewvc/abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/MultiContext.java?rev=1173209&view=auto
==============================================================================
--- abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/MultiContext.java (added)
+++ abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/MultiContext.java Tue Sep 20 15:56:46 2011
@@ -0,0 +1,90 @@
+/*
+ * 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.
+ */
+package org.apache.abdera2.common.templates;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+public class MultiContext 
+  extends CachingContext {
+
+  private static final long serialVersionUID = 1691294411780004133L;
+  private final Set<Context> contexts = 
+    new HashSet<Context>();
+  
+  public MultiContext(Context... contexts) {
+    for (Context context : contexts)
+      this.contexts.add(context);
+  }
+  
+  public MultiContext(Iterable<Context> contexts) {
+    for (Context context : contexts)
+      this.contexts.add(context);
+  }
+  
+  public MultiContext(Collection<Context> contexts) {
+    if (contexts == null)
+      throw new IllegalArgumentException();
+    this.contexts.addAll(contexts);
+  }
+  
+  public void add(Context context) {
+    if (context == null)
+      throw new IllegalArgumentException();
+    this.contexts.add(context);
+  }
+  
+  @SuppressWarnings("unchecked")
+  public void add(Object object) {
+    this.contexts.add(
+      object instanceof Context ? 
+        (Context)object :
+        object instanceof Map ?
+          new MapContext((Map<String,Object>)object) :
+          new ObjectContext(object)
+    );
+  }
+  
+  public boolean contains(String var) {
+    for (Context context : contexts)
+      if (context.contains(var))
+        return true;
+    return false;
+  }
+
+  public Iterator<String> iterator() {
+    Set<String> names = new HashSet<String>();
+    for (Context context : contexts) 
+      for (String name : context)
+        names.add(name);
+    return names.iterator();
+  }
+
+  @Override
+  protected <T> T resolveActual(String var) {
+    for (Context context : contexts)
+      if (context.contains(var))
+        return context.resolve(var);
+    return null;
+  }
+
+
+}

Propchange: abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/MultiContext.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/ObjectContext.java
URL: http://svn.apache.org/viewvc/abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/ObjectContext.java?rev=1173209&view=auto
==============================================================================
--- abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/ObjectContext.java (added)
+++ abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/ObjectContext.java Tue Sep 20 15:56:46 2011
@@ -0,0 +1,153 @@
+/*
+ * 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.
+ */
+package org.apache.abdera2.common.templates;
+
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.apache.abdera2.common.templates.CachingContext;
+import org.apache.abdera2.common.templates.ObjectContext;
+import org.apache.abdera2.common.anno.Name;
+
+@SuppressWarnings("unchecked")
+public final class ObjectContext extends CachingContext {
+
+    private static final long serialVersionUID = -1387599933658718221L;
+    private final Object target;
+    private final Map<String, AccessibleObject> accessors = new HashMap<String, AccessibleObject>();
+
+    public ObjectContext(Object object) {
+        this(object, false);
+    }
+
+    public ObjectContext(Object object, boolean isiri) {
+        if (object == null)
+            throw new IllegalArgumentException();
+        this.target = object;
+        setIri(isiri);
+        initMethods();
+    }
+
+    private void initMethods() {
+        Class<?> _class = target.getClass();
+        if (_class.isAnnotation() || _class.isArray() || _class.isEnum() || _class.isPrimitive())
+            throw new IllegalArgumentException();
+        if (!_class.isInterface()) {
+            Field[] fields = _class.getFields();
+            for (Field field : fields) {
+                if (!Modifier.isPrivate(field.getModifiers())) {
+                    accessors.put(getName(field), field);
+                }
+            }
+        }
+        Method[] methods = _class.getMethods();
+        for (Method method : methods) {
+            String name = method.getName();
+            if (!Modifier.isPrivate(method.getModifiers()) && method.getParameterTypes().length == 0
+                && !method.getReturnType().equals(Void.class)
+                && !isReserved(name)) {
+                accessors.put(getName(method), method);
+            }
+        }
+    }
+
+    private String getName(AccessibleObject object) {
+        String name = null;
+        Name varName = object.getAnnotation(Name.class);
+        if (varName != null)
+            return varName.value();
+        if (object instanceof Field) {
+            name = ((Field)object).getName().toLowerCase();
+        } else if (object instanceof Method) {
+            name = ((Method)object).getName().toLowerCase();
+            if (name.startsWith("get"))
+                name = name.substring(3);
+            else if (name.startsWith("is"))
+                name = name.substring(2);
+        }
+        return name;
+    }
+
+    private boolean isReserved(String name) {
+        return (name.equals("toString") || name.equals("hashCode")
+            || name.equals("notify")
+            || name.equals("notifyAll")
+            || name.equals("getClass") || name.equals("wait"));
+    }
+
+    @Override
+    protected <T> T resolveActual(String var) {
+        try {
+            var = var.toLowerCase();
+            AccessibleObject accessor = accessors.get(var);
+            if (accessor == null)
+                return null;
+            if (accessor instanceof Method) {
+                Method method = (Method)accessor;
+                return (T)method.invoke(target);
+            } else if (accessor instanceof Field) {
+                Field field = (Field)accessor;
+                return (T)field.get(target);
+            } else
+                return null;
+        } catch (InvocationTargetException e) {
+            throw new IllegalArgumentException("Accessor: " + var, e);
+        } catch (IllegalAccessException e) {
+            throw new IllegalArgumentException("Accessor: " + var, e);
+        }
+    }
+
+    public Iterator<String> iterator() {
+        return accessors.keySet().iterator();
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((target == null) ? 0 : target.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        final ObjectContext other = (ObjectContext)obj;
+        if (target == null) {
+            if (other.target != null)
+                return false;
+        } else if (!target.equals(other.target))
+            return false;
+        return true;
+    }
+
+    public boolean contains(String var) {
+      return accessors.containsKey(var);
+    }
+}

Propchange: abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/ObjectContext.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/Operation.java
URL: http://svn.apache.org/viewvc/abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/Operation.java?rev=1173209&view=auto
==============================================================================
--- abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/Operation.java (added)
+++ abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/Operation.java Tue Sep 20 15:56:46 2011
@@ -0,0 +1,494 @@
+/*
+ * 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.
+ */
+package org.apache.abdera2.common.templates;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Serializable;
+import java.nio.CharBuffer;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.apache.abdera2.common.templates.Context;
+import org.apache.abdera2.common.templates.Expression;
+import org.apache.abdera2.common.templates.Operation;
+import org.apache.abdera2.common.templates.Expression.VarSpec;
+import org.apache.abdera2.common.text.CharUtils;
+import org.apache.abdera2.common.text.UrlEncoding;
+
+import com.ibm.icu.text.Normalizer2;
+
+@SuppressWarnings("unchecked")
+public abstract class Operation implements Serializable {
+  
+    private static final long serialVersionUID = -1734350302144527120L;
+    public abstract String evaluate(Expression exp, Context context);
+
+    private static Map<String, Operation> operations = getOperations();
+
+    private static Map<String, Operation> getOperations() {
+        Map<String, Operation> ops = new HashMap<String, Operation>();
+        ops.put("", new DefaultOperation());
+        ops.put("+", new ReservedExpansionOperation());
+        ops.put("#", new FragmentExpansionOperation());
+        ops.put(".", new DotExpansionOperation());
+        ops.put("/", new PathExpansionOperation());
+        ops.put(";", new PathParamExpansionOperation());
+        ops.put("?", new FormExpansionOperation());
+        ops.put("&", new QueryExpansionOperation());
+        return ops;
+    }
+
+    /**
+     * Register a new operation. The built in operations cannot be 
+     * overridden. Key should be a single character. This method
+     * is not synchronized; it is not recommended that registrations 
+     * be allowed from multiple threads or while multiple threads are
+     * expanding templates. Perform all registrations <i>before</i>
+     * any template expansion occurs.
+     */
+    public static void register(String key, Operation operation) {
+        if ("+#./;?&".contains(key))
+          throw new IllegalArgumentException(
+            "Cannot override reserved operators");
+        operations.put(key, operation);
+    }
+
+    public static Operation get(String name) {
+        if (name == null)
+            name = "";
+        Operation op = operations.get(name);
+        if (op != null)
+            return op;
+        throw new UnsupportedOperationException(name);
+    }
+
+    protected static String eval(
+        VarSpec varspec, 
+        Context context,
+        boolean reserved, 
+        String explodeDelim, 
+        String explodePfx) {
+        String name = varspec.getName();
+        Object rep = context.resolve(name);
+        String val = toString(
+            rep, 
+            context, 
+            reserved, 
+            varspec.isExplode(), 
+            explodeDelim, 
+            explodePfx,
+            varspec.getLength());
+        return val;
+    }
+    
+    private static CharSequence trim(CharSequence val, int len) {
+      if (val != null && len > -1 && val.length() > len)
+        val = val.subSequence(0,len);
+      return val;
+    }
+    
+    private static String normalize(CharSequence s) {
+      return Normalizer2.getInstance(
+        null, 
+        "nfc", 
+        Normalizer2.Mode.COMPOSE)
+          .normalize(s);
+    }
+
+    private static String toString(
+        Object val, 
+        Context context, 
+        boolean reserved, 
+        boolean explode, 
+        String explodeDelim, 
+        String explodePfx,
+        int len) {
+        if (val == null)
+            return null;
+        if (val.getClass().isArray()) {
+            if (val instanceof byte[]) {
+                return UrlEncoding.encode((byte[])val);
+            } else if (val instanceof char[]) {
+                String chars = (String)trim(new String((char[])val),len);
+                return !reserved ?
+                  UrlEncoding.encode(
+                    normalize(chars), 
+                    context.isIri()
+                      ? CharUtils.Profile.IUNRESERVED : 
+                        CharUtils.Profile.UNRESERVED) :
+                  UrlEncoding.encode(
+                      normalize(chars),
+                      context.isIri()
+                        ? CharUtils.Profile.RESERVEDANDIUNRESERVED : 
+                          CharUtils.Profile.RESERVEDANDUNRESERVED);                
+            } else if (val instanceof short[]) {
+                StringBuilder buf = new StringBuilder();
+                short[] array = (short[])val;
+                for (short obj : array) {
+                    if (buf.length() > 0)
+                        buf.append(explode && explodeDelim != null ? explodeDelim : ",");
+                    if (explode && explodePfx != null) 
+                      buf.append(explodePfx);
+                    buf.append(trim(String.valueOf(obj),len));
+                }
+                return buf.toString();
+            } else if (val instanceof int[]) {
+                StringBuilder buf = new StringBuilder();
+                int[] array = (int[])val;
+                for (int obj : array) {
+                    if (buf.length() > 0)
+                        buf.append(explode && explodeDelim != null ? explodeDelim : ",");
+                    if (explode && explodePfx != null) 
+                      buf.append(explodePfx);
+                    buf.append(trim(String.valueOf(obj),len));
+                }
+                return buf.toString();
+            } else if (val instanceof long[]) {
+                StringBuilder buf = new StringBuilder();
+                long[] array = (long[])val;
+                for (long obj : array) {
+                    if (buf.length() > 0)
+                        buf.append(explode && explodeDelim != null ? explodeDelim : ",");
+                    if (explode && explodePfx != null) 
+                      buf.append(explodePfx);
+                    buf.append(trim(String.valueOf(obj),len));
+                }
+                return buf.toString();
+            } else if (val instanceof double[]) {
+                StringBuilder buf = new StringBuilder();
+                double[] array = (double[])val;
+                for (double obj : array) {
+                    if (buf.length() > 0)
+                        buf.append(explode && explodeDelim != null ? explodeDelim : ",");
+                    if (explode && explodePfx != null) 
+                      buf.append(explodePfx);
+                    buf.append(trim(String.valueOf(obj),len));
+                }
+                return buf.toString();
+            } else if (val instanceof float[]) {
+                StringBuilder buf = new StringBuilder();
+                float[] array = (float[])val;
+                for (float obj : array) {
+                    if (buf.length() > 0)
+                        buf.append(explode && explodeDelim != null ? explodeDelim : ",");
+                    if (explode && explodePfx != null) 
+                      buf.append(explodePfx);
+                    buf.append(trim(String.valueOf(obj),len));
+                }
+                return buf.toString();
+            } else if (val instanceof boolean[]) {
+                StringBuilder buf = new StringBuilder();
+                boolean[] array = (boolean[])val;
+                for (boolean obj : array) {
+                    if (buf.length() > 0)
+                        buf.append(explode && explodeDelim != null ? explodeDelim : ",");
+                    if (explode && explodePfx != null) 
+                      buf.append(explodePfx);
+                    buf.append(trim(String.valueOf(obj),len));
+                }
+                return buf.toString();
+            } else {
+                StringBuilder buf = new StringBuilder();
+                Object[] array = (Object[])val;
+                for (Object obj : array) {
+                  if (buf.length() > 0)
+                    buf.append(explode && explodeDelim != null ? explodeDelim : ",");
+                  if (explode && explodePfx != null) 
+                    buf.append(explodePfx);
+                  buf.append(toString(obj, context, reserved, false, null, null, len));
+                }
+                return buf.toString();
+            }
+        } else if (val instanceof InputStream) {
+            try {
+                if (len > -1) {
+                  byte[] buf = new byte[len];
+                  int r = ((InputStream)val).read(buf);
+                  byte[] dat = new byte[r];
+                  System.arraycopy(buf, 0, dat, 0, r);
+                  val = new ByteArrayInputStream(dat);
+                }
+                return UrlEncoding.encode((InputStream)val);
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+        } else if (val instanceof Readable) {
+            try { 
+                if (len > -1) {
+                  CharBuffer buf = CharBuffer.allocate(len);
+                  int r = ((Readable)val).read(buf);
+                  buf.limit(r);
+                  buf.position(0);
+                  val = buf;
+                }
+                return !reserved ?
+                    UrlEncoding.encode(
+                      (Readable)val, 
+                      "UTF-8", 
+                      context.isIri() ? 
+                          CharUtils.Profile.IUNRESERVED : 
+                          CharUtils.Profile.UNRESERVED) :
+                    UrlEncoding.encode(
+                      (Readable)val,
+                      "UTF-8",
+                      context.isIri() ?
+                          CharUtils.Profile.RESERVEDANDIUNRESERVED :
+                          CharUtils.Profile.RESERVEDANDUNRESERVED);
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+        } else if (val instanceof CharSequence) {
+            val = normalize((CharSequence)val);
+            return encode((CharSequence)val, context.isIri(), reserved);
+        } else if (val instanceof Byte) {
+            return UrlEncoding.encode(((Byte)val).byteValue());
+        } else if (val instanceof Iterable) {
+            StringBuilder buf = new StringBuilder();
+            Iterable<Object> i = (Iterable<Object>)val;
+            for (Object obj : i) {
+                if (buf.length() > 0)
+                  buf.append(explode && explodeDelim != null ? explodeDelim : ",");
+                if (explode && explodePfx != null) 
+                  buf.append(explodePfx);
+                buf.append(toString(obj, context, reserved, false, null, null, len));
+            }
+            return buf.toString();
+        } else if (val instanceof Iterator) {
+          StringBuilder buf = new StringBuilder();
+          Iterator<Object> i = (Iterator<Object>)val;
+          while (i.hasNext()) {
+              Object obj = i.next();
+              if (buf.length() > 0)
+                buf.append(explode && explodeDelim != null ? explodeDelim : ",");
+              if (explode && explodePfx != null) 
+                buf.append(explodePfx);
+              buf.append(toString(obj, context, reserved, false, null, null, len));
+          }
+          return buf.toString();
+        } else if (val instanceof Enumeration) {
+          StringBuilder buf = new StringBuilder();
+          Enumeration<Object> i = (Enumeration<Object>)val;
+          while (i.hasMoreElements()) {
+              Object obj = i.nextElement();
+              if (buf.length() > 0)
+                buf.append(explode && explodeDelim != null ? explodeDelim : ",");
+              if (explode && explodePfx != null) 
+                buf.append(explodePfx);
+              buf.append(toString(obj, context, reserved, false, null, null, len));
+          }
+          return buf.toString();
+        } else if (val instanceof Map) {
+            StringBuilder buf = new StringBuilder();
+            Map<Object,Object> map = (Map<Object,Object>)val;
+            for (Map.Entry<Object, Object> entry : map.entrySet()) {
+              String _key = toString(entry.getKey(), context, reserved, false, null, null, len);
+              String _val = toString(entry.getValue(), context, reserved, false, null, null, len);
+              if (buf.length() > 0)
+                buf.append(explode && explodeDelim != null ? explodeDelim : ",");
+              buf.append(_key)
+                 .append(explode ? '=' : ',')
+                 .append(_val);
+            }
+            return buf.toString();
+        } else {
+            if (val != null)
+              val = normalize(val.toString());
+            return encode(val != null ? val.toString() : null, context.isIri(), reserved);
+        }
+    }
+
+    private static String encode(CharSequence val, boolean isiri, boolean reserved) {
+        String v = normalize(val);
+        return !reserved ?
+          UrlEncoding.encode(v, 
+            isiri
+              ? CharUtils.Profile.IUNRESERVED : 
+                CharUtils.Profile.UNRESERVED) :
+          UrlEncoding.encode(v, 
+              isiri
+              ? CharUtils.Profile.RESERVEDANDIUNRESERVED : 
+                CharUtils.Profile.RESERVEDANDUNRESERVED);
+    }
+
+    /**
+     * Simple String Expansion ({VAR})
+     */
+    private static final class DefaultOperation extends Operation {
+      private static final long serialVersionUID = 8676696520810767327L;
+        public String evaluate(Expression exp, Context context) {
+            StringBuilder buf = new StringBuilder();
+            boolean first = true;
+            for (VarSpec varspec : exp) {
+              if (!first) buf.append(',');
+              String val = eval(varspec, context, false, ",", null);
+              buf.append(val != null ? val : "");
+              first = false;
+            }
+            return buf.toString();
+        }
+    }
+    
+    /**
+     * Reserved Expansion Operation ({+VAR})
+     */
+    private static final class ReservedExpansionOperation extends Operation {
+        private static final long serialVersionUID = 1736980072492867748L;
+        public String evaluate(Expression exp, Context context) {
+            StringBuilder buf = new StringBuilder();
+            boolean first = true;
+            for (VarSpec varspec : exp) {
+              if (!first) buf.append(',');
+              String val = eval(varspec, context, true, ",", null);
+              buf.append(val != null ? val : "");
+              first = false;
+            }
+            return buf.toString();
+        }
+    }
+
+    /**
+     * Fragment Expansion Operation ({#VAR})
+     */
+    private static final class FragmentExpansionOperation extends Operation {
+        private static final long serialVersionUID = -2207953454022197435L;
+        public String evaluate(Expression exp, Context context) {
+            StringBuilder buf = new StringBuilder();
+            boolean first = true;
+            for (VarSpec varspec : exp) {
+              if (!first) buf.append(',');
+              String val = eval(varspec, context, true, ",", null);
+              if (first && val != null)
+                buf.append('#');
+              buf.append(val != null ? val : "");
+              first = false;
+            }
+            return buf.toString();
+        }
+    }    
+
+    /**
+     * Dot Expansion Operation ({.VAR})
+     */
+    private static final class DotExpansionOperation extends Operation {
+        private static final long serialVersionUID = -4357734926260213270L;
+        public String evaluate(Expression exp, Context context) {
+            StringBuilder buf = new StringBuilder();
+            for (VarSpec varspec : exp) {
+              String val = eval(varspec, context, true, ".", null);
+              if (val != null)
+                buf.append('.');
+              buf.append(val != null ? val : "");
+            }
+            return buf.toString();
+        }
+    } 
+    
+
+    /**
+     * Path Expansion Operation ({/VAR})
+     */
+    private static final class PathExpansionOperation extends Operation {
+        private static final long serialVersionUID = 5578346646541533713L;
+        public String evaluate(Expression exp, Context context) {
+            StringBuilder buf = new StringBuilder();
+            for (VarSpec varspec : exp) {
+              String val = eval(varspec, context, false, "/", null);
+              if (val != null)
+                buf.append('/');
+              buf.append(val != null ? val : "");
+            }
+            return buf.toString();
+        }
+    }
+    
+    /**
+     * Path Param Expansion Operation ({;VAR})
+     */
+    private static final class PathParamExpansionOperation extends Operation {
+        private static final long serialVersionUID = 4556090632293646419L;
+        public String evaluate(Expression exp, Context context) {
+            StringBuilder buf = new StringBuilder();
+            for (VarSpec varspec : exp) {
+              String val = eval(varspec, context, false, ";", null);
+              if (val != null)
+                buf.append(';');
+              if (!varspec.isExplode()) {
+                if (val != null)
+                  buf.append(varspec.getName());
+                if (val != null && val.length() > 0)
+                  buf.append("=");
+              }
+              buf.append(val != null ? val : "");
+            }
+            return buf.toString();
+        }
+    }
+    
+    /**
+     * Form Expansion Operation ({?VAR})
+     */
+    private static final class FormExpansionOperation extends Operation {  
+        private static final long serialVersionUID = -2166695868296435715L;
+        public String evaluate(Expression exp, Context context) {
+            StringBuilder buf = new StringBuilder();
+            boolean first = true;
+            buf.append("?");
+            for (VarSpec varspec : exp) {
+              String val = eval(varspec, context, false, "&", varspec.getName() + "=");
+              if (context.contains(varspec.getName())) {
+                if (!first) buf.append('&');
+                if ((val != null && !varspec.isExplode()) || varspec.isNoval()) {
+                  buf.append(varspec.getName());
+                }
+                if (val != null && !varspec.isExplode() && (!varspec.isNoval() || val.length() > 0) )
+                  buf.append("=");
+                if (val != null && val.length() > 0)
+                  buf.append(val);
+              }
+              first = false;
+            } 
+            return buf.toString();
+        }
+    }
+    
+    /**
+     * Query Expansion Operation ({&VAR})
+     */
+    private static final class QueryExpansionOperation extends Operation {
+        private static final long serialVersionUID = 4029538625501399067L;
+        public String evaluate(Expression exp, Context context) {
+            StringBuilder buf = new StringBuilder();
+            for (VarSpec varspec : exp) {
+              String val = eval(varspec, context, false, "&", varspec.getName() + "=");
+              if (context.contains(varspec.getName())) {
+                if ((val != null && !varspec.isExplode()) || varspec.isNoval())
+                  buf.append('&').append(varspec.getName());
+                if (val != null && !varspec.isExplode() && (!varspec.isNoval() || val.length() > 0) )
+                  buf.append("=");
+                  if (val != null && val.length() > 0)
+                    buf.append(val);
+                }
+            }
+            return buf.toString();
+        }
+    }
+}

Propchange: abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/Operation.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/QueryContext.java
URL: http://svn.apache.org/viewvc/abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/QueryContext.java?rev=1173209&view=auto
==============================================================================
--- abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/QueryContext.java (added)
+++ abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/QueryContext.java Tue Sep 20 15:56:46 2011
@@ -0,0 +1,160 @@
+/*
+ * 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.
+ */
+package org.apache.abdera2.common.templates;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.abdera2.common.iri.IRI;
+
+/**
+ * Constructs a mutable Template Context based on an existing IRI/URI 
+ * Query String. This can be used to construct new IRI's based on an
+ * existing IRI -- for instance, when needing to construct an IRI that 
+ * contains all of the same querystring parameters as the original 
+ * IRI or when modifying querystring parameter values.
+ */
+public class QueryContext extends MapContext  {
+
+  private static final long serialVersionUID = -3083469437683051678L;
+
+  public QueryContext(IRI iri) {
+    super(parse(iri));
+  }
+  
+  public QueryContext(String iri) {
+    super(parse(new IRI(iri)));
+  }
+  
+  public Template getTemplate(boolean fragment, Context additionalParams) {
+    Context context = this;
+    if (additionalParams != null)
+      context = new DefaultingContext(context,additionalParams);
+    return QueryContext.templateFromContext(context, fragment);
+  }
+  
+  public Template getTemplate(boolean fragment) {
+    return QueryContext.templateFromContext(this, fragment);
+  }
+  
+  public Template getTemplate() {
+    return QueryContext.templateFromContext(this, false);
+  }
+  
+  public String expand(boolean fragment) {
+    return getTemplate(fragment).expand(this);
+  }
+  
+  public String expand() {
+    return getTemplate(false).expand(this);
+  }
+  
+  public String expand(boolean fragment, Context additionalParams) {
+    Context context = this;
+    if (additionalParams != null)
+      context = new DefaultingContext(context,additionalParams);
+    return getTemplate(fragment,additionalParams).expand(context);
+  }
+  
+  public String expand(Context additionalParams) {
+    return expand(false,additionalParams);
+  }
+  
+  private static Map<String,Object> parse(IRI iri) {
+    Map<String,Object> map = new HashMap<String,Object>();
+    if (iri != null) {
+      String query = iri.getQuery();
+      if (query != null) {
+        String[] params = query.split("\\s*&\\s*");
+        for (String param : params) {
+          String[] pair = param.split("\\s*=\\s*",2);
+          setval(map,pair[0],pair.length==1?null:pair[1]);
+        }
+      }
+    }
+    return map;
+  }
+  
+  @SuppressWarnings({ "rawtypes", "unchecked" })
+  private static void setval(Map<String,Object> map, String key, String val) {
+    if (map.containsKey(key)) {
+      Object value = map.get(key);
+      if (value instanceof Collection) {
+        ((Collection)value).add(val);
+      } else {
+        List<Object> l = new ArrayList<Object>();
+        l.add(value);
+        l.add(val);
+        map.put(key, l);
+      }
+    } else map.put(key,val);
+  }
+  
+  public static Template templateFromContext(Context context, boolean fragment) {
+    StringBuilder buf = new StringBuilder();
+    buf.append('{').append(fragment?'&':'?');
+    boolean first = true;
+    for (String name : context) {
+      if (!first) buf.append(',');
+      else first = false;
+      buf.append(name);
+      Object val = context.resolve(name);
+      if (val == null)
+        buf.append('^');
+      else if (val instanceof List)
+        buf.append('*');
+    }
+    buf.append('}');
+    return new Template(buf.toString());
+  }
+  
+  public static Template templateFromQuery(String query, boolean fragment, Context additionalParams) {
+    Context context = new QueryContext(query);
+    if (additionalParams != null)
+      context = new DefaultingContext(context,additionalParams);
+    StringBuilder buf = new StringBuilder(baseFromQuery(query));
+    buf.append(templateFromContext(context,fragment));
+    return new Template(buf.toString());
+  }
+  
+  public static String baseFromQuery(String query) {
+    IRI iri = new IRI(query);
+    String s = iri.resolve(iri.getPath()).toString();
+    return s.equals(query) ? "" : s;
+  }
+  
+  public static String expandQuery(String query, Context context) {
+    return expandQuery(query,context,(Template)null);
+  }
+  
+  public static String expandQuery(String query, Context context, String extender) {
+    return expandQuery(query,context,new Template(extender));
+  }
+  
+  public static String expandQuery(String query, Context context, Template extender) {
+    QueryContext qc = new QueryContext(query);
+    DefaultingContext dc = new DefaultingContext(context,qc);
+    Template temp = QueryContext.templateFromQuery(query, false, qc);
+    if (extender != null)
+      temp = temp.extend(extender);
+    return temp.expand(dc);  
+  }
+}

Propchange: abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/QueryContext.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/Route.java
URL: http://svn.apache.org/viewvc/abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/Route.java?rev=1173209&view=auto
==============================================================================
--- abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/Route.java (added)
+++ abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/Route.java Tue Sep 20 15:56:46 2011
@@ -0,0 +1,327 @@
+/*
+ * 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.
+ */
+package org.apache.abdera2.common.templates;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.abdera2.common.anno.URIRoute;
+
+/**
+ * A type of URI Template loosely based on Ruby on Rails style Routes. Example: Route feed_route = new
+ * Route("feed",":feed/:entry");
+ */
+@SuppressWarnings("unchecked")
+public class Route<T> implements Iterable<String>, Cloneable, Serializable {
+
+    private static final long serialVersionUID = -8979172281494208841L;
+
+    private static final Pattern VARIABLE = Pattern.compile("[\\*\\:](?:\\()?[0-9a-zA-Z]+(?:\\))?");
+    private static final String VARIABLE_CONTENT_MATCH = "([^:/\\?#\\[\\]@!\\$&'\\(\\)\\*\\+,;\\=]+)";
+    private static final String VARIABLE_CONTENT_PARSE = "([^:/\\?#\\[\\]@!\\$&'\\(\\)\\*\\+,;\\=]*)";
+    private final T key;
+    private final String pattern;
+    private final String[] tokens;
+    private final String[] variables;
+    private final Pattern regexMatch;
+    private final Pattern regexParse;
+
+    private Map<String, String> requirements;
+
+    private MapContext defaultValues;
+
+    public Route(T key, String pattern) {
+        this(key, pattern, null, null);
+    }
+
+    public Route(T key, String pattern, Map<String, Object> defaultValues, Map<String, String> requirements) {
+        this.key = key;
+        this.pattern = pattern;
+        this.tokens = initTokens();
+        this.variables = initVariables();
+        this.defaultValues = defaultValues != null ? new MapContext(defaultValues,true) : null;
+        this.requirements = requirements;
+        this.regexMatch = initRegexMatch();
+        this.regexParse = initRegexParse();
+    }
+
+    private String[] initTokens() {
+        Matcher matcher = VARIABLE.matcher(pattern);
+        List<String> tokens = new ArrayList<String>();
+        while (matcher.find()) {
+            String token = matcher.group();
+            if (!tokens.contains(token))
+                tokens.add(token);
+        }
+        return tokens.toArray(new String[tokens.size()]);
+    }
+
+    private String[] initVariables() {
+        List<String> list = new ArrayList<String>();
+        for (String token : this) {
+            String var = var(token);
+            if (!list.contains(var))
+                list.add(var);
+        }
+        String[] vars = list.toArray(new String[list.size()]);
+        Arrays.sort(vars);
+        return vars;
+    }
+
+    private Pattern initRegexMatch() {
+        StringBuffer match = new StringBuffer();
+        int cnt = 0;
+        for (String part : VARIABLE.split(pattern)) {
+            match.append(Pattern.quote(part));
+            if (cnt++ < tokens.length) {
+                match.append(VARIABLE_CONTENT_MATCH);
+            }
+        }
+        return Pattern.compile(match.toString());
+    }
+
+    private Pattern initRegexParse() {
+        StringBuffer parse = new StringBuffer();
+        int cnt = 0;
+        for (String part : VARIABLE.split(pattern)) {
+            parse.append(Pattern.quote(part));
+            if (cnt++ < tokens.length) {
+                parse.append(VARIABLE_CONTENT_PARSE);
+            }
+        }
+        return Pattern.compile(parse.toString());
+    }
+
+    /**
+     * Returns true if the given uri matches the route pattern
+     */
+    public boolean match(String uri) {
+        return regexMatch.matcher(uri).matches() && matchRequirements(uri);
+    }
+
+    /**
+     * Parses the given uri using the route pattern
+     */
+    public Map<String, String> parse(String uri) {
+        HashMap<String, String> vars = new HashMap<String, String>();
+        Matcher matcher = regexParse.matcher(uri);
+        if (matcher.matches()) {
+            for (int i = 0; i < matcher.groupCount(); i++) {
+                vars.put(var(tokens[i]), matcher.group(i + 1).length() > 0 ? matcher.group(i + 1) : null);
+            }
+        }
+
+        return vars;
+    }
+
+    /**
+     * Expand the route pattern given the specified context
+     */
+    public String expand(Context context) {
+        String pattern = this.pattern;
+        if (this.defaultValues != null) {
+          context = new DefaultingContext(context,this.defaultValues);
+        }
+        for (String token : this) {
+            String var = var(token);
+            Expression exp = new Expression(var);
+            String val = exp.evaluate(context);
+            pattern = replace(pattern, token, val!=null?val:getDefaultValue(var));
+        }
+        StringBuffer buf = new StringBuffer(pattern);
+        boolean qs = false;
+        for (String var : context) {
+            if (Arrays.binarySearch(variables, var) < 0) {
+                if (!qs) {
+                    buf.append("?");
+                    qs = true;
+                } else {
+                    buf.append("&");
+                }
+                Expression exp = new Expression(var);
+                String val = exp.evaluate(context);
+                if (val != null)
+                  buf.append(var).append("=").append(val);
+            }
+        }
+
+        return buf.toString();
+    }
+
+    public String getDefaultValue(String var) {
+        if (defaultValues == null)
+            return null;
+
+        return defaultValues.resolve(var);
+    }
+
+    public String getRequirement(String var) {
+        if (requirements == null)
+            return null;
+
+        return requirements.get(var);
+    }
+
+    private String var(String token) {
+        token = token.substring(1);
+        if (token.startsWith("("))
+            token = token.substring(1);
+        if (token.endsWith(")"))
+            token = token.substring(0, token.length() - 1);
+        return token;
+    }
+
+    /**
+     * Expand the route pattern given the specified context object
+     **/
+    public String expand(Object object) {
+        return expand(object, false);
+    }
+
+    /**
+     * Expand the route pattern using IRI escaping rules
+     */
+    @SuppressWarnings("rawtypes")
+    public String expand(Object object, boolean isiri) {
+        return expand(object instanceof Context ? (Context)object : object instanceof Map
+            ? new MapContext((Map)object, isiri) : new ObjectContext(object, isiri));
+    }
+
+    private String replace(String pattern, String token, String value) {
+        return pattern.replace(token, value);
+    }
+
+    public T getKey() {
+        return key;
+    }
+
+    public String getPattern() {
+        return pattern;
+    }
+
+    public Iterator<String> iterator() {
+        return Arrays.asList(tokens).iterator();
+    }
+
+    public String[] getVariables() {
+        return variables;
+    }
+
+    public Map<String, Object> getDefaultValues() {
+        return defaultValues;
+    }
+
+    public Map<String, String> getRequirements() {
+        return requirements;
+    }
+
+    public Route<T> clone() {
+        try {
+            return (Route<T>)super.clone();
+        } catch (Throwable e) {
+            return new Route<T>(key, pattern); // not going to happen, but just in case
+        }
+    }
+
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((key == null) ? 0 : key.hashCode());
+        result = prime * result + ((pattern == null) ? 0 : pattern.hashCode());
+        return result;
+    }
+
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        final Route<T> other = (Route<T>)obj;
+        if (key == null) {
+            if (other.key != null)
+                return false;
+        } else if (!key.equals(other.key))
+            return false;
+        if (pattern == null) {
+            if (other.pattern != null)
+                return false;
+        } else if (!pattern.equals(other.pattern))
+            return false;
+        return true;
+    }
+
+    public String toString() {
+        return pattern;
+    }
+
+    @SuppressWarnings("rawtypes")
+    public static String expand(String pattern, Context context) {
+        if (context == null || pattern == null)
+            throw new IllegalArgumentException();
+        Route<?> route = new Route(null, pattern);
+        return route.expand(context);
+    }
+
+    public static String expand(String pattern, Object object) {
+        return expand(pattern, object, false);
+    }
+
+    @SuppressWarnings("rawtypes")
+    public static String expand(String pattern, Object object, boolean isiri) {
+        if (object == null || pattern == null)
+            throw new IllegalArgumentException();
+        Route<?> route = new Route(null, pattern);
+        return route.expand(object, isiri);
+    }
+
+    public static String expandAnnotated(Object object) {
+        if (object == null)
+            throw new IllegalArgumentException();
+        Class<?> _class = object.getClass();
+        URIRoute uriroute = (URIRoute)_class.getAnnotation(URIRoute.class);
+        if (uriroute != null) {
+            return expand(uriroute.value(), object, uriroute.isiri());
+        } else {
+            throw new IllegalArgumentException("No Route provided");
+        }
+    }
+
+    private boolean matchRequirements(String uri) {
+        if (requirements != null && !requirements.isEmpty()) {
+            Map<String, String> parsedUri = parse(uri);
+            for (Map.Entry<String, String> requirement : requirements.entrySet()) {
+                Pattern patt = Pattern.compile(requirement.getValue());
+                if (parsedUri.containsKey(requirement.getKey()) && !patt.matcher(parsedUri.get(requirement.getKey()))
+                    .matches()) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+}

Propchange: abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/Route.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/Template.java
URL: http://svn.apache.org/viewvc/abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/Template.java?rev=1173209&view=auto
==============================================================================
--- abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/Template.java (added)
+++ abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/Template.java Tue Sep 20 15:56:46 2011
@@ -0,0 +1,264 @@
+/*
+ * 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.
+ */
+package org.apache.abdera2.common.templates;
+
+import java.io.Serializable;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.abdera2.common.anno.URITemplate;
+import org.apache.abdera2.common.templates.Context;
+import org.apache.abdera2.common.templates.Expression;
+import org.apache.abdera2.common.templates.MapContext;
+import org.apache.abdera2.common.templates.ObjectContext;
+import org.apache.abdera2.common.templates.Template;
+import org.apache.abdera2.common.templates.Expression.VarSpec;
+
+@SuppressWarnings("unchecked")
+public final class Template implements Iterable<Expression>, Serializable {
+
+    private static final long serialVersionUID = -613907262632631896L;
+
+    private static final Pattern EXPRESSION = Pattern.compile("\\{[^{}]+\\}");
+    private static final String EXP_START = "\\{";
+    private static final String EXP_STOP = "\\}";
+
+    private final String pattern;
+    private final Set<Expression> expressions = new HashSet<Expression>();
+    private final Set<String> variables = new HashSet<String>();
+
+    /**
+     * @param pattern A URI Template
+     */
+    public Template(String pattern) {
+        if (pattern == null)
+          throw new IllegalArgumentException("Template pattern must not be null");
+        this.pattern = pattern;
+        initExpressions();
+    }
+    
+    public Template(Object object) {
+      this(extractPattern(object));
+    }
+
+    private static String extractPattern(Object object) {
+      if (object == null)
+        return null;
+      if (object instanceof String)
+        return (String)object;
+      else if (object instanceof Template)
+        return ((Template)object).pattern;
+      Class<?> _class = object instanceof Class ? (Class<?>)object : object.getClass();
+      URITemplate uriTemplate = (URITemplate)_class.getAnnotation(URITemplate.class);
+      String pattern = 
+        uriTemplate != null ?
+           uriTemplate.value() :
+           object instanceof TemplateProvider ? 
+             ((TemplateProvider)object).getTemplate() : 
+             null;
+      if (pattern == null)
+        throw new IllegalArgumentException();
+      return pattern;
+    }
+
+    /**
+     * Iterate the template expressions
+     */
+    public Iterator<Expression> iterator() {
+        return expressions.iterator();
+    }
+
+    /**
+     * Return the array of template variables
+     */
+    private void initExpressions() {
+        Matcher matcher = EXPRESSION.matcher(pattern);
+        while (matcher.find()) {
+            String token = matcher.group();
+            token = token.substring(1, token.length() - 1);
+            Expression exp = new Expression(token);
+            for (VarSpec varspec : exp)
+              variables.add(varspec.getName());
+            expressions.add(exp);
+        }
+    }
+
+    /**
+     * Return the array of template variables
+     */
+    public Iterable<String> getVariables() {
+        return variables;
+    }
+
+    /**
+     * Expand the URI Template using the specified Context.
+     * 
+     * @param context The Context impl used to resolve variable values
+     * @return An expanded URI
+     */
+    public String expand(Context context) {
+        String pattern = this.pattern;
+        for (Expression exp : this)
+            pattern = 
+              replace(
+                pattern, 
+                exp, 
+                exp.evaluate(context));
+        return pattern;
+    }
+
+    /**
+     * Expand the URI Template using the non-private fields and methods of the specified object to resolve the template
+     * tokens
+     */
+    public String expand(Object object) {
+        return expand(object, false);
+    }
+
+    /**
+     * Expand the template using the non-private fields and methods of the specified object to resolve the template
+     * tokens. If isiri is true, IRI escaping rules will be used.
+     */
+    public String expand(Object object, boolean isiri) {
+        return expand(asContext(object,isiri));
+    }
+
+    private String replace(String pattern, Expression exp, String value) {
+        return pattern.replaceAll(EXP_START + Pattern.quote(exp.toString()) + EXP_STOP, value);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((pattern == null) ? 0 : pattern.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        final Template other = (Template)obj;
+        if (pattern == null) {
+            if (other.pattern != null)
+                return false;
+        } else if (!pattern.equals(other.pattern))
+            return false;
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return pattern;
+    }
+
+    public static String expand(String pattern, Context context) {
+        if (context == null || pattern == null)
+            throw new IllegalArgumentException();
+        return new Template(pattern).expand(context);
+    }
+
+    public static String expand(String pattern, Object object) {
+        return expand(pattern, object, false);
+    }
+
+    public static String expand(String pattern, Object object, boolean isiri) {
+        if (object == null || pattern == null)
+            throw new IllegalArgumentException();
+        return new Template(pattern).expand(object, isiri);
+    }
+
+    public static String expandAnnotated(Object object) {
+      return expandAnnotated(object,null);
+    }
+    
+    @SuppressWarnings("rawtypes")
+    private static Context asContext(Object obj, boolean isiri) {
+      return 
+        obj instanceof Context ? 
+          (Context)obj : 
+         obj instanceof Map ? 
+           new MapContext((Map)obj, isiri) : 
+           new ObjectContext(obj, isiri);
+    }
+    
+    /**
+     * Use an Object annotated with the URITemplate annotation to expand a template
+     */
+    public static String expandAnnotated(Object object, Object additional) {
+        if (object == null)
+            throw new IllegalArgumentException();
+        Object contextObject = null;
+        Class<?> _class = null;
+        if (object instanceof Class<?>) {
+          _class = (Class<?>)object;
+          contextObject = new AnnotationContext(_class);
+        } else {
+          _class = object.getClass();
+          contextObject = object;
+          if (_class.isAnnotationPresent(org.apache.abdera2.common.anno.Context.class)) {
+            additional = new AnnotationContext(_class);
+          }
+        }
+        URITemplate uritemplate = (URITemplate)_class.getAnnotation(URITemplate.class);
+        if (uritemplate != null) {
+            if (additional != null) {
+              Context add = asContext(additional, uritemplate.isiri());
+              Context main = asContext(contextObject, uritemplate.isiri());
+              contextObject = new DefaultingContext(add,main);
+            }
+            return expand(
+              uritemplate.value(), 
+              contextObject, 
+              uritemplate.isiri());
+        } else {
+            throw new IllegalArgumentException("No URI Template provided");
+        }
+
+    }
+    
+    public static Context getAnnotatedContext(Object object) {
+      return new AnnotationContext(object);
+    }
+
+    /**
+     * Create a new Template by appending the given template to this
+     */
+    public Template extend(Template template) {
+      StringBuilder buf = new StringBuilder(pattern);
+      if (template != null)
+        buf.append(template.pattern);
+      return new Template(buf.toString());
+    }
+    
+    public Template extend(String template) {
+      StringBuilder buf = new StringBuilder(pattern);
+      if (template != null)
+        buf.append(template);
+      return new Template(buf.toString());
+    }
+}

Propchange: abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/Template.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/TemplateManager.java
URL: http://svn.apache.org/viewvc/abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/TemplateManager.java?rev=1173209&view=auto
==============================================================================
--- abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/TemplateManager.java (added)
+++ abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/TemplateManager.java Tue Sep 20 15:56:46 2011
@@ -0,0 +1,242 @@
+/*
+ * 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.
+ */
+package org.apache.abdera2.common.templates;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.apache.abdera2.common.iri.IRI;
+
+
+public class TemplateManager<T>
+  implements Iterable<T> { 
+
+  private final Map<T,Template> templates = 
+    new HashMap<T,Template>();
+  private final boolean isiri;
+  private final IRI base;
+  private final Context contextDefaults;
+
+  public TemplateManager(String base) {
+    this(new IRI(base));
+  }
+  
+  public TemplateManager(IRI base) {
+    this.isiri = true;
+    this.base = base;
+    this.contextDefaults = null;
+  }
+  
+  public TemplateManager() {
+    this.isiri = true;
+    this.base = null;
+    this.contextDefaults = null;
+  }
+  
+  public TemplateManager(String base, boolean iri) {
+    this(new IRI(base),iri);
+  }
+  
+  public TemplateManager(IRI base, boolean iri) {
+    this.isiri = iri;
+    this.base = base;
+    this.contextDefaults = null;
+  }
+  
+  public TemplateManager(boolean iri) {
+    this.isiri = iri;
+    this.base = null;
+    this.contextDefaults = null;
+  }
+
+  public TemplateManager(String base, Context defaults) {
+    this(new IRI(base),defaults);
+  }
+  
+  public TemplateManager(IRI base, Context defaults) {
+    if (defaults == null)
+      throw new IllegalArgumentException();
+    this.isiri = defaults.isIri();
+    this.contextDefaults = defaults;
+    this.base = base;
+  }
+  
+  public TemplateManager(Context defaults) {
+    this((IRI)null,defaults);
+  }
+  
+  public TemplateManager(String base, Object defaults) {
+    this(new IRI(base),defaults);
+  }
+  
+  public TemplateManager(IRI base, Object defaults) {
+    this(base,defaults,true);
+  }
+ 
+  public TemplateManager(Object defaults) {
+    this((IRI)null,defaults,true);
+  }
+  
+  public TemplateManager(Object defaults, boolean isiri) {
+    this(_innerContext(defaults,isiri));
+  }
+  
+  public TemplateManager(String base, Object defaults, boolean isiri) {
+    this(new IRI(base),defaults,isiri);
+  }
+  
+  public TemplateManager(IRI base, Object defaults, boolean isiri) {
+    this(base,_innerContext(defaults,isiri));
+  }
+  
+  public Context getDefaultContext() {
+    return this.contextDefaults;
+  }
+  
+  public void add(T key, Template template) {
+    this.templates.put(key,template);
+  }
+  
+  public void add(T key, String template) {
+    add(key, new Template(template));
+  }
+  
+  public void add(T key, Object template) {
+    add(key, new Template(template));
+  }
+  
+  public void add(Map<T,Object> templates) {
+    TemplateManager<T> tm = fromMap(templates);
+    this.templates.putAll(tm.templates);
+  }
+  
+  public String expandAndResolve(T key, Object object, String base) {
+    IRI iri = expandAndResolve(key,object,new IRI(base));
+    return iri != null ? iri.toString() : null;
+  }
+  
+  public IRI expandAndResolve(T key, Object object, IRI base) {
+    String ex = expand(key,object);
+    return ex != null ? 
+        base == null ? 
+            new IRI(ex) : 
+            base.resolve(ex) : 
+        null;    
+  }
+  
+  public IRI expandAndResolve(T key, Object object) {
+    return expandAndResolve(key,object,base);
+  }
+ 
+  public String expandAndResolve(T key, Context context, String base) {
+    IRI iri = expandAndResolve(key,context,new IRI(base));
+    return iri != null ? iri.normalize().toString() : null;
+  }
+  
+  public IRI expandAndResolve(T key, Context context, IRI base) {
+    String ex = expand(key,context);
+    return ex != null ? 
+        base == null ? 
+            new IRI(ex) : 
+            base.resolve(ex) : 
+        null;    
+  }
+  
+  public IRI expandAndResolve(T key, Context context) {
+    return expandAndResolve(key,context,base);    
+  }
+  
+  public String expand(T key, Object object) {
+    if (!templates.containsKey(key))
+      return null;
+    Template template = templates.get(key);
+    return template.expand(_wrap(_innerContext(object,isiri),contextDefaults));
+  }
+  
+  public String expand(T key) {
+    if (contextDefaults == null)
+      throw new IllegalArgumentException();
+    return expand(key,contextDefaults);
+  }
+  
+  public String expand(T key, Context context) {
+    if (!templates.containsKey(key))
+      return null;
+    Template template = templates.get(key);
+    return template.expand(_wrap(context,contextDefaults));
+  }
+  
+  @SuppressWarnings("unchecked")
+  private static Context _innerContext(Object object, boolean isiri) {
+    return object instanceof Context ? (Context)object : object instanceof Map
+        ? new MapContext((Map<String,Object>)object, isiri) : new ObjectContext(object, isiri);
+  }
+  
+  private static Context _wrap(Context context, Context contextDefaults) {
+    return contextDefaults != null ? 
+      new DefaultingContext(context,contextDefaults) : context;
+  }
+
+  public Iterator<T> iterator() {
+    return templates.keySet().iterator();
+  }
+
+  @Override
+  public int hashCode() {
+    final int prime = 31;
+    int result = 1;
+    result = prime * result
+        + ((contextDefaults == null) ? 0 : contextDefaults.hashCode());
+    result = prime * result + (isiri ? 1231 : 1237);
+    result = prime * result + ((templates == null) ? 0 : templates.hashCode());
+    return result;
+  }
+
+  @Override
+  @SuppressWarnings("rawtypes")
+  public boolean equals(Object obj) {
+    if (this == obj)
+      return true;
+    if (obj == null)
+      return false;
+    if (getClass() != obj.getClass())
+      return false;
+    TemplateManager other = (TemplateManager) obj;
+    if (contextDefaults == null) {
+      if (other.contextDefaults != null)
+        return false;
+    } else if (!contextDefaults.equals(other.contextDefaults))
+      return false;
+    if (isiri != other.isiri)
+      return false;
+    if (templates == null) {
+      if (other.templates != null)
+        return false;
+    } else if (!templates.equals(other.templates))
+      return false;
+    return true;
+  }
+ 
+  public static <T>TemplateManager<T> fromMap(Map<T,Object> map) {
+    TemplateManager<T> tm = new TemplateManager<T>();
+    for (Map.Entry<T, Object> entry : map.entrySet()) {
+      tm.add(entry.getKey(),entry.getValue());
+    }
+    return tm;
+  }
+}

Propchange: abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/TemplateManager.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain



Mime
View raw message