abdera-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jmsn...@apache.org
Subject svn commit: r1239237 [5/12] - in /abdera/abdera2-server: ./ .settings/ etc/ examples/ examples/src/ examples/src/main/ examples/src/main/java/ examples/src/main/java/org/ examples/src/main/java/org/apache/ examples/src/main/java/org/apache/abdera2/ exa...
Date Wed, 01 Feb 2012 17:55:02 GMT
Added: abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/RegexTargetResolver.java
URL: http://svn.apache.org/viewvc/abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/RegexTargetResolver.java?rev=1239237&view=auto
==============================================================================
--- abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/RegexTargetResolver.java (added)
+++ abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/RegexTargetResolver.java Wed Feb  1 17:54:54 2012
@@ -0,0 +1,248 @@
+/*
+ * 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.protocol;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.abdera2.common.misc.MoreFunctions;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.LinkedHashMultimap;
+import com.google.common.collect.Multimap;
+import static org.apache.abdera2.common.misc.MorePredicates.*;
+/**
+ * <p>
+ * Provides a utility class helpful for determining which type of resource the client is requesting. Each resource type
+ * (e.g. service doc, collection, entry, edit uri, media resource, etc) is assigned a regex pattern. Given the request
+ * URI (path and querystring), this will determine which resource was selected and return an appropriate TargetMatcher.
+ * TargetMatcher is essentially just a simplified version of the java.util.regex.Matcher that also specifies the
+ * Resource Type.
+ * </p>
+ * 
+ * <pre>
+ *  RequestContext request = ...
+ *  RegexTargetResolver tr = new RegexTargetResolver();
+ *  tr.setPattern("/atom",ResourceType.INTROSPECTION)
+ *    .setPattern("/atom/([^/#?]+)",ResourceType.COLLECTION)
+ *    .setPattern("/atom/([^/#?]+)/([^/#?]+)",ResourceType.ENTRY)
+ *    .setPattern("/atom/([^/#?]+)/([^/#?]+)\\?edit",ResourceType.ENTRY_EDIT)
+ *    .setPattern("/atom/([^/#?]+)/([^/#?]+)\\?media",ResourceType.MEDIA)
+ *    .setPattern("/atom/([^/#?]+)/([^/#?]+)\\?edit-media",ResourceType.MEDIA_EDIT);
+ *  
+ *  Target target = tr.resolve(request);
+ *  System.out.println(target.getType());
+ *  System.out.println(targer.getParameter("foo"));
+ * </pre>
+ */
+public class RegexTargetResolver<R extends RequestContext>
+  implements Function<R,Target> {
+
+    protected final Map<Pattern, TargetType> patterns;
+    protected final Multimap<Pattern,String> fields = 
+      LinkedHashMultimap.create();
+
+    public RegexTargetResolver() {
+        this.patterns = new HashMap<Pattern, TargetType>();
+    }
+
+    public RegexTargetResolver(Map<String, TargetType> patterns) {
+        this.patterns = new HashMap<Pattern, TargetType>();
+        for (Map.Entry<String,TargetType> entry : patterns.entrySet())
+            setPattern(entry.getKey(), entry.getValue());
+    }
+
+    public RegexTargetResolver<R> setPattern(String pattern, TargetType type) {
+        return setPattern(pattern, type, new String[0]);
+    }
+
+    public RegexTargetResolver<R> setPattern(String pattern, TargetType type, String... fields) {
+        Pattern p = Pattern.compile(pattern);
+        this.patterns.put(p, type);
+        this.fields.putAll(p,Arrays.asList(fields));
+        return this;
+    }
+
+    public Target apply(R request) {
+      String uri = request.getTargetPath();
+      for (Pattern pattern : patterns.keySet()) {
+        Matcher matcher = pattern.matcher(uri);
+        if (matcher.matches()) 
+          return getTarget(
+            this.patterns.get(pattern), 
+            request, 
+            matcher, 
+            this.fields.get(pattern));
+      }
+      return null;
+    }
+
+    protected Target getTarget(
+      TargetType type, 
+      RequestContext request, 
+      Matcher matcher, 
+      Iterable<String> fields) {
+        return new RegexTarget(type, request, matcher, fields);
+    }
+
+    public String toString() {
+      StringBuilder buf = new StringBuilder();
+      buf.append("Regex Target Resolver:\n");
+      for (Pattern pattern : patterns.keySet())
+        buf.append(
+          String.format(
+            "%s, Type: %s, Fields: %s",
+            pattern,
+            this.patterns.get(pattern),
+            this.fields.get(pattern)));
+      return buf.toString();
+    }
+
+    public int hashCode() {
+      return MoreFunctions.genHashCode(1, fields,patterns);
+    }
+
+    @SuppressWarnings("unchecked")
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        final RegexTargetResolver<R> other = (RegexTargetResolver<R>)obj;
+        if (fields == null) {
+            if (other.fields != null)
+                return false;
+        } else if (!fields.equals(other.fields))
+            return false;
+        if (patterns == null) {
+            if (other.patterns != null)
+                return false;
+        } else if (!patterns.equals(other.patterns))
+            return false;
+        return true;
+    }
+
+    public static class RegexTarget 
+      extends SimpleTarget
+      implements Target {
+
+        private static final long serialVersionUID = 165211244926064449L;
+        protected Matcher matcher;
+        protected Iterable<String> fields;
+
+        public RegexTarget(
+          TargetType type, 
+          RequestContext context, 
+          Matcher matcher, 
+          Iterable<String> fields) {
+            super(type, context);
+            this.matcher = matcher;
+            this.fields = fields;
+        }
+
+        public String getParameter(String name) {
+            if (fields == null)
+                return super.getParameter(name);
+            int idx = Iterables.indexOf(fields, equalsIgnoreCase(name));
+            return idx > -1 && idx <= matcher.groupCount()-1 ? 
+              matcher.group(idx+1) : super.getParameter(name);
+        }
+
+        public Iterable<String> getParameterNames() {
+            Iterable<String> names = super.getParameterNames();
+            Set<String> list = new HashSet<String>();
+            for (String name : names)
+              list.add(name);
+            if (fields != null)
+                Iterables.addAll(list, fields);
+            return list;
+        }
+
+        @SuppressWarnings("unchecked")
+        @Override
+        public <T> T getMatcher() {
+            return (T)matcher.pattern();
+        }
+
+        @Override
+        public int hashCode() {
+          String m = matcher.group(0);
+          String p = matcher.pattern().pattern();
+          return MoreFunctions.genHashCode(1, m,p,type);
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj)
+                return true;
+            if (obj == null)
+                return false;
+            if (getClass() != obj.getClass())
+                return false;
+            final RegexTarget other = (RegexTarget)obj;
+            String m = matcher.group(0);
+            String p = matcher.pattern().pattern();
+            String m2 = other.matcher.group(0);
+            String p2 = other.matcher.pattern().pattern();
+            if (!super.equals(obj))
+                return false;
+            if (m == null) {
+                if (m2 != null)
+                    return false;
+            } else if (!m.equals(m2))
+                return false;
+            if (p == null) {
+                if (p2 != null)
+                    return false;
+            } else if (!p.equals(p2))
+                return false;
+            if (type == null) {
+                if (other.type != null)
+                    return false;
+            } else if (!type.equals(other.type))
+                return false;
+            return true;
+        }
+
+        public String toString() {
+            String m = matcher.group(0);
+            String p = matcher.pattern().pattern();
+            StringBuilder buf = new StringBuilder();
+            buf.append("RegexTarget[").append(p).append(" ==> ").append(m).append("] = ").append(type.toString())
+                .append("\n");
+            for (String param : getParameterNames()) {
+                buf.append("    ").append(param).append(" = ").append(getParameter(param)).append("\n");
+            }
+            return buf.toString();
+        }
+
+        public String getIdentity() {
+            return context.getUri().toString();
+        }
+
+    }
+
+}

