Return-Path: X-Original-To: apmail-cxf-commits-archive@www.apache.org Delivered-To: apmail-cxf-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id D9AF7DCC0 for ; Thu, 29 Nov 2012 16:48:43 +0000 (UTC) Received: (qmail 14146 invoked by uid 500); 29 Nov 2012 16:48:43 -0000 Delivered-To: apmail-cxf-commits-archive@cxf.apache.org Received: (qmail 14010 invoked by uid 500); 29 Nov 2012 16:48:42 -0000 Mailing-List: contact commits-help@cxf.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@cxf.apache.org Delivered-To: mailing list commits@cxf.apache.org Received: (qmail 13977 invoked by uid 99); 29 Nov 2012 16:48:40 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 29 Nov 2012 16:48:40 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 29 Nov 2012 16:48:39 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id 03ED723889E2 for ; Thu, 29 Nov 2012 16:48:19 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r840012 - in /websites/production/cxf/content: cache/docs.pageCache docs/jax-rs-basics.html Date: Thu, 29 Nov 2012 16:48:18 -0000 To: commits@cxf.apache.org From: buildbot@apache.org X-Mailer: svnmailer-1.0.8-patched Message-Id: <20121129164819.03ED723889E2@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: buildbot Date: Thu Nov 29 16:48:18 2012 New Revision: 840012 Log: Production update by buildbot for cxf Modified: websites/production/cxf/content/cache/docs.pageCache websites/production/cxf/content/docs/jax-rs-basics.html Modified: websites/production/cxf/content/cache/docs.pageCache ============================================================================== Binary files - no diff available. Modified: websites/production/cxf/content/docs/jax-rs-basics.html ============================================================================== --- websites/production/cxf/content/docs/jax-rs-basics.html (original) +++ websites/production/cxf/content/docs/jax-rs-basics.html Thu Nov 29 16:48:18 2012 @@ -722,6 +722,152 @@ Note that JAXRS MessageBodyWriter and Me

Note that by the time a custom ResourceComparator is called the provided resource classes or methods have already been successfully matched by the runtime.

+

For example, the optional HTTP request and URI parameters (query, matrix, headers, cookies) and form parameters do not affect the selection algorithm.
+A custom ResourceComparator can be used when this limitation is considered to be problematic. For example, the following shows one such implementation:

+ +
+
+
+public class QueryResourceInfoComperator extends OperationResourceInfoComparator implements
+         ResourceComparator {
+
+     public QueryResourceInfoComperator() {
+         super(null, null);
+     }
+
+     @Override
+     public int compare(ClassResourceInfo cri1, ClassResourceInfo cri2, Message message) {
+         // Leave Class selection to CXF
+         return 0;
+     }
+
+     @Override
+     public int compare(OperationResourceInfo oper1, OperationResourceInfo oper2, Message message) {
+
+         // Check if CXF can make a decision
+         int cxfResult = super.compare(oper1, oper2);
+         if (cxfResult != 0)
+             return cxfResult;
+
+         // Compare QueryParam annotations
+         Set<String>  qParams = getParams((String) message.get(Message.QUERY_STRING));
+         int op1Counter = getMatchingRate(getAnnotations(oper1.getMethodToInvoke().getParameterAnnotations()),
+                 qParams);
+         int op2Counter = getMatchingRate(getAnnotations(oper2.getMethodToInvoke().getParameterAnnotations()),
+                 qParams);
+
+         return op1Counter == op2Counter
+                 ? 0
+                 : op1Counter<  op2Counter
+                         ? 1
+                         : -1;
+     }
+
+     /**
+      * This method calculates a number indicating a good or bad match between
+      * queryParams from request and annotated method parameters. A higher number
+      * means a better match.
+      *
+      * @param annotations
+      *            Map contains name of QueryParam method parameters as a key and
+      *            a Boolean value indicating an existing default value for this
+      *            parameter.
+      * @param queryParams
+      *            A Set of query parameters provided within the request
+      * @return A positive or negative number, indicating a good match between
+      *         query and method
+      */
+     protected int getMatchingRate(Map<String, Boolean>  annotations, Set<String>  queryParams) {
+         int rate = 0;
+         for (String anno : annotations.keySet()) {
+             if (queryParams.contains(anno)) {
+                 // URL query matches one method parameter
+                 rate += 2;
+             } else if (!annotations.get(anno).booleanValue()) {
+                 // No default value exists for method parameter
+                 rate -= 1;
+             }
+         }
+         return rate;
+     }
+
+     /**
+      * @param opParamAnnos
+      *            Array containing all annotations for all method parameters
+      * @return Key in Map is QueryParam name, and Value indicates if a default
+      *         value is present.
+      */
+     protected Map<String, Boolean>  getAnnotations(Annotation[][] opParamAnnos) {
+         Map<String, Boolean>  parameterAnnos = new HashMap<String, Boolean>();
+
+         if (opParamAnnos.length == 0)
+             return parameterAnnos;
+
+         for (Annotation[] pAnnos : opParamAnnos) {
+             QueryParam qParam = null;
+             DefaultValue dValue = null;
+             for (Annotation anno : pAnnos) {
+                 if (anno instanceof QueryParam)
+                     qParam = (QueryParam) anno;
+                 if (anno instanceof DefaultValue)
+                     dValue = (DefaultValue) anno;
+             }
+             parameterAnnos.put(qParam.value(), Boolean.valueOf((dValue != null)));
+         }
+
+         return parameterAnnos;
+     }
+
+     /**
+      * @param query
+      *            URL Query
+      * @return A Set of all keys, contained within query.
+      */
+     protected Set<String>  getParams(String query) {
+         Set<String>  params = new HashSet<String>();
+         if (query == null || query.length() == 0)
+             return params;
+
+         try {
+             for (String param : query.split("&")) {
+                 String pair[] = param.split("=");
+                 String key = URLDecoder.decode(pair[0], "UTF-8");
+                 params.add(key);
+             }
+         } catch (UnsupportedEncodingException e) {
+             e.printStackTrace();
+         }
+         return params;
+     }
+}
+
+
+
+ +

Now consider this code:

+ +
+
+@Path("/paramTest")
+public class MySimpleService {
+
+      @GET
+      public String getFoo(@QueryParam("foo") String foo){
+          return "foo:" + foo;
+      }
+
+      @GET
+      public String getFooBar(@QueryParam("foo") String foo,
+@QueryParam("bar") String bar){
+          return "foo:" + foo + " bar:" + bar;
+      }
+
+  
+} 
+
+
+ +

Using the custom comparator will lead to getFoo() method accepting a single query parameter selected when a request URI has only one query parameter, and getFoo() method accepting multiple query parameters selected when a request URI has at least two query parameters. Further customizations can be made to get the parameter values affecting the selection process too.

Context annotations