You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by se...@apache.org on 2012/09/14 13:22:21 UTC

svn commit: r1384726 - in /cxf/trunk: rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/ rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/spec/ rt/frontend/jaxrs/src/main/java/o...

Author: sergeyb
Date: Fri Sep 14 11:22:20 2012
New Revision: 1384726

URL: http://svn.apache.org/viewvc?rev=1384726&view=rev
Log:
[CXF-4455] Wiring in new client filters into the existing RS client runtime

Added:
    cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/spec/ClientRequestFilterInterceptor.java   (with props)
    cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/spec/ClientResponseFilterInterceptor.java   (with props)
Modified:
    cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/JAXRSInvoker.java
    cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/AbstractClient.java
    cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/ClientProxyImpl.java
    cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/WebClient.java
    cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/spec/ClientRequestContextImpl.java
    cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/spec/ClientResponseContextImpl.java
    cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/AbstractResponseContextImpl.java
    cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/ContainerResponseContextImpl.java
    cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/ResponseImpl.java
    cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/interceptor/JAXRSInInterceptor.java
    cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/interceptor/JAXRSOutInterceptor.java
    cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/BookStore.java
    cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRS20ClientServerBookTest.java

Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/JAXRSInvoker.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/JAXRSInvoker.java?rev=1384726&r1=1384725&r2=1384726&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/JAXRSInvoker.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/JAXRSInvoker.java Fri Sep 14 11:22:20 2012
@@ -126,6 +126,15 @@ public class JAXRSInvoker extends Abstra
         boolean wasSuspended = exchange.remove(REQUEST_WAS_SUSPENDED) != null;
         
         if (!wasSuspended) {
+            
+            // Global and name-bound request filters
+            if (!ori.isSubResourceLocator() && JAXRSUtils.runContainerRequestFilters(
+                                                  providerFactory,
+                                                  exchange.getInMessage(),
+                                                  false, ori.getNameBindings())) {
+                return new MessageContentsList(exchange.get(Response.class));
+            }
+            
             pushOntoStack(ori, ClassHelper.getRealClass(resourceObject), inMessage);
                     
             if (cri.isRoot()) {
@@ -232,14 +241,6 @@ public class JAXRSInvoker extends Abstra
                                                          contentType,
                                                          acceptContentType,
                                                          true);
-                // Global and name-bound request filters
-                if (JAXRSUtils.runContainerRequestFilters(
-                                                      providerFactory,
-                                                      exchange.getInMessage(),
-                                                      false, ori.getNameBindings())) {
-                    return new MessageContentsList(exchange.get(Response.class));
-                }                
-
                 exchange.put(OperationResourceInfo.class, subOri);
                 msg.put(URITemplate.TEMPLATE_PARAMETERS, values);
                 // work out request parameters for the sub-resource class. Here we

Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/AbstractClient.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/AbstractClient.java?rev=1384726&r1=1384725&r2=1384726&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/AbstractClient.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/AbstractClient.java Fri Sep 14 11:22:20 2012
@@ -51,6 +51,7 @@ import javax.ws.rs.core.UriBuilder;
 import javax.ws.rs.ext.MessageBodyReader;
 import javax.ws.rs.ext.MessageBodyWriter;
 import javax.xml.stream.XMLStreamReader;
+import javax.xml.stream.XMLStreamWriter;
 
 import org.apache.cxf.Bus;
 import org.apache.cxf.common.i18n.BundleUtils;
@@ -59,8 +60,11 @@ import org.apache.cxf.endpoint.ConduitSe
 import org.apache.cxf.endpoint.Endpoint;
 import org.apache.cxf.endpoint.Retryable;
 import org.apache.cxf.helpers.CastUtils;
+import org.apache.cxf.interceptor.AbstractOutDatabindingInterceptor;
 import org.apache.cxf.interceptor.Fault;
 import org.apache.cxf.interceptor.Interceptor;
+import org.apache.cxf.jaxrs.client.spec.ClientRequestFilterInterceptor;
+import org.apache.cxf.jaxrs.client.spec.ClientResponseFilterInterceptor;
 import org.apache.cxf.jaxrs.impl.MetadataMap;
 import org.apache.cxf.jaxrs.impl.UriBuilderImpl;
 import org.apache.cxf.jaxrs.model.ParameterType;
@@ -74,6 +78,7 @@ import org.apache.cxf.message.ExchangeIm
 import org.apache.cxf.message.Message;
 import org.apache.cxf.message.MessageContentsList;
 import org.apache.cxf.message.MessageUtils;
+import org.apache.cxf.phase.Phase;
 import org.apache.cxf.phase.PhaseChainCache;
 import org.apache.cxf.phase.PhaseInterceptorChain;
 import org.apache.cxf.phase.PhaseManager;
@@ -326,6 +331,13 @@ public abstract class AbstractClient imp
     }
     
     protected ResponseBuilder setResponseBuilder(Message outMessage, Exchange exchange) throws Exception {
+        Response response = exchange.get(Response.class);
+        if (response != null) {
+            ResponseBuilder rb = Response.fromResponse(response);
+            state.setResponseBuilder(rb);
+            return rb.clone();
+        }
+        
         Integer status = getResponseCode(exchange);
         ResponseBuilder currentResponseBuilder = Response.status(status);
         
@@ -760,7 +772,9 @@ public abstract class AbstractClient imp
         List<Interceptor<? extends Message>> i1 = cfg.getBus().getOutInterceptors();
         List<Interceptor<? extends Message>> i2 = cfg.getOutInterceptors();
         List<Interceptor<? extends Message>> i3 = cfg.getConduitSelector().getEndpoint().getOutInterceptors();
-        return new PhaseChainCache().get(pm.getOutPhases(), i1, i2, i3);
+        PhaseInterceptorChain chain = new PhaseChainCache().get(pm.getOutPhases(), i1, i2, i3);
+        chain.add(new ClientRequestFilterInterceptor());
+        return chain;
     }
     
     protected static PhaseInterceptorChain setupInInterceptorChain(ClientConfiguration cfg) { 
@@ -768,8 +782,9 @@ public abstract class AbstractClient imp
         List<Interceptor<? extends Message>> i1 = cfg.getBus().getInInterceptors();
         List<Interceptor<? extends Message>> i2 = cfg.getInInterceptors();
         List<Interceptor<? extends Message>> i3 = cfg.getConduitSelector().getEndpoint().getInInterceptors();
-        
-        return new PhaseChainCache().get(pm.getInPhases(), i1, i2, i3);
+        PhaseInterceptorChain chain = new PhaseChainCache().get(pm.getInPhases(), i1, i2, i3);
+        chain.add(new ClientResponseFilterInterceptor());
+        return chain;
     }
     
     protected Message createMessage(Object body,
@@ -887,4 +902,37 @@ public abstract class AbstractClient imp
         outMessage.getExchange().put("org.apache.cxf.resource.operation.name", name);
     }
     
