cxf-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From serg...@apache.org
Subject svn commit: r738937 - in /cxf/trunk: rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/ rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/interceptor/ rt/frontend/jaxrs/src/main/java/org/...
Date Thu, 29 Jan 2009 17:45:44 GMT
Author: sergeyb
Date: Thu Jan 29 17:45:43 2009
New Revision: 738937

URL: http://svn.apache.org/viewvc?rev=738937&view=rev
Log:
CXF-1991: applying a 2nd quality patch on behalf of Andrzej Michalec plus fix for UriInfo.getMatchedURIs and ExceptionMapper injection issue  

Modified:
    cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/JAXRSInvoker.java
    cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/MetadataMap.java
    cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/UriBuilderImpl.java
    cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/UriInfoImpl.java
    cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/interceptor/JAXRSInInterceptor.java
    cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/model/MethodInvocationInfo.java
    cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/model/URITemplate.java
    cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/JAXRSUtils.java
    cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/impl/UriBuilderImplTest.java
    cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/model/URITemplateTest.java
    cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSClientServerBookTest.java

Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/JAXRSInvoker.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/JAXRSInvoker.java?rev=738937&r1=738936&r2=738937&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/JAXRSInvoker.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/JAXRSInvoker.java Thu Jan 29 17:45:43 2009
@@ -22,7 +22,9 @@
 
 import java.lang.reflect.Method;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
+import java.util.Map;
 import java.util.ResourceBundle;
 import java.util.logging.Logger;
 
@@ -116,7 +118,9 @@
         try {
             result = invoke(exchange, resourceObject, methodToInvoke, params);
         } catch (Fault ex) {
-            Response excResponse = JAXRSUtils.convertFaultToResponse(ex.getCause(), baseAddress);
+            Response excResponse = JAXRSUtils.convertFaultToResponse(ex.getCause(), 
+                                                                     baseAddress,
+                                                                     exchange.getInMessage());
             if (excResponse == null) {
                 ProviderFactory.getInstance(baseAddress).clearThreadLocalProxies();
                 ClassResourceInfo criRoot =
@@ -180,7 +184,9 @@
 
                 return this.invoke(exchange, newParams, newResourceObjects);
             } catch (WebApplicationException ex) {
-                Response excResponse = JAXRSUtils.convertFaultToResponse(ex, baseAddress);
+                Response excResponse = JAXRSUtils.convertFaultToResponse(ex, 
+                                                                         baseAddress,
+                                                                         exchange.getInMessage());
                 return new MessageContentsList(excResponse);
             }
         }
@@ -236,12 +242,29 @@
         return result;
     }
 