Propchange: abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/RegexTargetResolver.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/Request.java
URL: http://svn.apache.org/viewvc/abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/Request.java?rev=1239237&view=auto
==============================================================================
--- abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/Request.java (added)
+++ abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/Request.java Wed Feb  1 17:54:54 2012
@@ -0,0 +1,68 @@
+/*
+ * 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.protocol;
+
+import org.apache.abdera2.common.http.EntityTag;
+import org.joda.time.DateTime;
+
+/**
+ * A protocol request. This is used as a base for both server and client requests
+ */
+public interface Request extends Message {
+
+    /**
+     * Get the value of the Accept header
+     */
+    String getAccept();
+
+    /**
+     * Get the value of the Accept-Charset header
+     */
+    String getAcceptCharset();
+
+    /**
+     * Get the value of the Accept-Encoding header
+     */
+    String getAcceptEncoding();
+
+    /**
+     * Get the value of the Accept-Language header
+     */
+    String getAcceptLanguage();
+
+    /**
+     * Get a listing of Etags from the If-Match header
+     */
+    Iterable<EntityTag> getIfMatch();
+
+    /**
+     * Get the value of the If-Modified-Since header
+     */
+    DateTime getIfModifiedSince();
+
+    /**
+     * Get a listing of ETags from the If-None-Match header
+     */
+    Iterable<EntityTag> getIfNoneMatch();
+
+    /**
+     * Get the value of the If-Unmodified-Since header
+     */
+    DateTime getIfUnmodifiedSince();
+
+}

Propchange: abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/Request.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/RequestContext.java
URL: http://svn.apache.org/viewvc/abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/RequestContext.java?rev=1239237&view=auto
==============================================================================
--- abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/RequestContext.java (added)
+++ abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/RequestContext.java Wed Feb  1 17:54:54 2012
@@ -0,0 +1,210 @@
+/*
+ * 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.protocol;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.security.Principal;
+import java.util.Locale;
+
+import javax.security.auth.Subject;
+
+import org.apache.abdera2.common.iri.IRI;
+
+/**
+ * The RequestContext provides access to every detail of the Request.
+ */
+public interface RequestContext
+  extends Request, Iterable<RequestContext.Property> {
+
+    /**
+     * RequestContext attributes can either have Session or Request scope. Request scope attributes are only valid
+     * within the context of the current request. Session scope attributes, however, will remain valid as long as the
+     * Session is active. Container scope attributes are set on the Web container (e.g. the ServletContext)
+     */
+    public enum Scope {
+        REQUEST, SESSION, CONTAINER
+    };
+
+    /**
+     * Special properties provided by the server
+     */
+    public enum Property {
+        SESSIONID, 
+        SESSIONCREATED, 
+        SESSIONACCESSED, 
+        SESSIONTIMEOUT, 
+        CHARACTERENCODING, 
+        LOCALES, 
+        PROTOCOL, 
+        REMOTEADDRESS, 
+        REMOTEHOST, 
+        REMOTEUSER, 
+        SCHEME, 
+        PRINCIPAL, 
+        AUTHTYPE, 
+        CONTENTLENGTH, 
+        CONTENTTYPE, 
+        CONTEXTPATH, 
+        LOCALADDR, 
+        LOCALNAME, 
+        SERVERNAME, 
+        SERVERPORT, 
+        SECURE, 
+        PARTS,
+    };
+
+    /**
+     * Get the Provider associated with this request
+     */
+    <P extends Provider>P getProvider();
+
+    /**
+     * Get this requests resolved Target
+     */
+    Target getTarget();
+
+    /**
+     * Get this requests resolved Subject
+     */
+    Subject getSubject();
+
+    /**
+     * Get this requests authenticated Principal object
+     */
+    Principal getPrincipal();
+
+    /**
+     * Get the client's preferred locale as specified in the request
+     */
+    Locale getPreferredLocale();
+
+    /**
+     * Get a listing of the client's preferred locales as specified in the request. The listing will be sorted in order
+     * of preference.
+     */
+    Iterable<Locale> getPreferredLocales();
+
+    /**
+     * Get the HTTP method
+     */
+    String getMethod();
+
+    /**
+     * Get the request URI
+     */
+    IRI getUri();
+
+    /**
+     * Get the absolute request URI (includes server name, port, etc)
+     */
+    IRI getResolvedUri();
+
+    /**
+     * Get the absolute base URI ... this is the request URI up to the Context Path of the web application within which
+     * the Abdera Servlet is deployed
+     */
+    IRI getBaseUri();
+
+    /**
+     * Get the specified system property
+     */
+    <T>T getProperty(Property property);
+
+    /**
+     * Get the specified request parameter
+     */
+    String getParameter(String name);
+
+    /**
+     * Return the listing of parameter names
+     */
+    Iterable<String> getParameterNames();
+
+    /**
+     * Return all the values for the specified parameter
+     */
+    Iterable<String> getParameters(String name);
+
+    /**
+     * Get the named attribute from the specified scope
+     */
+    <T>T getAttribute(Scope scope, String name);
+
+    /**
+     * Return the list of attribute names in the specified scope
+     */
+    Iterable<String> getAttributeNames(Scope scope);
+
+    /**
+     * Set the named attribute in the request scope
+     */
+    <T extends RequestContext>T setAttribute(String name, Object value);
+
+    /**
+     * Set the named attribute in the specified scope. If Session scope is specific, a new session will be created if
+     * one does not already exist
+     */
+    <T extends RequestContext>T setAttribute(Scope scope, String name, Object value);
+
+    /**
+     * Get the InputStream containing the request entity
+     */
+    InputStream getInputStream() throws IOException;
+
+    /**
+     * Get a Reader containing the request entity
+     */
+    Reader getReader() throws IOException;
+    
+    /**
+     * Check to see if the authenticated user is in the specified role
+     */
+    boolean isUserInRole(String role);
+
+    /**
+     * Return the web applications context path
+     */
+    String getContextPath();
+
+    /**
+     * Returns the subset of the request URI that is to be used to resolve the Target (everything after the context
+     * path)
+     */
+    String getTargetPath();
+
+    /**
+     * Returns the subset of the request URI that is the base of the target path (e.g.
+     * HttpServletRequest.getServletPath())
+     * 
+     * @return
+     */
+    String getTargetBasePath();
+
+    /**
+     * Construct a URL using the Provider's Target Builder
+     */
+    String urlFor(Object key, Object param);
+
+    /**
+     * Construct an absolute URL using the Provider's Target Builder. Relative URL's are resolved against the base URI
+     */
+    String absoluteUrlFor(Object key, Object param);
+
+}