+    protected abstract class AbstractBodyWriter extends AbstractOutDatabindingInterceptor {
+
+        public AbstractBodyWriter() {
+            super(Phase.WRITE);
+        }
+        
+        @SuppressWarnings("unchecked")
+        public void handleMessage(Message outMessage) throws Fault {
+            
+            MessageContentsList objs = MessageContentsList.getContentsList(outMessage);
+            if (objs == null || objs.size() == 0) {
+                return;
+            }
+            
+            OutputStream os = outMessage.getContent(OutputStream.class);
+            if (os == null) {
+                XMLStreamWriter writer = outMessage.getContent(XMLStreamWriter.class);
+                if (writer == null) {
+                    return;
+                }
+            }
+            
+            MultivaluedMap<String, Object> headers = 
+                (MultivaluedMap<String, Object>)outMessage.get(Message.PROTOCOL_HEADERS);
+            
+            Object body = objs.get(0);
+            
+            doWriteBody(outMessage, body, headers, os);
+        }
+        
+        protected abstract void doWriteBody(Message outMessage, Object body,
+                                 MultivaluedMap<String, Object> headers, OutputStream os) throws Fault;
+    }
 }

Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/ClientProxyImpl.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/ClientProxyImpl.java?rev=1384726&r1=1384725&r2=1384726&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/ClientProxyImpl.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/ClientProxyImpl.java Fri Sep 14 11:22:20 2012
@@ -43,13 +43,11 @@ import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.MultivaluedMap;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriBuilder;
-import javax.xml.stream.XMLStreamWriter;
 
 import org.apache.cxf.common.i18n.BundleUtils;
 import org.apache.cxf.common.logging.LogUtils;
 import org.apache.cxf.endpoint.Endpoint;
 import org.apache.cxf.helpers.CastUtils;
