You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by bi...@apache.org on 2011/12/01 19:54:12 UTC
svn commit: r1209182 - in /cxf/trunk:
common/common/src/main/java/org/apache/cxf/common/util/
rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/cors/
rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/model/wadl/
rt/frontend/jaxrs/src/main/java/or...
Author: bimargulies
Date: Thu Dec 1 18:54:10 2011
New Revision: 1209182
URL: http://svn.apache.org/viewvc?rev=1209182&view=rev
Log:
CXF-3943: add an annotation to allow finer control than global params in the spring configuration.
Added:
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/cors/CrossOriginResourceSharing.java (with props)
Modified:
cxf/trunk/common/common/src/main/java/org/apache/cxf/common/util/ReflectionUtil.java
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/cors/CrossOriginResourceSharingFilter.java
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/model/wadl/Description.java
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/AnnotationUtils.java
cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/cors/BasicCrossOriginTest.java
cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/cors/ConfigServer.java
Modified: cxf/trunk/common/common/src/main/java/org/apache/cxf/common/util/ReflectionUtil.java
URL: http://svn.apache.org/viewvc/cxf/trunk/common/common/src/main/java/org/apache/cxf/common/util/ReflectionUtil.java?rev=1209182&r1=1209181&r2=1209182&view=diff
==============================================================================
--- cxf/trunk/common/common/src/main/java/org/apache/cxf/common/util/ReflectionUtil.java (original)
+++ cxf/trunk/common/common/src/main/java/org/apache/cxf/common/util/ReflectionUtil.java Thu Dec 1 18:54:10 2011
@@ -23,6 +23,7 @@ import java.beans.BeanInfo;
import java.beans.PropertyDescriptor;
import java.io.File;
import java.io.IOException;
+import java.lang.annotation.Annotation;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
@@ -265,4 +266,22 @@ public final class ReflectionUtil {
}
return m;
}
+
+
+ /**
+ * Look for a specified annotation on a method. If there, return it. If not, search it's containing class.
+ * Assume that the annotation is marked @Inherited.
+ *
+ * @param m method to examine
+ * @param annotationType the annotation type to look for.
+ * @return
+ */
+ public static <T extends Annotation> T getAnnotationForMethodOrContainingClass(Method m,
+ Class<T> annotationType) {
+ T annotation = m.getAnnotation(annotationType);
+ if (annotation != null) {
+ return annotation;
+ }
+ return m.getDeclaringClass().getAnnotation(annotationType);
+ }
}
Added: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/cors/CrossOriginResourceSharing.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/cors/CrossOriginResourceSharing.java?rev=1209182&view=auto
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/cors/CrossOriginResourceSharing.java (added)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/cors/CrossOriginResourceSharing.java Thu Dec 1 18:54:10 2011
@@ -0,0 +1,92 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. 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.
+ */
+
+package org.apache.cxf.jaxrs.cors;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Attach <a href="http://www.w3.org/TR/cors/">CORS</a> information
+ * to a resource. This annotation is read by {@link CrossOriginResourceSharingFilter}.
+ * If this annotation is present on a method, or
+ * on the method's class (or its superclasses), then it completely
+ * overrides any parameters set in {@link CrossOriginResourceSharingFilter}.
+ * If a particular parameter of this annotation is not specified, then the
+ * default value is used, <em>not</em> the parameters of the filter.
+ *
+ * Note that the CORS specification censors the headers on a
+ * preflight OPTIONS request. As a result, the filter cannot determine
+ * exactly which method corresponds to the request, and so uses only
+ * class-level annotations to set policies.
+ */
+@Target({ElementType.TYPE, ElementType.METHOD })
+@Retention(RetentionPolicy.RUNTIME)
+@Inherited
+public @interface CrossOriginResourceSharing {
+ /**
+ * If true, this resource will return
+ * <pre>Access-Control-Allow-Origin: *</pre>
+ * for a valid request.
+ */
+ boolean allowAllOrigins() default false;
+ /**
+ * A list of permitted origins. This is ignored
+ * if {@link #allowAllOrigins()} is true.
+ */
+ String[] allowOrigins();
+ /**
+ * A list of HTTP methods. This is used only for preflight,
+ * and is only valid on a class.
+ */
+ String[] allowMethods();
+ /**
+ * A list of headers that the client may include
+ * in an actual request.
+ */
+ String[] allowHeaders();
+ /**
+ * If true, this resource will return
+ * <pre>Access-Control-Allow-Credentials: true</pre>
+ */
+ boolean allowCredentials() default false;
+ /**
+ * A list of headers to return in <tt>
+ * Access-Control-Expose-Headers</tt>.
+ */
+ String[] exposeHeaders();
+ /**
+ * The value to return in <tt>Access-Control-Max-Age</tt>.
+ * If this is negative, then no header is returned. The default
+ * value is -1.
+ */
+ int maxAge() default -1;
+ /**
+ * Controls the implementation of preflight processing
+ * on an OPTIONS method.
+ * If the current method is OPTIONS, and this method wants to
+ * handle the preflight process for itself, set this value to
+ * <tt>true</tt>. In the default, false, case, the filter
+ * performs preflight processing.
+ */
+ boolean localPreflight() default false;
+}
Propchange: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/cors/CrossOriginResourceSharing.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/cors/CrossOriginResourceSharing.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/cors/CrossOriginResourceSharingFilter.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/cors/CrossOriginResourceSharingFilter.java?rev=1209182&r1=1209181&r2=1209182&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/cors/CrossOriginResourceSharingFilter.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/cors/CrossOriginResourceSharingFilter.java Thu Dec 1 18:54:10 2011
@@ -22,12 +22,14 @@ package org.apache.cxf.jaxrs.cors;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import java.util.Set;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.ResponseBuilder;
+import org.apache.cxf.common.util.ReflectionUtil;
import org.apache.cxf.jaxrs.ext.RequestHandler;
import org.apache.cxf.jaxrs.ext.ResponseHandler;
import org.apache.cxf.jaxrs.model.ClassResourceInfo;
@@ -35,18 +37,14 @@ import org.apache.cxf.jaxrs.model.Operat
import org.apache.cxf.message.Message;
/**
- * An single class that provides both an input
- * and an output filter for CORS, following http://www.w3.org/TR/cors/.
- * The input examines the input headers. If the request is valid, it stores
- * the information in the Exchange to allow the response handler
- * to add the appropriate headers to the response.
- *
- * If you need complex or subtle control of the behavior here (e.g. clearing
- * the prefight cache) you might be better off reading the source of this
- * and implementing this inside your service.
+ * An single class that provides both an input and an output filter for CORS, following
+ * http://www.w3.org/TR/cors/. The input examines the input headers. If the request is valid, it stores the
+ * information in the Exchange to allow the response handler to add the appropriate headers to the response.
+ * If you need complex or subtle control of the behavior here (e.g. clearing the prefight cache) you might be
+ * better off reading the source of this and implementing this inside your service.
*/
public class CrossOriginResourceSharingFilter implements RequestHandler, ResponseHandler {
-
+
@Context
private HttpHeaders headers;
@@ -54,41 +52,47 @@ public class CrossOriginResourceSharingF
* This would be a rather painful list to maintain for real, since it's entirely dependent on the
* deployment.
*/
- private List<String> allowedOrigins = Collections.emptyList();
- private List<String> allowedMethods = Collections.emptyList();
- private List<String> allowedHeaders = Collections.emptyList();
+ private List<String> allowOrigins = Collections.emptyList();
+ private List<String> allowMethods = Collections.emptyList();
+ private List<String> allowHeaders = Collections.emptyList();
private boolean allowAllOrigins;
-
private boolean allowCredentials;
-
- private List<String> exposeHeaders;
-
+ private List<String> exposeHeaders = Collections.emptyList();
private Integer maxAge;
- public CrossOriginResourceSharingFilter() {
- exposeHeaders = Collections.emptyList();
+ private CrossOriginResourceSharing getAnnotation(OperationResourceInfo ori) {
+ return ReflectionUtil.getAnnotationForMethodOrContainingClass(ori.getAnnotatedMethod(),
+ CrossOriginResourceSharing.class);
}
public Response handleRequest(Message m, ClassResourceInfo resourceClass) {
+ OperationResourceInfo opResInfo = m.getExchange().get(OperationResourceInfo.class);
+ CrossOriginResourceSharing annotation = getAnnotation(opResInfo);
+
if ("OPTIONS".equals(m.get(Message.HTTP_REQUEST_METHOD))) {
- OperationResourceInfo opResInfo = m.getExchange().get(OperationResourceInfo.class);
- if (opResInfo != null) { // OPTIONS method defined in service bean
+ // what if someone wants to use options for something else, and also for preflight?
+ // in that case, they set the localPreflight flag, and we bow out.
+ if (opResInfo != null && (annotation == null || annotation.localPreflight())) {
return null; // continue handling
}
- return preflight(m, resourceClass);
+ return preflightRequest(m, annotation, resourceClass);
}
+ return simpleRequest(m, annotation);
+ }
+
+ private Response simpleRequest(Message m, CrossOriginResourceSharing ann) {
List<String> values = headers.getRequestHeader(CorsHeaderConstants.HEADER_ORIGIN);
// 5.1.1 there has to be an origin
if (values == null || values.size() == 0) {
return null;
}
// 5.1.2 check all the origins
- if (!allowAllOrigins && !allowedOrigins.containsAll(values)) {
+ if (!effectiveAllowAllOrigins(ann) && !effectiveAllowOrigins(ann).containsAll(values)) {
return null;
}
// 5.1.3 credentials lives in the output filter
// in any case
- if (allowAllOrigins) {
+ if (effectiveAllowAllOrigins(ann)) {
m.getExchange().put(CorsHeaderConstants.HEADER_ORIGIN, Arrays.asList(new String[] {
"*"
}));
@@ -97,14 +101,31 @@ public class CrossOriginResourceSharingF
}
// 5.1.4 expose headers lives on the output side.
-
+
// note what kind of processing we're doing.
m.getExchange().put(CrossOriginResourceSharingFilter.class.getName(), "simple");
return null;
}
- private Response preflight(Message m, ClassResourceInfo resourceClass) {
-
+ /**
+ * handle preflight.
+ *
+ * @param m the incoming message.
+ * @param ann the annotation, if any, derived from a method that matched the OPTIONS request for the
+ * preflight. probably completely useless.
+ * @param resourceClass the resource class passed into the filter.
+ * @return
+ */
+ private Response preflightRequest(Message m, CrossOriginResourceSharing optionAnn,
+ ClassResourceInfo resourceClass) {
+ /*
+ * CORS doesn't send enough information with a preflight to accurately identity the single method
+ * that will handle the request. So the code uses annotations from the containing class,
+ * only.
+ */
+ CrossOriginResourceSharing ann
+ = resourceClass.getResourceClass().getAnnotation(CrossOriginResourceSharing.class);
+
List<String> values = headers.getRequestHeader(CorsHeaderConstants.HEADER_ORIGIN);
String origin;
// 5.2.1 -- must have origin, must have one origin.
@@ -113,7 +134,8 @@ public class CrossOriginResourceSharingF
}
origin = values.get(0);
// 5.2.2 must be on the list or we must be matching *.
- if (!allowAllOrigins && !allowedOrigins.contains(origin)) {
+ boolean effectiveAllowAllOrigins = effectiveAllowAllOrigins(ann);
+ if (!effectiveAllowAllOrigins && !effectiveAllowOrigins(ann).contains(origin)) {
return null;
}
@@ -131,17 +153,19 @@ public class CrossOriginResourceSharingF
List<String> requestHeaders = headers.getRequestHeader(CorsHeaderConstants.HEADER_AC_REQUEST_HEADERS);
// 5.2.5 reject if the method is not on the list.
- if (allowedMethods.size() != 0 && !allowedMethods.contains(requestMethod)) {
+ List<String> effectiveAllowMethods = effectiveAllowMethods(ann);
+
+ if (!effectiveAllowMethods.contains(requestMethod)) {
return null;
}
// 5.2.6 reject if the header is not listed.
- if (allowedHeaders.size() != 0 && !allowedHeaders.containsAll(requestHeaders)) {
+ if (!effectiveAllowHeaders(ann).containsAll(requestHeaders)) {
return null;
}
// 5.2.7: add allow credentials and allow-origin as required: this lives in the Output filter
- if (allowAllOrigins) {
+ if (effectiveAllowAllOrigins(ann)) {
m.getExchange().put(CorsHeaderConstants.HEADER_ORIGIN, Arrays.asList(new String[] {
"*"
}));
@@ -160,119 +184,202 @@ public class CrossOriginResourceSharingF
return Response.ok().build();
}
- /**
- * The origin strings to allow. Call {@link #setAllowAllOrigins(boolean)} to enable '*'.
- * @param allowedOrigins a list of case-sensitive origin strings.
- */
- public void setAllowedOrigins(List<String> allowedOrigins) {
- this.allowedOrigins = allowedOrigins;
- }
-
- public List<String> getAllowedOrigins() {
- return allowedOrigins;
- }
-
- /**
- * Whether to implement Access-Control-Allow-Origin: *
- * @param allowAllOrigins if true, all origins are accepted and * is returned in the header.
- * Sections 5.1.1 and 5.1.2, and 5.2.1 and 5.2.2.
- * If false, then the list of allowed origins must be
- */
- public void setAllowAllOrigins(boolean allowAllOrigins) {
- this.allowAllOrigins = allowAllOrigins;
- }
-
- public List<String> getAllowedMethods() {
- return allowedMethods;
- }
-
- /**
- * The list of allowed non-simple methods for preflight checks.
- * Section 5.2.3.
- * @param allowedMethods a list of case-sensitive HTTP method names.
- */
- public void setAllowedMethods(List<String> allowedMethods) {
- this.allowedMethods = allowedMethods;
- }
-
- public List<String> getAllowedHeaders() {
- return allowedHeaders;
- }
-
- /**
- * The list of allowed headers for preflight checks.
- * Section 5.2.6
- * @param allowedHeaders a list of permitted headers.
- */
- public void setAllowedHeaders(List<String> allowedHeaders) {
- this.allowedHeaders = allowedHeaders;
- }
-
- public List<String> getExposeHeaders() {
- return exposeHeaders;
- }
-
- public Integer getMaxAge() {
- return maxAge;
- }
-
public Response handleResponse(Message m, OperationResourceInfo ori, Response response) {
String op = (String)m.getExchange().get(CrossOriginResourceSharingFilter.class.getName());
if (op == null) {
return response; // we're not here.
}
+ CrossOriginResourceSharing annotation;
+
List<String> originHeader = getHeadersFromInput(m, CorsHeaderConstants.HEADER_ORIGIN);
ResponseBuilder rbuilder = Response.fromResponse(response);
if ("simple".equals(op)) {
+ annotation = getAnnotation(ori);
// 5.1.3: add Allow-Origin supplied from the input side, plus allow-credentials as requested
addHeaders(rbuilder, CorsHeaderConstants.HEADER_AC_ALLOW_ORIGIN, originHeader);
- rbuilder.header(CorsHeaderConstants.HEADER_AC_ALLOW_CREDENTIALS,
- Boolean.toString(allowCredentials));
+ rbuilder.header(CorsHeaderConstants.HEADER_AC_ALLOW_CREDENTIALS,
+ Boolean.toString(effectiveAllowCredentials(annotation)));
// 5.1.4 add allowed headers
- List<String> rqAllowedHeaders
- = getHeadersFromInput(m, CorsHeaderConstants.HEADER_AC_ALLOW_METHODS);
+ List<String> rqAllowedHeaders = getHeadersFromInput(m,
+ CorsHeaderConstants.HEADER_AC_ALLOW_HEADERS);
if (rqAllowedHeaders != null) {
addHeaders(rbuilder, CorsHeaderConstants.HEADER_AC_ALLOW_METHODS, rqAllowedHeaders);
}
- if (exposeHeaders.size() > 0) {
- addHeaders(rbuilder, CorsHeaderConstants.HEADER_AC_EXPOSE_HEADERS, exposeHeaders);
+
+ List<String> effectiveExposeHeaders = effectiveExposeHeaders(annotation);
+ if (effectiveExposeHeaders.size() > 0) {
+ addHeaders(rbuilder, CorsHeaderConstants.HEADER_AC_EXPOSE_HEADERS, effectiveExposeHeaders);
}
// if someone wants to clear the cache, we can't help them.
return rbuilder.build();
} else {
+ annotation = ori.getAnnotatedMethod().getDeclaringClass()
+ .getAnnotation(CrossOriginResourceSharing.class);
// preflight
// 5.2.7 add Allow-Origin supplied from the input side, plus allow-credentials as requested
addHeaders(rbuilder, CorsHeaderConstants.HEADER_AC_ALLOW_ORIGIN, originHeader);
- rbuilder.header(CorsHeaderConstants.HEADER_AC_ALLOW_CREDENTIALS,
- Boolean.toString(allowCredentials));
+ rbuilder.header(CorsHeaderConstants.HEADER_AC_ALLOW_CREDENTIALS,
+ Boolean.toString(allowCredentials));
// 5.2.8 max-age
- if (maxAge != null) {
- rbuilder.header(CorsHeaderConstants.HEADER_AC_MAX_AGE, maxAge.toString());
+ if (effectiveMaxAge(annotation) != null) {
+ rbuilder.header(CorsHeaderConstants.HEADER_AC_MAX_AGE,
+ effectiveMaxAge(annotation).toString());
}
// 5.2.9 add allowed methods
/*
* Currently, input side just lists the one requested method, and spec endorses that.
*/
- addHeaders(rbuilder, CorsHeaderConstants.HEADER_AC_ALLOW_METHODS,
- getHeadersFromInput(m, CorsHeaderConstants.HEADER_AC_ALLOW_METHODS));
+ addHeaders(rbuilder, CorsHeaderConstants.HEADER_AC_ALLOW_METHODS,
+ getHeadersFromInput(m, CorsHeaderConstants.HEADER_AC_ALLOW_METHODS));
// 5.2.10 add allowed headers
- List<String> rqAllowedHeaders
- = getHeadersFromInput(m, CorsHeaderConstants.HEADER_AC_ALLOW_HEADERS);
+ List<String> rqAllowedHeaders = getHeadersFromInput(m,
+ CorsHeaderConstants.HEADER_AC_ALLOW_HEADERS);
if (rqAllowedHeaders != null) {
addHeaders(rbuilder, CorsHeaderConstants.HEADER_AC_ALLOW_HEADERS, rqAllowedHeaders);
}
return rbuilder.build();
-
+
+ }
+ }
+
+ private boolean effectiveAllowAllOrigins(CrossOriginResourceSharing ann) {
+ if (ann != null) {
+ return ann.allowAllOrigins();
+ } else {
+ return allowAllOrigins;
+ }
+ }
+
+ private boolean effectiveAllowCredentials(CrossOriginResourceSharing ann) {
+ if (ann != null) {
+ return ann.allowCredentials();
+ } else {
+ return allowCredentials;
+ }
+ }
+
+ private List<String> effectiveAllowOrigins(CrossOriginResourceSharing ann) {
+ if (ann != null) {
+ if (ann.allowOrigins() == null) {
+ return Collections.emptyList();
+ }
+ return Arrays.asList(ann.allowOrigins());
+ } else {
+ return allowOrigins;
+ }
+ }
+
+ private List<String> effectiveAllowMethods(CrossOriginResourceSharing ann) {
+ if (ann != null) {
+ if (ann.allowMethods() == null) {
+ return Collections.emptyList();
+ }
+ return Arrays.asList(ann.allowMethods());
+ } else {
+ return allowMethods;
+ }
+ }
+
+ private List<String> effectiveAllowHeaders(CrossOriginResourceSharing ann) {
+ if (ann != null) {
+ if (ann.allowHeaders() == null) {
+ return Collections.emptyList();
+ }
+ return Arrays.asList(ann.allowHeaders());
+ } else {
+ return allowHeaders;
}
}
+ private List<String> effectiveExposeHeaders(CrossOriginResourceSharing ann) {
+ if (ann != null) {
+ if (ann.exposeHeaders() == null) {
+ return Collections.emptyList();
+ }
+ return Arrays.asList(ann.exposeHeaders());
+ } else {
+ return exposeHeaders;
+ }
+ }
+
+ private Integer effectiveMaxAge(CrossOriginResourceSharing ann) {
+ if (ann != null) {
+ int ma = ann.maxAge();
+ if (ma < 0) {
+ return null;
+ } else {
+ return Integer.valueOf(ma);
+ }
+ } else {
+ return maxAge;
+ }
+ }
+
+ /**
+ * The origin strings to allow. Call {@link #setAllowAllOrigins(boolean)} to enable '*'.
+ *
+ * @param allowedOrigins a list of case-sensitive origin strings.
+ */
+ public void setAllowOrigins(List<String> allowedOrigins) {
+ this.allowOrigins = allowedOrigins;
+ }
+
+ public List<String> getAllowOrigins() {
+ return allowOrigins;
+ }
+
+ /**
+ * Whether to implement Access-Control-Allow-Origin: *
+ *
+ * @param allowAllOrigins if true, all origins are accepted and * is returned in the header. Sections
+ * 5.1.1 and 5.1.2, and 5.2.1 and 5.2.2. If false, then the list of allowed origins must be
+ */
+ public void setAllowAllOrigins(boolean allowAllOrigins) {
+ this.allowAllOrigins = allowAllOrigins;
+ }
+
+ public List<String> getAllowMethods() {
+ return allowMethods;
+ }
+
+ /**
+ * The list of allowed non-simple methods for preflight checks. Section 5.2.3.
+ *
+ * @param allowedMethods a list of case-sensitive HTTP method names.
+ */
+ public void setAllowMethods(List<String> allowedMethods) {
+ this.allowMethods = allowedMethods;
+ }
+
+ public List<String> getAllowHeaders() {
+ return allowHeaders;
+ }
+
+ /**
+ * The list of allowed headers for preflight checks. Section 5.2.6
+ *
+ * @param allowedHeaders a list of permitted headers.
+ */
+ public void setAllowHeaders(List<String> allowedHeaders) {
+ this.allowHeaders = allowedHeaders;
+ }
+
+ public List<String> getExposeHeaders() {
+ return exposeHeaders;
+ }
+
+ public Integer getMaxAge() {
+ return maxAge;
+ }
+
public boolean isAllowCredentials() {
return allowCredentials;
}
/**
- * The value for the Access-Control-Allow-Credentials header. If false, no header is added.
- * If true, the header is added with the value 'true'.
+ * The value for the Access-Control-Allow-Credentials header. If false, no header is added. If true, the
+ * header is added with the value 'true'.
+ *
* @param allowCredentials
*/
public void setAllowCredentials(boolean allowCredentials) {
@@ -281,6 +388,7 @@ public class CrossOriginResourceSharingF
/**
* A list of non-simple headers to be exposed via Access-Control-Expose-Headers.
+ *
* @param exposeHeaders the list of (case-sensitive) header names.
*/
public void setExposeHeaders(List<String> exposeHeaders) {
@@ -289,6 +397,7 @@ public class CrossOriginResourceSharingF
/**
* The value for Access-Control-Max-Age.
+ *
* @param maxAge An integer 'delta-seconds' or null. If null, no header is added.
*/
public void setMaxAge(Integer maxAge) {
Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/model/wadl/Description.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/model/wadl/Description.java?rev=1209182&r1=1209181&r2=1209182&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/model/wadl/Description.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/model/wadl/Description.java Thu Dec 1 18:54:10 2011
@@ -27,7 +27,7 @@ import java.lang.annotation.Target;
/**
* Can be used to document resource classes and methods
*
- * See {@link <a href="http://www.w3.org/Submission/wadl/#x3-80002.3">WADL Documentation</a>}.
+ * See <a href="http://www.w3.org/Submission/wadl/#x3-80002.3">WADL Documentation</a>.
*/
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/AnnotationUtils.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/AnnotationUtils.java?rev=1209182&r1=1209181&r2=1209182&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/AnnotationUtils.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/AnnotationUtils.java Thu Dec 1 18:54:10 2011
@@ -55,7 +55,7 @@ import org.apache.cxf.common.logging.Log
import org.apache.cxf.jaxrs.ext.MessageContext;
public final class AnnotationUtils {
-
+
private static final Logger LOG = LogUtils.getL7dLogger(AnnotationUtils.class);
private static final ResourceBundle BUNDLE = BundleUtils.getBundle(AnnotationUtils.class);
@@ -67,13 +67,12 @@ public final class AnnotationUtils {
PARAM_ANNOTATION_CLASSES = initParamAnnotationClasses();
METHOD_ANNOTATION_CLASSES = initMethodAnnotationClasses();
}
-
-
+
private AnnotationUtils() {
-
+
}
-
- private static Set<Class> initContextClasses() {
+
+ private static Set<Class> initContextClasses() {
Set<Class> classes = new HashSet<Class>();
classes.add(UriInfo.class);
classes.add(SecurityContext.class);
@@ -90,17 +89,16 @@ public final class AnnotationUtils {
classes.add(ServletContext.class);
} catch (Throwable ex) {
// it is not a problem on the client side and the exception will be
- // thrown later on if the injection of one of these contexts will be
+ // thrown later on if the injection of one of these contexts will be
// attempted on the server side
- LOG.fine(new org.apache.cxf.common.i18n.Message("NO_SERVLET_API",
- BUNDLE).toString());
+ LOG.fine(new org.apache.cxf.common.i18n.Message("NO_SERVLET_API", BUNDLE).toString());
}
// CXF-specific
classes.add(MessageContext.class);
return classes;
}
-
- private static Set<Class> initParamAnnotationClasses() {
+
+ private static Set<Class> initParamAnnotationClasses() {
Set<Class> classes = new HashSet<Class>();
classes.add(PathParam.class);
classes.add(QueryParam.class);
@@ -110,8 +108,8 @@ public final class AnnotationUtils {
classes.add(FormParam.class);
return classes;
}
-
- private static Set<Class> initMethodAnnotationClasses() {
+
+ private static Set<Class> initMethodAnnotationClasses() {
Set<Class> classes = new HashSet<Class>();
classes.add(HttpMethod.class);
classes.add(Path.class);
@@ -119,20 +117,19 @@ public final class AnnotationUtils {
classes.add(Consumes.class);
return classes;
}
-
- public static boolean isContextClass(Class<?> contextClass) {
+
+ public static boolean isContextClass(Class<?> contextClass) {
return CONTEXT_CLASSES.contains(contextClass);
}
-
- public static boolean isParamAnnotationClass(Class<?> annotationClass) {
+
+ public static boolean isParamAnnotationClass(Class<?> annotationClass) {
return PARAM_ANNOTATION_CLASSES.contains(annotationClass);
}
-
- public static boolean isValidParamAnnotationClass(Class<?> annotationClass) {
- return PARAM_ANNOTATION_CLASSES.contains(annotationClass)
- || Context.class == annotationClass;
+
+ public static boolean isValidParamAnnotationClass(Class<?> annotationClass) {
+ return PARAM_ANNOTATION_CLASSES.contains(annotationClass) || Context.class == annotationClass;
}
-
+
public static boolean isValidParamAnnotations(Annotation[] paramAnnotations) {
for (Annotation a : paramAnnotations) {
if (AnnotationUtils.isValidParamAnnotationClass(a.annotationType())) {
@@ -141,12 +138,12 @@ public final class AnnotationUtils {
}
return false;
}
-
- public static boolean isMethodAnnotation(Annotation a) {
+
+ public static boolean isMethodAnnotation(Annotation a) {
return METHOD_ANNOTATION_CLASSES.contains(a.annotationType())
|| a.annotationType().getAnnotation(HttpMethod.class) != null;
}
-
+
public static String getAnnotationValue(Annotation a) {
String value = null;
if (a.annotationType() == PathParam.class) {
@@ -164,41 +161,41 @@ public final class AnnotationUtils {
}
return value;
}
-
- public static <T> T getAnnotation(Annotation[] anns, Class<T> type) {
+
+ public static <T> T getAnnotation(Annotation[] anns, Class<T> type) {
if (anns == null) {
return null;
}
- for (Annotation a : anns) {
+ for (Annotation a : anns) {
if (a.annotationType() == type) {
return type.cast(a);
}
}
return null;
}
-
+
public static Method getAnnotatedMethod(Method m) {
Method annotatedMethod = doGetAnnotatedMethod(m);
return annotatedMethod == null ? m : annotatedMethod;
}
-
+
private static Method doGetAnnotatedMethod(Method m) {
-
+
if (m == null) {
return m;
}
-
+
for (Annotation a : m.getAnnotations()) {
if (AnnotationUtils.isMethodAnnotation(a)) {
return m;
- }
+ }
}
for (Annotation[] paramAnnotations : m.getParameterAnnotations()) {
if (isValidParamAnnotations(paramAnnotations)) {
return m;
}
}
-
+
Class<?> superC = m.getDeclaringClass().getSuperclass();
if (superC != null && Object.class != superC) {
try {
@@ -220,12 +217,10 @@ public final class AnnotationUtils {
// ignore
}
}
-
+
return null;
}
-
-
-
+
public static String getHttpMethodValue(Method m) {
for (Annotation a : m.getAnnotations()) {
HttpMethod httpM = a.annotationType().getAnnotation(HttpMethod.class);
@@ -235,14 +230,12 @@ public final class AnnotationUtils {
}
return null;
}
-
- public static <A extends Annotation> A getMethodAnnotation(Method m,
- Class<A> aClass) {
+
+ public static <A extends Annotation> A getMethodAnnotation(Method m, Class<A> aClass) {
return m == null ? null : m.getAnnotation(aClass);
}
-
- public static <A extends Annotation> A getClassAnnotation(Class<?> c,
- Class<A> aClass) {
+
+ public static <A extends Annotation> A getClassAnnotation(Class<?> c, Class<A> aClass) {
if (c == null) {
return null;
}
@@ -250,12 +243,12 @@ public final class AnnotationUtils {
if (p != null) {
return p;
}
-
+
p = getClassAnnotation(c.getSuperclass(), aClass);
if (p != null) {
return p;
}
-
+
// finally try the first one on the interface
for (Class<?> i : c.getInterfaces()) {
p = getClassAnnotation(i, aClass);
@@ -265,11 +258,11 @@ public final class AnnotationUtils {
}
return null;
}
-
+
public static String getDefaultParameterValue(Annotation[] anns) {
-
+
DefaultValue dv = AnnotationUtils.getAnnotation(anns, DefaultValue.class);
return dv != null ? dv.value() : null;
-
}
+
}
Modified: cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/cors/BasicCrossOriginTest.java
URL: http://svn.apache.org/viewvc/cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/cors/BasicCrossOriginTest.java?rev=1209182&r1=1209181&r2=1209182&view=diff
==============================================================================
--- cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/cors/BasicCrossOriginTest.java (original)
+++ cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/cors/BasicCrossOriginTest.java Thu Dec 1 18:54:10 2011
@@ -29,6 +29,7 @@ import org.apache.cxf.jaxrs.cors.CorsHea
import org.apache.cxf.systest.jaxrs.AbstractSpringServer;
import org.apache.cxf.testutil.common.AbstractBusClientServerTestBase;
import org.apache.http.Header;
+import org.apache.http.HeaderElement;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
@@ -73,6 +74,16 @@ public class BasicCrossOriginTest extend
assertEquals(1, aaoHeaders.length);
assertEquals("*", aaoHeaders[0].getValue());
}
+
+ private List<String> headerValues(Header[] headers) {
+ List<String> values = new ArrayList<String>();
+ for (Header h : headers) {
+ for (HeaderElement e : h.getElements()) {
+ values.add(e.getName());
+ }
+ }
+ return values;
+ }
private void assertAllOrigin(boolean allOrigins, String[] originList, String[] requestOrigins,
boolean permitted) throws ClientProtocolException, IOException {
@@ -103,9 +114,10 @@ public class BasicCrossOriginTest extend
assertEquals(1, aaoHeaders.length);
assertEquals("*", aaoHeaders[0].getValue());
} else {
- assertEquals(requestOrigins.length, aaoHeaders.length);
+ List<String> ovalues = headerValues(aaoHeaders);
+ assertEquals(requestOrigins.length, ovalues.size());
for (int x = 0; x < requestOrigins.length; x++) {
- assertEquals(requestOrigins[x], aaoHeaders[x].getValue());
+ assertEquals(requestOrigins[x], ovalues.get(x));
}
}
} else {
@@ -158,7 +170,6 @@ public class BasicCrossOriginTest extend
}, true);
}
- @org.junit.Ignore
@Test
public void allowTwoPassTwo() throws Exception {
// allow two, pass two
Modified: cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/cors/ConfigServer.java
URL: http://svn.apache.org/viewvc/cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/cors/ConfigServer.java?rev=1209182&r1=1209181&r2=1209182&view=diff
==============================================================================
--- cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/cors/ConfigServer.java (original)
+++ cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/cors/ConfigServer.java Thu Dec 1 18:54:10 2011
@@ -43,7 +43,7 @@ public class ConfigServer {
inputFilter.setAllowAllOrigins(true);
} else {
inputFilter.setAllowAllOrigins(false);
- inputFilter.setAllowedOrigins(Arrays.asList(origins));
+ inputFilter.setAllowOrigins(Arrays.asList(origins));
}
return "ok";
}