+    @SuppressWarnings("unchecked")
     private void pushOntoStack(OperationResourceInfo ori, Class<?> realClass, Message msg) {
         OperationResourceInfoStack stack = msg.get(OperationResourceInfoStack.class);
         if (stack == null) {
             stack = new OperationResourceInfoStack();
             msg.put(OperationResourceInfoStack.class, stack);
         }
-        stack.push(new MethodInvocationInfo(ori, realClass));
+        
+        
+        MultivaluedMap<String, String> params = 
+            (MultivaluedMap)msg.get(URITemplate.TEMPLATE_PARAMETERS);
+        List<String> values = null;
+        if (params == null || params.size() == 1) {
+            values = Collections.emptyList();
+        } else {
+            values = new ArrayList<String>(params.size() - 1);
+            // if we have {bar}/{foo}/{bar} then we have a problem
+            for (Map.Entry<String, List<String>> entry : params.entrySet()) {
+                if (!entry.getKey().equals(URITemplate.FINAL_MATCH_GROUP)) {
+                    values.addAll(entry.getValue());
+                }
+            }
+        }
+        stack.push(new MethodInvocationInfo(ori, realClass, values));
     }
 }

Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/MetadataMap.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/MetadataMap.java?rev=738937&r1=738936&r2=738937&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/MetadataMap.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/MetadataMap.java Thu Jan 29 17:45:43 2009
@@ -21,7 +21,7 @@
 
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.HashMap;
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -33,7 +33,7 @@
     private Map<K, List<V>> m;
     
     public MetadataMap() {
-        this(new HashMap<K, List<V>>());
+        this(new LinkedHashMap<K, List<V>>());
     }
     
     public MetadataMap(Map<K, List<V>> store) {

Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/UriBuilderImpl.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/UriBuilderImpl.java?rev=738937&r1=738936&r2=738937&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/UriBuilderImpl.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/UriBuilderImpl.java Thu Jan 29 17:45:43 2009
@@ -24,9 +24,15 @@
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Iterator;
+import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 import javax.ws.rs.Path;
 import javax.ws.rs.core.MultivaluedMap;
@@ -34,10 +40,13 @@
 import javax.ws.rs.core.UriBuilder;
 import javax.ws.rs.core.UriBuilderException;
 
+import org.apache.cxf.jaxrs.model.URITemplate;
 import org.apache.cxf.jaxrs.utils.JAXRSUtils;
 
 public class UriBuilderImpl extends UriBuilder {
 
+    private static final Pattern DECODE_PATTERN = Pattern.compile("%[0-9a-fA-F][0-9a-fA-F]");
+
     private String scheme;
     private String userInfo;
     private int port;
@@ -46,22 +55,96 @@
     private String fragment;
     private MultivaluedMap<String, String> query = new MetadataMap<String, String>();
 
+    /**
+     * Creates builder with empty URI.
+     */
     public UriBuilderImpl() {
     }
 
-    public UriBuilderImpl(URI uri) {
+    /**
+     * Creates builder initialized with given URI.
+     * 
+     * @param uri initial value for builder
+     * @throws IllegalArgumentException when uri is null
+     */
+    public UriBuilderImpl(URI uri) throws IllegalArgumentException {
         setUriParts(uri);
     }
 
     @Override
     public URI build(Object... values) throws IllegalArgumentException, UriBuilderException {
         try {
-            return new URI(scheme, userInfo, host, port, buildPath(), buildQuery(), fragment);
+            String path = buildPath();
+            path = substituteVarargs(path, values);
+            return new URI(scheme, userInfo, host, port, path, buildQuery(), fragment);
+        } catch (URISyntaxException ex) {
+            throw new UriBuilderException("URI can not be built", ex);
+        }
+    }
+
+    private String substituteVarargs(String path, Object... values) {
+        Map<String, String> varValueMap = new HashMap<String, String>();
+        URITemplate templ = new URITemplate(path);
+        // vars in set are properly ordered due to linking in hash set
+        Set<String> uniqueVars = new LinkedHashSet<String>(templ.getVariables());
+        if (values.length < uniqueVars.size()) {
+            throw new IllegalArgumentException("Unresolved variables; only " + values.length
+                                               + " value(s) given for " + uniqueVars.size()
+                                               + " unique variable(s)");
+        }
+        int idx = 0;
+        for (String var : uniqueVars) {
+            Object oval = values[idx++];
+            varValueMap.put(var, oval.toString());
+        }
+        return templ.substitute(varValueMap);
+    }
+
+    @Override
+    public URI buildFromEncoded(Object... values) throws IllegalArgumentException, UriBuilderException {
+        // Problem: multi-arg URI c-tor always forces encoding, operation contract would be broken;
+        // use os single-arg URI c-tor requires unnecessary concatenate-parse roundtrip.
+        // Solution: decode back given values and pass as non-decoded to regular build() method
+        for (int i = 0; i < values.length; i++) {
+            values[i] = decodePartiallyEncoded(values[i].toString());
+        }
+        return build(values);
+    }
+
+    @Override
+    public URI buildFromMap(Map<String, ? extends Object> map) throws IllegalArgumentException,
+        UriBuilderException {
+        try {
+            String path = buildPath();
+            path = substituteMapped(path, map);
+            return new URI(scheme, userInfo, host, port, path, buildQuery(), fragment);
         } catch (URISyntaxException ex) {
             throw new UriBuilderException("URI can not be built", ex);
         }
     }
 
+    private String substituteMapped(String path, Map<String, ? extends Object> varValueMap) {
+        URITemplate templ = new URITemplate(path);
+        Set<String> uniqueVars = new HashSet<String>(templ.getVariables());
+        if (varValueMap.size() < uniqueVars.size()) {
+            throw new IllegalArgumentException("Unresolved variables; only " + varValueMap.size()
+                                               + " value(s) given for " + uniqueVars.size()
+                                               + " unique variable(s)");
+        }
+        return templ.substitute(varValueMap);
+    }
+
+    @Override
+    public URI buildFromEncodedMap(Map<String, ? extends Object> map) throws IllegalArgumentException,
+        UriBuilderException {
+        // see buildFromEncoded() comment
+        Map<String, String> decodedMap = new HashMap<String, String>(map.size());
+        for (Map.Entry<String, ? extends Object> entry : map.entrySet()) {
+            decodedMap.put(entry.getKey(), decodePartiallyEncoded(entry.getValue().toString()));
+        }
+        return buildFromMap(decodedMap);
+    }
+
     // CHECKSTYLE:OFF
     @Override
     public UriBuilder clone() {
@@ -96,6 +179,7 @@
         return path(((Path)ann).value());
     }
 
+    @SuppressWarnings("unchecked")
     @Override
     public UriBuilder path(Class resource, String method) throws IllegalArgumentException {
         if (resource == null) {
@@ -186,6 +270,9 @@
     }
 
     private void setUriParts(URI uri) {
+        if (uri == null) {
+            throw new IllegalArgumentException("uri is null");
+        }
         scheme = uri.getScheme();
         port = uri.getPort();
         host = uri.getHost();
@@ -197,15 +284,17 @@
 
     private String buildPath() {
         StringBuilder sb = new StringBuilder();
-        for (PathSegment ps : paths) {
-            String p = ps.getPath();
-            if (!p.startsWith("/") && (sb.length() == 0 || sb.charAt(sb.length() - 1) != '/')) {
-                sb.append('/');
+        Iterator<PathSegment> iter = paths.iterator();
+        while (iter.hasNext()) {
+            String p = iter.next().getPath();
+            if (p.length() != 0 || !iter.hasNext()) {
+                if (!p.startsWith("/")) {
+                    sb.append('/');
+                }
+                sb.append(p);
             }
-            sb.append(p);
         }
         return sb.toString();
-
     }
 
     private String buildQuery() {
@@ -221,29 +310,6 @@
     }
 
     @Override
-    public URI buildFromEncoded(Object... values) throws IllegalArgumentException, UriBuilderException {
-        try {
-            return new URI(scheme, userInfo, host, port, buildPath(), buildQuery(), fragment);
-        } catch (URISyntaxException ex) {
-            throw new UriBuilderException("URI can not be built", ex);
-        }
-    }
-
-    @Override
-    public URI buildFromEncodedMap(Map<String, ? extends Object> arg0) throws IllegalArgumentException,
-        UriBuilderException {
-        // TODO Auto-generated method stub
-        throw new UnsupportedOperationException("Not implemented :/");
-    }
-
-    @Override
-    public URI buildFromMap(Map<String, ? extends Object> arg0) throws IllegalArgumentException,
-        UriBuilderException {
-        // TODO Auto-generated method stub
-        throw new UnsupportedOperationException("Not implemented :/");
-    }
-
-    @Override
     public UriBuilder matrixParam(String name, Object... values) throws IllegalArgumentException {
         // TODO Auto-generated method stub
         throw new UnsupportedOperationException("Not implemented :/");
@@ -297,4 +363,21 @@
         throw new UnsupportedOperationException("Not implemented :/");
     }
 
+    /**
+     * Decode partially encoded string. Decode only values that matches patter "percent char followed by two
+     * hexadecimal digits".
+     * 
+     * @param encoded fully or partially encoded string.
+     * @return decoded string
+     */
+    private String decodePartiallyEncoded(String encoded) {
+        Matcher m = DECODE_PATTERN.matcher(encoded);
+        StringBuffer sb = new StringBuffer();
+        while (m.find()) {
+            String found = m.group();
+            m.appendReplacement(sb, JAXRSUtils.uriDecode(found));
+        }
+        m.appendTail(sb);
+        return sb.toString();
+    }
 }

Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/UriInfoImpl.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/UriInfoImpl.java?rev=738937&r1=738936&r2=738937&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/UriInfoImpl.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/UriInfoImpl.java Thu Jan 29 17:45:43 2009
@@ -146,6 +146,7 @@
 
     public List<String> getMatchedURIs(boolean decode) {
         if (stack != null) {
+            List<String> objects = new ArrayList<String>();
             List<String> uris = new ArrayList<String>(stack.size());
             String sum = "";
             for (MethodInvocationInfo invocation : stack) {
@@ -162,7 +163,8 @@
                     }
                 }
                 UriBuilder ub = UriBuilder.fromPath(sum);
-                uris.add(ub.build().normalize().getPath());
+                objects.addAll(invocation.getTemplateValues());
+                uris.add(ub.build(objects.toArray()).normalize().getPath());
             }
             return uris;
         }

Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/interceptor/JAXRSInInterceptor.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/interceptor/JAXRSInInterceptor.java?rev=738937&r1=738936&r2=738937&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/interceptor/JAXRSInInterceptor.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/interceptor/JAXRSInInterceptor.java Thu Jan 29 17:45:43 2009
@@ -67,7 +67,7 @@
         try {
             processRequest(message, originalAddress);
         } catch (RuntimeException ex) {
-            Response excResponse = JAXRSUtils.convertFaultToResponse(ex, originalAddress);
+            Response excResponse = JAXRSUtils.convertFaultToResponse(ex, originalAddress, message);
             if (excResponse == null) {
                 ProviderFactory.getInstance(originalAddress).clearThreadLocalProxies();
                 throw ex;

Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/model/MethodInvocationInfo.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/model/MethodInvocationInfo.java?rev=738937&r1=738936&r2=738937&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/model/MethodInvocationInfo.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/model/MethodInvocationInfo.java Thu Jan 29 17:45:43 2009
@@ -18,17 +18,23 @@
  */
 package org.apache.cxf.jaxrs.model;
 
+import java.util.Collections;
+import java.util.List;
+
 /**
- * A pair of {@link OperationResourceInfo} representing a resource method being invoked 
- * and actual {@link Class} of the object this method is invoked upon.
+ * A triple of {@link OperationResourceInfo} representing a resource method being invoked, 
+ * actual {@link Class} of the object this method is invoked upon, and a list of template variable values
+ * matched during the selection of this method
  */
 public class MethodInvocationInfo {
     private OperationResourceInfo ori;
     private Class<?> realClass;
+    private List<String> templateValues;
     
-    public MethodInvocationInfo(OperationResourceInfo ori, Class<?> realClass) {
+    public MethodInvocationInfo(OperationResourceInfo ori, Class<?> realClass, List<String> templateValues) {
         this.ori = ori;
         this.realClass = realClass;
+        this.templateValues = Collections.unmodifiableList(templateValues);
     }
     
     public OperationResourceInfo getMethodInfo() {
@@ -38,4 +44,8 @@
     public Class<?> getRealClass() {
         return realClass;
     }
+    
+    public List<String> getTemplateValues() {
+        return templateValues;
+    }
 }

Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/model/URITemplate.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/model/URITemplate.java?rev=738937&r1=738936&r2=738937&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/model/URITemplate.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/model/URITemplate.java Thu Jan 29 17:45:43 2009
@@ -19,9 +19,11 @@
 
 package org.apache.cxf.jaxrs.model;
 
-
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -33,40 +35,38 @@
 import org.apache.cxf.jaxrs.utils.JAXRSUtils;
 
 public final class URITemplate {
-    
+
     public static final String TEMPLATE_PARAMETERS = "jaxrs.template.parameters";
     public static final String LIMITED_REGEX_SUFFIX = "(/.*)?";
     public static final String FINAL_MATCH_GROUP = "FINAL_MATCH_GROUP";
-    
+
     /**
      * The regular expression for matching URI templates and names.
      */
-    private static final Pattern TEMPLATE_NAMES_PATTERN = 
-        Pattern.compile("\\{(\\w[-\\w\\.]*)(\\:(.+?))?\\}");
+    private static final Pattern TEMPLATE_NAMES_PATTERN = Pattern.compile("\\{(\\w[-\\w\\.]*)(\\:(.+?))?\\}");
 
     private static final String DEFAULT_PATH_VARIABLE_REGEX = "([^/]+?)";
     private static final String CHARACTERS_TO_ESCAPE = ".";
-    
+
     private final String template;
     private final List<String> templateVariables = new ArrayList<String>();
     private final List<String> customTemplateVariables = new ArrayList<String>();
     private final Pattern templateRegexPattern;
     private final String literals;
 
-    
     public URITemplate(String theTemplate) {
-        
+
         this.template = theTemplate;
-        
+
         StringBuilder literalChars = new StringBuilder();
         StringBuilder patternBuilder = new StringBuilder();
-        
+
         // compute a regular expression from URI template
         Matcher matcher = TEMPLATE_NAMES_PATTERN.matcher(template);
         int i = 0;
         while (matcher.find()) {
             templateVariables.add(matcher.group(1).trim());
-            
+
             String substr = escapeCharacters(template.substring(i, matcher.start()));
             literalChars.append(substr);
             patternBuilder.append(substr);
@@ -78,42 +78,42 @@
                 customTemplateVariables.add(matcher.group(1).trim());
             } else {
                 patternBuilder.append(DEFAULT_PATH_VARIABLE_REGEX);
-            } 
+            }
         }
         String substr = escapeCharacters(template.substring(i, template.length()));
         literalChars.append(substr);
         patternBuilder.append(substr);
 
         literals = literalChars.toString();
-        
+
         int endPos = patternBuilder.length() - 1;
         boolean endsWithSlash = (endPos >= 0) ? patternBuilder.charAt(endPos) == '/' : false;
         if (endsWithSlash) {
             patternBuilder.deleteCharAt(endPos);
         }
         patternBuilder.append(LIMITED_REGEX_SUFFIX);
-        
+
         templateRegexPattern = Pattern.compile(patternBuilder.toString());
     }
 
     public String getLiteralChars() {
         return literals;
     }
-    
+
     public String getValue() {
         return template;
     }
-    
-    public int getNumberOfGroups() {
-        return templateVariables.size();
-    }
-    
-    public int getNumberOfGroupsWithCustomExpression() {
-        return customTemplateVariables.size();
+
+    public List<String> getVariables() {
+        return Collections.unmodifiableList(templateVariables);
+    }
+
+    public List<String> getCustomVariables() {
+        return Collections.unmodifiableList(customTemplateVariables);
     }
-    
+
     private static String escapeCharacters(String expression) {
-        
+
         StringBuilder sb = new StringBuilder();
         for (int i = 0; i < expression.length(); i++) {
             char ch = expression.charAt(i);
@@ -121,11 +121,11 @@
         }
         return sb.toString();
     }
-    
+
     private static boolean isReservedCharacter(char ch) {
         return CHARACTERS_TO_ESCAPE.indexOf(ch) != -1;
     }
-    
+
     public boolean match(String uri, MultivaluedMap<String, String> templateVariableToValue) {
 
         if (uri == null) {
@@ -170,46 +170,124 @@
         }
 
         // The right hand side value, might be used to further resolve sub-resources.
-        
+
         String finalGroup = m.group(i);
         templateVariableToValue.putSingle(FINAL_MATCH_GROUP, finalGroup == null ? "/" : finalGroup);
-        
 
         return true;
     }
-    
-    public static URITemplate createTemplate(ClassResourceInfo cri,
-                                             Path path) {
-        
+
+    /**
+     * Substitutes template variables with listed values. List of values is counterpart for
+     * {@link #getVariables() list of variables}. When list of value is shorter than variables substitution
+     * is partial. When variable has pattern, value must fit to pattern, otherwise
+     * {@link IllegalArgumentException} is thrown.
+     * <p>
+     * Example1: for template "/{a}/{b}/{a}" {@link #getVariables()} returns "[a, b, a]"; providing here list
+     * of value "[foo, bar, baz]" results with "/foo/bar/baz".
+     * <p>
+     * Example2: for template "/{a}/{b}/{a}" providing list of values "[foo]" results with "/foo/{b}/{a}".
+     * 
+     * @param values values for variables
+     * @return template with bound variables.
+     * @throws IllegalArgumentException when values is null, any value does not match pattern etc.
+     */
+    public String substitute(List<String> values) throws IllegalArgumentException {
+        if (values == null) {
+            throw new IllegalArgumentException("values is null");
+        }
+        Matcher m = TEMPLATE_NAMES_PATTERN.matcher(template);
+        Iterator<String> valIter = values.iterator();
+        StringBuffer sb = new StringBuffer();
+        while (m.find() && valIter.hasNext()) {
+            String value = valIter.next();
+            String varPattern = m.group(2);
+            if (varPattern != null) {
+                // variable has pattern, matching formats e.g.
+                // for "{a:\d\d}" variable value must have two digits etc.
+                Pattern p = Pattern.compile(varPattern);
+                if (!p.matcher(":" + value).matches()) {
+                    throw new IllegalArgumentException("Value '" + value + "' does not match variable "
+                                                       + m.group());
+                }
+            }
+            m.appendReplacement(sb, value);
+        }
+        m.appendTail(sb);
+        return sb.toString();
+    }
+
+    /**
+     * Substitutes template variables with mapped values. Variables are mapped to values; if not all variables
+     * are bound result will still contain variables. Note that all variables with the same name are replaced
+     * by one value.
+     * <p>
+     * Example: for template "/{a}/{b}/{a}" {@link #getVariables()} returns "[a, b, a]"; providing here
+     * mapping "[a: foo, b: bar]" results with "/foo/bar/foo" (full substitution) and for mapping "[b: baz]"
+     * result is "{a}/baz/{a}" (partial substitution).
+     * 
+     * @param valuesMap map variables to their values; on each value Object.toString() is called.
+     * @return template with bound variables.
+     * @throws IllegalArgumentException when size of list of values differs from list of variables or list
+     *                 contains nulls.
+     */
+    public String substitute(Map<String, ? extends Object> valuesMap) throws IllegalArgumentException {
+        if (valuesMap == null) {
+            throw new IllegalArgumentException("valuesMap is null");
+        }
+        Matcher m = TEMPLATE_NAMES_PATTERN.matcher(template);
+        StringBuffer sb = new StringBuffer();
+        while (m.find()) {
+            Object value = valuesMap.get(m.group(1));
+            if (value == null) {
+                continue;
+            }
+            String sval = value.toString();
+            String varPattern = m.group(2);
+            if (varPattern != null) {
+                Pattern p = Pattern.compile(varPattern);
+                if (!p.matcher(":" + sval).matches()) {
+                    throw new IllegalArgumentException("Value '" + sval + "' does not match variable "
+                                                       + m.group());
+                }
+            }
+            m.appendReplacement(sb, sval);
+        }
+        m.appendTail(sb);
+        return sb.toString();
+    }
+
+    public static URITemplate createTemplate(ClassResourceInfo cri, Path path) {
+
         if (path == null) {
             return new URITemplate("/");
         }
-        
+
         String pathValue = path.value();
         if (!pathValue.startsWith("/")) {
             pathValue = "/" + pathValue;
         }
-        
+
         return new URITemplate(pathValue);
     }
-    
+
     public static int compareTemplates(URITemplate t1, URITemplate t2) {
         String l1 = t1.getLiteralChars();
         String l2 = t2.getLiteralChars();
         if (!l1.equals(l2)) {
-            // descending order 
-            return l1.length() < l2.length() ? 1 : -1; 
+            // descending order
+            return l1.length() < l2.length() ? 1 : -1;
         }
-        
-        int g1 = t1.getNumberOfGroups();
-        int g2 = t2.getNumberOfGroups();
-        // descending order 
+
+        int g1 = t1.templateVariables.size();
+        int g2 = t2.templateVariables.size();
+        // descending order
         int result = g1 < g2 ? 1 : g1 > g2 ? -1 : 0;
         if (result == 0) {
-            int gCustom1 = t1.getNumberOfGroupsWithCustomExpression();
-            int gCustom2 = t2.getNumberOfGroupsWithCustomExpression();
+            int gCustom1 = t1.customTemplateVariables.size();
+            int gCustom2 = t2.customTemplateVariables.size();
             if (gCustom1 != gCustom2) {
-                // descending order 
+                // descending order
                 return gCustom1 < gCustom2 ? 1 : -1;
             }
         }

Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/JAXRSUtils.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/JAXRSUtils.java?rev=738937&r1=738936&r2=738937&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/JAXRSUtils.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/JAXRSUtils.java Thu Jan 29 17:45:43 2009
@@ -91,7 +91,6 @@
 import org.apache.cxf.jaxrs.provider.AbstractConfigurableProvider;
 import org.apache.cxf.jaxrs.provider.ProviderFactory;
 import org.apache.cxf.message.Message;
-import org.apache.cxf.message.MessageImpl;
 import org.apache.cxf.transport.http.AbstractHTTPDestination;
 
 public final class JAXRSUtils {
@@ -931,11 +930,10 @@
     }
     
     @SuppressWarnings("unchecked")
-    public static Response convertFaultToResponse(Throwable ex, String baseAddress) {
+    public static Response convertFaultToResponse(Throwable ex, String baseAddress, Message inMessage) {
         
         ExceptionMapper mapper = 
-            ProviderFactory.getInstance(baseAddress).createExceptionMapper(ex.getClass(),
-                                                                new MessageImpl());
+            ProviderFactory.getInstance(baseAddress).createExceptionMapper(ex.getClass(), inMessage);
         if (mapper != null) {
             Response excResponse = mapper.toResponse(ex);
             if (excResponse != null) {

Modified: cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/impl/UriBuilderImplTest.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/impl/UriBuilderImplTest.java?rev=738937&r1=738936&r2=738937&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/impl/UriBuilderImplTest.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/impl/UriBuilderImplTest.java Thu Jan 29 17:45:43 2009
@@ -21,6 +21,9 @@
 
 import java.lang.reflect.Method;
 import java.net.URI;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
 
 import org.apache.cxf.jaxrs.resources.Book;
 import org.apache.cxf.jaxrs.resources.BookStore;
@@ -31,14 +34,122 @@
 
 public class UriBuilderImplTest extends Assert {
 
+    @Test(expected = IllegalArgumentException.class)
+    public void testCtorNull() throws Exception {
+        new UriBuilderImpl(null);
+    }
+
+    @Test
+    public void testCtorAndBuild() throws Exception {
+        URI uri = new URI("http://foo/bar/baz?query=1#fragment");
+        URI newUri = new UriBuilderImpl(uri).build();
+        assertEquals("URI is not built correctly", uri, newUri);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testUriNull() throws Exception {
+        new UriBuilderImpl().uri(null);
+    }
+
     @Test
     public void testUri() throws Exception {
         URI uri = new URI("http://foo/bar/baz?query=1#fragment");
         URI newUri = new UriBuilderImpl().uri(uri).build();
-        assertEquals("URI is not built correctly", newUri, uri);
+        assertEquals("URI is not built correctly", uri, newUri);
+    }
+
+    @Test
+    public void testBuildValues() throws Exception {
+        URI uri = new URI("http://zzz");
+        URI newUri = new UriBuilderImpl(uri).path("/{b}/{a}/{b}").build("foo", "bar", "baz");
+        assertEquals("URI is not built correctly", new URI("http://zzz/foo/bar/foo"), newUri);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testBuildMissingValues() throws Exception {
+        URI uri = new URI("http://zzz");
+        new UriBuilderImpl(uri).path("/{b}/{a}/{b}").build("foo");
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testBuildMissingValues2() throws Exception {
+        URI uri = new URI("http://zzz");
+        new UriBuilderImpl(uri).path("/{b}").build();
+    }
+
+    @Test
+    public void testBuildValueWithBrackets() throws Exception {
+        URI uri = new URI("http://zzz");
+        URI newUri = new UriBuilderImpl(uri).path("/{a}").build("{foo}");
+        assertEquals("URI is not built correctly", new URI("http://zzz/%7Bfoo%7D"), newUri);
+    }
+    
+    @Test
+    public void testBuildValuesPct() throws Exception {
+        URI uri = new URI("http://zzz");
+        URI newUri = new UriBuilderImpl(uri).path("/{a}").build("foo%25/bar%");
+        assertEquals("URI is not built correctly", new URI("http://zzz/foo%2525/bar%25"), newUri);
     }
 
     @Test
+    public void testBuildValuesPctEncoded() throws Exception {
+        URI uri = new URI("http://zzz");
+        URI newUri = new UriBuilderImpl(uri).path("/{a}/{b}").buildFromEncoded("foo%25", "bar%");
+        assertEquals("URI is not built correctly", new URI("http://zzz/foo%25/bar%25"), newUri);
+    }
+
+    @Test
+    public void testBuildFromMapValues() throws Exception {
+        URI uri = new URI("http://zzz");
+        Map<String, String> map = new HashMap<String, String>();
+        map.put("b", "foo");
+        map.put("a", "bar");
+        Map<String, String> immutable = Collections.unmodifiableMap(map);
+        URI newUri = new UriBuilderImpl(uri).path("/{b}/{a}/{b}").buildFromMap(immutable);
+        assertEquals("URI is not built correctly", new URI("http://zzz/foo/bar/foo"), newUri);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testBuildFromMapMissingValues() throws Exception {
+        URI uri = new URI("http://zzz");
+        Map<String, String> map = new HashMap<String, String>();
+        map.put("b", "foo");
+        Map<String, String> immutable = Collections.unmodifiableMap(map);
+        new UriBuilderImpl(uri).path("/{b}/{a}/{b}").buildFromMap(immutable);
+    }
+
+    @Test
+    public void testBuildFromMapValueWithBrackets() throws Exception {
+        URI uri = new URI("http://zzz");
+        Map<String, String> map = new HashMap<String, String>();
+        map.put("a", "{foo}");
+        Map<String, String> immutable = Collections.unmodifiableMap(map);
+        URI newUri = new UriBuilderImpl(uri).path("/{a}").buildFromMap(immutable);
+        assertEquals("URI is not built correctly", new URI("http://zzz/%7Bfoo%7D"), newUri);
+    }
+    
+    @Test
+    public void testBuildFromMapValuesPct() throws Exception {
+        URI uri = new URI("http://zzz");
+        Map<String, String> map = new HashMap<String, String>();
+        map.put("a", "foo%25/bar%");
+        Map<String, String> immutable = Collections.unmodifiableMap(map);        
+        URI newUri = new UriBuilderImpl(uri).path("/{a}").buildFromMap(immutable);
+        assertEquals("URI is not built correctly", new URI("http://zzz/foo%2525/bar%25"), newUri);
+    }
+
+    @Test
+    public void testBuildFromMapValuesPctEncoded() throws Exception {
+        URI uri = new URI("http://zzz");
+        Map<String, String> map = new HashMap<String, String>();
+        map.put("a", "foo%25");
+        map.put("b", "bar%");
+        Map<String, String> immutable = Collections.unmodifiableMap(map);        
+        URI newUri = new UriBuilderImpl(uri).path("/{a}/{b}").buildFromEncodedMap(immutable);
+        assertEquals("URI is not built correctly", new URI("http://zzz/foo%25/bar%25"), newUri);
+    }
+    
+    @Test
     public void testAddPath() throws Exception {
         URI uri = new URI("http://foo/bar");
         URI newUri = new UriBuilderImpl().uri(uri).path("baz").build();
@@ -55,10 +166,24 @@
     }
 
     @Test
+    public void testAddPathSlashes2() throws Exception {
+        URI uri = new URI("http://foo/");
+        URI newUri = new UriBuilderImpl().uri(uri).path("/bar///baz").path("blah//").build();
+        assertEquals("URI is not built correctly", new URI("http://foo/bar/baz/blah/"), newUri);
+    }
+
+    @Test
+    public void testAddPathSlashes3() throws Exception {
+        URI uri = new URI("http://foo/");
+        URI newUri = new UriBuilderImpl().uri(uri).path("/bar/").path("").path("baz").build();
+        assertEquals("URI is not built correctly", new URI("http://foo/bar/baz"), newUri);
+    }
+
+    @Test
     public void testAddPathClass() throws Exception {
         URI uri = new URI("http://foo/");
-        URI newUri = new UriBuilderImpl().uri(uri).path(BookStore.class).path("bar").build();
-        assertEquals("URI is not built correctly", new URI("http://foo/bookstore/bar"), newUri);
+        URI newUri = new UriBuilderImpl().uri(uri).path(BookStore.class).path("/").build();
+        assertEquals("URI is not built correctly", new URI("http://foo/bookstore/"), newUri);
     }
 
     @Test(expected = IllegalArgumentException.class)

Modified: cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/model/URITemplateTest.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/model/URITemplateTest.java?rev=738937&r1=738936&r2=738937&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/model/URITemplateTest.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/model/URITemplateTest.java Thu Jan 29 17:45:43 2009
@@ -18,10 +18,15 @@
  */
 package org.apache.cxf.jaxrs.model;
 
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
 import javax.ws.rs.core.MultivaluedMap;
 
 import org.apache.cxf.jaxrs.impl.MetadataMap;
+
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
@@ -37,69 +42,69 @@
     public void testMatchBasic() throws Exception {
         URITemplate uriTemplate = new URITemplate("/customers/{id}");
         MultivaluedMap<String, String> values = new MetadataMap<String, String>();
-        
+
         boolean match = uriTemplate.match("/customers/123/", values);
         assertTrue(match);
         String value = values.getFirst("id");
         assertEquals("123", value);
     }
-    
+
     @Test
     public void testMatchWithMatrixAndTemplate() throws Exception {
         URITemplate uriTemplate = new URITemplate("/customers/{id}");
         MultivaluedMap<String, String> values = new MetadataMap<String, String>();
-        
+
         boolean match = uriTemplate.match("/customers/123;123456/", values);
         assertTrue(match);
         String value = values.getFirst("id");
         assertEquals("123;123456", value);
     }
-    
+
     @Test
     public void testMatchWithMatrixOnClearPath1() throws Exception {
         URITemplate uriTemplate = new URITemplate("/customers/{id}");
         MultivaluedMap<String, String> values = new MetadataMap<String, String>();
-        
+
         boolean match = uriTemplate.match("/customers;123456/123/", values);
         assertTrue(match);
         String value = values.getFirst("id");
         assertEquals("123", value);
     }
-    
+
     @Test
     public void testMatchWithMatrixOnClearPath2() throws Exception {
         URITemplate uriTemplate = new URITemplate("/customers/{id}/orders/{order}");
         MultivaluedMap<String, String> values = new MetadataMap<String, String>();
-        
+
         assertTrue(uriTemplate.match("/customers;123456/123/orders;456/3", values));
         assertEquals("123", values.getFirst("id"));
         assertEquals("3", values.getFirst("order"));
     }
-    
+
     @Test
     public void testMatchWithMatrixOnClearPath3() throws Exception {
         URITemplate uriTemplate = new URITemplate("/{id}/customers/");
         MultivaluedMap<String, String> values = new MetadataMap<String, String>();
-        
+
         boolean match = uriTemplate.match("/123/customers;123456/", values);
         assertTrue(match);
         String value = values.getFirst("id");
         assertEquals("123", value);
     }
-    
+
     @Test
     public void testMatchWithMatrixOnClearPath4() throws Exception {
         URITemplate uriTemplate = new URITemplate("/customers");
         MultivaluedMap<String, String> values = new MetadataMap<String, String>();
-        
+
         assertTrue(uriTemplate.match("/customers;123456/123/orders;456/3", values));
     }
-    
+
     @Test
     public void testMatchBasicTwoParametersVariation1() throws Exception {
         URITemplate uriTemplate = new URITemplate("/customers/{name}/{department}");
         MultivaluedMap<String, String> values = new MetadataMap<String, String>();
-        
+
         boolean match = uriTemplate.match("/customers/john/CS", values);
         assertTrue(match);
         String name = values.getFirst("name");
@@ -107,111 +112,111 @@
         assertEquals("john", name);
         assertEquals("CS", department);
     }
-    
+
     @Test
     public void testMatchBasicTwoParametersVariation2() throws Exception {
         URITemplate uriTemplate = new URITemplate("/customers/name/{name}/dep/{department}");
         MultivaluedMap<String, String> values = new MetadataMap<String, String>();
-        
+
         boolean match = uriTemplate.match("/customers/name/john/dep/CS", values);
         assertTrue(match);
         String name = values.getFirst("name");
         String department = values.getFirst("department");
         assertEquals("john", name);
         assertEquals("CS", department);
-    }    
-    
+    }
+
     @Test
     public void testURITemplateWithSubResource() throws Exception {
-        //So "/customers" is the URITemplate for the root resource class
+        // So "/customers" is the URITemplate for the root resource class
         URITemplate uriTemplate = new URITemplate("/customers");
         MultivaluedMap<String, String> values = new MetadataMap<String, String>();
-        
+
         boolean match = uriTemplate.match("/customers/123", values);
         assertTrue(match);
         String subResourcePath = values.getFirst(URITemplate.FINAL_MATCH_GROUP);
         assertEquals("/123", subResourcePath);
     }
-        
+
     @Test
     public void testURITemplateWithSubResourceVariation2() throws Exception {
-        //So "/customers" is the URITemplate for the root resource class
+        // So "/customers" is the URITemplate for the root resource class
         URITemplate uriTemplate = new URITemplate("/customers");
         MultivaluedMap<String, String> values = new MetadataMap<String, String>();
-        
+
         boolean match = uriTemplate.match("/customers/name/john/dep/CS", values);
         assertTrue(match);
         String subResourcePath = values.getFirst(URITemplate.FINAL_MATCH_GROUP);
         assertEquals("/name/john/dep/CS", subResourcePath);
     }
-        
+
     @Test
-    /* Test a sub-resource locator method like this
-     * @HttpMethod("GET") @UriTemplate("/books/{bookId}/") 
-     * public Book getBook(@UriParam("bookId") String id)
+    /*
+     * Test a sub-resource locator method like this @HttpMethod("GET") @UriTemplate("/books/{bookId}/") public
+     * Book getBook(@UriParam("bookId") String id)
      */
     public void testURITemplateWithSubResourceVariation3() throws Exception {
         URITemplate uriTemplate = new URITemplate("/books/{bookId}/");
         MultivaluedMap<String, String> values = new MetadataMap<String, String>();
-        
+
         boolean match = uriTemplate.match("/books/123/chapter/1", values);
         assertTrue(match);
         String subResourcePath = values.getFirst(URITemplate.FINAL_MATCH_GROUP);
         assertEquals("/chapter/1", subResourcePath);
     }
-    
+
     @Test
     public void testBasicCustomExpression() throws Exception {
         URITemplate uriTemplate = new URITemplate("/books/{bookId:[^/]+?}");
         MultivaluedMap<String, String> values = new MetadataMap<String, String>();
-        
+
         boolean match = uriTemplate.match("/books/123/chapter/1", values);
         assertTrue(match);
         assertEquals("123", values.getFirst("bookId"));
         String subResourcePath = values.getFirst(URITemplate.FINAL_MATCH_GROUP);
         assertEquals("/chapter/1", subResourcePath);
     }
-    
+
     @Test
     public void testBasicCustomExpression2() throws Exception {
         URITemplate uriTemplate = new URITemplate("/books/{bookId:123}");
         MultivaluedMap<String, String> values = new MetadataMap<String, String>();
-        
+
         boolean match = uriTemplate.match("/books/123/chapter/1", values);
         assertTrue(match);
         assertEquals("123", values.getFirst("bookId"));
         String subResourcePath = values.getFirst(URITemplate.FINAL_MATCH_GROUP);
         assertEquals("/chapter/1", subResourcePath);
     }
-    
+
     @Test
     public void testBasicCustomExpression3() throws Exception {
         URITemplate uriTemplate = new URITemplate("/books/{bookId:\\d\\d\\d}");
         MultivaluedMap<String, String> values = new MetadataMap<String, String>();
-        
+
         boolean match = uriTemplate.match("/books/123/chapter/1", values);
         assertTrue(match);
         assertEquals("123", values.getFirst("bookId"));
         String subResourcePath = values.getFirst(URITemplate.FINAL_MATCH_GROUP);
         assertEquals("/chapter/1", subResourcePath);
     }
-    
+
     @Test
     public void testEscaping() throws Exception {
         URITemplate uriTemplate = new URITemplate("/books/a.db");
         MultivaluedMap<String, String> values = new MetadataMap<String, String>();
-        
+
         assertTrue(uriTemplate.match("/books/a.db", values));
         assertFalse(uriTemplate.match("/books/adbc", values));
         assertFalse(uriTemplate.match("/books/acdb", values));
 
     }
-    
+
     @Test
     public void testBasicCustomExpression4() throws Exception {
         URITemplate uriTemplate = new URITemplate("/books/{bookId:...\\.}");
         MultivaluedMap<String, String> values = new MetadataMap<String, String>();
-        
+
         assertTrue(uriTemplate.match("/books/123.", values));
         assertEquals("123.", values.getFirst("bookId"));
         values.clear();
@@ -220,12 +225,12 @@
         assertFalse(uriTemplate.match("/books/abcd", values));
         assertFalse(uriTemplate.match("/books/abc", values));
     }
-    
+
     @Test
     public void testMultipleExpression2() throws Exception {
         URITemplate uriTemplate = new URITemplate("/books/{bookId:123}/chapter/{id}");
         MultivaluedMap<String, String> values = new MetadataMap<String, String>();
-        
+
         boolean match = uriTemplate.match("/books/123/chapter/1", values);
         assertTrue(match);
         assertEquals("123", values.getFirst("bookId"));
@@ -233,16 +238,16 @@
         String subResourcePath = values.getFirst(URITemplate.FINAL_MATCH_GROUP);
         assertEquals("/", subResourcePath);
     }
-    
+
     @Test
     public void testFailCustomExpression() throws Exception {
         URITemplate uriTemplate = new URITemplate("/books/{bookId:124}");
         MultivaluedMap<String, String> values = new MetadataMap<String, String>();
-        
+
         boolean match = uriTemplate.match("/books/123/chapter/1", values);
         assertFalse(match);
     }
-    
+
     @Test
     public void testBaseTail1() {
         URITemplate uriTemplate = new URITemplate("/{base:base.+}/{tail}");
@@ -252,7 +257,7 @@
         assertEquals("base1", values.getFirst("base"));
         assertEquals("tails", values.getFirst("tail"));
     }
-    
+
     @Test
     public void testBaseTail2() {
         URITemplate uriTemplate = new URITemplate("/{base:.+base}/{tail}");
@@ -263,7 +268,7 @@
         assertEquals("1base", values.getFirst("base"));
         assertEquals("tails", values.getFirst("tail"));
     }
-    
+
     @Test
     public void testBaseTail3() {
         URITemplate uriTemplate = new URITemplate("/{base:base.+suffix}/{tail}");
@@ -274,4 +279,100 @@
         assertEquals("base1suffix", values.getFirst("base"));
         assertEquals("tails", values.getFirst("tail"));
     }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testSubstituteListNull() throws Exception {
+        new URITemplate("anything").substitute((List<String>)null);
+    }
+
+    @Test
+    public void testSubstituteList() throws Exception {
+        URITemplate ut = new URITemplate("/foo/{a}/{b:\\d\\d}/{c}");
+        List<String> list = Arrays.asList("foo", "99", "baz");
+        assertEquals("Wrong substitution", "/foo/foo/99/baz", ut.substitute(list));
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testSubstituteListWrongPattern() throws Exception {
+        URITemplate ut = new URITemplate("/foo/{b:\\d\\d}");
+        List<String> list = Arrays.asList("foo", "not-two-digits");
+        ut.substitute(list);
+    }
+
+    @Test
+    public void testSubstituteListSameVars() throws Exception {
+        URITemplate ut = new URITemplate("/foo/{a}/{a}/{a}");
+        List<String> list = Arrays.asList("bar", "baz", "blah");
+        assertEquals("Wrong substitution", "/foo/bar/baz/blah", ut.substitute(list));
+    }
+    
+    @Test
+    public void testSubstituteListIncomplete() throws Exception {
+        URITemplate ut = new URITemplate("/foo/{a}/{c}/{b}");
+        List<String> list = Arrays.asList("bar", "baz");
+        assertEquals("Wrong substitution", "/foo/bar/baz/{b}", ut.substitute(list));
+    }
+
+    @Test
+    public void testSubstituteListExceeding() throws Exception {
+        URITemplate ut = new URITemplate("/foo/{a}/{b}");
+        List<String> list = Arrays.asList("bar", "baz", "blah");
+        assertEquals("Wrong substitution", "/foo/bar/baz", ut.substitute(list));
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testSubstituteMapNull() throws Exception {
+        new URITemplate("anything").substitute((Map<String, String>)null);
+    }
+
+    @Test
+    public void testSubstituteMap() throws Exception {
+        URITemplate ut = new URITemplate("/foo/{a}/{b:\\d\\d}/{c}");
+        Map<String, String> map = new HashMap<String, String>();
+        map.put("c", "foo");
+        map.put("b", "11");
+        map.put("a", "bar");
+        assertEquals("Wrong substitution", "/foo/bar/11/foo", ut.substitute(map));
+    }
+
+    @Test
+    public void testSubstituteMapSameVars() throws Exception {
+        URITemplate ut = new URITemplate("/foo/{a}/{a}/{a}");
+        Map<String, String> map = new HashMap<String, String>();
+        map.put("a", "bar");
+        assertEquals("Wrong substitution", "/foo/bar/bar/bar", ut.substitute(map));
+    }
+
+    @Test
+    public void testSubstituteMapIncomplete() throws Exception {
+        URITemplate ut = new URITemplate("/foo/{a}/{b}/{a:\\d}");
+        Map<String, String> map = new HashMap<String, String>();
+        map.put("b", "bar");
+        assertEquals("Wrong substitution", "/foo/{a}/bar/{a:\\d}", ut.substitute(map));
+    }
+
+    @Test
+    public void testSubstituteMapSameVarWithPattern() throws Exception {
+        URITemplate ut = new URITemplate("/foo/{a}/{a:\\d}");
+        Map<String, String> map = new HashMap<String, String>();
+        map.put("a", "0");
+        assertEquals("Wrong substitution", "/foo/0/0", ut.substitute(map));
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testSubstituteMapSameVarWithPatternFail() throws Exception {
+        URITemplate ut = new URITemplate("/foo/{a}/{a:\\d}");
+        Map<String, String> map = new HashMap<String, String>();
+        map.put("a", "not-a-digit");
+        ut.substitute(map);
+    }
+
+    @Test
+    public void testSubstituteMapExceeding() throws Exception {
+        URITemplate ut = new URITemplate("/foo/{a}");
+        Map<String, String> map = new HashMap<String, String>();
+        map.put("b", "baz");
+        map.put("a", "blah");
+        assertEquals("Wrong substitution", "/foo/blah", ut.substitute(map));
+    }
 }

Modified: cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSClientServerBookTest.java
URL: http://svn.apache.org/viewvc/cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSClientServerBookTest.java?rev=738937&r1=738936&r2=738937&view=diff
==============================================================================
--- cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSClientServerBookTest.java (original)
+++ cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSClientServerBookTest.java Thu Jan 29 17:45:43 2009
@@ -703,9 +703,9 @@
 
     @Test
     public void testUriInfoMatchedUrisDecode() throws Exception {
-        String expected = "[/bookstore/booksubresource/{bookId}/, "
-                          + "/bookstore/booksubresource/{bookId}/chapters/sub/{chapterid}/, "
-                          + "/bookstore/booksubresource/{bookId}/chapters/sub/{chapterid}/matched!uris]";
+        String expected = "[/bookstore/booksubresource/123/, "
+                          + "/bookstore/booksubresource/123/chapters/sub/1/, "
+                          + "/bookstore/booksubresource/123/chapters/sub/1/matched!uris]";
         getAndCompare("http://localhost:9080/bookstore/"
                       + "booksubresource/123/chapters/sub/1/matched%21uris?decode=true", 
                       expected, 
@@ -715,9 +715,9 @@
     @Test
     public void testUriInfoMatchedUrisNoDecode() throws Exception {
         //note '%21' instead of '!'
-        String expected = "[/bookstore/booksubresource/{bookId}/, "
-            + "/bookstore/booksubresource/{bookId}/chapters/sub/{chapterid}/, "
-            + "/bookstore/booksubresource/{bookId}/chapters/sub/{chapterid}/matched%21uris]";
+        String expected = "[/bookstore/booksubresource/123/, "
+            + "/bookstore/booksubresource/123/chapters/sub/1/, "
+            + "/bookstore/booksubresource/123/chapters/sub/1/matched%21uris]";
         getAndCompare("http://localhost:9080/bookstore/"
                       + "booksubresource/123/chapters/sub/1/matched%21uris?decode=false", 
                       expected,



Mime
View raw message