Propchange: abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/RequestContext.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/RequestProcessor.java
URL: http://svn.apache.org/viewvc/abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/RequestProcessor.java?rev=1239237&view=auto
==============================================================================
--- abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/RequestProcessor.java (added)
+++ abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/RequestProcessor.java Wed Feb  1 17:54:54 2012
@@ -0,0 +1,139 @@
+/*
+ * 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.protocol;
+
+import org.apache.abdera2.common.misc.ExceptionHelper;
+import org.apache.abdera2.common.misc.MoreFunctions;
+
+import com.google.common.base.Function;
+import com.google.common.base.Predicate;
+
+/**
+ * Request processors implement the actual business logic for handling requests to the Atompub server and producing the
+ * related response.
+ */
+public abstract class RequestProcessor 
+  implements Function<RequestContext,ResponseContext> {
+ 
+  protected final WorkspaceManager workspaceManager;
+  protected final CollectionAdapter adapter;
+  protected final Predicate<RequestContext> predicate;
+  
+  protected RequestProcessor(
+    WorkspaceManager workspaceManager, 
+    CollectionAdapter adapter) {
+    this.workspaceManager = workspaceManager;
+    this.adapter = adapter;
+    this.predicate = null;
+  }
+  
+  protected RequestProcessor(
+      WorkspaceManager workspaceManager, 
+      CollectionAdapter adapter,
+      Predicate<RequestContext> predicate) {
+      this.workspaceManager = workspaceManager;
+      this.adapter = adapter;
+      this.predicate = predicate;
+    }
+  
+  private boolean applies(RequestContext request, Predicate<RequestContext> predicate) {
+    return predicate != null && predicate.apply(request);
+  }
+  
+  protected ResponseContext actuallyApply(RequestContext request) {
+    boolean adapter_ok = applies(request, adapter.acceptable());
+    boolean pred_ok = applies(request, predicate);
+    if (!adapter_ok && !pred_ok) // fail only if both are false
+      return ProviderHelper.notallowed(request);
+    Function<RequestContext,ResponseContext> handler = 
+      adapter.handlerFor(
+        request.getTarget(),
+        request.getMethod());
+    return handler != null ?
+      handler.apply(request) :
+      ProviderHelper.notfound(request);
+  }
+  
+  public ResponseContext apply(RequestContext request) {
+    return actuallyApply(request);
+  }
+
+  public static abstract class RequestProcessorSupplier<T extends RequestProcessor> 
+    implements Function<CollectionAdapter,T> {
+    protected final WorkspaceManager workspaceManager;
+    protected RequestProcessorSupplier(
+      WorkspaceManager workspaceManager) {
+      this.workspaceManager = workspaceManager;
+    }
+  }
+  
+  public static <T extends RequestProcessor>Function<CollectionAdapter,T> forClass(
+      final Class<T> _class, 
+      final WorkspaceManager workspaceManager,
+      final Predicate<RequestContext> predicate) {
+      try {
+        final Function<Object[],T> c =
+          MoreFunctions.<T>createInstance(
+            _class, 
+            WorkspaceManager.class, 
+            CollectionAdapter.class, 
+            Predicate.class);
+        return new RequestProcessorSupplier<T>(workspaceManager) {
+          public T apply(CollectionAdapter adapter) {
+            try {
+              return c.apply(
+                MoreFunctions.array(
+                  workspaceManager,
+                  adapter,
+                  predicate));
+            } catch (Throwable t) {
+              throw ExceptionHelper.propogate(t);
+            }
+          }
+        };
+      } catch (Throwable t) {
+        throw ExceptionHelper.propogate(t);
+      }
+    }
+  
+  public static <T extends RequestProcessor>Function<CollectionAdapter,T> forClass(
+    final Class<T> _class, 
+    final WorkspaceManager workspaceManager) {
+    try {
+      final Function<Object[],T> c =
+        MoreFunctions.<T>createInstance(
+          _class, 
+          WorkspaceManager.class, 
+          CollectionAdapter.class);
+      return new RequestProcessorSupplier<T>(workspaceManager) {
+        public T apply(CollectionAdapter adapter) {
+          try {
+            return c.apply(
+              MoreFunctions.array(
+                workspaceManager,
+                adapter));
+          } catch (Throwable t) {
+            throw ExceptionHelper.propogate(t);
+          }
+        }
+      };
+    } catch (Throwable t) {
+      throw ExceptionHelper.propogate(t);
+    }
+  }
+}

Propchange: abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/RequestProcessor.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/RequestTemplateContext.java
URL: http://svn.apache.org/viewvc/abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/RequestTemplateContext.java?rev=1239237&view=auto
==============================================================================
--- abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/RequestTemplateContext.java (added)
+++ abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/RequestTemplateContext.java Wed Feb  1 17:54:54 2012
@@ -0,0 +1,179 @@
+/*
+ * 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.protocol;
+
+import java.security.Principal;
+import java.util.Iterator;
+import java.util.Locale;
+
+import org.apache.abdera2.common.protocol.RequestContext.Scope;
+import org.apache.abdera2.common.templates.Context;
+import org.apache.abdera2.common.templates.DelegatingContext;
+
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * A Template Context implementation based on a RequestContext object.
+ * this allows a URI Template to be expanded using properties and 
+ * attributes from the RequestContext
+ */
+public class RequestTemplateContext 
+  extends DelegatingContext {
+
+  private static final long serialVersionUID = 4332356546022014897L;
+
+  private final transient RequestContext request;
+
+  public RequestTemplateContext(
+    RequestContext request, 
+    Context subcontext) {
+      super(subcontext);
+      this.request = request;
+  }
+  
+  private String[] split(String val) {
+      if (val.equals(""))
+          return new String[0];
+      String[] segments = val.split("/");
+      return segments.length > 0 ? segments : null;
+  }
+
+  @Override
+  public boolean contains(String var) {
+    if (super.contains(var)) return true;
+    return resolveActual(var) != null;
+  }
+  
+  @Override
+  @SuppressWarnings("unchecked")
+  protected <T> T resolveActual(String var) {
+      Variable variable = Variable.get(var);
+      if (variable == null)
+          return subcontext != null ? (T)subcontext.resolve(var) : null;
+      switch (variable) {
+          case REQUEST_URI:
+              return (T)request.getUri().toString();
+          case REQUEST_RESOLVED_URI:
+              return (T)request.getResolvedUri().toString();
+          case REQUEST_CONTENT_TYPE:
+              return (T)request.getContentType().toString();
+          case REQUEST_CONTEXT_PATH:
+              return (T)split(request.getContextPath());
+          case REQUEST_PARAMETER:
+              String name = Variable.REQUEST_PARAMETER.label(var);
+              return (T)request.getParameter(name);
+          case REQUEST_LANGUAGE:
+              return (T)request.getAcceptLanguage();
+          case REQUEST_CHARSET:
+              return (T)request.getAcceptCharset();
+          case REQUEST_USER:
+              Principal p = request.getPrincipal();
+              return p != null ? (T)p.getName() : null;
+          case SESSION_ATTRIBUTE:
+              name = Variable.SESSION_ATTRIBUTE.label(var);
+              return (T)request.getAttribute(Scope.SESSION, name);
+          case REQUEST_ATTRIBUTE:
+              name = Variable.REQUEST_ATTRIBUTE.label(var);
+              return (T)request.getAttribute(Scope.REQUEST, name);
+          case REQUEST_HEADER:
+              name = Variable.REQUEST_HEADER.label(var);
+              return (T)request.getHeader(name);
+          case TARGET_PARAMETER:
+              name = Variable.TARGET_PARAMETER.label(var);
+              return (T)request.getTarget().getParameter(name);
+          case TARGET_IDENTITY:
+              return (T)request.getTarget().getIdentity();
+          case TARGET_PATH:
+              return (T)split(request.getTargetPath());
+          case TARGET_BASE:
+              return (T)split(request.getTargetBasePath());
+          default:
+              return subcontext != null ? (T)subcontext.resolve(var) : null;
+      }
+  }
+
+  @Override
+  public Iterator<String> iterator() {
+    ImmutableSet.Builder<String> vars = ImmutableSet.builder();
+    vars.addAll(subcontext);
+    for (String var : request.getParameterNames())
+        vars.add(toVar(Variable.REQUEST_PARAMETER, var));
+    for (String var : request.getAttributeNames(Scope.SESSION))
+        vars.add(toVar(Variable.SESSION_ATTRIBUTE, var));
+    for (String var : request.getAttributeNames(Scope.REQUEST))
+        vars.add(toVar(Variable.REQUEST_ATTRIBUTE, var));
+    for (String var : request.getHeaderNames())
+        vars.add(toVar(Variable.REQUEST_HEADER, var));
+    Target target = request.getTarget();
+    for (String var : target.getParameterNames())
+        vars.add(toVar(Variable.TARGET_PARAMETER, var));
+    vars.add(Variable.REQUEST_CONTEXT_PATH.name().toLowerCase());
+    vars.add(Variable.REQUEST_CONTENT_TYPE.name().toLowerCase());
+    vars.add(Variable.REQUEST_URI.name().toLowerCase());
+    vars.add(Variable.REQUEST_RESOLVED_URI.name().toLowerCase());
+    vars.add(Variable.REQUEST_LANGUAGE.name().toLowerCase());
+    vars.add(Variable.REQUEST_CHARSET.name().toLowerCase());
+    vars.add(Variable.REQUEST_USER.name().toLowerCase());
+    vars.add(Variable.TARGET_IDENTITY.name().toLowerCase());
+    vars.add(Variable.TARGET_PATH.name().toLowerCase());
+    vars.add(Variable.TARGET_BASE.name().toLowerCase());
+    return vars.build().iterator();
+  }
+  
+  private static String toVar(Variable variable, String label) {
+    return String.format("%s_%s", variable.name().toLowerCase(), label);
+  }
+
+  public static enum Variable {
+    REQUEST_CONTEXT_PATH, 
+    REQUEST_CONTENT_TYPE, 
+    REQUEST_URI, 
+    REQUEST_RESOLVED_URI, 
+    REQUEST_PARAMETER, 
+    REQUEST_LANGUAGE, 
+    REQUEST_CHARSET, 
+    REQUEST_USER, 
+    SESSION_ATTRIBUTE, 
+    REQUEST_ATTRIBUTE, 
+    REQUEST_HEADER, 
+    TARGET_PARAMETER, 
+    TARGET_IDENTITY, 
+    TARGET_PATH, 
+    TARGET_BASE;
+
+    static Variable get(String var) {
+      if (var == null) return null;
+      var = var.toUpperCase(Locale.US);
+      for (Variable variable : Variable.values())
+        if (var.startsWith(variable.name()))
+          return variable;
+      return null;
+    }
+    
+    boolean match(String var) {
+      if (var == null) return false;
+      var = var.toUpperCase(Locale.US);
+      return var.startsWith(name());
+    }
+
+    String label(String var) {
+        return var.substring(name().length() + 1);
+    }
+  }
+
+}

