Author: cschneider
Date: Wed Feb 1 10:30:19 2012
New Revision: 1239041
URL: http://svn.apache.org/viewvc?rev=1239041&view=rev
Log:
CXF-4081 Move gzip feature to core
Added:
cxf/trunk/rt/core/src/main/java/org/apache/cxf/transport/
cxf/trunk/rt/core/src/main/java/org/apache/cxf/transport/common/
cxf/trunk/rt/core/src/main/java/org/apache/cxf/transport/common/gzip/
cxf/trunk/rt/core/src/main/java/org/apache/cxf/transport/common/gzip/GZIPFeature.java
cxf/trunk/rt/core/src/main/java/org/apache/cxf/transport/common/gzip/GZIPInInterceptor.java
cxf/trunk/rt/core/src/main/java/org/apache/cxf/transport/common/gzip/GZIPOutInterceptor.java
cxf/trunk/rt/core/src/main/java/org/apache/cxf/transport/common/gzip/Messages.properties
cxf/trunk/rt/core/src/test/java/org/apache/cxf/transport/common/
cxf/trunk/rt/core/src/test/java/org/apache/cxf/transport/common/gzip/
cxf/trunk/rt/core/src/test/java/org/apache/cxf/transport/common/gzip/GZIPAcceptEncodingTest.java
Removed:
cxf/trunk/rt/transports/common/
Modified:
cxf/trunk/osgi/karaf/features/src/main/resources/features.xml
cxf/trunk/rt/core/src/main/java/org/apache/cxf/service/factory/AnnotationsFactoryBeanListener.java
cxf/trunk/rt/pom.xml
cxf/trunk/rt/transports/jms/pom.xml
Modified: cxf/trunk/osgi/karaf/features/src/main/resources/features.xml
URL:
http://svn.apache.org/viewvc/cxf/trunk/osgi/karaf/features/src/main/resources/features.xml?rev=1239041&r1=1239040&r2=1239041&view=diff
==============================================================================
--- cxf/trunk/osgi/karaf/features/src/main/resources/features.xml (original)
+++ cxf/trunk/osgi/karaf/features/src/main/resources/features.xml Wed Feb 1
10:30:19 2012
@@ -99,7 +99,6 @@
<bundle
start-level='40'>mvn:org.apache.cxf/cxf-api/${project.version}</bundle>
<bundle
start-level='40'>mvn:org.apache.cxf/cxf-rt-core/${project.version}</bundle>
<bundle
start-level='40'>mvn:org.apache.cxf/cxf-rt-management/${project.version}</bundle>
- <bundle
start-level='40'>mvn:org.apache.cxf/cxf-rt-transports-common/${project.version}</bundle>
<bundle
start-level='40'>mvn:org.apache.cxf.karaf/cxf-karaf-commands/${project.version}</bundle>
</feature>
<feature name="cxf-ws-policy" version="${project.version}"
resolver='(obr)'>
Modified:
cxf/trunk/rt/core/src/main/java/org/apache/cxf/service/factory/AnnotationsFactoryBeanListener.java
URL:
http://svn.apache.org/viewvc/cxf/trunk/rt/core/src/main/java/org/apache/cxf/service/factory/AnnotationsFactoryBeanListener.java?rev=1239041&r1=1239040&r2=1239041&view=diff
==============================================================================
---
cxf/trunk/rt/core/src/main/java/org/apache/cxf/service/factory/AnnotationsFactoryBeanListener.java
(original)
+++
cxf/trunk/rt/core/src/main/java/org/apache/cxf/service/factory/AnnotationsFactoryBeanListener.java
Wed Feb 1 10:30:19 2012
@@ -60,6 +60,7 @@ import org.apache.cxf.service.model.Bind
import org.apache.cxf.service.model.FaultInfo;
import org.apache.cxf.service.model.InterfaceInfo;
import org.apache.cxf.service.model.OperationInfo;
+import org.apache.cxf.transport.common.gzip.GZIPFeature;
/**
*
@@ -247,13 +248,8 @@ public class AnnotationsFactoryBeanListe
private void addGZipSupport(Endpoint ep, Bus bus, GZIP annotation) {
if (annotation != null) {
try {
- Class<?> cls = ClassLoaderUtils
-
.loadClass("org.apache.cxf.transport.common.gzip.GZIPFeature",
- this.getClass());
-
- AbstractFeature feature = (AbstractFeature)cls.newInstance();
- cls.getMethod("setThreshold", new Class[] {Integer.TYPE})
- .invoke(feature, annotation.threshold());
+ GZIPFeature feature = new GZIPFeature();
+ feature.setThreshold(annotation.threshold());
feature.initialize(ep, bus);
} catch (Exception e) {
//ignore - just assume it's an unsupported/unknown annotation
Added:
cxf/trunk/rt/core/src/main/java/org/apache/cxf/transport/common/gzip/GZIPFeature.java
URL:
http://svn.apache.org/viewvc/cxf/trunk/rt/core/src/main/java/org/apache/cxf/transport/common/gzip/GZIPFeature.java?rev=1239041&view=auto
==============================================================================
---
cxf/trunk/rt/core/src/main/java/org/apache/cxf/transport/common/gzip/GZIPFeature.java
(added)
+++
cxf/trunk/rt/core/src/main/java/org/apache/cxf/transport/common/gzip/GZIPFeature.java
Wed Feb 1 10:30:19 2012
@@ -0,0 +1,101 @@
+/**
+ * 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.transport.common.gzip;
+
+import java.util.List;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.common.injection.NoJSR250Annotations;
+import org.apache.cxf.feature.AbstractFeature;
+import org.apache.cxf.interceptor.Interceptor;
+import org.apache.cxf.interceptor.InterceptorProvider;
+import org.apache.cxf.message.Message;
+
+/**
+ * This class is used to control GZIP compression of messages.
+ * Attaching this feature to an endpoint will allow the endpoint to handle
+ * compressed requests, and will cause outgoing responses to be compressed if
+ * the client indicates (via the Accept-Encoding header) that it can handle
+ * them.
+ * <pre>
+ * <![CDATA[
+ * <jaxws:endpoint ...>
+ * <jaxws:features>
+ * <bean class="org.apache.cxf.transport.http.gzip.GZIPFeature"/>
+ * </jaxws:features>
+ * </jaxws:endpoint>
+ * ]]>
+ * </pre>
+ * Attaching this feature to a client will cause outgoing request messages to
+ * be compressed and incoming compressed responses to be uncompressed. If you
+ * want the service to know that your client can accept compressed responses,
+ * you will also need to set the "AcceptEncoding" value in the relevant HTTP
+ * conduit client configuration.
+ * <pre>
+ * <![CDATA[
+ * <http-conf:conduit
name="{http://apache.org/hello_world_soap_http}SoapPort.http-conduit">
+ * <http-conf:client AcceptEncoding="gzip" />
+ * </http-conf:conduit>
+ * ]]>
+ * </pre>
+ */
+@NoJSR250Annotations
+public class GZIPFeature extends AbstractFeature {
+ private static final GZIPInInterceptor IN = new GZIPInInterceptor();
+ private static final GZIPOutInterceptor OUT = new GZIPOutInterceptor();
+
+ /**
+ * The compression threshold to pass to the outgoing interceptor.
+ */
+ int threshold = -1;
+
+ @Override
+ protected void initializeProvider(InterceptorProvider provider, Bus bus) {
+ provider.getInInterceptors().add(IN);
+ if (threshold == -1) {
+ provider.getOutInterceptors().add(OUT);
+ provider.getOutFaultInterceptors().add(OUT);
+ } else {
+ GZIPOutInterceptor out = new GZIPOutInterceptor();
+ out.setThreshold(threshold);
+ remove(provider.getOutInterceptors());
+ remove(provider.getOutFaultInterceptors());
+ provider.getOutInterceptors().add(out);
+ provider.getOutFaultInterceptors().add(out);
+ }
+ }
+
+ private void remove(List<Interceptor<? extends Message>> outInterceptors) {
+ int x = outInterceptors.size();
+ while (x > 0) {
+ --x;
+ if (outInterceptors.get(x) instanceof GZIPOutInterceptor) {
+ outInterceptors.remove(x);
+ }
+ }
+ }
+
+ public void setThreshold(int threshold) {
+ this.threshold = threshold;
+ }
+
+ public int getThreshold() {
+ return threshold;
+ }
+}
Added:
cxf/trunk/rt/core/src/main/java/org/apache/cxf/transport/common/gzip/GZIPInInterceptor.java
URL:
http://svn.apache.org/viewvc/cxf/trunk/rt/core/src/main/java/org/apache/cxf/transport/common/gzip/GZIPInInterceptor.java?rev=1239041&view=auto
==============================================================================
---
cxf/trunk/rt/core/src/main/java/org/apache/cxf/transport/common/gzip/GZIPInInterceptor.java
(added)
+++
cxf/trunk/rt/core/src/main/java/org/apache/cxf/transport/common/gzip/GZIPInInterceptor.java
Wed Feb 1 10:30:19 2012
@@ -0,0 +1,101 @@
+/**
+ * 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.transport.common.gzip;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.List;
+import java.util.Map;
+import java.util.ResourceBundle;
+import java.util.logging.Logger;
+import java.util.zip.GZIPInputStream;
+
+import org.apache.cxf.common.i18n.BundleUtils;
+import org.apache.cxf.common.logging.LogUtils;
+import org.apache.cxf.helpers.CastUtils;
+import org.apache.cxf.helpers.HttpHeaderHelper;
+import org.apache.cxf.interceptor.AttachmentInInterceptor;
+import org.apache.cxf.interceptor.Fault;
+import org.apache.cxf.message.Message;
+import org.apache.cxf.phase.AbstractPhaseInterceptor;
+import org.apache.cxf.phase.Phase;
+
+/**
+ * CXF interceptor that uncompresses those incoming messages that have "gzip"
+ * content-encoding. An instance of this class should be added as an in and
+ * inFault interceptor on clients that need to talk to a service that returns
+ * gzipped responses or on services that want to accept gzipped requests. For
+ * clients, you probably also want to use
+ * {@link
org.apache.cxf.transports.http.configuration.HTTPClientPolicy#setAcceptEncoding}
+ * to let the server know you can handle compressed responses. To compress
+ * outgoing messages, see {@link GZIPOutInterceptor}. This class was originally
+ * based on one of the CXF samples (configuration_interceptor).
+ *
+ * @author Ian Roberts ([email protected])
+ */
+public class GZIPInInterceptor extends AbstractPhaseInterceptor<Message> {
+
+
+ private static final ResourceBundle BUNDLE =
BundleUtils.getBundle(GZIPInInterceptor.class);
+ private static final Logger LOG =
LogUtils.getL7dLogger(GZIPInInterceptor.class);
+
+ public GZIPInInterceptor() {
+ super(Phase.RECEIVE);
+ addBefore(AttachmentInInterceptor.class.getName());
+ }
+
+ public void handleMessage(Message message) throws Fault {
+ // check for Content-Encoding header - we are only interested in
+ // messages that say they are gzipped.
+ Map<String, List<String>> protocolHeaders = CastUtils.cast((Map<?,
?>)message
+ .get(Message.PROTOCOL_HEADERS));
+ if (protocolHeaders != null) {
+ List<String> contentEncoding =
HttpHeaderHelper.getHeader(protocolHeaders,
+
HttpHeaderHelper.CONTENT_ENCODING);
+ if (contentEncoding == null) {
+ contentEncoding =
protocolHeaders.get(GZIPOutInterceptor.SOAP_JMS_CONTENTENCODING);
+ }
+ if (contentEncoding != null
+ && (contentEncoding.contains("gzip") ||
contentEncoding.contains("x-gzip"))) {
+ try {
+ LOG.fine("Uncompressing response");
+ InputStream is = message.getContent(InputStream.class);
+ if (is == null) {
+ return;
+ }
+
+ // wrap an unzipping stream around the original one
+ GZIPInputStream zipInput = new GZIPInputStream(is);
+ message.setContent(InputStream.class, zipInput);
+
+ // remove content encoding header as we've now dealt with
it
+ for (String key : protocolHeaders.keySet()) {
+ if (key.equalsIgnoreCase("Content-Encoding")) {
+ protocolHeaders.remove(key);
+ break;
+ }
+ }
+ } catch (IOException ex) {
+ throw new Fault(new
org.apache.cxf.common.i18n.Message("COULD_NOT_UNZIP", BUNDLE), ex);
+ }
+ }
+ }
+ }
+
+}
Added:
cxf/trunk/rt/core/src/main/java/org/apache/cxf/transport/common/gzip/GZIPOutInterceptor.java
URL:
http://svn.apache.org/viewvc/cxf/trunk/rt/core/src/main/java/org/apache/cxf/transport/common/gzip/GZIPOutInterceptor.java?rev=1239041&view=auto
==============================================================================
---
cxf/trunk/rt/core/src/main/java/org/apache/cxf/transport/common/gzip/GZIPOutInterceptor.java
(added)
+++
cxf/trunk/rt/core/src/main/java/org/apache/cxf/transport/common/gzip/GZIPOutInterceptor.java
Wed Feb 1 10:30:19 2012
@@ -0,0 +1,323 @@
+/**
+ * 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.transport.common.gzip;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.ResourceBundle;
+import java.util.TreeMap;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.zip.GZIPOutputStream;
+
+import org.apache.cxf.common.i18n.BundleUtils;
+import org.apache.cxf.common.logging.LogUtils;
+import org.apache.cxf.helpers.CastUtils;
+import org.apache.cxf.helpers.HttpHeaderHelper;
+import org.apache.cxf.interceptor.Fault;
+import org.apache.cxf.interceptor.MessageSenderInterceptor;
+import org.apache.cxf.io.AbstractThresholdOutputStream;
+import org.apache.cxf.message.Exchange;
+import org.apache.cxf.message.Message;
+import org.apache.cxf.phase.AbstractPhaseInterceptor;
+import org.apache.cxf.phase.Phase;
+
+/**
+ * CXF interceptor that compresses outgoing messages using gzip and sets the
+ * HTTP Content-Encoding header appropriately. An instance of this class should
+ * be added as an out interceptor on clients that need to talk to a service
that
+ * accepts gzip-encoded requests or on a service that wants to be able to
return
+ * compressed responses. In server mode, the interceptor only compresses
+ * responses if the client indicated (via an Accept-Encoding header on the
+ * request) that it can understand them. To handle gzip-encoded input messages,
+ * see {@link GZIPInInterceptor}. This interceptor supports a compression
+ * {@link #threshold} (default 1kB) - messages smaller than this threshold will
+ * not be compressed. To force compression of all messages, set the threshold
to
+ * 0. This class was originally based on one of the CXF samples
+ * (configuration_interceptor).
+ *
+ * @author Ian Roberts ([email protected])
+ */
+public class GZIPOutInterceptor extends AbstractPhaseInterceptor<Message> {
+
+ /**
+ * Enum giving the possible values for whether we should gzip a particular
+ * message.
+ */
+ public static enum UseGzip {
+ NO, YES, FORCE
+ }
+
+ /**
+ * Key under which we store the original output stream on the message, for
+ * use by the ending interceptor.
+ */
+ public static final String ORIGINAL_OUTPUT_STREAM_KEY =
GZIPOutInterceptor.class.getName()
+ +
".originalOutputStream";
+
+ /**
+ * Key under which we store an indication of whether compression is
+ * permitted or required, for use by the ending interceptor.
+ */
+ public static final String USE_GZIP_KEY =
GZIPOutInterceptor.class.getName() + ".useGzip";
+
+ /**
+ * Key under which we store the name which should be used for the
+ * content-encoding of the outgoing message. Typically "gzip" but may be
+ * "x-gzip" if we are processing a response message and this is the name
+ * given by the client in Accept-Encoding.
+ */
+ public static final String GZIP_ENCODING_KEY =
GZIPOutInterceptor.class.getName() + ".gzipEncoding";
+
+ public static final String SOAP_JMS_CONTENTENCODING =
"SOAPJMS_contentEncoding";
+
+ private static final ResourceBundle BUNDLE =
BundleUtils.getBundle(GZIPOutInterceptor.class);
+ private static final Logger LOG =
LogUtils.getL7dLogger(GZIPOutInterceptor.class);
+
+
+ /**
+ * Compression threshold in bytes - messages smaller than this will not be
+ * compressed.
+ */
+ private int threshold = 1024;
+
+ public GZIPOutInterceptor() {
+ super(Phase.PREPARE_SEND);
+ addAfter(MessageSenderInterceptor.class.getName());
+ }
+ public GZIPOutInterceptor(int threshold) {
+ super(Phase.PREPARE_SEND);
+ addAfter(MessageSenderInterceptor.class.getName());
+ this.threshold = threshold;
+ }
+
+ public void setThreshold(int threshold) {
+ this.threshold = threshold;
+ }
+
+ public int getThreshold() {
+ return threshold;
+ }
+
+ public void handleMessage(Message message) throws Fault {
+ UseGzip use = gzipPermitted(message);
+ if (use != UseGzip.NO) {
+ // remember the original output stream, we will write compressed
+ // data to this later
+ OutputStream os = message.getContent(OutputStream.class);
+ if (os == null) {
+ return;
+ }
+ message.put(ORIGINAL_OUTPUT_STREAM_KEY, os);
+ message.put(USE_GZIP_KEY, use);
+
+ // new stream to cache the message
+ GZipThresholdOutputStream cs
+ = new GZipThresholdOutputStream(threshold,
+ os,
+ use == UseGzip.FORCE,
+ message);
+ message.setContent(OutputStream.class, cs);
+ }
+ }
+
+ /**
+ * Checks whether we can, cannot or must use gzip compression on this
output
+ * message. Gzip is always permitted if the message is a client request. If
+ * the message is a server response we check the Accept-Encoding header of
+ * the corresponding request message - with no Accept-Encoding we assume
+ * that gzip is not permitted. For the full gory details, see <a
+ *
href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.3">section
+ * 14.3 of RFC 2616</a> (HTTP 1.1).
+ *
+ * @param message the outgoing message.
+ * @return whether to attempt gzip compression for this message.
+ * @throws Fault if the Accept-Encoding header does not allow any encoding
+ * that we can support (identity, gzip or x-gzip).
+ */
+ private UseGzip gzipPermitted(Message message) throws Fault {
+ UseGzip permitted = UseGzip.NO;
+ if (Boolean.TRUE.equals(message.get(Message.REQUESTOR_ROLE))) {
+ LOG.fine("Requestor role, so gzip enabled");
+ permitted = UseGzip.YES;
+ message.put(GZIP_ENCODING_KEY, "gzip");
+ addHeader(message, "Accept-Encoding", "gzip;q=1.0, identity;
q=0.5, *;q=0");
+ } else {
+ LOG.fine("Response role, checking accept-encoding");
+ Exchange exchange = message.getExchange();
+ Message request = exchange.getInMessage();
+ Map<String, List<String>> requestHeaders = CastUtils.cast((Map<?,
?>)request
+ .get(Message.PROTOCOL_HEADERS));
+ if (requestHeaders != null) {
+ List<String> acceptEncodingHeader =
CastUtils.cast(HttpHeaderHelper
+ .getHeader(requestHeaders,
HttpHeaderHelper.ACCEPT_ENCODING));
+ List<String> jmsEncodingHeader =
CastUtils.cast(requestHeaders.get(SOAP_JMS_CONTENTENCODING));
+ if (jmsEncodingHeader != null &&
jmsEncodingHeader.contains("gzip")) {
+ permitted = UseGzip.YES;
+ message.put(GZIP_ENCODING_KEY, "gzip");
+ }
+ if (acceptEncodingHeader != null) {
+ if (LOG.isLoggable(Level.FINE)) {
+ LOG.fine("Accept-Encoding header: " +
acceptEncodingHeader);
+ }
+ // Accept-Encoding is a comma separated list of entries, so
+ // we split it into its component parts and build two
+ // lists, one with all the "q=0" encodings and the other
+ // with the rest (no q, or q=<non-zero>).
+ List<String> zeros = new ArrayList<String>(3);
+ List<String> nonZeros = new ArrayList<String>(3);
+
+ // regular expression that matches any encoding with a
+ // q-value of 0 (or 0.0, 0.00, etc.).
+ Pattern zeroQ = Pattern.compile(";\\s*q=0(?:\\.0+)?$");
+ for (String headerLine : acceptEncodingHeader) {
+ String[] encodings =
headerLine.trim().split("[,\\s]*,\\s*");
+
+ for (String enc : encodings) {
+ Matcher m = zeroQ.matcher(enc);
+ if (m.find()) {
+ zeros.add(enc.substring(0, m.start()));
+ } else if (enc.indexOf(';') >= 0) {
+ nonZeros.add(enc.substring(0,
enc.indexOf(';')));
+ } else {
+ nonZeros.add(enc);
+ }
+ }
+ }
+
+ // identity encoding is permitted if (a) it is not
+ // specifically disabled by an identity;q=0 and (b) if
+ // there is a *;q=0 then there is also an explicit
+ // identity[;q=<non-zero>]
+ //
+ // [x-]gzip is permitted if (a) there is an explicit
+ // [x-]gzip[;q=<non-zero>], or (b) there is a
+ // *[;q=<non-zero>] and no [x-]gzip;q=0 to disable it.
+ boolean identityEnabled = !zeros.contains("identity")
+ && (!zeros.contains("*") ||
nonZeros.contains("identity"));
+ boolean gzipEnabled = nonZeros.contains("gzip")
+ || (nonZeros.contains("*") &&
!zeros.contains("gzip"));
+ boolean xGzipEnabled = nonZeros.contains("x-gzip")
+ || (nonZeros.contains("*") &&
!zeros.contains("x-gzip"));
+
+ if (identityEnabled && !gzipEnabled && !xGzipEnabled) {
+ permitted = UseGzip.NO;
+ } else if (identityEnabled && gzipEnabled) {
+ permitted = UseGzip.YES;
+ message.put(GZIP_ENCODING_KEY, "gzip");
+ } else if (identityEnabled && xGzipEnabled) {
+ permitted = UseGzip.YES;
+ message.put(GZIP_ENCODING_KEY, "x-gzip");
+ } else if (!identityEnabled && gzipEnabled) {
+ permitted = UseGzip.FORCE;
+ message.put(GZIP_ENCODING_KEY, "gzip");
+ } else if (!identityEnabled && xGzipEnabled) {
+ permitted = UseGzip.FORCE;
+ message.put(GZIP_ENCODING_KEY, "x-gzip");
+ } else {
+ throw new Fault(new
org.apache.cxf.common.i18n.Message("NO_SUPPORTED_ENCODING",
+
BUNDLE));
+ }
+ } else {
+ LOG.fine("No accept-encoding header");
+ }
+ }
+ }
+
+ if (LOG.isLoggable(Level.FINE)) {
+ LOG.fine("gzip permitted: " + permitted);
+ }
+ return permitted;
+ }
+
+ static class GZipThresholdOutputStream extends
AbstractThresholdOutputStream {
+ Message message;
+
+ public GZipThresholdOutputStream(int t, OutputStream orig,
+ boolean force, Message msg) {
+ super(t);
+ super.wrappedStream = orig;
+ message = msg;
+ if (force) {
+ setupGZip();
+ }
+ }
+
+ private void setupGZip() {
+
+ }
+
+ @Override
+ public void thresholdNotReached() {
+ //nothing
+ LOG.fine("Message is smaller than compression threshold, not
compressing.");
+ }
+
+ @Override
+ public void thresholdReached() throws IOException {
+ LOG.fine("Compressing message.");
+ // Set the Content-Encoding HTTP header
+ String enc = (String)message.get(GZIP_ENCODING_KEY);
+ addHeader(message, "Content-Encoding", enc);
+ // if this is a response message, add the Vary header
+ if (!Boolean.TRUE.equals(message.get(Message.REQUESTOR_ROLE))) {
+ addHeader(message, "Vary", "Accept-Encoding");
+ }
+
+ // gzip the result
+ GZIPOutputStream zipOutput = new GZIPOutputStream(wrappedStream);
+ wrappedStream = zipOutput;
+ }
+ }
+
+ /**
+ * Adds a value to a header. If the given header name is not currently
+ * set in the message, an entry is created with the given single value.
+ * If the header is already set, the value is appended to the first
+ * element of the list, following a comma.
+ *
+ * @param message the message
+ * @param name the header to set
+ * @param value the value to add
+ */
+ private static void addHeader(Message message, String name, String value) {
+ Map<String, List<String>> protocolHeaders = CastUtils.cast((Map<?,
?>)message
+ .get(Message.PROTOCOL_HEADERS));
+ if (protocolHeaders == null) {
+ protocolHeaders = new TreeMap<String,
List<String>>(String.CASE_INSENSITIVE_ORDER);
+ message.put(Message.PROTOCOL_HEADERS, protocolHeaders);
+ }
+ List<String> header =
CastUtils.cast((List<?>)protocolHeaders.get(name));
+ if (header == null) {
+ header = new ArrayList<String>();
+ protocolHeaders.put(name, header);
+ }
+ if (header.size() == 0) {
+ header.add(value);
+ } else {
+ header.set(0, header.get(0) + "," + value);
+ }
+ }
+
+}
Added:
cxf/trunk/rt/core/src/main/java/org/apache/cxf/transport/common/gzip/Messages.properties
URL:
http://svn.apache.org/viewvc/cxf/trunk/rt/core/src/main/java/org/apache/cxf/transport/common/gzip/Messages.properties?rev=1239041&view=auto
==============================================================================
---
cxf/trunk/rt/core/src/main/java/org/apache/cxf/transport/common/gzip/Messages.properties
(added)
+++
cxf/trunk/rt/core/src/main/java/org/apache/cxf/transport/common/gzip/Messages.properties
Wed Feb 1 10:30:19 2012
@@ -0,0 +1,23 @@
+#
+#
+# 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.
+#
+#
+COULD_NOT_UNZIP=Could not unzip compressed message.
+COULD_NOT_ZIP=Could not compress message.
+NO_SUPPORTED_ENCODING=No supported content encodings available.
Added:
cxf/trunk/rt/core/src/test/java/org/apache/cxf/transport/common/gzip/GZIPAcceptEncodingTest.java
URL:
http://svn.apache.org/viewvc/cxf/trunk/rt/core/src/test/java/org/apache/cxf/transport/common/gzip/GZIPAcceptEncodingTest.java?rev=1239041&view=auto
==============================================================================
---
cxf/trunk/rt/core/src/test/java/org/apache/cxf/transport/common/gzip/GZIPAcceptEncodingTest.java
(added)
+++
cxf/trunk/rt/core/src/test/java/org/apache/cxf/transport/common/gzip/GZIPAcceptEncodingTest.java
Wed Feb 1 10:30:19 2012
@@ -0,0 +1,139 @@
+/**
+ * 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.transport.common.gzip;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+import org.apache.cxf.helpers.HttpHeaderHelper;
+import org.apache.cxf.interceptor.Fault;
+import org.apache.cxf.interceptor.InterceptorChain;
+import org.apache.cxf.message.Exchange;
+import org.apache.cxf.message.ExchangeImpl;
+import org.apache.cxf.message.Message;
+import org.apache.cxf.message.MessageImpl;
+import org.easymock.EasyMock;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import static
org.apache.cxf.transport.common.gzip.GZIPOutInterceptor.UseGzip.FORCE;
+import static
org.apache.cxf.transport.common.gzip.GZIPOutInterceptor.UseGzip.YES;
+
+/**
+ * Test for the parsing of Accept-Encoding by the GZIPOutInterceptor. For
+ * Accept-Encoding values that enable gzip we expect an extra interceptor to be
+ * added to the out message, and the {@link GZIPOutInterceptor#USE_GZIP_KEY} to
+ * be set correctly. For Accept-Encoding values that do not enable gzip the
+ * interceptor should not be added.
+ */
+public class GZIPAcceptEncodingTest extends Assert {
+
+ private GZIPOutInterceptor interceptor;
+ private Message inMessage;
+ private Message outMessage;
+ private InterceptorChain outInterceptors;
+
+ @Before
+ public void setUp() throws Exception {
+ interceptor = new GZIPOutInterceptor();
+ inMessage = new MessageImpl();
+ outMessage = new MessageImpl();
+ Exchange exchange = new ExchangeImpl();
+ exchange.setInMessage(inMessage);
+ inMessage.setExchange(exchange);
+ inMessage.setContent(InputStream.class, new ByteArrayInputStream(new
byte[0]));
+ exchange.setOutMessage(outMessage);
+ outMessage.setExchange(exchange);
+ outMessage.setContent(OutputStream.class, new ByteArrayOutputStream());
+ outInterceptors = EasyMock.createMock(InterceptorChain.class);
+ outMessage.setInterceptorChain(outInterceptors);
+ }
+
+ @Test
+ public void testNoAcceptEncoding() throws Exception {
+ EasyMock.replay(outInterceptors);
+ interceptor.handleMessage(outMessage);
+ }
+
+ @Test
+ public void testAcceptGzip() throws Exception {
+ singleTest("gzip", true, YES, "gzip");
+ }
+
+ @Test
+ public void testAcceptXGzip() throws Exception {
+ singleTest("x-gzip, x-compress", true, YES, "x-gzip");
+ }
+
+ @Test
+ public void testAcceptStar() throws Exception {
+ singleTest("*", true, YES, "gzip");
+ }
+
+ @Test
+ public void testAcceptOnlyGzip() throws Exception {
+ singleTest("gzip, identity; q=0", true, FORCE, "gzip");
+ }
+
+ @Test
+ public void testOnlyIdentitySupported() throws Exception {
+ singleTest("deflate", false, null, null);
+ }
+
+ @Test
+ public void testGzipExplicitlyDisabled() throws Exception {
+ singleTest("gzip; q=0.00", false, null, null);
+ }
+
+ @Test(expected = Fault.class)
+ public void testNoValidEncodings() throws Exception {
+ EasyMock.replay();
+ setAcceptEncoding("*;q=0, deflate;q=0.5");
+ interceptor.handleMessage(outMessage);
+ }
+
+ private void singleTest(String encoding, boolean expectEndingInterceptor,
+ GZIPOutInterceptor.UseGzip expectedUseGzip, String
expectedGzipEncoding)
+ throws Exception {
+
+ EasyMock.replay(outInterceptors);
+ setAcceptEncoding(encoding);
+ interceptor.handleMessage(outMessage);
+ assertSame("Wrong value of " + GZIPOutInterceptor.USE_GZIP_KEY,
expectedUseGzip, outMessage
+ .get(GZIPOutInterceptor.USE_GZIP_KEY));
+ assertEquals("Wrong value of " + GZIPOutInterceptor.GZIP_ENCODING_KEY,
expectedGzipEncoding,
+ outMessage.get(GZIPOutInterceptor.GZIP_ENCODING_KEY));
+ }
+
+ private void setAcceptEncoding(String enc) {
+ Map<String, List<String>> protocolHeaders
+ = new TreeMap<String, List<String>>(String.CASE_INSENSITIVE_ORDER);
+
protocolHeaders.put(HttpHeaderHelper.getHeaderKey(HttpHeaderHelper.ACCEPT_ENCODING),
Collections
+ .singletonList(enc));
+ inMessage.put(Message.PROTOCOL_HEADERS, protocolHeaders);
+ }
+}
Modified: cxf/trunk/rt/pom.xml
URL:
http://svn.apache.org/viewvc/cxf/trunk/rt/pom.xml?rev=1239041&r1=1239040&r2=1239041&view=diff
==============================================================================
--- cxf/trunk/rt/pom.xml (original)
+++ cxf/trunk/rt/pom.xml Wed Feb 1 10:30:19 2012
@@ -45,7 +45,6 @@
<module>frontend/jaxws</module>
<module>frontend/jaxrs</module>
<module>frontend/js</module>
- <module>transports/common</module>
<module>transports/http</module>
<module>transports/http-jetty</module>
<module>transports/jms</module>
Modified: cxf/trunk/rt/transports/jms/pom.xml
URL:
http://svn.apache.org/viewvc/cxf/trunk/rt/transports/jms/pom.xml?rev=1239041&r1=1239040&r2=1239041&view=diff
==============================================================================
--- cxf/trunk/rt/transports/jms/pom.xml (original)
+++ cxf/trunk/rt/transports/jms/pom.xml Wed Feb 1 10:30:19 2012
@@ -60,11 +60,6 @@
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
- <artifactId>cxf-rt-transports-common</artifactId>
- <version>${project.version}</version>
- </dependency>
- <dependency>
- <groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-management</artifactId>
<version>${project.version}</version>
</dependency>