You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wink.apache.org by ro...@apache.org on 2010/04/22 17:53:19 UTC
svn commit: r936913 - in /incubator/wink/trunk: wink-common/
wink-common/src/main/java/org/apache/wink/common/internal/contexts/
wink-common/src/main/java/org/apache/wink/common/internal/utils/
wink-common/src/test/java/org/apache/wink/common/internal/...
Author: rott
Date: Thu Apr 22 15:53:19 2010
New Revision: 936913
URL: http://svn.apache.org/viewvc?rev=936913&view=rev
Log:
WINK-262: followup for perf improvements, make default response Content-Type header charset attribute concatenation behavior configurable
Added:
incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/contexts/MediaTypeCharsetAdjuster.java
incubator/wink/trunk/wink-server/src/main/java/org/apache/wink/server/internal/contexts/ServerMediaTypeCharsetAdjuster.java
incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/contexts/ServerMediaTypeCharsetAdjusterTest.java
Modified:
incubator/wink/trunk/wink-common/pom.xml
incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/utils/MediaTypeUtils.java
incubator/wink/trunk/wink-common/src/test/java/org/apache/wink/common/internal/providers/jaxb/ProvidersJAXBTest.java
incubator/wink/trunk/wink-server/pom.xml
incubator/wink/trunk/wink-server/src/main/java/org/apache/wink/server/internal/DeploymentConfiguration.java
incubator/wink/trunk/wink-server/src/main/java/org/apache/wink/server/internal/handlers/FlushResultHandler.java
incubator/wink/trunk/wink-server/src/main/java/org/apache/wink/server/internal/handlers/ServerMessageContext.java
incubator/wink/trunk/wink-server/src/main/resources/META-INF/wink-default.properties
Modified: incubator/wink/trunk/wink-common/pom.xml
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-common/pom.xml?rev=936913&r1=936912&r2=936913&view=diff
==============================================================================
--- incubator/wink/trunk/wink-common/pom.xml (original)
+++ incubator/wink/trunk/wink-common/pom.xml Thu Apr 22 15:53:19 2010
@@ -69,6 +69,12 @@
<groupId>javax.ws.rs</groupId>
<artifactId>jsr311-api</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.jmock</groupId>
+ <artifactId>jmock-junit3</artifactId>
+ <version>2.5.1</version>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<build>
<plugins>
Added: incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/contexts/MediaTypeCharsetAdjuster.java
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/contexts/MediaTypeCharsetAdjuster.java?rev=936913&view=auto
==============================================================================
--- incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/contexts/MediaTypeCharsetAdjuster.java (added)
+++ incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/contexts/MediaTypeCharsetAdjuster.java Thu Apr 22 15:53:19 2010
@@ -0,0 +1,29 @@
+/*
+ * 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.wink.common.internal.contexts;
+
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+
+public interface MediaTypeCharsetAdjuster {
+
+ public MediaType setDefaultCharsetOnMediaTypeHeader(MultivaluedMap<String, Object> httpHeaders,
+ MediaType mediaType);
+}
Modified: incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/utils/MediaTypeUtils.java
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/utils/MediaTypeUtils.java?rev=936913&r1=936912&r2=936913&view=diff
==============================================================================
--- incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/utils/MediaTypeUtils.java (original)
+++ incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/utils/MediaTypeUtils.java Thu Apr 22 15:53:19 2010
@@ -24,14 +24,13 @@ import java.util.Comparator;
import java.util.LinkedHashSet;
import java.util.Set;
-import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import org.apache.wink.common.RuntimeContext;
+import org.apache.wink.common.internal.contexts.MediaTypeCharsetAdjuster;
import org.apache.wink.common.internal.runtime.RuntimeContextTLS;
import org.apache.wink.common.internal.uri.UriEncoder;
-import org.apache.wink.common.utils.ProviderUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -256,33 +255,14 @@ public class MediaTypeUtils {
*/
public static MediaType setDefaultCharsetOnMediaTypeHeader(MultivaluedMap<String, Object> httpHeaders,
MediaType mediaType) {
- logger.debug("setDefaultCharsetOnMediaTypeHeader({}, {}) entry", httpHeaders, mediaType); //$NON-NLS-1$
-
- if (httpHeaders != null && httpHeaders.get(HttpHeaders.CONTENT_TYPE) == null) {
- // only correct the MediaType if the MediaType was not explicitly
- // set
- logger
- .debug("Media Type not explicitly set on Response so going to correct charset parameter if necessary"); //$NON-NLS-1$
- if (ProviderUtils.getCharsetOrNull(mediaType) == null) { //$NON-NLS-1$
- try {
- RuntimeContext context = RuntimeContextTLS.getRuntimeContext();
- HttpHeaders requestHeaders = null;
- if (context != null) {
- requestHeaders = context.getHttpHeaders();
- }
- String charsetValue = ProviderUtils.getCharset(mediaType, requestHeaders);
- String newMediaTypeStr = mediaType.toString() + ";charset=" + charsetValue;
- mediaType = MediaType.valueOf(newMediaTypeStr);
- httpHeaders.putSingle(HttpHeaders.CONTENT_TYPE, newMediaTypeStr); //$NON-NLS-1$
- logger
- .debug("Changed media type to be {} in Content-Type HttpHeader", newMediaTypeStr); //$NON-NLS-1$
- } catch (Exception e) {
- logger.debug("Caught exception while trying to set the charset", e); //$NON-NLS-1$
- }
+ RuntimeContext context = RuntimeContextTLS.getRuntimeContext();
+ MediaTypeCharsetAdjuster adjuster = null;
+ if (context != null) {
+ adjuster = context.getAttribute(MediaTypeCharsetAdjuster.class);
+ if (adjuster != null) {
+ return adjuster.setDefaultCharsetOnMediaTypeHeader(httpHeaders, mediaType);
}
}
-
- logger.debug("setDefaultCharsetOnMediaTypeHeader() exit returning {}", mediaType); //$NON-NLS-1$
return mediaType;
}
Modified: incubator/wink/trunk/wink-common/src/test/java/org/apache/wink/common/internal/providers/jaxb/ProvidersJAXBTest.java
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-common/src/test/java/org/apache/wink/common/internal/providers/jaxb/ProvidersJAXBTest.java?rev=936913&r1=936912&r2=936913&view=diff
==============================================================================
--- incubator/wink/trunk/wink-common/src/test/java/org/apache/wink/common/internal/providers/jaxb/ProvidersJAXBTest.java (original)
+++ incubator/wink/trunk/wink-common/src/test/java/org/apache/wink/common/internal/providers/jaxb/ProvidersJAXBTest.java Thu Apr 22 15:53:19 2010
@@ -19,24 +19,39 @@
*******************************************************************************/
package org.apache.wink.common.internal.providers.jaxb;
-import static org.junit.Assert.assertTrue;
-
import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.MessageBodyReader;
+import javax.ws.rs.ext.MessageBodyWriter;
+import javax.ws.rs.ext.Providers;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
+import org.apache.wink.common.internal.CaseInsensitiveMultivaluedMap;
import org.apache.wink.common.internal.providers.entity.xml.JAXBXmlProvider;
import org.apache.wink.common.internal.providers.jaxb.jaxb1.AddNumbers;
+import org.apache.wink.common.model.JAXBUnmarshalOptions;
+import org.apache.wink.common.model.XmlFormattingOptions;
+import org.jmock.Expectations;
+import org.jmock.integration.junit3.MockObjectTestCase;
import org.junit.Before;
import org.junit.Test;
-public class ProvidersJAXBTest {
+public class ProvidersJAXBTest extends MockObjectTestCase {
public class MyJAXBXmlProvider extends JAXBXmlProvider {
+ MyJAXBXmlProvider() {
+ super();
+ providers = ProvidersJAXBTest.this.providers;
+ }
+
/*
* simulate what would happen if application had supplied a JAXBContext provider
*/
@@ -55,19 +70,66 @@ public class ProvidersJAXBTest {
"<arg1>2</arg1>" +
"</ns2:addNumbers>";
- private MessageBodyReader jaxbProvider = null;
+ static final String expectedXml = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>" +
+ "<addNumbers xmlns=\"http://org/apache/wink/common/internal/providers/jaxb/jaxb1\">" +
+ "<arg0>0</arg0>" +
+ "<arg1>0</arg1>" +
+ "</addNumbers>";
+
+ private MessageBodyReader jaxbProviderReader = null;
+ private MessageBodyWriter jaxbProviderWriter = null;
+ private Providers providers;
@Before
public void setUp() {
- jaxbProvider = new MyJAXBXmlProvider();
+ providers = mock(Providers.class);
+ checking(new Expectations() {{
+ allowing(providers).getContextResolver(JAXBContext.class, MediaType.TEXT_XML_TYPE); will(returnValue(new MyJAXBContextResolver()));
+ allowing(providers).getContextResolver(XmlFormattingOptions.class, MediaType.TEXT_XML_TYPE); will(returnValue(null));
+ allowing(providers).getContextResolver(JAXBUnmarshalOptions.class, MediaType.TEXT_XML_TYPE); will(returnValue(null));
+ }});
+ jaxbProviderReader = new MyJAXBXmlProvider();
+ jaxbProviderWriter = new MyJAXBXmlProvider();
}
@Test
public void testJAXBUnmarshallingWithAlternateContext1() throws Exception {
- assertTrue(jaxbProvider.isReadable(AddNumbers.class, null, null, MediaType.TEXT_XML_TYPE));
+ assertTrue(jaxbProviderReader.isReadable(AddNumbers.class, null, null, MediaType.TEXT_XML_TYPE));
ByteArrayInputStream bais = new ByteArrayInputStream(xml.getBytes());
- Object obj = jaxbProvider.readFrom(AddNumbers.class, null, null, MediaType.TEXT_XML_TYPE, null, bais);
+ Object obj = jaxbProviderReader.readFrom(AddNumbers.class, null, null, MediaType.TEXT_XML_TYPE, null, bais);
assertTrue(obj instanceof AddNumbers);
}
+ public class MyJAXBContextResolver implements ContextResolver<JAXBContext> {
+
+ public JAXBContext getContext(Class<?> arg0) {
+ try {
+ return JAXBContext.newInstance(arg0);
+ } catch (JAXBException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void testJAXBMarshalling() throws WebApplicationException, IOException {
+ assertTrue(jaxbProviderWriter.isWriteable(AddNumbers.class, null, null, MediaType.TEXT_XML_TYPE));
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ jaxbProviderWriter.writeTo(new AddNumbers(), AddNumbers.class, null, null, MediaType.TEXT_XML_TYPE, null, baos);
+ assertEquals(expectedXml, baos.toString());
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void testJAXBMarshallingWithMap() throws WebApplicationException, IOException {
+ assertTrue(jaxbProviderWriter.isWriteable(AddNumbers.class, null, null, MediaType.TEXT_XML_TYPE));
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ MultivaluedMap map = new CaseInsensitiveMultivaluedMap<Object>();
+ jaxbProviderWriter.writeTo(new AddNumbers(), AddNumbers.class, null, null, MediaType.TEXT_XML_TYPE, map, baos);
+ assertEquals(expectedXml, baos.toString());
+ }
+
+
}
Modified: incubator/wink/trunk/wink-server/pom.xml
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-server/pom.xml?rev=936913&r1=936912&r2=936913&view=diff
==============================================================================
--- incubator/wink/trunk/wink-server/pom.xml (original)
+++ incubator/wink/trunk/wink-server/pom.xml Thu Apr 22 15:53:19 2010
@@ -100,6 +100,12 @@
<version>3.2.1</version>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.jmock</groupId>
+ <artifactId>jmock-junit3</artifactId>
+ <version>2.5.1</version>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<build>
<plugins>
Modified: incubator/wink/trunk/wink-server/src/main/java/org/apache/wink/server/internal/DeploymentConfiguration.java
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-server/src/main/java/org/apache/wink/server/internal/DeploymentConfiguration.java?rev=936913&r1=936912&r2=936913&view=diff
==============================================================================
--- incubator/wink/trunk/wink-server/src/main/java/org/apache/wink/server/internal/DeploymentConfiguration.java (original)
+++ incubator/wink/trunk/wink-server/src/main/java/org/apache/wink/server/internal/DeploymentConfiguration.java Thu Apr 22 15:53:19 2010
@@ -92,6 +92,10 @@ public class DeploymentConfiguration {
"wink.mediaTypeMapperFactoryClass"; //$NON-NLS-1$
private static final String VALIDATE_LOCATION_HEADER =
"wink.validateLocationHeader"; //$NON-NLS-1$
+ private static final String DEFAULT_RESPONSE_CHARSET =
+ "wink.response.defaultCharset"; // $NON-NLS-1$
+ private static final String USE_ACCEPT_CHARSET =
+ "wink.response.useAcceptCharset"; // $NON-NLS-1$
// handler chains
private RequestHandlersChain requestHandlersChain;
private ResponseHandlersChain responseHandlersChain;
@@ -557,5 +561,34 @@ public class DeploymentConfiguration {
public String[] getHttpMethodOverrideHeaders() {
return httpMethodOverrideHeaders;
}
+
+ /**
+ * isDefaultResponseCharset will write charset=UTF-8 to the response Content-Type header if a response
+ * charset is not already explicitly defined.
+ * @return boolean
+ */
+ public boolean isDefaultResponseCharset() {
+ String val = properties.getProperty(DEFAULT_RESPONSE_CHARSET);
+ return Boolean.valueOf(val).booleanValue();
+ }
+
+ public void setDefaultResponseCharset(boolean val) {
+ properties.setProperty(DEFAULT_RESPONSE_CHARSET, Boolean.toString(val));
+ }
+
+ /**
+ * isUseAcceptCharset will use the Accept-Charset header, if present, to write a charset to the response Content-Type
+ * header if a response charset is not already explicitly defined. This setting will override the isDefaultResponseCharset
+ * setting when the Accept-Charset header is present.
+ * @return
+ */
+ public boolean isUseAcceptCharset() {
+ String val = properties.getProperty(USE_ACCEPT_CHARSET);
+ return Boolean.valueOf(val).booleanValue();
+ }
+
+ public void setUseAcceptCharset(boolean val) {
+ properties.setProperty(USE_ACCEPT_CHARSET, Boolean.toString(val));
+ }
}
Added: incubator/wink/trunk/wink-server/src/main/java/org/apache/wink/server/internal/contexts/ServerMediaTypeCharsetAdjuster.java
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-server/src/main/java/org/apache/wink/server/internal/contexts/ServerMediaTypeCharsetAdjuster.java?rev=936913&view=auto
==============================================================================
--- incubator/wink/trunk/wink-server/src/main/java/org/apache/wink/server/internal/contexts/ServerMediaTypeCharsetAdjuster.java (added)
+++ incubator/wink/trunk/wink-server/src/main/java/org/apache/wink/server/internal/contexts/ServerMediaTypeCharsetAdjuster.java Thu Apr 22 15:53:19 2010
@@ -0,0 +1,96 @@
+/*
+ * 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.wink.server.internal.contexts;
+
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+
+import org.apache.wink.common.RuntimeContext;
+import org.apache.wink.common.internal.contexts.MediaTypeCharsetAdjuster;
+import org.apache.wink.common.internal.runtime.RuntimeContextTLS;
+import org.apache.wink.common.utils.ProviderUtils;
+import org.apache.wink.server.internal.DeploymentConfiguration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ServerMediaTypeCharsetAdjuster implements MediaTypeCharsetAdjuster {
+
+ final private static ServerMediaTypeCharsetAdjuster instance =
+ new ServerMediaTypeCharsetAdjuster();
+ // enforce singleton
+ private ServerMediaTypeCharsetAdjuster() {
+ }
+
+ public static ServerMediaTypeCharsetAdjuster getInstance() {
+ return instance;
+ }
+
+ private static final Logger logger =
+ LoggerFactory
+ .getLogger(ServerMediaTypeCharsetAdjuster.class);
+
+ public MediaType setDefaultCharsetOnMediaTypeHeader(MultivaluedMap<String, Object> httpHeaders,
+ MediaType mediaType) {
+ logger.debug("setDefaultCharsetOnMediaTypeHeader({}, {}) entry", httpHeaders, mediaType); //$NON-NLS-1$
+
+ RuntimeContext context = RuntimeContextTLS.getRuntimeContext();
+ DeploymentConfiguration config = context.getAttribute(DeploymentConfiguration.class);
+ if (config.isDefaultResponseCharset() || config.isUseAcceptCharset()) {
+ if (httpHeaders != null && (httpHeaders.isEmpty() || httpHeaders
+ .get(HttpHeaders.CONTENT_TYPE) == null)) {
+ // only correct the MediaType if the MediaType was not explicitly
+ // set
+ logger.debug("Media Type not explicitly set on Response so going to correct charset parameter if necessary"); //$NON-NLS-1$
+ if (ProviderUtils.getCharsetOrNull(mediaType) == null) { //$NON-NLS-1$
+ try {
+ String charsetValue = "UTF-8";
+ if (config.isUseAcceptCharset()) {
+ // configuration says to inspect and use the Accept-Charset header to determine response charset
+ HttpHeaders requestHeaders = null;
+ if (context != null) {
+ requestHeaders = context.getHttpHeaders();
+ }
+ charsetValue = ProviderUtils.getCharset(mediaType, requestHeaders);
+ }
+ String newMediaTypeStr = mediaType.toString() + ";charset=" + charsetValue;
+ mediaType = MediaType.valueOf(newMediaTypeStr);
+ if (context != null) {
+ HttpServletResponse response =
+ context.getAttribute(HttpServletResponse.class);
+ response.setContentType(newMediaTypeStr);
+ }
+ logger.debug("Changed media type to be {} in Content-Type HttpHeader", newMediaTypeStr); //$NON-NLS-1$
+ } catch (Exception e) {
+ logger.debug("Caught exception while trying to set the charset", e); //$NON-NLS-1$
+ }
+
+ }
+ }
+ } else {
+ logger.debug("No default charset was applied to the response Content-Type header due to deployment configuration directive."); // $NON-NLS-1$
+ }
+
+ logger.debug("setDefaultCharsetOnMediaTypeHeader() exit returning {}", mediaType); //$NON-NLS-1$
+ return mediaType;
+ }
+
+}
Modified: incubator/wink/trunk/wink-server/src/main/java/org/apache/wink/server/internal/handlers/FlushResultHandler.java
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-server/src/main/java/org/apache/wink/server/internal/handlers/FlushResultHandler.java?rev=936913&r1=936912&r2=936913&view=diff
==============================================================================
--- incubator/wink/trunk/wink-server/src/main/java/org/apache/wink/server/internal/handlers/FlushResultHandler.java (original)
+++ incubator/wink/trunk/wink-server/src/main/java/org/apache/wink/server/internal/handlers/FlushResultHandler.java Thu Apr 22 15:53:19 2010
@@ -133,12 +133,9 @@ public class FlushResultHandler extends
return;
}
- // we have an entity, set the response media type
+ // we have an entity, get the response media type
+ // the actual writing will take places in the flush
MediaType responseMediaType = context.getResponseMediaType();
- if (responseMediaType != null) {
- logger.debug("Set response Content-Type to: {} ", responseMediaType); //$NON-NLS-1$
- httpResponse.setContentType(responseMediaType.toString());
- }
// get the provider to write the entity
Providers providers = context.getProviders();
@@ -172,7 +169,7 @@ public class FlushResultHandler extends
}
FlushHeadersOutputStream outputStream =
- new FlushHeadersOutputStream(httpResponse, headers);
+ new FlushHeadersOutputStream(httpResponse, headers, responseMediaType);
if (logger.isDebugEnabled()) {
logger
.debug("{}@{}.writeTo({}, {}, {}, {}, {}, {}, {}) being called", new Object[] { //$NON-NLS-1$
@@ -218,7 +215,7 @@ public class FlushResultHandler extends
.getName());
FlushHeadersOutputStream outputStream =
- new FlushHeadersOutputStream(httpResponse, httpHeaders);
+ new FlushHeadersOutputStream(httpResponse, httpHeaders, responseMediaType);
if (logger.isDebugEnabled()) {
logger.debug("{}.writeTo({}, {}, {}) being called", new Object[] { //$NON-NLS-1$
Integer.toHexString(System.identityHashCode(dataContentHandler)), entity,
@@ -267,17 +264,20 @@ public class FlushResultHandler extends
// headers that a provider MAY have added to the response, before it
// actually started writing to stream.
- private boolean writeStarted;
- private HttpServletResponse httpResponse;
- private ServletOutputStream outputStream;
- private MultivaluedMap<String, Object> headers;
+ private boolean writeStarted;
+ final private HttpServletResponse httpResponse;
+ final private ServletOutputStream outputStream;
+ final private MultivaluedMap<String, Object> headers;
+ final private MediaType responseMediaType;
public FlushHeadersOutputStream(HttpServletResponse httpResponse,
- MultivaluedMap<String, Object> headers) throws IOException {
+ MultivaluedMap<String, Object> headers,
+ MediaType responseMediaType) throws IOException {
this.writeStarted = false;
this.httpResponse = httpResponse;
this.outputStream = httpResponse.getOutputStream();
this.headers = headers;
+ this.responseMediaType = responseMediaType;
}
@Override
@@ -312,6 +312,11 @@ public class FlushResultHandler extends
private void flushHeaders() {
if (!writeStarted) {
+ if (httpResponse.getContentType() == null) {
+ logger.debug("Set response Content-Type to: {} ", responseMediaType); //$NON-NLS-1$
+ httpResponse.setContentType(responseMediaType.toString());
+ }
+
FlushResultHandler.flushHeaders(httpResponse, headers);
writeStarted = true;
}
Modified: incubator/wink/trunk/wink-server/src/main/java/org/apache/wink/server/internal/handlers/ServerMessageContext.java
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-server/src/main/java/org/apache/wink/server/internal/handlers/ServerMessageContext.java?rev=936913&r1=936912&r2=936913&view=diff
==============================================================================
--- incubator/wink/trunk/wink-server/src/main/java/org/apache/wink/server/internal/handlers/ServerMessageContext.java (original)
+++ incubator/wink/trunk/wink-server/src/main/java/org/apache/wink/server/internal/handlers/ServerMessageContext.java Thu Apr 22 15:53:19 2010
@@ -40,6 +40,7 @@ import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.ext.Providers;
+import org.apache.wink.common.internal.contexts.MediaTypeCharsetAdjuster;
import org.apache.wink.common.internal.contexts.ProvidersImpl;
import org.apache.wink.common.internal.registry.ProvidersRegistry;
import org.apache.wink.common.internal.runtime.AbstractRuntimeContext;
@@ -49,6 +50,7 @@ import org.apache.wink.server.internal.M
import org.apache.wink.server.internal.contexts.HttpHeadersImpl;
import org.apache.wink.server.internal.contexts.RequestImpl;
import org.apache.wink.server.internal.contexts.SecurityContextImpl;
+import org.apache.wink.server.internal.contexts.ServerMediaTypeCharsetAdjuster;
import org.apache.wink.server.internal.contexts.UriInfoImpl;
import org.apache.wink.server.internal.registry.ResourceRegistry;
import org.apache.wink.server.internal.utils.LinkBuildersImpl;
@@ -85,6 +87,7 @@ public class ServerMessageContext extend
setAttribute(DeploymentConfiguration.class, configuration);
setAttribute(ResourceRegistry.class, configuration.getResourceRegistry());
setAttribute(ProvidersRegistry.class, configuration.getProvidersRegistry());
+ setAttribute(MediaTypeCharsetAdjuster.class, ServerMediaTypeCharsetAdjuster.getInstance());
initContexts();
List<Application> apps = configuration.getApplications();
@@ -224,8 +227,12 @@ public class ServerMessageContext extend
@Override
public void setContentType(String type) {
userContentType = type;
- MediaType realResponseMimeType = getRealResponseMimeType(type);
- super.setContentType(realResponseMimeType.toString());
+ if (mediaTypeMapper == null) {
+ super.setContentType(type);
+ } else {
+ MediaType realResponseMimeType = getRealResponseMimeType(type);
+ super.setContentType(realResponseMimeType.toString());
+ }
}
@Override
Modified: incubator/wink/trunk/wink-server/src/main/resources/META-INF/wink-default.properties
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-server/src/main/resources/META-INF/wink-default.properties?rev=936913&r1=936912&r2=936913&view=diff
==============================================================================
--- incubator/wink/trunk/wink-server/src/main/resources/META-INF/wink-default.properties (original)
+++ incubator/wink/trunk/wink-server/src/main/resources/META-INF/wink-default.properties Thu Apr 22 15:53:19 2010
@@ -43,4 +43,15 @@ wink.rootResource=atom+html
wink.serviceDocumentCssPath=
# Indicates if wink should load all META-INF/wink-application files found in classpath
-wink.loadApplications=true
\ No newline at end of file
+wink.loadApplications=true
+
+# Response Content-Type header should be UTF-8 if none is already specified
+# true: default to UTF-8 (default)
+# false: do not assign a default charset to the Content-Type response header
+wink.response.defaultCharset=true
+
+# Response Content-Type header should default to the highest q-valued Accept-Charset value if Accept-Charset header exists
+# This option overrides wink.response.defaultCharset when the Accept-Charset header is present
+# true: use highest q-valued Accept-Charset value as the charset in the response Content-Type header
+# false: do not use Accept-Charset values as a default on the response Content-Type header
+wink.response.useAcceptCharset=false
Added: incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/contexts/ServerMediaTypeCharsetAdjusterTest.java
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/contexts/ServerMediaTypeCharsetAdjusterTest.java?rev=936913&view=auto
==============================================================================
--- incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/contexts/ServerMediaTypeCharsetAdjusterTest.java (added)
+++ incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/contexts/ServerMediaTypeCharsetAdjusterTest.java Thu Apr 22 15:53:19 2010
@@ -0,0 +1,276 @@
+/*******************************************************************************
+ * 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.wink.server.internal.contexts;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+
+import org.apache.wink.common.RuntimeContext;
+import org.apache.wink.common.internal.MultivaluedMapImpl;
+import org.apache.wink.common.internal.runtime.RuntimeContextTLS;
+import org.apache.wink.server.internal.DeploymentConfiguration;
+import org.jmock.Expectations;
+import org.jmock.integration.junit3.MockObjectTestCase;
+import org.junit.Test;
+
+public class ServerMediaTypeCharsetAdjusterTest extends MockObjectTestCase {
+
+ RuntimeContext context = null;
+ HttpServletResponse servletResponse = null;
+ DeploymentConfiguration myConfig = new DeploymentConfiguration();
+
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ myConfig.init();
+ // default is true in the real config
+ myConfig.setDefaultResponseCharset(true);
+ // default is false in the real config
+ myConfig.setUseAcceptCharset(false);
+
+ // common expectations
+ context = mock(RuntimeContext.class);
+ checking(new Expectations() {{
+ allowing(context).getAttribute(DeploymentConfiguration.class); will(returnValue(myConfig));
+ }});
+
+ RuntimeContextTLS.setRuntimeContext(context);
+ }
+
+ @Test
+ public void testSetDefaultCharsetOnMediaTypeHeaderWithDefaultConfig() {
+
+ final String expected = "application/xml";
+
+ ServerMediaTypeCharsetAdjuster serverMediaTypeCharsetAdjuster = ServerMediaTypeCharsetAdjuster.getInstance();
+
+ // null httpHeaders param
+ MediaType mediaType = serverMediaTypeCharsetAdjuster.setDefaultCharsetOnMediaTypeHeader(null, MediaType.APPLICATION_XML_TYPE);
+ assertEquals(expected, mediaType.toString());
+ }
+
+ @Test
+ public void testSetDefaultCharsetOnMediaTypeHeaderWithConfigTrueNullParam() {
+
+ final String expected = "application/xml";
+
+ ServerMediaTypeCharsetAdjuster serverMediaTypeCharsetAdjuster = ServerMediaTypeCharsetAdjuster.getInstance();
+
+ myConfig.setDefaultResponseCharset(true);
+
+ // null httpHeaders param
+ MediaType mediaType = serverMediaTypeCharsetAdjuster.setDefaultCharsetOnMediaTypeHeader(null, MediaType.APPLICATION_XML_TYPE);
+ assertEquals(expected, mediaType.toString());
+
+ }
+
+ @Test
+ public void testSetDefaultCharsetOnMediaTypeHeaderWithConfigTrueAndNullHeadersAndFalseConfig() {
+
+ final String expected = "application/xml";
+
+ servletResponse = mock(HttpServletResponse.class);
+
+ ServerMediaTypeCharsetAdjuster serverMediaTypeCharsetAdjuster = ServerMediaTypeCharsetAdjuster.getInstance();
+
+ // switch off the default
+ myConfig.setDefaultResponseCharset(false);
+
+ // empty map
+ MediaType mediaType = serverMediaTypeCharsetAdjuster.setDefaultCharsetOnMediaTypeHeader(new MultivaluedMapImpl<String, Object>(), MediaType.APPLICATION_XML_TYPE);
+ // no charset attribute due to setDefaultResponseCharset(false)
+ assertEquals(expected, mediaType.toString());
+
+ }
+
+ @Test
+ public void testSetDefaultCharsetOnMediaTypeHeaderWithConfigTrueAndNullHeaders() {
+
+ final String expected = "application/xml;charset=UTF-8";
+
+ servletResponse = mock(HttpServletResponse.class);
+ checking(new Expectations() {{
+ oneOf(servletResponse).setContentType(expected);
+ oneOf(context).getAttribute(HttpServletResponse.class); will(returnValue(servletResponse));
+ }});
+
+ ServerMediaTypeCharsetAdjuster serverMediaTypeCharsetAdjuster = ServerMediaTypeCharsetAdjuster.getInstance();
+
+ // empty map
+ MediaType mediaType = serverMediaTypeCharsetAdjuster.setDefaultCharsetOnMediaTypeHeader(new MultivaluedMapImpl<String, Object>(), MediaType.APPLICATION_XML_TYPE);
+ assertEquals(expected, mediaType.toString());
+
+ }
+
+ @Test
+ public void testSetDefaultCharsetOnMediaTypeHeaderWithConfigTrueAndNullAcceptCharsetHeader() {
+
+ final String expected = "application/xml;charset=UTF-8";
+
+ final HttpHeaders httpHeaders = mock(HttpHeaders.class);
+ servletResponse = mock(HttpServletResponse.class);
+ checking(new Expectations() {{
+ oneOf(servletResponse).setContentType(expected);
+ oneOf(context).getAttribute(HttpServletResponse.class); will(returnValue(servletResponse));
+ oneOf(context).getHttpHeaders(); will(returnValue(httpHeaders));
+ oneOf(httpHeaders).getRequestHeader(HttpHeaders.ACCEPT_CHARSET); will(returnValue(null));
+ }});
+
+ ServerMediaTypeCharsetAdjuster serverMediaTypeCharsetAdjuster = ServerMediaTypeCharsetAdjuster.getInstance();
+
+ // exercise code path that reads the Accept-Charset header
+ myConfig.setUseAcceptCharset(true);
+
+ // empty map
+ MediaType mediaType = serverMediaTypeCharsetAdjuster.setDefaultCharsetOnMediaTypeHeader(new MultivaluedMapImpl<String, Object>(), MediaType.APPLICATION_XML_TYPE);
+ assertEquals(expected, mediaType.toString());
+
+ }
+
+ @Test
+ public void testSetDefaultCharsetOnMediaTypeHeaderWithConfigTrueAndAcceptCharsetHeader() {
+
+ final String expected = "application/xml;charset=ISO-8859-1";
+
+ final List<String> acceptHeaders = new ArrayList<String>();
+ acceptHeaders.add("UTF-16");
+
+ final HttpHeaders httpHeaders = mock(HttpHeaders.class);
+ servletResponse = mock(HttpServletResponse.class);
+ checking(new Expectations() {{
+ oneOf(servletResponse).setContentType(expected);
+ oneOf(context).getAttribute(HttpServletResponse.class); will(returnValue(servletResponse));
+ oneOf(context).getHttpHeaders(); will(returnValue(httpHeaders));
+ oneOf(httpHeaders).getRequestHeader(HttpHeaders.ACCEPT_CHARSET); will(returnValue(acceptHeaders));
+ }});
+
+ // non-empty map, just to make sure production code path is as expected
+ MultivaluedMap<String, Object> map = new MultivaluedMapImpl<String, Object>();
+ map.add("nonsense", null);
+
+ ServerMediaTypeCharsetAdjuster serverMediaTypeCharsetAdjuster = ServerMediaTypeCharsetAdjuster.getInstance();
+
+ // exercise code path that reads the Accept-Charset header
+ myConfig.setUseAcceptCharset(true);
+
+ // empty map
+ MediaType mediaType = serverMediaTypeCharsetAdjuster.setDefaultCharsetOnMediaTypeHeader(map, MediaType.APPLICATION_XML_TYPE);
+ // still defaults back to ISO-8859-1 because it is silently added as top q-valued charset on the client-originated Accept-Header. See HTTP spec.
+ assertEquals(expected, mediaType.toString());
+
+ }
+
+ @Test
+ public void testSetDefaultCharsetOnMediaTypeHeaderWithConfigTrueAndAcceptCharsetButFalse() {
+
+ final String expected = "application/xml;charset=UTF-8";
+
+ final List<String> acceptHeaders = new ArrayList<String>();
+ acceptHeaders.add("UTF-16;q=1.0");
+ acceptHeaders.add("ISO-8859-1;q=0.5"); // re-prioritize silently added charset to lower q-value than UTF-16
+
+ final HttpHeaders httpHeaders = mock(HttpHeaders.class);
+ servletResponse = mock(HttpServletResponse.class);
+ checking(new Expectations() {{
+ oneOf(servletResponse).setContentType(expected);
+ oneOf(context).getAttribute(HttpServletResponse.class); will(returnValue(servletResponse));
+ }});
+
+ ServerMediaTypeCharsetAdjuster serverMediaTypeCharsetAdjuster = ServerMediaTypeCharsetAdjuster.getInstance();
+
+ // leave useAcceptHeader to the default of false
+
+ MediaType mediaType = serverMediaTypeCharsetAdjuster.setDefaultCharsetOnMediaTypeHeader(new MultivaluedMapImpl<String, Object>(), MediaType.APPLICATION_XML_TYPE);
+ // UTF-16 has highest q-value, but Accept-Charset is being ignored due to config, so...
+ assertEquals(expected, mediaType.toString());
+
+ }
+
+ @Test
+ public void testSetDefaultCharsetOnMediaTypeHeaderWithConfigTrueAndAcceptCharset() {
+
+ final String expected = "application/xml;charset=UTF-16";
+
+ final List<String> acceptHeaders = new ArrayList<String>();
+ acceptHeaders.add("UTF-16;q=1.0");
+ acceptHeaders.add("ISO-8859-1;q=0.5"); // re-prioritize silently added charset to lower q-value than UTF-16
+
+ final HttpHeaders httpHeaders = mock(HttpHeaders.class);
+ servletResponse = mock(HttpServletResponse.class);
+ checking(new Expectations() {{
+ oneOf(servletResponse).setContentType(expected);
+ oneOf(context).getAttribute(HttpServletResponse.class); will(returnValue(servletResponse));
+ oneOf(context).getHttpHeaders(); will(returnValue(httpHeaders));
+ oneOf(httpHeaders).getRequestHeader(HttpHeaders.ACCEPT_CHARSET); will(returnValue(acceptHeaders));
+ }});
+
+ ServerMediaTypeCharsetAdjuster serverMediaTypeCharsetAdjuster = ServerMediaTypeCharsetAdjuster.getInstance();
+
+ // exercise code path that reads the Accept-Charset header
+ myConfig.setUseAcceptCharset(true);
+
+ MediaType mediaType = serverMediaTypeCharsetAdjuster.setDefaultCharsetOnMediaTypeHeader(new MultivaluedMapImpl<String, Object>(), MediaType.APPLICATION_XML_TYPE);
+ // UTF-16 has highest q-value
+ assertEquals(expected, mediaType.toString());
+
+ }
+
+ @Test
+ public void testSetDefaultCharsetOnMediaTypeHeaderWithConfigFalseAndAcceptCharset() {
+
+ final String expected = "application/xml;charset=UTF-16";
+
+ final List<String> acceptHeaders = new ArrayList<String>();
+ acceptHeaders.add("UTF-16;q=1.0");
+ acceptHeaders.add("ISO-8859-1;q=0.5"); // re-prioritize silently added charset to lower q-value than UTF-16
+
+ final HttpHeaders httpHeaders = mock(HttpHeaders.class);
+ servletResponse = mock(HttpServletResponse.class);
+ checking(new Expectations() {{
+ oneOf(servletResponse).setContentType(expected);
+ oneOf(context).getAttribute(HttpServletResponse.class); will(returnValue(servletResponse));
+ oneOf(context).getHttpHeaders(); will(returnValue(httpHeaders));
+ oneOf(httpHeaders).getRequestHeader(HttpHeaders.ACCEPT_CHARSET); will(returnValue(acceptHeaders));
+ }});
+
+ ServerMediaTypeCharsetAdjuster serverMediaTypeCharsetAdjuster = ServerMediaTypeCharsetAdjuster.getInstance();
+
+ // make sure when user expects to be using Accept-Header, they really do use it
+
+ // default is true in the real config. Resetting to false here to confirm code path is correct
+ myConfig.setUseAcceptCharset(false);
+ // exercise code path that reads the Accept-Charset header
+ myConfig.setUseAcceptCharset(true);
+
+ MediaType mediaType = serverMediaTypeCharsetAdjuster.setDefaultCharsetOnMediaTypeHeader(new MultivaluedMapImpl<String, Object>(), MediaType.APPLICATION_XML_TYPE);
+ // UTF-16 has highest q-value
+ assertEquals(expected, mediaType.toString());
+
+ }
+
+
+}