Propchange: abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/RequestTemplateContext.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/Response.java
URL: http://svn.apache.org/viewvc/abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/Response.java?rev=1239237&view=auto
==============================================================================
--- abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/Response.java (added)
+++ abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/Response.java Wed Feb  1 17:54:54 2012
@@ -0,0 +1,80 @@
+/*
+ * 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.protocol;
+
+import org.apache.abdera2.common.iri.IRI;
+import org.apache.abdera2.common.http.EntityTag;
+import org.apache.abdera2.common.http.ResponseType;
+import org.joda.time.DateTime;
+
+/**
+ * Base interface for an Atompub protocol response message
+ */
+public interface Response extends Message {
+
+    /**
+     * Get the Entity Tag returned by the server
+     */
+    EntityTag getEntityTag();
+
+    /**
+     * Get the response type classification
+     */
+    ResponseType getType();
+
+    /**
+     * Get the specific response status code
+     */
+    int getStatus();
+
+    /**
+     * Get the response status text
+     */
+    String getStatusText();
+
+    /**
+     * Get the value of the Last-Modified response header
+     */
+    DateTime getLastModified();
+
+    /**
+     * Get the value of the Content-Length response header
+     */
+    long getContentLength();
+
+    /**
+     * Get the value of the Allow response header
+     */
+    String getAllow();
+
+    /**
+     * Get the value of the Location response header
+     */
+    IRI getLocation();
+
+    /**
+     * Get the age of this response as specified by the server
+     */
+    long getAge();
+
+    /**
+     * Get the date/time this response expires
+     */
+    DateTime getExpires();
+
+}

Propchange: abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/Response.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/ResponseContext.java
URL: http://svn.apache.org/viewvc/abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/ResponseContext.java?rev=1239237&view=auto
==============================================================================
--- abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/ResponseContext.java (added)
+++ abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/ResponseContext.java Wed Feb  1 17:54:54 2012
@@ -0,0 +1,214 @@
+/*
+ * 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.protocol;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.apache.abdera2.common.text.CharUtils.Profile;
+import org.apache.abdera2.common.http.CacheControl;
+import org.apache.abdera2.common.http.EntityTag;
+import org.apache.abdera2.common.http.Preference;
+import org.apache.abdera2.common.http.WebLink;
+import org.apache.abdera2.common.iri.IRI;
+import org.joda.time.DateTime;
+
+/**
+ * The ResponseContext encapsulates a server response
+ */
+public interface ResponseContext extends Response {
+
+    /**
+     * True if the response contains a binary entity as opposed to a character based entity. Default is false. If true,
+     * the AbderaServlet will pass in the OutputStream for writing out, if false, the AbderaServlet will pass in the
+     * Writer.
+     */
+    boolean isBinary();
+
+    /**
+     * True if the response contains a binary entity as opposed to a character based entity. Default is false. If true,
+     * the AbderaServlet will pass in the OutputStream for writing out, if false, the AbderaServlet will pass in the
+     * Writer.
+     */
+    <B extends ResponseContext>B setBinary(boolean binary);
+
+    /**
+     * True if the response contains an entity
+     */
+    boolean hasEntity();
+
+    /**
+     * Write the response out to the specified OutputStream
+     */
+    void writeTo(OutputStream out) throws IOException;
+
+    /**
+     * Write the response out to the specified Writer
+     */
+    void writeTo(java.io.Writer javaWriter) throws IOException;
+
+    /**
+     * Remove the specified header from the response
+     */
+    <B extends ResponseContext>B removeHeader(String name);
+
+    /**
+     * Set an RFC 2047 encoded header in the response
+     */
+    <B extends ResponseContext>B setEncodedHeader(String name, String charset, String value);
+
+    /**
+     * Set an RFC 2047 encoded header in the response
+     */
+    <B extends ResponseContext>B setEncodedHeader(String name, String charset, String... vals);
+
+    /**
+     * Set a pct-encoded header in the response
+     */
+    <B extends ResponseContext>B setEscapedHeader(String name, Profile profile, String value);
+
+    /**
+     * Set the value of a header in the response
+     */
+    <B extends ResponseContext>B setHeader(String name, Object value);
+
+    /**
+     * Set the value of a header in the response
+     */
+    <B extends ResponseContext>B setHeader(String name, Object... vals);
+
+    /**
+     * Add an RFC 2047 encoded header in the response
+     */
+    <B extends ResponseContext>B addEncodedHeader(String name, String charset, String value);
+
+    /**
+     * Add an RFC 2047 encoded header in the response
+     */
+    <B extends ResponseContext>B addEncodedHeaders(String name, String charset, String... vals);
+
+    /**
+     * Add a header to the response
+     */
+    <B extends ResponseContext>B addHeader(String name, Object value);
+
+    /**
+     * Add a header to the response
+     */
+    <B extends ResponseContext>B addHeaders(String name, Object... vals);
+
+    /**
+     * Set the value of the Age header
+     */
+    <B extends ResponseContext>B setAge(long age);
+
+    /**
+     * Set the value of the Content-Language header
+     */
+    <B extends ResponseContext>B setContentLanguage(String language);
+
+    /**
+     * Set the value of the Content-Length header
+     */
+    <B extends ResponseContext>B setContentLength(long length);
+
+    /**
+     * Set the value of the Content-Location header
+     */
+    <B extends ResponseContext>B setContentLocation(String uri);
+
+    /**
+     * Set the value of the Slug header
+     */
+    <B extends ResponseContext>B setSlug(String slug);
+
+    /**
+     * Set the value of the Content-Type header
+     */
+    <B extends ResponseContext>B setContentType(String type);
+
+    /**
+     * Set the value of the Content-Type header
+     */
+    <B extends ResponseContext>B setContentType(String type, String charset);
+
+    /**
+     * Set the value of the ETag header
+     */
+    <B extends ResponseContext>B setEntityTag(String etag);
+
+    /**
+     * Set the value of the ETag header
+     */
+    <B extends ResponseContext>B setEntityTag(EntityTag etag);
+
+    /**
+     * Set the value of the Expires header
+     */
+    <B extends ResponseContext>B setExpires(DateTime date);
+
+    /**
+     * Set the value of the Last-Modified header
+     */
+    <B extends ResponseContext>B setLastModified(DateTime date);
+
+    /**
+     * Set the value of the Location header
+     */
+    <B extends ResponseContext>B setLocation(String uri);
+
+    /**
+     * Set the value of the Location header
+     */
+    <B extends ResponseContext>B setLocation(IRI iri);
+    
+    /**
+     * Set the response status code
+     */
+    <B extends ResponseContext>B setStatus(int status);
+
+    /**
+     * Set the response status text
+     */
+    <B extends ResponseContext>B setStatusText(String text);
+
+    /**
+     * Specify the HTTP methods allowed
+     */
+    <B extends ResponseContext>B setAllow(String method);
+
+    /**
+     * Specify the HTTP methods allowed
+     */
+    <B extends ResponseContext>B setAllow(String... methods);
+    
+    /**
+     * Specify the CacheControl header
+     */
+    <B extends ResponseContext>B setCacheControl(CacheControl cc);
+    
+    /**
+     * Specify the CacheControl header
+     */
+    <B extends ResponseContext>B setCacheControl(String cc);
+
+    <B extends ResponseContext>B setWebLinks(WebLink link, WebLink... links);
+    
+    <B extends ResponseContext>B setPrefer(Preference pref, Preference... prefs);
+
+}