-import org.apache.cxf.interceptor.AbstractOutDatabindingInterceptor;
 import org.apache.cxf.interceptor.Fault;
 import org.apache.cxf.interceptor.InterceptorProvider;
 import org.apache.cxf.jaxrs.ext.multipart.Attachment;
@@ -66,8 +64,6 @@ import org.apache.cxf.jaxrs.utils.FormUt
 import org.apache.cxf.jaxrs.utils.InjectionUtils;
 import org.apache.cxf.message.Exchange;
 import org.apache.cxf.message.Message;
-import org.apache.cxf.message.MessageContentsList;
-import org.apache.cxf.phase.Phase;
 
 /**
  * Proxy-based client implementation
@@ -532,8 +528,6 @@ public class ClientProxyImpl extends Abs
         
         Object[] results = preProcessResult(outMessage);
         if (results != null && results.length == 1) {
-            // this can happen if a connection exception has occurred and
-            // failover feature used this client to invoke on a different address  
             return results[0];
         }
         
@@ -603,38 +597,23 @@ public class ClientProxyImpl extends Abs
         throw new ClientException(errorMsg.toString());
     }
     
-    // TODO : what we really need to do is to refactor JAXRSOutInterceptor so that
-    // it can handle both client requests and server responses - it may need to be split into
-    // several interceptors - in fact we need to do the same for JAXRSInInterceptor so that we can do
-    // on onMessage() properly
-    
-    private class BodyWriter extends AbstractOutDatabindingInterceptor {
-
-        public BodyWriter() {
-            super(Phase.WRITE);
-        }
+    private class BodyWriter extends AbstractBodyWriter {
         
-        @SuppressWarnings("unchecked")
-        public void handleMessage(Message outMessage) throws Fault {
+        protected void doWriteBody(Message outMessage, Object body,
+                                 MultivaluedMap<String, Object> headers, 
+                                 OutputStream os) throws Fault {
+            
             
             OperationResourceInfo ori = outMessage.getContent(OperationResourceInfo.class);
-            OutputStream os = outMessage.getContent(OutputStream.class);
-            if ((os == null && outMessage.getContent(XMLStreamWriter.class) == null)
-                || ori == null) {
+            if (ori == null) {
                 return;
             }
-            MessageContentsList objs = MessageContentsList.getContentsList(outMessage);
-            if (objs == null || objs.size() == 0) {
-                return;
-            }
-            MultivaluedMap<String, Object> headers = 
-                (MultivaluedMap<String, Object>)outMessage.get(Message.PROTOCOL_HEADERS);
+            
             Method method = ori.getMethodToInvoke();
             int bodyIndex = (Integer)outMessage.get("BODY_INDEX");
             Method aMethod = ori.getAnnotatedMethod();
             Annotation[] anns = aMethod == null || bodyIndex == -1 ? new Annotation[0] 
                                                   : aMethod.getParameterAnnotations()[bodyIndex];
-            Object body = objs.get(0);
             try {
                 if (bodyIndex != -1) {
                     Class<?> paramClass = method.getParameterTypes()[bodyIndex];

Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/WebClient.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/WebClient.java?rev=1384726&r1=1384725&r2=1384726&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/WebClient.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/WebClient.java Fri Sep 14 11:22:20 2012
@@ -40,13 +40,11 @@ import javax.ws.rs.core.PathSegment;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.Response.ResponseBuilder;
 import javax.ws.rs.core.UriBuilder;
-import javax.xml.stream.XMLStreamWriter;
 
 import org.apache.cxf.Bus;
 import org.apache.cxf.bus.spring.SpringBusFactory;
 import org.apache.cxf.feature.Feature;
 import org.apache.cxf.helpers.CastUtils;
-import org.apache.cxf.interceptor.AbstractOutDatabindingInterceptor;
 import org.apache.cxf.interceptor.Fault;
 import org.apache.cxf.jaxrs.ext.form.Form;
 import org.apache.cxf.jaxrs.impl.ResponseImpl;
@@ -58,8 +56,6 @@ import org.apache.cxf.jaxrs.utils.JAXRSU
 import org.apache.cxf.jaxrs.utils.ParameterizedCollectionType;
 import org.apache.cxf.message.Exchange;
 import org.apache.cxf.message.Message;
-import org.apache.cxf.message.MessageContentsList;
-import org.apache.cxf.phase.Phase;
 
 
 /**
@@ -802,8 +798,6 @@ public class WebClient extends AbstractC
         try {
             Object[] results = preProcessResult(m);
             if (results != null && results.length == 1) {
-                // this can happen if a connection exception has occurred and
-                // failover feature used this client to invoke on a different address  
                 return (Response)results[0];
             }
         } catch (Exception ex) {
@@ -856,27 +850,11 @@ public class WebClient extends AbstractC
     }
     
     
-    private class BodyWriter extends AbstractOutDatabindingInterceptor {
+    private class BodyWriter extends AbstractBodyWriter {
 
-        public BodyWriter() {
-            super(Phase.WRITE);
-        }
-        
-        @SuppressWarnings("unchecked")
-        public void handleMessage(Message outMessage) throws Fault {
-            
-            OutputStream os = outMessage.getContent(OutputStream.class);
-            XMLStreamWriter writer = outMessage.getContent(XMLStreamWriter.class);
-            if (os == null && writer == null) {
-                return;
-            }
-            MessageContentsList objs = MessageContentsList.getContentsList(outMessage);
-            if (objs == null || objs.size() == 0) {
-                return;
-            }
-            MultivaluedMap<String, Object> headers = 
-                (MultivaluedMap<String, Object>)outMessage.get(Message.PROTOCOL_HEADERS);
-            Object body = objs.get(0);
+        protected void doWriteBody(Message outMessage, Object body,
+                                   MultivaluedMap<String, Object> headers, 
+                                   OutputStream os) throws Fault {    
             
             Map<String, Object> requestContext = WebClient.this.getRequestContext(outMessage);
             Class<?> requestClass = null;

Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/spec/ClientRequestContextImpl.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/spec/ClientRequestContextImpl.java?rev=1384726&r1=1384725&r2=1384726&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/spec/ClientRequestContextImpl.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/spec/ClientRequestContextImpl.java Fri Sep 14 11:22:20 2012
@@ -22,16 +22,21 @@ import java.io.OutputStream;
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Type;
 import java.net.URI;
+import java.util.List;
+import java.util.Map;
 
 import javax.ws.rs.client.Client;
 import javax.ws.rs.client.ClientRequestContext;
 import javax.ws.rs.client.Configuration;
+import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.MultivaluedMap;
 
 import org.apache.cxf.jaxrs.impl.AbstractRequestContextImpl;
+import org.apache.cxf.jaxrs.impl.MetadataMap;
 import org.apache.cxf.message.Message;
 
+
 public class ClientRequestContextImpl extends AbstractRequestContextImpl
     implements ClientRequestContext {
 
@@ -82,21 +87,25 @@ public class ClientRequestContextImpl ex
     }
 
     @Override
-    public URI getUri() {
-        String requestURI = (String)m.get(Message.REQUEST_URI);
-        return requestURI  == null ? null : URI.create(requestURI);
-    }
-
-    @Override
     public boolean hasEntity() {
         // TODO Auto-generated method stub
         return false;
     }
-
+    
     @Override
-    public void setEntity(Object arg0, Annotation[] arg1, MediaType arg2) {
-        // TODO Auto-generated method stub
+    public void setEntity(Object entity, Annotation[] anns, MediaType mt) {
+        if (mt != null) {
+            MultivaluedMap<String, Object> headers = getHeaders();
+            headers.putSingle(HttpHeaders.CONTENT_TYPE, mt);
+            m.put(Message.CONTENT_TYPE, mt.toString());
+        }
+    }
 
+    
+    @Override
+    public URI getUri() {
+        String requestURI = (String)m.get(Message.REQUEST_URI);
+        return requestURI  == null ? null : URI.create(requestURI);
     }
 
     @Override
@@ -112,15 +121,18 @@ public class ClientRequestContextImpl ex
 
     }
 
+    @SuppressWarnings("unchecked")
     @Override
     public MultivaluedMap<String, Object> getHeaders() {
-        return null;    
+        h = null;
+        return new MetadataMap<String, Object>(
+            (Map<String, List<Object>>)m.get(Message.PROTOCOL_HEADERS), false, true, true);    
 
     }
 
     @Override
     public MultivaluedMap<String, String> getStringHeaders() {
-        return null;
+        return h.getRequestHeaders();
     }
 
 }

Added: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/spec/ClientRequestFilterInterceptor.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/spec/ClientRequestFilterInterceptor.java?rev=1384726&view=auto
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/spec/ClientRequestFilterInterceptor.java (added)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/spec/ClientRequestFilterInterceptor.java Fri Sep 14 11:22:20 2012
@@ -0,0 +1,83 @@
+/**
+ * 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.client.spec;
+
+import java.io.IOException;
+import java.util.List;
+
+import javax.ws.rs.client.ClientException;
+import javax.ws.rs.client.ClientRequestContext;
+import javax.ws.rs.client.ClientRequestFilter;
+import javax.ws.rs.core.Response;
+
+import org.apache.cxf.interceptor.AbstractOutDatabindingInterceptor;
+import org.apache.cxf.interceptor.Fault;
+import org.apache.cxf.jaxrs.model.ProviderInfo;
+import org.apache.cxf.jaxrs.provider.ProviderFactory;
+import org.apache.cxf.jaxrs.utils.InjectionUtils;
+import org.apache.cxf.message.Exchange;
+import org.apache.cxf.message.Message;
+import org.apache.cxf.message.MessageImpl;
+import org.apache.cxf.phase.Phase;
+import org.apache.cxf.transport.MessageObserver;
+
+public class ClientRequestFilterInterceptor extends AbstractOutDatabindingInterceptor {
+
+    public ClientRequestFilterInterceptor() {
+        super(Phase.WRITE);
+    }
+    
+    public void handleMessage(Message outMessage) throws Fault {
+        ProviderFactory pf = ProviderFactory.getInstance(outMessage);
+        if (pf == null) {
+            return;
+        }
+        
+        List<ProviderInfo<ClientRequestFilter>> filters = pf.getClientRequestFilters();
+        if (!filters.isEmpty()) {
+            
+            final Exchange exchange = outMessage.getExchange(); 
+            final ClientRequestContext context = new ClientRequestContextImpl(outMessage, false); 
+            for (ProviderInfo<ClientRequestFilter> filter : filters) {
+                InjectionUtils.injectContexts(filter.getProvider(), filter, outMessage);
+                try {
+                    filter.getProvider().filter(context);
+                    
+                    Response response = outMessage.getExchange().get(Response.class);
+                    if (response != null) {
+                        outMessage.getInterceptorChain().abort();
+                        
+                        Message inMessage = new MessageImpl();
+                        inMessage.setExchange(exchange);
+                        inMessage.put(Message.RESPONSE_CODE, response.getStatus());
+                        inMessage.put(Message.PROTOCOL_HEADERS, response.getMetadata());
+                        exchange.setInMessage(inMessage);
+                        
+                        MessageObserver observer = exchange.get(MessageObserver.class);
+                        observer.onMessage(inMessage);
+                        return;
+                    }
+                } catch (IOException ex) {
+                    throw new ClientException(ex);
+                }
+            }
+        }
+    }
+    
+}

Propchange: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/spec/ClientRequestFilterInterceptor.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/spec/ClientRequestFilterInterceptor.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/spec/ClientResponseContextImpl.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/spec/ClientResponseContextImpl.java?rev=1384726&r1=1384725&r2=1384726&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/spec/ClientResponseContextImpl.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/spec/ClientResponseContextImpl.java Fri Sep 14 11:22:20 2012
@@ -45,8 +45,11 @@ public class ClientResponseContextImpl e
     @SuppressWarnings("unchecked")
     @Override
     public MultivaluedMap<String, String> getHeaders() {
-        return new MetadataMap<String, String>(
-            (Map<String, List<String>>)m.get(Message.PROTOCOL_HEADERS), false, true, true);
+        Object headers = m.get(Message.PROTOCOL_HEADERS);
+        if (headers != null) {
+            return new MetadataMap<String, String>((Map<String, List<String>>)headers, false, true, true);
+        }
+        return (MultivaluedMap<String, String>)(MultivaluedMap<?, ?>)r.getHeaders();
     }
 
     

Added: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/spec/ClientResponseFilterInterceptor.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/spec/ClientResponseFilterInterceptor.java?rev=1384726&view=auto
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/spec/ClientResponseFilterInterceptor.java (added)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/spec/ClientResponseFilterInterceptor.java Fri Sep 14 11:22:20 2012
@@ -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.cxf.jaxrs.client.spec;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.List;
+import java.util.Map;
+
+import javax.ws.rs.client.ClientException;
+import javax.ws.rs.client.ClientRequestContext;
+import javax.ws.rs.client.ClientResponseContext;
+import javax.ws.rs.client.ClientResponseFilter;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.ResponseBuilder;
+
+import org.apache.cxf.interceptor.AbstractInDatabindingInterceptor;
+import org.apache.cxf.interceptor.Fault;
+import org.apache.cxf.jaxrs.model.ProviderInfo;
+import org.apache.cxf.jaxrs.provider.ProviderFactory;
+import org.apache.cxf.jaxrs.utils.InjectionUtils;
+import org.apache.cxf.message.Message;
+import org.apache.cxf.phase.Phase;
+
+public class ClientResponseFilterInterceptor extends AbstractInDatabindingInterceptor {
+
+    public ClientResponseFilterInterceptor() {
+        super(Phase.UNMARSHAL);
+    }
+    
+    public void handleMessage(Message inMessage) throws Fault {
+        ProviderFactory pf = ProviderFactory.getInstance(inMessage);
+        if (pf == null) {
+            return;
+        }
+        
+        List<ProviderInfo<ClientResponseFilter>> filters = pf.getClientResponseFilters();
+        if (!filters.isEmpty()) {
+            ClientRequestContext reqContext = new ClientRequestContextImpl(inMessage.getExchange().getInMessage(),
+                                                                        true);
+            
+            ClientResponseContext respContext = new ClientResponseContextImpl(getResponse(inMessage), 
+                                                                              inMessage);
+            for (ProviderInfo<ClientResponseFilter> filter : filters) {
+                InjectionUtils.injectContexts(filter.getProvider(), filter, inMessage);
+                try {
+                    filter.getProvider().filter(reqContext, respContext);
+                } catch (IOException ex) {
+                    throw new ClientException(ex);
+                }
+            }
+        }
+    }
+    
+    protected Response getResponse(Message inMessage) {
+        Response resp = inMessage.getExchange().get(Response.class);
+        if (resp != null) {
+            return resp;
+        }
+        ResponseBuilder rb = Response.status((Integer)inMessage.get(Message.RESPONSE_CODE));
+        rb.entity(inMessage.get(InputStream.class));
+        
+        @SuppressWarnings("unchecked")
+        Map<String, List<String>> protocolHeaders = 
+            (Map<String, List<String>>)inMessage.get(Message.PROTOCOL_HEADERS);
+        for (Map.Entry<String, List<String>> entry : protocolHeaders.entrySet()) {
+            if (null == entry.getKey()) {
+                continue;
+            }
+            if (entry.getValue().size() > 0) {
+                for (String val : entry.getValue()) {
+                    rb.header(entry.getKey(), val);
+                }
+            }
+        }
+        
+                
+        return rb.build();
+    }
+}

Propchange: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/spec/ClientResponseFilterInterceptor.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/spec/ClientResponseFilterInterceptor.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/AbstractResponseContextImpl.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/AbstractResponseContextImpl.java?rev=1384726&r1=1384725&r2=1384726&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/AbstractResponseContextImpl.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/AbstractResponseContextImpl.java Fri Sep 14 11:22:20 2012
@@ -26,6 +26,7 @@ import java.util.Map;
 import java.util.Set;
 
 import javax.ws.rs.core.EntityTag;
+import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.Link;
 import javax.ws.rs.core.Link.Builder;
 import javax.ws.rs.core.MediaType;
@@ -36,6 +37,7 @@ import javax.ws.rs.core.Response.StatusT
 
 import org.apache.cxf.message.Message;
 
+
 public abstract class AbstractResponseContextImpl {
 
     protected Message m;
@@ -111,7 +113,6 @@ public abstract class AbstractResponseCo
     }
 
     public MultivaluedMap<String, String> getStringHeaders() {
-        //TODO: right now this view is not modifiable
         return r.getStringHeaders();
     }
 
@@ -124,12 +125,24 @@ public abstract class AbstractResponseCo
     }
 
     public void setEntity(Object entity, Annotation[] anns, MediaType mt) {
-        ((ResponseImpl)r).setEntity(entity);
+        ((ResponseImpl)r).setEntity(entity, anns);
+        if (mt != null) {
+            r.getMetadata().putSingle(HttpHeaders.CONTENT_TYPE, mt);
+            m.put(Message.CONTENT_TYPE, mt.toString());
+        }
         updateMessageResponse();
-        //TODO: review this code after API gets finalized
+    }
+    
+    protected Annotation[] getResponseEntityAnnotations() {
+        return ((ResponseImpl)r).getEntityAnnotations();
+    }
+    
+    protected Class<?> getResponseEntityClass() {
+        return r.getEntity().getClass();
     }
     
     public void setStatus(int status) {
+        m.put(Message.RESPONSE_CODE, status);
         ((ResponseImpl)r).setStatus(status);
         updateMessageResponse();
     }

Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/ContainerResponseContextImpl.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/ContainerResponseContextImpl.java?rev=1384726&r1=1384725&r2=1384726&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/ContainerResponseContextImpl.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/ContainerResponseContextImpl.java Fri Sep 14 11:22:20 2012
@@ -43,18 +43,22 @@ public class ContainerResponseContextImp
     
     @Override
     public Annotation[] getEntityAnnotations() {
-        Method method = ori == null ? null : ori.getAnnotatedMethod();
-        return method == null ? null : method.getAnnotations();
+        Annotation[] anns = super.getResponseEntityAnnotations();
+        if (anns == null) {
+            Method method = ori == null ? null : ori.getAnnotatedMethod();
+            anns = method == null ? new Annotation[]{} : method.getAnnotations();
+        }
+        return anns;
     }
 
     @Override
     public Class<?> getEntityClass() {
-        return ori == null ? null : ori.getMethodToInvoke().getReturnType();
+        return ori == null ? getResponseEntityClass() : ori.getMethodToInvoke().getReturnType();
     }
 
     @Override
     public Type getEntityType() {
-        return ori == null ? null : ori.getMethodToInvoke().getGenericReturnType();
+        return ori == null ? getResponseEntityClass() : ori.getMethodToInvoke().getGenericReturnType();
     }
     
     @Override

Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/ResponseImpl.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/ResponseImpl.java?rev=1384726&r1=1384725&r2=1384726&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/ResponseImpl.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/ResponseImpl.java Fri Sep 14 11:22:20 2012
@@ -54,6 +54,7 @@ import org.apache.cxf.message.Message;
 public final class ResponseImpl extends Response {
     private int status;
     private Object entity;
+    private Annotation[] entityAnnotations; 
     private MultivaluedMap<String, Object> metadata;
     
     private Message responseMessage;
@@ -77,8 +78,13 @@ public final class ResponseImpl extends 
         this.status = s;
     }
     
-    void setEntity(Object entity) { 
-        this.entity = entity;
+    void setEntity(Object e, Annotation[] anns) { 
+        this.entity = e;
+        this.entityAnnotations = anns;
+    }
+    
+    Annotation[] getEntityAnnotations() {
+        return entityAnnotations;
     }
 
     //TODO: This method is needed because on the client side the

Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/interceptor/JAXRSInInterceptor.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/interceptor/JAXRSInInterceptor.java?rev=1384726&r1=1384725&r2=1384726&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/interceptor/JAXRSInInterceptor.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/interceptor/JAXRSInInterceptor.java Fri Sep 14 11:22:20 2012
@@ -208,11 +208,6 @@ public class JAXRSInInterceptor extends 
             }
         }
 
-        // Global and name-bound request filters
-        if (JAXRSUtils.runContainerRequestFilters(providerFactory, message, false, ori.getNameBindings())) {
-            return;
-        }
-        
         if (LOG.isLoggable(Level.FINE)) {
             LOG.fine("Request path is: " + rawPath);
             LOG.fine("Request HTTP method is: " + httpMethod);

Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/interceptor/JAXRSOutInterceptor.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/interceptor/JAXRSOutInterceptor.java?rev=1384726&r1=1384725&r2=1384726&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/interceptor/JAXRSOutInterceptor.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/interceptor/JAXRSOutInterceptor.java Fri Sep 14 11:22:20 2012
@@ -139,11 +139,6 @@ public class JAXRSOutInterceptor extends
             }
         }
         
-        // TODO: enable or remove, depending on the API clarifications
-        // Global pre-match response filters 
-        // JAXRSUtils.runContainerResponseFilters(providerFactory, response, message, ori, true);
-        
-        
         List<ProviderInfo<ResponseHandler>> handlers = 
             ProviderFactory.getInstance(message).getResponseHandlers();
         for (ProviderInfo<ResponseHandler> rh : handlers) {

Modified: cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/BookStore.java
URL: http://svn.apache.org/viewvc/cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/BookStore.java?rev=1384726&r1=1384725&r2=1384726&view=diff
==============================================================================
--- cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/BookStore.java (original)
+++ cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/BookStore.java Fri Sep 14 11:22:20 2012
@@ -62,6 +62,7 @@ import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.MultivaluedMap;
 import javax.ws.rs.core.PathSegment;
 import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.ResponseBuilder;
 import javax.ws.rs.core.SecurityContext;
 import javax.ws.rs.core.StreamingOutput;
 import javax.ws.rs.core.UriBuilder;
@@ -429,8 +430,14 @@ public class BookStore {
     @GET
     @Path("/bookheaders/simple/")
     @CustomHeaderAdded
-    public Book getBookByHeaderSimple(@HeaderParam("BOOK") String header) throws Exception {
-        return doGetBook(header);
+    public Response getBookByHeaderSimple(@HeaderParam("BOOK") String headerBook,
+                                          @HeaderParam("Simple") String headerSimple) throws Exception {
+        
+        ResponseBuilder builder = Response.ok(doGetBook(headerBook));
+        if (headerSimple != null) {
+            builder.header("Simple", headerSimple);
+        }
+        return builder.build();
     }
     
     @GET

Modified: cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRS20ClientServerBookTest.java
URL: http://svn.apache.org/viewvc/cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRS20ClientServerBookTest.java?rev=1384726&r1=1384725&r2=1384726&view=diff
==============================================================================
--- cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRS20ClientServerBookTest.java (original)
+++ cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRS20ClientServerBookTest.java Fri Sep 14 11:22:20 2012
@@ -19,6 +19,15 @@
 
 package org.apache.cxf.systest.jaxrs;
 
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.ws.rs.client.ClientRequestContext;
+import javax.ws.rs.client.ClientRequestFilter;
+import javax.ws.rs.client.ClientResponseContext;
+import javax.ws.rs.client.ClientResponseFilter;
+import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.Response;
 
 import org.apache.cxf.jaxrs.client.WebClient;
@@ -49,11 +58,55 @@ public class JAXRS20ClientServerBookTest
     }
     
     private void doTestBook(String address) {
-        WebClient wc = WebClient.create(address);
+        List<Object> providers = new ArrayList<Object>();
+        providers.add(new ClientHeaderRequestFilter());
+        providers.add(new ClientHeaderResponseFilter());
+        WebClient wc = WebClient.create(address, providers);
         Book book = wc.get(Book.class);
         assertEquals(124L, book.getId());
         Response response = wc.getResponse();
         assertEquals("OK", response.getHeaderString("Response"));
         assertEquals("custom", response.getHeaderString("Custom"));
+        assertEquals("simple", response.getHeaderString("Simple"));
+        assertEquals("http://localhost/redirect", response.getHeaderString(HttpHeaders.LOCATION));
+    }
+    
+    @Test
+    public void testClientFiltersLocalResponse() {
+        String address = "http://localhost:" + PORT + "/bookstores";
+        List<Object> providers = new ArrayList<Object>();
+        providers.add(new ClientCacheRequestFilter());
+        providers.add(new ClientHeaderResponseFilter());
+        WebClient wc = WebClient.create(address, providers);
+        Response r = wc.get();
+        assertEquals(201, r.getStatus());
+        assertEquals("http://localhost/redirect", r.getHeaderString(HttpHeaders.LOCATION));
+    }
+    
+    private static class ClientCacheRequestFilter implements ClientRequestFilter {
+
+        @Override
+        public void filter(ClientRequestContext context) throws IOException {
+            context.abortWith(Response.status(201).build());
+        }
+    }
+    
+    private static class ClientHeaderRequestFilter implements ClientRequestFilter {
+
+        @Override
+        public void filter(ClientRequestContext context) throws IOException {
+            context.getHeaders().putSingle("Simple", "simple");
+        }
+    }
+    
+    private static class ClientHeaderResponseFilter implements ClientResponseFilter {
+
+        @Override
+        public void filter(ClientRequestContext reqContext, 
+                           ClientResponseContext respContext) throws IOException {
+            respContext.getHeaders().putSingle(HttpHeaders.LOCATION, "http://localhost/redirect");
+            
+        }
+        
     }
 }