Propchange: abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/ResponseContext.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/ResponseContextException.java
URL: http://svn.apache.org/viewvc/abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/ResponseContextException.java?rev=1239237&view=auto
==============================================================================
--- abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/ResponseContextException.java (added)
+++ abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/ResponseContextException.java Wed Feb  1 17:54:54 2012
@@ -0,0 +1,69 @@
+/*
+ * 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.protocol;
+
+import org.apache.abdera2.common.http.ResponseType;
+
+
+public class ResponseContextException extends RuntimeException {
+
+    private static final long serialVersionUID = -3031651143835987024L;
+
+    private ResponseContext responseContext;
+
+    public ResponseContextException(ResponseContext responseContext, Throwable t) {
+        super(t);
+        this.responseContext = responseContext;
+    }
+
+    public ResponseContextException(ResponseContext responseContext) {
+        super();
+        this.responseContext = responseContext;
+    }
+
+    public ResponseContextException(int responseCode) {
+        this(new EmptyResponseContext(responseCode));
+    }
+
+    public ResponseContextException(int responseCode, Throwable t) {
+        this(new EmptyResponseContext(responseCode), t);
+    }
+
+    public ResponseContextException(String msg, int responseCode) {
+        this.responseContext = new EmptyResponseContext(responseCode);
+        this.responseContext.setStatusText(msg);
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T extends ResponseContext>T getResponseContext() {
+        return (T)responseContext;
+    }
+
+    @Override
+    public String getMessage() {
+        return responseContext.getStatusText();
+    }
+
+    public int getStatusCode() {
+        return responseContext.getStatus();
+    }
+    
+    public ResponseType getResponseType() {
+      return ResponseType.select(getStatusCode());
+    }
+}

Propchange: abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/ResponseContextException.java
------------------------------------------------------------------------------
    svn:executable = *

Propchange: abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/ResponseContextException.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/RouteManager.java
URL: http://svn.apache.org/viewvc/abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/RouteManager.java?rev=1239237&view=auto
==============================================================================
--- abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/RouteManager.java (added)
+++ abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/RouteManager.java Wed Feb  1 17:54:54 2012
@@ -0,0 +1,301 @@
+/*
+ * 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.protocol;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.abdera2.common.templates.CachingContext;
+import org.apache.abdera2.common.templates.Context;
+import org.apache.abdera2.common.templates.MapContext;
+import org.apache.abdera2.common.templates.ObjectContext;
+import org.apache.abdera2.common.templates.Route;
+
+import com.google.common.base.Function;
+import com.google.common.base.Supplier;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * This is a largely experimental implementation of a Target Resolver and Target Builder based on URL patterns similar
+ * (but not identical) to Ruby on Rails style routes. For instance:
+ * 
+ * <pre>
+ * RouteManager rm =
+ *     new RouteManager().addRoute(&quot;entry&quot;, &quot;:collection/:entry&quot;, TargetType.TYPE_ENTRY)
+ *         .addRoute(&quot;feed&quot;, &quot;:collection&quot;, TargetType.TYPE_COLLECTION);
+ * </pre>
+ * 
+ * The RouteManager can be used by Provider implementations as the target resolver and target builder
+ */
+public class RouteManager<T,X extends RequestContext,R> 
+  implements Function<X,Target>, 
+             TargetBuilder<R> {
+
+    public static <T,X extends RequestContext,R>Generator<T,X,R> make() {
+      return new Generator<T,X,R>();
+    }
+  
+    public static class Generator<T, X extends RequestContext,R> 
+      implements Supplier<RouteManager<T,X,R>> {
+
+      protected final ImmutableList.Builder<RouteTargetType<R>> targets = 
+        ImmutableList.builder();
+      protected final ImmutableMap.Builder<R, Route<R>> routes = 
+        ImmutableMap.builder();
+      protected final ImmutableMap.Builder<Route<R>, CollectionAdapter> route2CA = 
+        ImmutableMap.builder();
+      public Generator<T,X,R> withAll(RouteManager<T,X,R> other) {
+        this.targets.addAll(other.targets);
+        this.routes.putAll(other.routes);
+        this.route2CA.putAll(other.route2CA);
+        return this;
+      }
+      public Generator<T,X,R> with(Route<R>... routes) {
+        for (Route<R> route : routes)
+          with(route, null);
+        return this;
+      }
+      public Generator<T,X,R> with(R key, String pattern) {
+        return with(key, pattern, null);
+      }
+      public Generator<T,X,R> with(
+        Route<R> route, 
+        TargetType type) {
+        routes.put(route.getKey(), route);
+        if (type != null)
+          targets.add(new RouteTargetType<R>(route, type));
+        return this;
+      }
+      public Generator<T,X,R> with(
+        R key, 
+        String pattern, 
+        TargetType type) {
+        return with(new Route<R>(key, pattern), type);
+      }
+      public Generator<T,X,R> with(
+        R key, 
+        String pattern, 
+        TargetType type, 
+        CollectionAdapter collectionAdapter) {
+        Route<R> route = new Route<R>(key, pattern);
+        route2CA.put(route, collectionAdapter);
+        return with(route, type);
+      }
+      public RouteManager<T, X, R> get() {
+        return new RouteManager<T,X,R>(this);
+      }
+    }
+  
+    protected static class RouteTargetType<T> {
+      protected Route<T> route;
+      protected TargetType targetType;
+      RouteTargetType(Route<T> route, TargetType targetType) {
+        this.route = route;
+        this.targetType = targetType;
+      }
+      public Route<T> getRoute() {
+        return route;
+      }
+      public TargetType getTargetType() {
+        return targetType;
+      }
+    }
+
+    protected final List<RouteTargetType<R>> targets;
+    protected final Map<R, Route<R>> routes;
+    protected final Map<Route<R>, CollectionAdapter> route2CA;;
+
+    RouteManager(Generator<T,X,R> gen) {
+      this.targets = gen.targets.build();
+      this.routes = gen.routes.build();
+      this.route2CA = gen.route2CA.build();
+    }
+    
+    public Target apply(X request) {
+      String uri = request.getTargetPath();
+      int idx = uri.indexOf('?');
+      if (idx != -1) {
+          uri = uri.substring(0, idx);
+      }
+
+      RouteTargetType<R> target = get(uri);
+      if (target == null) {
+          target = match(uri);
+      }
+
+      if (target != null) {
+          return getTarget(request, target, uri);
+      }
+
+      return null;
+    }
+
+    private RouteTargetType<R> get(String uri) {
+      for (RouteTargetType<R> target : targets) {
+        if (target.route.getPattern().equals(uri)) {
+          return target;
+        }
+      }
+      return null;
+    }
+
+    private RouteTargetType<R> match(String uri) {
+      for (RouteTargetType<R> target : targets) {
+        if (target.route.match(uri)) {
+          return target;
+        }
+      }
+      return null;
+    }
+
+    private Target getTarget(RequestContext context, RouteTargetType<R> target, String uri) {
+        CollectionAdapter ca = route2CA.get(target.route);
+        if (ca != null) {
+            context.setAttribute(AbstractWorkspaceManager.COLLECTION_ADAPTER_ATTRIBUTE, ca);
+        }
+        return getTarget(context, target.route, uri, target.targetType);
+    }
+
+    private Target getTarget(RequestContext context, Route<R> route, String uri, TargetType type) {
+        return new RouteTarget(type, context, route, uri);
+    }
+
+    public String urlFor(Request context, R key, Object param) {
+        RequestContext rc = (RequestContext) context;
+        Route<R> route = routes.get(key);
+        return route != null ? rc.getContextPath() + route.expand(getContext(param)) : null;
+    }
+
+    private Context getContext(Object param) {
+        Context context = new EmptyContext();
+        if (param != null) {
+            if (param instanceof Map) {
+                context = new MapContext(cleanMapCtx(param), true);
+            } else if (param instanceof Context) {
+                context = (Context)param;
+            } else {
+                context = new ObjectContext(param, true);
+            }
+        }
+        return context;
+    }
+
+    @SuppressWarnings("unchecked")
+    private Map<String, Object> cleanMapCtx(Object param) {
+        Map<String, Object> map = new HashMap<String, Object>();
+        for (Map.Entry<String, Object> entry : ((Map<String, Object>)param).entrySet()) {
+            map.put(entry.getKey().replaceFirst("^:", ""), entry.getValue());
+        }
+        ((Map<String, Object>)param).clear();
+        ((Map<String, Object>)param).putAll(map);
+        return (Map<String, Object>)param;
+    }
+
+    private static class EmptyContext 
+      extends CachingContext {
+      private static final long serialVersionUID = 4681906592987534451L;
+      public EmptyContext() {
+        super(false);
+      }
+      public boolean contains(String var) {
+        return false;
+      }  
+      protected <T> T resolveActual(String var) {
+        return null;
+      }
+      public Iterator<String> iterator() {
+        return ImmutableSet.<String>of().iterator();
+      }
+    }
+
+    public static class RouteTarget extends SimpleTarget {
+        private final Map<String, String> params;
+        private final Route<?> route;
+
+        public RouteTarget(
+          TargetType type, 
+          RequestContext context, 
+          Route<?> route, String uri) {
+            super(type, context);
+            this.route = route;
+            this.params = route.parse(uri);
+        }
+
+        public Route<?> getRoute() {
+            return route;
+        }
+
+        @SuppressWarnings("unchecked")
+        @Override
+        public <T> T getMatcher() {
+            return (T)getRoute();
+        }
+
+        public String getParameter(String name) {
+            return params.containsKey(name) ? params.get(name) : super.getParameter(name);
+        }
+
+        public Iterable<String> getParameterNames() {
+            Iterable<String> ns = super.getParameterNames();
+            Set<String> names = new HashSet<String>();
+            for (String name : ns)
+              names.add(name);
+            for (String name : params.keySet())
+                names.add(name);
+            return names;
+        }
+
+        @Override
+        public int hashCode() {
+          final int prime = 31;
+          int result = super.hashCode();
+          result = prime * result + ((params == null) ? 0 : params.hashCode());
+          result = prime * result + ((route == null) ? 0 : route.hashCode());
+          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;
+          RouteTarget other = (RouteTarget) obj;
+          if (params == null) {
+            if (other.params != null)
+              return false;
+          } else if (!params.equals(other.params))
+            return false;
+          if (route == null) {
+            if (other.route != null)
+              return false;
+          } else if (!route.equals(other.route))
+            return false;
+          return true;
+        }
+       
+    }
+}

Propchange: abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/RouteManager.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/ServiceManager.java
URL: http://svn.apache.org/viewvc/abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/ServiceManager.java?rev=1239237&view=auto
==============================================================================
--- abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/ServiceManager.java (added)
+++ abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/ServiceManager.java Wed Feb  1 17:54:54 2012
@@ -0,0 +1,55 @@
+/*
+ * 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.protocol;
+
+import java.util.Map;
+
+import org.apache.abdera2.common.Discover;
+import org.apache.abdera2.common.anno.DefaultImplementation;
+import org.apache.abdera2.common.protocol.servlet.async.ProcessorQueue;
+import org.apache.abdera2.common.protocol.servlet.async.TaskExecutor;
+import org.apache.abdera2.common.pusher.ChannelManager;
+
+@DefaultImplementation("org.apache.abdera2.protocol.server.AtompubServiceManager")
+public interface ServiceManager {
+  
+  public abstract <P extends Provider>P newProvider(
+    Map<String, Object> properties);
+
+  public abstract ProcessorQueue newProcessorQueue(
+    Map<String, Object> properties);
+
+  public abstract TaskExecutor newTaskExecutor(
+    Map<String, Object> properties);
+
+  public abstract ChannelManager newChannelManager(
+      Map<String, Object> properties);
+
+  public static class Factory {
+    
+    public static ServiceManager getInstance() {
+      return getInstance(
+        "org.apache.abdera2.protocol.server.AtompubServiceManager");
+    }
+  
+    public static ServiceManager getInstance(String impl) {
+      return Discover.locate(ServiceManager.class, impl);
+    }
+    
+  }
+}
\ No newline at end of file

Propchange: abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/ServiceManager.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/SimpleResponseContext.java
URL: http://svn.apache.org/viewvc/abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/SimpleResponseContext.java?rev=1239237&view=auto
==============================================================================
--- abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/SimpleResponseContext.java (added)
+++ abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/SimpleResponseContext.java Wed Feb  1 17:54:54 2012
@@ -0,0 +1,69 @@
+/*
+ * 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.protocol;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+
+
+/**
+ * A simple base implementation of AbstractResponseContext that makes it a bit easier to create custom ResponseContext
+ * implementations e.g. new SimpleResponseContext() { public boolean hasEntity() { return true; } public void
+ * writeEntity(Writer writer) { ... } }
+ */
+public abstract class SimpleResponseContext extends AbstractResponseContext {
+
+    protected String encoding = "UTF-8";
+
+    protected SimpleResponseContext() {
+        this(null);
+    }
+
+    protected SimpleResponseContext(String encoding) {
+        if (encoding != null) {
+            this.encoding = encoding;
+        }
+    }
+
+    protected SimpleResponseContext setEncoding(String encoding) {
+        this.encoding = encoding;
+        return this;
+    }
+
+    protected String getEncoding() {
+        return this.encoding;
+    }
+
+    public void writeTo(OutputStream out) throws IOException {
+        if (hasEntity()) {
+            OutputStreamWriter writer = new OutputStreamWriter(out, encoding);
+            writeTo(writer);
+            writer.flush();
+        }
+    }
+
+    public void writeTo(Writer writer) throws IOException {
+        if (hasEntity())
+            writeEntity(writer);
+    }
+
+    protected abstract void writeEntity(Writer writer) throws IOException;
+
+}

Propchange: abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/SimpleResponseContext.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/SimpleSubjectResolver.java
URL: http://svn.apache.org/viewvc/abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/SimpleSubjectResolver.java?rev=1239237&view=auto
==============================================================================
--- abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/SimpleSubjectResolver.java (added)
+++ abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/SimpleSubjectResolver.java Wed Feb  1 17:54:54 2012
@@ -0,0 +1,120 @@
+/*
+ * 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.protocol;
+
+import java.io.Serializable;
+import java.security.Principal;
+
+import javax.security.auth.Subject;
+
+import org.apache.abdera2.common.misc.MoreFunctions;
+
+import com.google.common.base.Function;
+
+/**
+ * The default subject resolver implementation
+ */
+public class SimpleSubjectResolver 
+  implements Function<Request,Subject> {
+
+    public static final Principal ANONYMOUS = 
+      new AnonymousPrincipal();
+
+    public Subject apply(Request request) {
+        RequestContext context = (RequestContext)request;
+        return apply(context.getPrincipal());
+    }
+
+    public Subject apply(Principal principal) {
+        Subject subject = new Subject();
+        subject.getPrincipals().add((principal != null) ? principal : ANONYMOUS);
+        return subject;
+    }
+
+    public Subject apply(String userid) {
+        if (userid == null)
+            return apply(ANONYMOUS);
+        return apply(new SimplePrincipal(userid));
+    }
+
+    static class SimplePrincipal implements Principal, Serializable {
+        private static final long serialVersionUID = 7161420960293729670L;
+        final String name;
+
+        SimplePrincipal(String name) {
+            this.name = name;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public String toString() {
+            return name;
+        }
+
+        @Override
+        public int hashCode() {
+          return MoreFunctions.genHashCode(1, name);
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj)
+                return true;
+            if (obj == null)
+                return false;
+            if (getClass() != obj.getClass())
+                return false;
+            final SimplePrincipal other = (SimplePrincipal)obj;
+            if (name == null) {
+                if (other.name != null)
+                    return false;
+            } else if (!name.equals(other.name))
+                return false;
+            return true;
+        }
+
+    }
+
+    final static String name = "Anonymous";
+    public static final class AnonymousPrincipal 
+      implements Principal, Serializable {
+        private static final long serialVersionUID = -5050930075733261944L;
+        public String getName() {
+          return name;
+        }
+        public String toString() {
+          return name;
+        }
+        public int hashCode() {
+          return MoreFunctions.genHashCode(1, name);
+        }
+        @Override
+        public boolean equals(Object obj) {
+          if (this == obj)
+            return true;
+          if (obj == null)
+            return false;
+          if (getClass() != obj.getClass())
+            return false;
+          return true;
+        }
+        
+    }
+}

Propchange: abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/SimpleSubjectResolver.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/SimpleTarget.java
URL: http://svn.apache.org/viewvc/abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/SimpleTarget.java?rev=1239237&view=auto
==============================================================================
--- abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/SimpleTarget.java (added)
+++ abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/SimpleTarget.java Wed Feb  1 17:54:54 2012
@@ -0,0 +1,97 @@
+/*
+ * 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.protocol;
+
+import java.util.Iterator;
+
+import org.apache.abdera2.common.misc.MoreFunctions;
+
+
+
+@SuppressWarnings("unchecked")
+public class SimpleTarget
+  implements Target {
+
+    protected final TargetType type;
+    protected final RequestContext context;
+
+    public SimpleTarget(TargetType type, RequestContext context) {
+        this.type = type;
+        this.context = context;
+    }
+
+    public String getIdentity() {
+        return context.getUri().toString();
+    }
+
+    public String getParameter(String name) {
+        return context.getParameter(name);
+    }
+
+    public Iterable<String> getParameterNames() {
+        return context.getParameterNames();
+    }
+
+    public Iterator<String> iterator() {
+        return getParameterNames().iterator();
+    }
+
+    public TargetType getType() {
+        return type;
+    }
+
+    public <T extends RequestContext>T getRequestContext() {
+        return (T)context;
+    }
+
+    public String toString() {
+        return String.format("%s - %s",getType(),getIdentity());
+    }
+
+    public <T> T getMatcher() {
+        return (T)null;
+    }
+
+    @Override
+    public int hashCode() {
+      return MoreFunctions.genHashCode(1, context, type);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        final SimpleTarget other = (SimpleTarget)obj;
+        if (context == null) {
+            if (other.context != null)
+                return false;
+        } else if (!context.equals(other.context))
+            return false;
+        if (type == null) {
+            if (other.type != null)
+                return false;
+        } else if (!type.equals(other.type))
+            return false;
+        return true;
+    }
+
+}

Propchange: abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/SimpleTarget.java
------------------------------------------------------------------------------
    svn:executable = *

Propchange: abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/SimpleTarget.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/Target.java
URL: http://svn.apache.org/viewvc/abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/Target.java?rev=1239237&view=auto
==============================================================================
--- abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/Target.java (added)
+++ abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/Target.java Wed Feb  1 17:54:54 2012
@@ -0,0 +1,61 @@
+/*
+ * 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.protocol;
+
+import com.google.common.base.Predicate;
+
+/**
+ * Identifies the target of the request.
+ */
+public interface Target extends Iterable<String> {
+
+    /**
+     * Return the resolved Target Type
+     */
+    TargetType getType();
+
+    /**
+     * Return the identity of this target. Usually this will just be the request URI
+     */
+    String getIdentity();
+
+    /**
+     * Return the named target parameter
+     */
+    String getParameter(String name);
+
+    /**
+     * Return a listing of all parameter names
+     */
+    Iterable<String> getParameterNames();
+
+    /**
+     * Return the object that matches with the uri
+     * 
+     * @return
+     */
+    public <T> T getMatcher();
+
+    public static final Predicate<Target> NOT_FOUND = 
+      new Predicate<Target>() {
+        public boolean apply(Target input) {
+          return input == null || 
+                 input.getType() == TargetType.TYPE_NOT_FOUND;
+        }
+    };
+}

Propchange: abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/Target.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/TargetBuilder.java
URL: http://svn.apache.org/viewvc/abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/TargetBuilder.java?rev=1239237&view=auto
==============================================================================
--- abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/TargetBuilder.java (added)
+++ abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/TargetBuilder.java Wed Feb  1 17:54:54 2012
@@ -0,0 +1,31 @@
+/*
+ * 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.protocol;
+
+/**
+ * The TargetBuilder component is responsible for constructing appropriate IRIs/URIs for various kinds of targets based
+ * on specified input parameters. The input params are specific to the Target Manager implementation.
+ */
+public interface TargetBuilder<T> {
+
+    /**
+     * Construct a URL for the specified key
+     */
+    String urlFor(Request context, T key, Object param);
+
+}

Propchange: abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/TargetBuilder.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/TargetFunctionResolver.java
URL: http://svn.apache.org/viewvc/abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/TargetFunctionResolver.java?rev=1239237&view=auto
==============================================================================
--- abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/TargetFunctionResolver.java (added)
+++ abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/TargetFunctionResolver.java Wed Feb  1 17:54:54 2012
@@ -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.protocol;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.abdera2.common.iri.IRI;
+import org.apache.abdera2.common.misc.ExceptionHelper;
+import org.apache.abdera2.common.misc.MoreFunctions;
+
+import com.google.common.base.Function;
+import com.google.common.base.Predicate;
+import com.google.common.base.Supplier;
+import com.google.common.collect.Iterables;
+
+/**
+ * A TargetResolver based on a Set of Function objects. Each 
+ * Function is attempted in the order it is added to the 
+ * resolver. If the Function returns a Target, execution 
+ * stops and the target is returned, otherwise the next 
+ * function in the list is tried
+ */
+public class TargetFunctionResolver<R extends RequestContext>
+  implements Function<R,Target> {
+
+  public static <R extends RequestContext>TargetFunctionResolver<R> create(
+    TargetFunction<R>... functions) {
+      return create(Arrays.asList(functions));
+  }
+  
+  public static <R extends RequestContext>TargetFunctionResolver<R> create( 
+    Iterable<TargetFunction<R>> functions) {
+      return new TargetFunctionResolver<R>(functions);
+  }
+  
+  protected final Set<TargetFunction<R>> functions = 
+    new LinkedHashSet<TargetFunction<R>>();
+
+  private TargetFunctionResolver(
+    Iterable<TargetFunction<R>> functions) {
+      Iterables.addAll(this.functions, functions);
+  }
+
+  public TargetFunctionResolver<R> addFunction(
+    TargetFunction<R> function) {
+      this.functions.add(function);
+      return this;
+  }
+
+  public Target apply(R request) {
+    for (TargetFunction<R> f : functions) {
+      Target target = f.apply(request);
+      if (target != null)
+        return target;
+    }
+    return null;
+  }
+
+  @Override
+  public int hashCode() {
+    return MoreFunctions.genHashCode(1, functions);
+  }
+
+  @Override
+  public boolean equals(Object obj) {
+    if (this == obj)
+      return true;
+    if (obj == null)
+      return false;
+    if (getClass() != obj.getClass())
+      return false;
+    TargetFunctionResolver<?> other = 
+      (TargetFunctionResolver<?>) obj;
+    if (functions == null) {
+      if (other.functions != null)
+        return false;
+    } else if (!functions.equals(other.functions))
+      return false;
+    return true;
+  }
+
+  /**
+   * A Function that Resolves a Target from a RequestContext
+   */
+  public static abstract class TargetFunction<R extends RequestContext>
+    implements Function<R,Target> {
+        
+  }
+ 
+  /**
+   * Returns a Generator used to build PredicateTargetfunction instances
+   */
+  public static <R extends RequestContext>PredicateTargetFunction.Generator<R> make() {
+    return new PredicateTargetFunction.Generator<R>();
+  }
+  
+  /**
+   * A TargetFunction that is based on a map of Predicates and Functions.
+   * The RequestContext is tested against each Predicate in the order the
+   * Predicate was added. If apply() returns true, the associated Function
+   * is used to return the appropriate Target instance.
+   */
+  public static class PredicateTargetFunction<R extends RequestContext>
+    extends TargetFunction<R> {    
+    public static class Generator<R extends RequestContext> implements Supplier<TargetFunction<R>> {
+      private final Map<Predicate<R>,Function<R,Target>> map =
+        new LinkedHashMap<Predicate<R>,Function<R,Target>>();
+      public Generator<R> set(Predicate<R> test, Function<R,Target> function) {
+        map.put(test,function);
+        return this;
+      }
+      public TargetFunction<R> get() {
+        return new PredicateTargetFunction<R>(map);
+      }
+    }
+    
+    private final Map<Predicate<R>,Function<R,Target>> map =
+      new HashMap<Predicate<R>,Function<R,Target>>();
+    
+    protected PredicateTargetFunction(
+      Map<Predicate<R>,Function<R,Target>> map) {
+        this.map.putAll(map);
+    }
+    
+    public Target apply(R input) { 
+      try {
+        for (Predicate<R> test : map.keySet())
+          if (test.apply(input))
+            return map.get(test).apply(input);
+        return null;
+      } catch (Throwable t) {
+        throw ExceptionHelper.propogate(t);
+      }
+    }
+  }
+  
+  /**
+   * A TargetFunction that resolves Targets based primarily off the 
+   * Request URI
+   */
+  public static abstract class RequestUriFunction<R extends RequestContext>
+    extends TargetFunction<R>
+    implements Function<R,Target> {
+    public Target apply(R input) {
+      return apply(input,input.getResolvedUri());
+    }
+    protected abstract Target apply(R context,IRI uri);
+  }
+  
+  /**
+   * A Predicate that tests the Request URI
+   */
+  public static abstract class RequestUriPredicate<R extends RequestContext> 
+    implements Predicate<R> {
+    public boolean apply(R input) {
+      return apply(input.getResolvedUri());
+    }
+    protected abstract boolean apply(IRI uri);
+  }
+  
+  /**
+   * A TargetFunction that performs a Regex Pattern match on the 
+   * Request URI. If the Pattern matches, a RegexTarget instance
+   * is returned. This Function can be used either directly by 
+   * the TargetFunctionResolver or as part of the PredicateTargetFunction
+   */
+  public static class RegexUriFunction<R extends RequestContext>
+    extends RequestUriFunction<R> {
+    private final Pattern pattern;
+    private final TargetType type;
+    private final Iterable<String> fields;
+    public RegexUriFunction(TargetType type, Pattern pattern, String... fields) {
+      this.type = type;
+      this.pattern = pattern;
+      this.fields = Arrays.<String>asList(fields);
+    }
+    public RegexUriFunction(TargetType type, String pattern, String... fields) {
+      this(type,Pattern.compile(pattern),fields);
+    }
+    protected Target apply(R context,IRI uri) {
+      Matcher matcher = pattern.matcher(uri.toString());
+      return matcher.matches() ?
+        new RegexTargetResolver.RegexTarget(type,context,matcher,fields) : 
+        null;
+    }  
+  }
+  
+  /**
+   * Predicate that tests the Request URI against a Regex Pattern
+   */
+  public static class RegexUriPredicate<R extends RequestContext> 
+    extends RequestUriPredicate<R> {
+    private final Pattern pattern;
+    public RegexUriPredicate(Pattern pattern) {
+      this.pattern = pattern;
+    }
+    public RegexUriPredicate(String pattern) {
+      this(Pattern.compile(pattern));
+    }
+    protected boolean apply(IRI uri) {
+      return pattern.matcher(uri.toString()).matches();
+    }
+  }
+  
+  public static <R extends RequestContext>Function<R,Target> functionForRegex(Pattern pattern, TargetType type, String... fields) {
+    return new RegexUriFunction<R>(type,pattern,fields);
+  }
+  
+  public static <R extends RequestContext>Function<R,Target> functionForRegex(String pattern, TargetType type, String... fields) {
+    return new RegexUriFunction<R>(type,pattern,fields);
+  }
+  
+  public static <R extends RequestContext>Predicate<R> predicateForRegex(Pattern pattern) {
+    return new RegexUriPredicate<R>(pattern);
+  }
+  
+  public static <R extends RequestContext>Predicate<R> predicateForRegex(String pattern) {
+    return new RegexUriPredicate<R>(pattern);
+  }
+}

Propchange: abdera/abdera2-server/server/src/main/java/org/apache/abdera2/common/protocol/TargetFunctionResolver.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain



Mime
View raw message