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 2009/02/12 19:26:09 UTC

svn commit: r743825 [1/2] - in /cxf/trunk: rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/ rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/form/ rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/ rt/frontend/jaxrs/src/main...

Author: sergeyb
Date: Thu Feb 12 18:26:07 2009
New Revision: 743825

URL: http://svn.apache.org/viewvc?rev=743825&view=rev
Log:
JAXRS : prototyping client api - many more things to come

Added:
    cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/
    cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/AbstractClient.java   (with props)
    cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/Client.java   (with props)
    cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/ClientProxyImpl.java   (with props)
    cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/JAXRSClientFactory.java   (with props)
    cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/ResponseExceptionMapper.java   (with props)
    cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/WebClient.java   (with props)
    cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/form/
    cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/form/Form.java   (with props)
    cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/FormEncodingProvider.java
      - copied, changed from r739958, cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/FormEncodingReaderProvider.java
    cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/client/
    cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/client/WebClientTest.java   (with props)
    cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/provider/FormEncodingProviderTest.java
      - copied, changed from r739958, cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/provider/FormEncodingReaderProviderTest.java
Removed:
    cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/FormEncodingReaderProvider.java
    cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/StringProvider.java
    cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/provider/FormEncodingReaderProviderTest.java
Modified:
    cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/MetadataMap.java
    cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/RequestImpl.java
    cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/ResponseBuilderImpl.java
    cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/UriBuilderImpl.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/provider/PrimitiveTextProvider.java
    cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/ProviderFactory.java
    cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/HttpUtils.java
    cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/InjectionUtils.java
    cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/JAXRSUtils.java
    cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/ParameterType.java
    cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/impl/UriBuilderImplTest.java
    cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/provider/ProviderFactoryTest.java
    cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxrs/BookNotFoundFault.java
    cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxrs/BookStoreJaxrsJaxws.java
    cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxrs/BookStoreSoapRestImpl.java
    cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxrs/BookSubresource.java
    cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxrs/BookSubresourceImpl.java
    cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSSoapBookTest.java
    cxf/trunk/systests/src/test/resources/jaxrs_soap_rest/WEB-INF/beans.xml

Added: 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=743825&view=auto
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/AbstractClient.java (added)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/AbstractClient.java Thu Feb 12 18:26:07 2009
@@ -0,0 +1,328 @@
+/**
+ * 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;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import java.net.HttpURLConnection;
+import java.net.URI;
+import java.net.URL;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Cookie;
+import javax.ws.rs.core.EntityTag;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.ResponseBuilder;
+import javax.ws.rs.core.UriBuilder;
+import javax.ws.rs.ext.MessageBodyReader;
+import javax.ws.rs.ext.MessageBodyWriter;
+
+import org.apache.cxf.helpers.IOUtils;
+import org.apache.cxf.jaxrs.impl.MetadataMap;
+import org.apache.cxf.jaxrs.impl.UriBuilderImpl;
+import org.apache.cxf.jaxrs.provider.ProviderFactory;
+import org.apache.cxf.jaxrs.utils.HttpUtils;
+import org.apache.cxf.message.MessageImpl;
+
+public class AbstractClient implements Client {
+    
+    private MultivaluedMap<String, String> requestHeaders = new MetadataMap<String, String>();
+    private ResponseBuilder responseBuilder;
+    
+    private URI baseURI;
+    private UriBuilder currentBuilder;
+    
+    protected AbstractClient(URI baseURI, URI currentURI) {
+        this.baseURI = baseURI;
+        this.currentBuilder = new UriBuilderImpl(currentURI);
+    }
+    
+    protected AbstractClient(Client client, boolean inheritHeaders) {
+        this.baseURI = client.getCurrentURI();
+        this.currentBuilder = new UriBuilderImpl(client.getCurrentURI());
+        if (inheritHeaders) {
+            this.requestHeaders = client.getHeaders();
+        }
+    }
+    
+    public Client header(String name, Object... values) {
+        if (values == null) {
+            throw new IllegalArgumentException();
+        }
+        if (HttpHeaders.CONTENT_TYPE.equals(name) && values.length > 1) {
+            throw new WebApplicationException();
+        }
+        for (Object o : values) {
+            requestHeaders.add(name, o.toString());
+        }
+        return this;
+    }
+
+    public Client headers(MultivaluedMap<String, String> map) {
+        requestHeaders.putAll(map);
+        return this;
+    }
+    
+    public Client accept(MediaType... types) {
+        for (MediaType mt : types) {
+            requestHeaders.add(HttpHeaders.ACCEPT, mt.toString());
+        }
+        return this;
+    }
+
+    public Client type(MediaType ct) {
+        return type(ct.toString());
+    }
+    
+    public Client type(String type) {
+        requestHeaders.putSingle(HttpHeaders.CONTENT_TYPE, type);
+        return this;
+    }
+
+    public Client accept(String... types) {
+        for (String type : types) {
+            requestHeaders.add(HttpHeaders.ACCEPT, type);
+        }
+        return this;
+    }
+
+    public Client cookie(Cookie cookie) {
+        requestHeaders.add(HttpHeaders.COOKIE, cookie.toString());
+        return this;
+    }
+
+    public Client modified(Date date, boolean ifNot) {
+        SimpleDateFormat dateFormat = HttpUtils.getHttpDateFormat();
+        String hName = ifNot ? HttpHeaders.IF_UNMODIFIED_SINCE : HttpHeaders.IF_MODIFIED_SINCE;
+        requestHeaders.putSingle(hName, dateFormat.format(date));
+        return this;
+    }
+
+    public Client language(String language) {
+        requestHeaders.putSingle(HttpHeaders.CONTENT_LANGUAGE, language);
+        return this;
+    }
+
+    public Client match(EntityTag tag, boolean ifNot) {
+        String hName = ifNot ? HttpHeaders.IF_NONE_MATCH : HttpHeaders.IF_MATCH; 
+        requestHeaders.putSingle(hName, tag.toString());
+        return this;
+    }
+
+    public Client acceptLanguage(String... languages) {
+        for (String s : languages) {
+            requestHeaders.add(HttpHeaders.ACCEPT_LANGUAGE, s);
+        }
+        return this;
+    }
+
+    public Client acceptEncoding(String... encs) {
+        for (String s : encs) {
+            requestHeaders.add(HttpHeaders.ACCEPT_ENCODING, s);
+        }
+        return this;
+    }
+
+    public Client encoding(String enc) {
+        requestHeaders.putSingle(HttpHeaders.CONTENT_ENCODING, enc);
+        return this;
+    }
+    
+    protected List<MediaType> getAccept() {
+        List<String> headers = requestHeaders.get(HttpHeaders.ACCEPT);
+        if (headers == null || headers.size() == 0) {
+            return null;
+        }
+        List<MediaType> types = new ArrayList<MediaType>();
+        for (String s : headers) {
+            types.add(MediaType.valueOf(s));
+        }
+        return types;
+    }
+
+    public MultivaluedMap<String, String> getHeaders() {
+        MultivaluedMap<String, String> map = new MetadataMap<String, String>();
+        map.putAll(requestHeaders);
+        return map;
+    }
+    
+    protected MediaType getType() {
+        String type = requestHeaders.getFirst(HttpHeaders.CONTENT_TYPE);
+        return type == null ? null : MediaType.valueOf(type);
+    }
+
+    public URI getBaseURI() {
+        return baseURI;
+    }
+
+    public URI getCurrentURI() {
+        return getCurrentBuilder().clone().build();
+    }
+    
+    protected UriBuilder getCurrentBuilder() {
+        return currentBuilder;
+    }
+
+    public Response getResponse() {
+        if (responseBuilder == null) {
+            throw new IllegalStateException();
+        }
+        Response r = responseBuilder.build();
+        responseBuilder = null;
+        return r;
+    }
+    
+    public Client reset() {
+        requestHeaders.clear();
+        resetResponse();
+        return this;
+    }
+    
+    protected void resetResponse() {
+        responseBuilder = null;
+    }
+    
+    protected void resetBaseAddress(URI uri) {
+        baseURI = uri;
+        currentBuilder = new UriBuilderImpl(baseURI);
+    }
+    
+    protected ResponseBuilder setResponseBuilder(HttpURLConnection conn) throws IOException {
+        int status = conn.getResponseCode();
+        responseBuilder = Response.status(status);
+        for (Map.Entry<String, List<String>> entry : conn.getHeaderFields().entrySet()) {
+            for (String s : entry.getValue()) {
+                responseBuilder.header(entry.getKey(), s);
+            }
+        }
+        if (status >= 400) {
+            try {
+                InputStream errorStream = conn.getErrorStream();
+                if (errorStream != null) {
+                    responseBuilder.entity(IOUtils.readStringFromStream(errorStream));
+                }
+            } catch (Exception ex) {
+                // nothing we can do really
+            }
+        }
+        return responseBuilder;
+    }
+
+    @SuppressWarnings("unchecked")
+    protected static void writeBody(Object o, Class<?> cls, Type type, Annotation[] anns, 
+        MultivaluedMap<String, String> headers, OutputStream os) {
+        
+        if (o == null) {
+            return;
+        }
+        
+        MediaType contentType = MediaType.valueOf(headers.getFirst("Content-Type")); 
+        
+        MessageBodyWriter mbr = ProviderFactory.getInstance().createMessageBodyWriter(
+            cls, type, anns, contentType, new MessageImpl());
+        if (mbr != null) {
+            try {
+                mbr.writeTo(o, cls, type, anns, contentType, headers, os);
+                os.flush();
+            } catch (Exception ex) {
+                throw new WebApplicationException();
+            }
+             
+        } else {
+            throw new WebApplicationException();
+        }
+                                                                                 
+    }
+    
+    @SuppressWarnings("unchecked")
+    protected static Object readBody(Response r, HttpURLConnection conn, Class<?> cls, Type type, 
+                                     Annotation[] anns) {
+
+        try {
+            int status = conn.getResponseCode();
+            if (status < 200 || status == 204 || status > 300) {
+                return null;
+            }
+        } catch (IOException ex) {
+            // won't happen at this stage
+        }
+        
+        MediaType contentType = getResponseContentType(r);
+        
+        MessageBodyReader mbr = ProviderFactory.getInstance().createMessageBodyReader(
+            cls, type, anns, contentType, new MessageImpl());
+        if (mbr != null) {
+            try {
+                return mbr.readFrom(cls, type, anns, contentType, r.getMetadata(), conn.getInputStream());
+            } catch (Exception ex) {
+                throw new WebApplicationException();
+            }
+             
+        } else {
+            throw new WebApplicationException();
+        }
+                                                                                 
+    }
+    
+    private static MediaType getResponseContentType(Response r) {
+        MultivaluedMap<String, Object> map = r.getMetadata();
+        if (map.containsKey(HttpHeaders.CONTENT_TYPE)) {
+            return MediaType.valueOf(map.getFirst(HttpHeaders.CONTENT_TYPE).toString());
+        }
+        return MediaType.WILDCARD_TYPE;
+    }
+    
+    protected static HttpURLConnection createHttpConnection(URI uri, String methodName) {
+        try {
+            URL url = uri.toURL();
+            HttpURLConnection connect = (HttpURLConnection)url.openConnection();
+            connect.setDoOutput(true);
+            connect.setRequestMethod(methodName);
+            return connect;
+        } catch (Exception ex) {
+            throw new WebApplicationException(ex);
+        }
+    }
+    
+    protected static void setAllHeaders(MultivaluedMap<String, String> headers, HttpURLConnection conn) {
+        for (Map.Entry<String, List<String>> entry : headers.entrySet()) {
+            StringBuilder b = new StringBuilder();    
+            for (int i = 0; i < entry.getValue().size(); i++) {
+                String value = entry.getValue().get(i);
+                b.append(value);
+                if (i + 1 < entry.getValue().size()) {
+                    b.append(',');
+                }
+            }
+            conn.setRequestProperty(entry.getKey(), b.toString());
+        }
+    }
+
+}

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

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

Added: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/Client.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/Client.java?rev=743825&view=auto
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/Client.java (added)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/Client.java Thu Feb 12 18:26:07 2009
@@ -0,0 +1,58 @@
+/**
+ * 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;
+
+import java.net.URI;
+import java.util.Date;
+
+import javax.ws.rs.core.Cookie;
+import javax.ws.rs.core.EntityTag;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Response;
+
+public interface Client {
+    
+    Client type(MediaType ct);
+    Client type(String type);
+    Client accept(MediaType... types);
+    Client accept(String... types);
+    
+    Client language(String language);
+    Client acceptLanguage(String ...languages);
+    
+    Client encoding(String enc);
+    Client acceptEncoding(String ...encs);
+    
+    Client match(EntityTag tag, boolean ifNot);
+    Client modified(Date date, boolean ifNot);
+    
+    Client cookie(Cookie cookie);
+    
+    Client header(String name, Object... values);
+    Client headers(MultivaluedMap<String, String> map);
+    
+    Client reset();
+    
+    MultivaluedMap<String, String> getHeaders();
+    URI getBaseURI();
+    URI getCurrentURI();
+    
+    Response getResponse();
+}

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

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

Added: 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=743825&view=auto
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/ClientProxyImpl.java (added)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/ClientProxyImpl.java Thu Feb 12 18:26:07 2009
@@ -0,0 +1,379 @@
+/**
+ * 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;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.net.HttpURLConnection;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import javax.ws.rs.CookieParam;
+import javax.ws.rs.FormParam;
+import javax.ws.rs.HeaderParam;
+import javax.ws.rs.MatrixParam;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+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 org.apache.cxf.jaxrs.impl.MetadataMap;
+import org.apache.cxf.jaxrs.model.ClassResourceInfo;
+import org.apache.cxf.jaxrs.model.OperationResourceInfo;
+import org.apache.cxf.jaxrs.provider.ProviderFactory;
+import org.apache.cxf.jaxrs.utils.AnnotationUtils;
+import org.apache.cxf.jaxrs.utils.InjectionUtils;
+import org.apache.cxf.jaxrs.utils.JAXRSUtils;
+import org.apache.cxf.jaxrs.utils.ParameterType;
+
+public class ClientProxyImpl extends AbstractClient implements InvocationHandler {
+
+    private ClassResourceInfo cri;
+    private boolean inheritHeaders; 
+    
+    public ClientProxyImpl(URI baseURI, URI currentURI, ClassResourceInfo cri, boolean inheritHeaders) {
+        super(baseURI, currentURI);
+        this.cri = cri;
+        this.inheritHeaders = inheritHeaders;
+    }
+    
+    public Object invoke(Object o, Method m, Object[] params) throws Throwable {
+        
+        resetResponse();
+        
+        Class<?> declaringClass = m.getDeclaringClass();
+        if (Client.class == declaringClass) {
+            return m.invoke(this, params);
+        }
+        
+        OperationResourceInfo ori = cri.getMethodDispatcher().getOperationResourceInfo(m);
+        if (ori == null) {
+            throw new WebApplicationException(400);
+        }
+        
+        
+        MultivaluedMap<ParameterType, Parameter> types = 
+            getParametersInfo(ori, m, params);
+        List<Object> pathParams = getParamValues(types, params, ParameterType.PATH);
+        
+        int bodyIndex = getBodyIndex(types, ori.isSubResourceLocator());
+        
+        UriBuilder builder = getCurrentBuilder().clone(); 
+        if (cri.isRoot()) {
+            builder.path(ori.getClassResourceInfo().getServiceClass());
+        }
+        builder.path(m);
+        handleMatrixes(types, params, builder);
+        handleQueries(types, params, builder);
+        
+        URI uri = builder.build(pathParams.toArray()).normalize();
+        
+        MultivaluedMap<String, String> headers = getHeaders();
+        MultivaluedMap<String, String> paramHeaders = new MetadataMap<String, String>();
+        handleHeaders(paramHeaders, types, params);
+        handleCookies(paramHeaders, types, params);
+                
+        if (ori.isSubResourceLocator()) {
+            Object proxy = 
+                JAXRSClientFactory.create(getBaseURI(), uri, m.getReturnType(), false, inheritHeaders);
+            if (inheritHeaders) {
+                WebClient.client(proxy).headers(headers);
+            }
+            WebClient.client(proxy).headers(paramHeaders);
+            return proxy;
+        } 
+        
+        headers.putAll(paramHeaders);
+        
+        HttpURLConnection connect = createHttpConnection(uri, ori.getHttpMethod());
+        setRequestHeaders(connect, headers, ori, types.containsKey(ParameterType.FORM), 
+            bodyIndex == -1 ? null : params[bodyIndex].getClass(), m.getReturnType());
+        if (bodyIndex != -1 || types.containsKey(ParameterType.FORM)) {
+            if (bodyIndex != -1) {
+                writeBody(params[bodyIndex], params[bodyIndex].getClass(), 
+                          m.getGenericParameterTypes()[bodyIndex],
+                          m.getParameterAnnotations()[bodyIndex], headers, connect.getOutputStream());
+            } else {
+                MultivaluedMap<String, String> form = handleForm(types, params);
+                writeBody(form, form.getClass(), form.getClass(), m.getDeclaredAnnotations(),
+                          headers, connect.getOutputStream());
+            }
+        }
+        
+        Response r = setResponseBuilder(connect).clone().build();
+        
+        checkResponse(m, r);
+        if (m.getReturnType() == Void.class) { 
+            return null;
+        }
+        
+        return readBody(r, connect, m.getReturnType(), 
+                        m.getGenericReturnType(), m.getDeclaredAnnotations());
+    }
+
+    private static MultivaluedMap<ParameterType, Parameter> getParametersInfo(OperationResourceInfo ori, 
+                                                                              Method m, Object[] params) {
+        MultivaluedMap<ParameterType, Parameter> map = new MetadataMap<ParameterType, Parameter>();
+        Annotation[][] paramAnns = m.getParameterAnnotations();
+        if (paramAnns.length == 0) {
+            return map;
+        }
+        for (int i = 0; i < paramAnns.length; i++) {
+            Parameter p = getParameter(i, paramAnns[i], ori);
+            map.add(p.getType(), p);
+        }
+        if (map.containsKey(ParameterType.REQUEST_BODY)) {
+            if (map.get(ParameterType.REQUEST_BODY).size() > 1) {
+                throw new WebApplicationException();
+            }
+            if (map.containsKey(ParameterType.FORM)) {
+                throw new WebApplicationException();
+            }
+        }
+        return map;
+    }
+    
+    private static int getBodyIndex(MultivaluedMap<ParameterType, Parameter> map, boolean subresource) {
+        List<Parameter> list = map.get(ParameterType.REQUEST_BODY);
+        int index  = list == null ? -1 : list.get(0).getIndex(); 
+        if (subresource && index != -1) {
+            throw new WebApplicationException();
+        }
+        return index;
+    }
+    
+    private static void checkResponse(Method m, Response r) throws Throwable {
+        
+        int status = r.getStatus();
+        
+        if (status >= 400) {
+            
+            ProviderFactory pf = ProviderFactory.getInstance();
+            for (Class<?> exType : m.getExceptionTypes()) {
+                ResponseExceptionMapper<?> mapper = pf.createResponseExceptionMapper(exType);
+                if (mapper != null) {
+                    Throwable t = mapper.fromResponse(r);
+                    if (t != null) {
+                        throw t;
+                    }
+                }
+            }
+            
+            throw new WebApplicationException(r);
+        }
+    }
+    
+    
+    private MultivaluedMap<String, String> setRequestHeaders(HttpURLConnection conn,
+                                                             MultivaluedMap<String, String> headers,          
+                                                             OperationResourceInfo ori,
+                                                             boolean formParams,
+                                                             Class<?> bodyClass,
+                                                             Class<?> responseClass) {
+        try {
+            if (headers.getFirst(HttpHeaders.CONTENT_TYPE) == null) {
+                if (formParams || bodyClass != null && MultivaluedMap.class.isAssignableFrom(bodyClass)) {
+                    headers.putSingle(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED);
+                } else {
+                    String cType = 
+                        bodyClass != null && InjectionUtils.isPrimitive(bodyClass) 
+                            ? MediaType.TEXT_PLAIN : ori.getConsumeTypes().isEmpty() 
+                        || ori.getConsumeTypes().get(0).equals(MediaType.WILDCARD) 
+                        ? MediaType.APPLICATION_XML : ori.getConsumeTypes().get(0).toString();   
+                    headers.putSingle(HttpHeaders.CONTENT_TYPE, cType);
+                }
+            }
+            
+            List<MediaType> accepts = getAccept();
+            if (accepts == null) {
+                accepts = InjectionUtils.isPrimitive(responseClass) 
+                    ? Collections.singletonList(MediaType.TEXT_PLAIN_TYPE)
+                    : ori.getProduceTypes().size() == 0 
+                    || ori.getConsumeTypes().get(0).equals(MediaType.WILDCARD_TYPE) 
+                    ? Collections.singletonList(MediaType.APPLICATION_XML_TYPE) : ori.getProduceTypes();
+                for (MediaType mt : accepts) {
+                    headers.add(HttpHeaders.ACCEPT, mt.toString());
+                }
+            }
+            setAllHeaders(headers, conn);
+            
+        } catch (Exception ex) {
+            throw new WebApplicationException();
+        }
+        return headers;
+    }
+    
+    private static List<Object> getParamValues(MultivaluedMap<ParameterType, Parameter> map, 
+                                               Object[] params, ParameterType key) {
+        List<Parameter> indexList =  getParameters(map, key);
+        List<Object> list = new ArrayList<Object>(indexList.size());
+        for (Parameter p : indexList) {
+            list.add(JAXRSUtils.encode(p.isEncoded(), params[p.getIndex()].toString()));
+        }
+        return list;
+    }
+    
+    @SuppressWarnings("unchecked")
+    private static List<Parameter> getParameters(MultivaluedMap<ParameterType, Parameter> map, 
+                                           ParameterType key) {
+        return  map.get(key) == null ? Collections.EMPTY_LIST : map.get(key);
+    }
+    
+    private static void handleQueries(MultivaluedMap<ParameterType, Parameter> map, 
+                                      Object[] params,
+                                      UriBuilder ub) {
+        List<Parameter> qs = getParameters(map, ParameterType.QUERY);
+        for (Parameter p : qs) {
+            if (params[p.getIndex()] != null) {
+                ub.queryParam(p.getValue(), 
+                               JAXRSUtils.encode(p.isEncoded(), params[p.getIndex()].toString()));
+            }
+        }
+    }
+    
+    private static void handleMatrixes(MultivaluedMap<ParameterType, Parameter> map, Object[] params,
+                                UriBuilder ub) {
+        List<Parameter> mx = getParameters(map, ParameterType.MATRIX);
+        for (Parameter p : mx) {
+            if (params[p.getIndex()] != null) {
+                ub.matrixParam(p.getValue(), 
+                                JAXRSUtils.encode(p.isEncoded(), params[p.getIndex()].toString()));
+            }
+        }
+    }
+
+    private MultivaluedMap<String, String> handleForm(MultivaluedMap<ParameterType, Parameter> map, 
+                                                      Object[] params) {
+        
+        MultivaluedMap<String, String> form = new MetadataMap<String, String>();
+        
+        List<Parameter> fm = getParameters(map, ParameterType.FORM);
+        for (Parameter p : fm) {
+            if (params[p.getIndex()] != null) {
+                form.add(p.getValue(), params[p.getIndex()].toString());
+            }
+        }
+        
+        return form;
+    }
+    
+    private void handleHeaders(MultivaluedMap<String, String> headers,
+                               MultivaluedMap<ParameterType, Parameter> map, Object[] params) {
+        List<Parameter> hs = getParameters(map, ParameterType.HEADER);
+        for (Parameter p : hs) {
+            if (params[p.getIndex()] != null) {
+                headers.add(p.getValue(), params[p.getIndex()].toString());
+            }
+        }
+    }
+    
+    private void handleCookies(MultivaluedMap<String, String> headers,
+                               MultivaluedMap<ParameterType, Parameter> map, Object[] params) {
+        List<Parameter> cs = getParameters(map, ParameterType.COOKIE);
+        for (Parameter p : cs) {
+            if (params[p.getIndex()] != null) {
+                headers.add(HttpHeaders.COOKIE, p.getValue() + '=' + params[p.getIndex()].toString());
+            }
+        }
+    }
+    
+    private static Parameter getParameter(int index, Annotation[] anns, OperationResourceInfo ori) {
+        
+        Context ctx = AnnotationUtils.getAnnotation(anns, Context.class);
+        if (ctx != null) {
+            throw new WebApplicationException();
+        }
+        
+        boolean isEncoded = AnnotationUtils.isEncoded(anns, ori);
+        PathParam a = AnnotationUtils.getAnnotation(anns, PathParam.class); 
+        if (a != null) {
+            return new Parameter(ParameterType.PATH, index, a.value(), isEncoded);
+        } 
+        
+        QueryParam q = AnnotationUtils.getAnnotation(anns, QueryParam.class);
+        if (q != null) {
+            return new Parameter(ParameterType.QUERY, index, q.value(), isEncoded);
+        }
+        
+        MatrixParam m = AnnotationUtils.getAnnotation(anns, MatrixParam.class);
+        if (m != null) {
+            return new Parameter(ParameterType.MATRIX, index, m.value(), isEncoded);
+        }  
+    
+        FormParam f = AnnotationUtils.getAnnotation(anns, FormParam.class);
+        if (f != null) {
+            return new Parameter(ParameterType.FORM, index, f.value(), isEncoded);
+        }  
+        
+        HeaderParam h = AnnotationUtils.getAnnotation(anns, HeaderParam.class);
+        if (h != null) {
+            return new Parameter(ParameterType.HEADER, index, h.value(), isEncoded);
+        }  
+        
+        Parameter p = null;
+        CookieParam c = AnnotationUtils.getAnnotation(anns, CookieParam.class);
+        if (c != null) {
+            p = new Parameter(ParameterType.COOKIE, index, c.value(), isEncoded);
+        } else {
+            p = new Parameter(ParameterType.REQUEST_BODY, index, null, isEncoded); 
+        }
+        
+        return p;
+        
+    }
+    
+    
+    private static class Parameter {
+        private ParameterType type;
+        private int ind;
+        private String aValue;
+        private boolean isEncoded;
+        
+        public Parameter(ParameterType type, int ind, String aValue, boolean encoded) {
+            this.type = type;
+            this.ind = ind;
+            this.aValue = aValue; 
+            this.isEncoded = encoded;
+        }
+        
+        public int getIndex() {
+            return ind;
+        }
+        
+        public String getValue() {
+            return aValue;
+        }
+        
+        public ParameterType getType() {
+            return type;
+        }
+        
+        public boolean isEncoded() {
+            return isEncoded;
+        }
+    }
+}

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

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

Added: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/JAXRSClientFactory.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/JAXRSClientFactory.java?rev=743825&view=auto
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/JAXRSClientFactory.java (added)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/JAXRSClientFactory.java Thu Feb 12 18:26:07 2009
@@ -0,0 +1,79 @@
+/**
+ * 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;
+
+import java.lang.reflect.Proxy;
+import java.net.URI;
+
+import javax.ws.rs.Path;
+import javax.ws.rs.core.MediaType;
+
+import org.apache.cxf.jaxrs.model.ClassResourceInfo;
+import org.apache.cxf.jaxrs.utils.AnnotationUtils;
+import org.apache.cxf.jaxrs.utils.ResourceUtils;
+
+public final class JAXRSClientFactory {
+    
+    private JAXRSClientFactory() { 
+        
+    }
+    
+    public static <T> T create(String baseAddress, Class<T> cls) {
+        return create(URI.create(baseAddress), cls);
+    }
+    
+    public static <T> T create(URI baseURI, Class<T> cls) {
+        return create(baseURI, baseURI, cls, true, false);
+    }
+    
+    public static <T> T create(URI baseURI, Class<T> cls, boolean inheritHeaders) {
+        return create(baseURI, baseURI, cls, true, inheritHeaders);
+    }
+    
+    public static <T> T create(String baseAddress, Class<T> cls, MediaType contentType, 
+                               MediaType... acceptTypes) {
+        T proxy = create(baseAddress, cls);
+        WebClient.client(proxy).type(contentType).accept(acceptTypes);
+        return proxy;
+    }
+    
+    public static <T> T fromClient(Client client, Class<T> cls) {
+        return fromClient(client, cls, false);
+    }
+    
+    public static <T> T fromClient(Client client, Class<T> cls, boolean inheritHeaders) {
+        if (client.getClass().isAssignableFrom(cls)) {
+            return cls.cast(client);
+        }
+        T proxy = create(client.getCurrentURI(), client.getCurrentURI(), cls, 
+                         AnnotationUtils.getClassAnnotation(cls, Path.class) != null, inheritHeaders);
+        if (inheritHeaders) {
+            WebClient.client(proxy).headers(client.getHeaders());
+        }
+        return proxy;
+    }
+    
+    static <T> T create(URI baseURI, URI currentURI, Class<T> cls, boolean root, boolean inheritHeaders) {
+        ClassResourceInfo classResourceInfo = ResourceUtils.createClassResourceInfo(cls, cls, root, true);
+        
+        return cls.cast(Proxy.newProxyInstance(cls.getClassLoader(),
+                        new Class[]{cls, Client.class},
+                        new ClientProxyImpl(baseURI, currentURI, classResourceInfo, inheritHeaders)));
+    }
+}

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

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

Added: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/ResponseExceptionMapper.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/ResponseExceptionMapper.java?rev=743825&view=auto
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/ResponseExceptionMapper.java (added)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/ResponseExceptionMapper.java Thu Feb 12 18:26:07 2009
@@ -0,0 +1,25 @@
+/**
+ * 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;
+
+import javax.ws.rs.core.Response;
+
+public interface ResponseExceptionMapper<E extends Throwable> {
+    E fromResponse(Response r);
+}

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

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

Added: 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=743825&view=auto
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/WebClient.java (added)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/WebClient.java Thu Feb 12 18:26:07 2009
@@ -0,0 +1,269 @@
+/**
+ * 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;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.annotation.Annotation;
+import java.net.HttpURLConnection;
+import java.net.URI;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Cookie;
+import javax.ws.rs.core.EntityTag;
+import javax.ws.rs.core.HttpHeaders;
+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 org.apache.cxf.jaxrs.ext.form.Form;
+import org.apache.cxf.jaxrs.utils.HttpUtils;
+import org.apache.cxf.jaxrs.utils.JAXRSUtils;
+
+
+
+public class WebClient extends AbstractClient {
+    
+    public WebClient(String baseAddress) {
+        this(URI.create(baseAddress));
+    }
+    
+    public WebClient(URI baseURI) {
+        super(baseURI, baseURI);
+    }
+    
+    public WebClient(Client client) {
+        this(client, false);
+    }
+    
+    public WebClient(Client client, boolean inheritHeaders) {
+        super(client, inheritHeaders);
+    }
+    
+    public Response invoke(String httpMethod, Object body) {
+        return doInvoke(httpMethod, body, InputStream.class);
+    }
+    
+    private Response doInvoke(String httpMethod, Object body, Class<?> responseClass) {
+        HttpURLConnection conn = getConnection(httpMethod);
+        
+        MultivaluedMap<String, String> headers = getHeaders();
+        if (body != null && headers.getFirst(HttpHeaders.CONTENT_TYPE) == null) {
+            headers.putSingle(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_XML_TYPE.toString());
+        }
+        if (responseClass != null && headers.getFirst(HttpHeaders.ACCEPT) == null) {
+            headers.putSingle(HttpHeaders.ACCEPT, MediaType.APPLICATION_XML_TYPE.toString());
+        }
+        setAllHeaders(headers, conn);
+        if (body != null) {
+            try {
+                writeBody(body, body.getClass(), body.getClass(), 
+                      new Annotation[]{}, headers, conn.getOutputStream());
+            } catch (IOException ex) {
+                throw new WebApplicationException(ex);
+            }
+        }
+        try {
+            ResponseBuilder rb = setResponseBuilder(conn).clone();
+            Response currentResponse = rb.clone().build();
+            Object entity = readBody(currentResponse, conn, responseClass, responseClass,
+                                     new Annotation[]{});
+            rb.entity(entity);
+            
+            return rb.build();
+        } catch (IOException ex) {
+            throw new WebApplicationException(ex);
+        }
+    }
+    
+    public Response post(Object o) {
+        return invoke("POST", o);
+    }
+    
+    public Response put(Object o) {
+        return invoke("PUT", o);
+    }
+
+    public Response get() {
+        return invoke("GET", null);
+    }
+    
+    public Response head() {
+        return invoke("HEAD", null);
+    }
+    
+    public Response options() {
+        return invoke("OPTIONS", null);
+    }
+    
+    public Response delete() {
+        return invoke("DELETE", null);
+    }
+    
+    public Response form(Map<String, List<Object>> values) {
+        type(MediaType.APPLICATION_FORM_URLENCODED_TYPE);
+        return doInvoke("POST", values, InputStream.class);
+    }
+    
+    public Response form(Form form) {
+        type(MediaType.APPLICATION_FORM_URLENCODED_TYPE);
+        return doInvoke("POST", form.getData(), InputStream.class);
+    }
+    
+    public <T> T invoke(String httpMethod, Object body, Class<T> responseClass) {
+        Response r = doInvoke(httpMethod, body, responseClass);
+        
+        if (r.getStatus() >= 400) {
+            throw new WebApplicationException(r);
+        }
+        
+        return responseClass.cast(r.getEntity());
+    }
+    
+    public <T> T post(Object o, Class<T> responseClass) {
+        return invoke("POST", o, responseClass);
+    }
+    
+    public <T> T get(Class<T> responseClass) {
+        return invoke("GET", null, responseClass);
+    }
+    
+    public WebClient path(String path) {
+        getCurrentBuilder().path(path);
+        return this;
+    }
+    
+    public WebClient query(String name, Object ...values) {
+        getCurrentBuilder().queryParam(name, values);
+        return this;
+    }
+    
+    public WebClient matrix(String name, Object ...values) {
+        getCurrentBuilder().matrixParam(name, values);
+        return this;
+    }
+    
+    public WebClient to(String newAddress) {
+        resetBaseAddress(URI.create(newAddress));
+        return this;
+    }
+    
+    public WebClient back(boolean fast) {
+        if (fast) {
+            getCurrentBuilder().replacePath(getBaseURI().getPath());
+        } else {
+            URI uri = getCurrentURI();
+            if (uri == getBaseURI()) {
+                return this;
+            }
+            List<PathSegment> segments = JAXRSUtils.getPathSegments(uri.getPath(), false);
+            getCurrentBuilder().replacePath(null);
+            for (int i = 0; i < segments.size() - 1; i++) {
+                getCurrentBuilder().path(HttpUtils.fromPathSegment(segments.get(i)));
+            }
+            
+        }
+        return this;
+    }
+    
+    @Override
+    public WebClient type(MediaType ct) {
+        return (WebClient)super.type(ct);
+    }
+    
+    @Override
+    public WebClient type(String type) {
+        return (WebClient)super.type(type);
+    }
+    
+    @Override
+    public WebClient accept(MediaType... types) {
+        return (WebClient)super.accept(types);
+    }
+    
+    @Override
+    public WebClient accept(String... types) {
+        return (WebClient)super.accept(types);
+    }
+    
+    @Override
+    public WebClient language(String language) {
+        return (WebClient)super.language(language);
+    }
+    
+    @Override
+    public WebClient acceptLanguage(String ...languages) {
+        return (WebClient)super.acceptLanguage(languages);
+    }
+    
+    @Override
+    public WebClient encoding(String encoding) {
+        return (WebClient)super.encoding(encoding);
+    }
+    
+    @Override
+    public WebClient acceptEncoding(String ...encodings) {
+        return (WebClient)super.acceptEncoding(encodings);
+    }
+    
+    @Override
+    public WebClient match(EntityTag tag, boolean ifNot) {
+        return (WebClient)super.match(tag, ifNot);
+    }
+    
+    @Override
+    public WebClient modified(Date date, boolean ifNot) {
+        return (WebClient)super.modified(date, ifNot);
+    }
+    
+    @Override
+    public WebClient cookie(Cookie cookie) {
+        return (WebClient)super.cookie(cookie);
+    }
+    
+    @Override
+    public WebClient header(String name, Object... values) {
+        return (WebClient)super.header(name, values);
+    }
+    
+    @Override
+    public WebClient headers(MultivaluedMap<String, String> map) {
+        return (WebClient)super.headers(map);
+    }
+    
+    @Override
+    public WebClient reset() {
+        return (WebClient)super.reset();
+    }
+    
+    
+    protected HttpURLConnection getConnection(String methodName) {
+        return createHttpConnection(getCurrentBuilder().clone().build(), methodName);
+    }
+    
+    public static Client client(Object proxy) {
+        return (Client)proxy;
+    }
+    
+}

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

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

Added: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/form/Form.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/form/Form.java?rev=743825&view=auto
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/form/Form.java (added)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/form/Form.java Thu Feb 12 18:26:07 2009
@@ -0,0 +1,39 @@
+/**
+ * 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.ext.form;
+
+import javax.ws.rs.core.MultivaluedMap;
+
+import org.apache.cxf.jaxrs.impl.MetadataMap;
+
+public class Form {
+    private MultivaluedMap<String, Object> map = 
+        new MetadataMap<String, Object>();
+    
+    public Form set(String name, Object value) {
+        map.add(name, value);
+        return this;
+    }
+    
+    public MultivaluedMap<String, Object> getData() {
+        return new MetadataMap<String, Object>(map);
+    }
+    
+}

Propchange: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/form/Form.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/form/Form.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/MetadataMap.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/MetadataMap.java?rev=743825&r1=743824&r2=743825&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/MetadataMap.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/MetadataMap.java Thu Feb 12 18:26:07 2009
@@ -121,4 +121,6 @@
     public String toString() {
         return m.toString();
     }
+    
+     
 }

Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/RequestImpl.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/RequestImpl.java?rev=743825&r1=743824&r2=743825&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/RequestImpl.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/RequestImpl.java Thu Feb 12 18:26:07 2009
@@ -23,7 +23,6 @@
 import java.text.SimpleDateFormat;
 import java.util.Date;
 import java.util.List;
-import java.util.Locale;
 import java.util.Map;
 
 import javax.ws.rs.core.EntityTag;
@@ -33,6 +32,7 @@
 import javax.ws.rs.core.Response.ResponseBuilder;
 import javax.ws.rs.core.Variant;
 
+import org.apache.cxf.jaxrs.utils.HttpUtils;
 import org.apache.cxf.message.Message;
 
 /**
@@ -85,8 +85,8 @@
             return null;
         }
         
-        SimpleDateFormat dateFormat = 
-            new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.ENGLISH);
+        SimpleDateFormat dateFormat = HttpUtils.getHttpDateFormat();
+
         dateFormat.setLenient(false);
         Date dateSince = null;
         try {

Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/ResponseBuilderImpl.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/ResponseBuilderImpl.java?rev=743825&r1=743824&r2=743825&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/ResponseBuilderImpl.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/ResponseBuilderImpl.java Thu Feb 12 18:26:07 2009
@@ -44,10 +44,8 @@
 
     private ResponseBuilderImpl(ResponseBuilderImpl copy) {
         status = copy.status;
-        if (entity != null) {
-            entity = copy.entity;
-            metadata.putAll(copy.metadata);
-        }
+        metadata.putAll(copy.metadata);
+        entity = copy.entity;
     }
        
     public Response build() {

Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/UriBuilderImpl.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/UriBuilderImpl.java?rev=743825&r1=743824&r2=743825&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/UriBuilderImpl.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/UriBuilderImpl.java Thu Feb 12 18:26:07 2009
@@ -284,15 +284,21 @@
         scheme = uri.getScheme();
         port = uri.getPort();
         host = uri.getHost();
-        paths = JAXRSUtils.getPathSegments(uri.getPath(), false);
-        if (!paths.isEmpty()) {
-            matrix = paths.get(paths.size() - 1).getMatrixParameters();
-        }
+        setPathAndMatrix(uri.getPath());
         fragment = uri.getFragment();
         query = JAXRSUtils.getStructuredParams(uri.getQuery(), "&", true);
         userInfo = uri.getUserInfo();
     }
 
+    private void setPathAndMatrix(String path) {
+        paths = JAXRSUtils.getPathSegments(path, false);
+        if (!paths.isEmpty()) {
+            matrix = paths.get(paths.size() - 1).getMatrixParameters();
+        } else {
+            matrix.clear();
+        }
+    }
+    
     private String buildPath() {
         StringBuilder sb = new StringBuilder();
         Iterator<PathSegment> iter = paths.iterator();
@@ -366,7 +372,12 @@
 
     @Override
     public UriBuilder replacePath(String path) {
-        paths = JAXRSUtils.getPathSegments(path, false);
+        if (path == null) {
+            paths.clear();
+            matrix.clear();
+        } else {
+            setPathAndMatrix(path);
+        }
         return this;
     }
 

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=743825&r1=743824&r2=743825&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 Thu Feb 12 18:26:07 2009
@@ -91,7 +91,6 @@
             rp.preprocess(message, new UriInfoImpl(message, null));
         }
         
-        String httpMethod = (String)message.get(Message.HTTP_REQUEST_METHOD);
         String requestContentType = (String)message.get(Message.CONTENT_TYPE);
         if (requestContentType == null) {
             requestContentType = "*/*";
@@ -127,6 +126,7 @@
 
         message.getExchange().put(ROOT_RESOURCE_CLASS, resource);
 
+        String httpMethod = (String)message.get(Message.HTTP_REQUEST_METHOD);
         OperationResourceInfo ori = null;     
         
         List<ProviderInfo<RequestHandler>> shs = 

Copied: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/FormEncodingProvider.java (from r739958, cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/FormEncodingReaderProvider.java)
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/FormEncodingProvider.java?p2=cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/FormEncodingProvider.java&p1=cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/FormEncodingReaderProvider.java&r1=739958&r2=743825&rev=743825&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/FormEncodingReaderProvider.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/FormEncodingProvider.java Thu Feb 12 18:26:07 2009
@@ -21,16 +21,22 @@
 
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.OutputStream;
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Type;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
 
 import javax.ws.rs.Consumes;
 import javax.ws.rs.Encoded;
+import javax.ws.rs.Produces;
 import javax.ws.rs.WebApplicationException;
 import javax.ws.rs.core.Context;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.MultivaluedMap;
 import javax.ws.rs.ext.MessageBodyReader;
+import javax.ws.rs.ext.MessageBodyWriter;
 import javax.ws.rs.ext.Provider;
 
 import org.apache.cxf.jaxrs.ext.MessageContext;
@@ -38,11 +44,14 @@
 import org.apache.cxf.jaxrs.impl.MetadataMap;
 import org.apache.cxf.jaxrs.utils.AnnotationUtils;
 import org.apache.cxf.jaxrs.utils.FormUtils;
+import org.apache.cxf.jaxrs.utils.JAXRSUtils;
 import org.apache.cxf.jaxrs.utils.multipart.AttachmentUtils;
 
+@Produces("application/x-www-form-urlencoded")
 @Consumes({"application/x-www-form-urlencoded", "multipart/form-data" })
 @Provider
-public class FormEncodingReaderProvider implements MessageBodyReader<Object> {
+public class FormEncodingProvider implements 
+    MessageBodyReader<Object>, MessageBodyWriter<MultivaluedMap<String, String>> {
         
     private FormValidator validator;
     @Context private MessageContext mc;
@@ -120,4 +129,31 @@
             validator.validate(params);
         }
     }
+
+    public long getSize(MultivaluedMap t, Class<?> type, Type genericType, Annotation[] annotations, 
+                        MediaType mediaType) {
+        return -1;
+    }
+
+    public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, 
+                               MediaType mediaType) {
+        return MultivaluedMap.class.isAssignableFrom(type);
+    }
+
+    public void writeTo(MultivaluedMap<String, String> map, Class<?> c, Type t, Annotation[] anns, 
+                        MediaType mt, MultivaluedMap<String, Object> headers, OutputStream os) 
+        throws IOException, WebApplicationException {
+        boolean encoded = AnnotationUtils.getAnnotation(anns, Encoded.class) != null;
+        for (Iterator<Map.Entry<String, List<String>>> it = map.entrySet().iterator(); it.hasNext();) {
+            Map.Entry<String, List<String>> entry = it.next();
+            for (String value : entry.getValue()) {
+                os.write(entry.getKey().getBytes("UTF-8"));
+                os.write('=');
+                os.write(JAXRSUtils.encode(encoded, value).getBytes("UTF-8"));
+                if (it.hasNext()) {
+                    os.write('&');
+                }
+            }
+        }
+    }
 }

Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/PrimitiveTextProvider.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/PrimitiveTextProvider.java?rev=743825&r1=743824&r2=743825&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/PrimitiveTextProvider.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/PrimitiveTextProvider.java Thu Feb 12 18:26:07 2009
@@ -24,8 +24,6 @@
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Type;
 
-import javax.ws.rs.Consumes;
-import javax.ws.rs.Produces;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.MultivaluedMap;
 import javax.ws.rs.ext.MessageBodyReader;
@@ -35,15 +33,11 @@
 import org.apache.cxf.jaxrs.utils.InjectionUtils;
 import org.apache.cxf.jaxrs.utils.ParameterType;
 
-@Produces("text/plain")
-@Consumes("text/plain")
 public class PrimitiveTextProvider 
     implements MessageBodyReader<Object>, MessageBodyWriter<Object> {
 
     private static boolean isSupported(Class<?> type) { 
-        return type.isPrimitive() 
-            || Number.class.isAssignableFrom(type)
-            || Boolean.class.isAssignableFrom(type);
+        return InjectionUtils.isPrimitive(type);
     }
     
     public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mt) {

Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/ProviderFactory.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/ProviderFactory.java?rev=743825&r1=743824&r2=743825&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/ProviderFactory.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/ProviderFactory.java Thu Feb 12 18:26:07 2009
@@ -37,6 +37,7 @@
 import javax.ws.rs.ext.MessageBodyReader;
 import javax.ws.rs.ext.MessageBodyWriter;
 
+import org.apache.cxf.jaxrs.client.ResponseExceptionMapper;
 import org.apache.cxf.jaxrs.ext.MappingsHandler;
 import org.apache.cxf.jaxrs.ext.ParameterHandler;
 import org.apache.cxf.jaxrs.ext.RequestHandler;
@@ -75,6 +76,8 @@
         new ArrayList<ProviderInfo<ResponseHandler>>(1);
     private List<ProviderInfo<ParameterHandler>> jaxrsParamHandlers = 
         new ArrayList<ProviderInfo<ParameterHandler>>(1);
+    private List<ProviderInfo<ResponseExceptionMapper>> userResponseExceptionMappers = 
+        new ArrayList<ProviderInfo<ResponseExceptionMapper>>(1);
     private RequestPreprocessor requestPreprocessor;
     
     private ProviderFactory() {
@@ -91,12 +94,12 @@
                      responseHandlers,
                      defaultExceptionMappers,
                      jaxrsParamHandlers,
+                     userResponseExceptionMappers,
                      new JAXBElementProvider(),
                      new JSONProvider(),
                      new BinaryDataProvider(),
-                     new StringProvider(),
                      new SourceProvider(),
-                     new FormEncodingReaderProvider(),
+                     new FormEncodingProvider(),
                      new PrimitiveTextProvider(),
                      new ActivationProvider(),
                      new WebApplicationExceptionMapper(),
@@ -176,20 +179,7 @@
         List<ExceptionMapper<T>> candidates = new LinkedList<ExceptionMapper<T>>();
         
         for (ProviderInfo<ExceptionMapper> em : mappers) {
-            Type[] types = em.getProvider().getClass().getGenericInterfaces();
-            for (Type t : types) {
-                if (t instanceof ParameterizedType) {
-                    ParameterizedType pt = (ParameterizedType)t;
-                    Type[] args = pt.getActualTypeArguments();
-                    for (int i = 0; i < args.length; i++) {
-                        if (((Class<?>)args[i]).isAssignableFrom(exceptionType)) {
-                            InjectionUtils.injectContextFields(em.getProvider(), em, m);
-                            InjectionUtils.injectContextMethods(em.getProvider(), em, m);
-                            candidates.add(em.getProvider());
-                        }
-                    }
-                }
-            }
+            handleMapper((List)candidates, em, exceptionType, m);
         }
         if (candidates.size() == 0) {
             return null;
@@ -204,18 +194,7 @@
         List<ParameterHandler<T>> candidates = new LinkedList<ParameterHandler<T>>();
         
         for (ProviderInfo<ParameterHandler> em : jaxrsParamHandlers) {
-            Type[] types = em.getProvider().getClass().getGenericInterfaces();
-            for (Type t : types) {
-                if (t instanceof ParameterizedType) {
-                    ParameterizedType pt = (ParameterizedType)t;
-                    Type[] args = pt.getActualTypeArguments();
-                    for (int i = 0; i < args.length; i++) {
-                        if (((Class<?>)args[i]).isAssignableFrom(paramType)) {
-                            candidates.add(em.getProvider());
-                        }
-                    }
-                }
-            }
+            handleMapper((List)candidates, em, paramType, null);
         }
         if (candidates.size() == 0) {
             return null;
@@ -224,6 +203,44 @@
         return candidates.get(0);
     }
     
+    @SuppressWarnings("unchecked")
+    public <T extends Throwable> ResponseExceptionMapper<T> createResponseExceptionMapper(
+                                 Class<?> paramType) {
+        
+        List<ResponseExceptionMapper<T>> candidates = new LinkedList<ResponseExceptionMapper<T>>();
+        
+        for (ProviderInfo<ResponseExceptionMapper> em : userResponseExceptionMappers) {
+            handleMapper((List)candidates, em, paramType, null);
+        }
+        if (candidates.size() == 0) {
+            return null;
+        }
+        Collections.sort(candidates, new ResponseExceptionMapperComparator());
+        return candidates.get(0);
+    }
+    
+    private static void handleMapper(List<Object> candidates, ProviderInfo em, 
+                                     Class<?> expectedType, Message m) {
+        Type[] types = em.getProvider().getClass().getGenericInterfaces();
+        for (Type t : types) {
+            if (t instanceof ParameterizedType) {
+                ParameterizedType pt = (ParameterizedType)t;
+                Type[] args = pt.getActualTypeArguments();
+                for (int i = 0; i < args.length; i++) {
+                    if (((Class<?>)args[i]).isAssignableFrom(expectedType)) {
+                        if (m != null) {
+                            InjectionUtils.injectContextFields(em.getProvider(), em, m);
+                            InjectionUtils.injectContextMethods(em.getProvider(), em, m);
+                        }
+                        candidates.add(em.getProvider());
+                    }
+                }
+            }
+        }
+    }
+    
+    
+    
     public <T> MessageBodyReader<T> createMessageBodyReader(Class<T> bodyType,
                                                             Type parameterType,
                                                             Annotation[] parameterAnnotations,
@@ -296,6 +313,7 @@
                               List<ProviderInfo<ResponseHandler>> responseFilters,
                               List<ProviderInfo<ExceptionMapper>> excMappers,
                               List<ProviderInfo<ParameterHandler>> paramHandlers,
+                              List<ProviderInfo<ResponseExceptionMapper>> responseExcMappers,
                               Object... providers) {
         
         for (Object o : providers) {
@@ -323,6 +341,10 @@
                 excMappers.add(new ProviderInfo<ExceptionMapper>((ExceptionMapper)o)); 
             }
             
+            if (ResponseExceptionMapper.class.isAssignableFrom(o.getClass())) {
+                responseExcMappers.add(new ProviderInfo<ResponseExceptionMapper>((ResponseExceptionMapper)o)); 
+            }
+            
             if (ParameterHandler.class.isAssignableFrom(o.getClass())) {
                 paramHandlers.add(new ProviderInfo<ParameterHandler>((ParameterHandler)o)); 
             }
@@ -495,6 +517,7 @@
                      responseHandlers,
                      userExceptionMappers,
                      jaxrsParamHandlers,
+                     userResponseExceptionMappers,
                      userProviders.toArray());
     }
 
@@ -599,6 +622,16 @@
         
     }
     
+    private static class ResponseExceptionMapperComparator implements 
+        Comparator<ResponseExceptionMapper<? extends Throwable>> {
+    
+        public int compare(ResponseExceptionMapper<? extends Throwable> em1, 
+                           ResponseExceptionMapper<? extends Throwable> em2) {
+            return compareClasses(em1.getClass(), em2.getClass());
+        }
+        
+    }
+    
     private static class ParameterHandlerComparator implements 
         Comparator<ParameterHandler<? extends Object>> {
 

Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/HttpUtils.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/HttpUtils.java?rev=743825&r1=743824&r2=743825&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/HttpUtils.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/HttpUtils.java Thu Feb 12 18:26:07 2009
@@ -22,8 +22,11 @@
 import java.net.MalformedURLException;
 import java.net.URI;
 import java.net.URL;
+import java.text.SimpleDateFormat;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
+import java.util.TimeZone;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.ws.rs.core.PathSegment;
@@ -43,6 +46,14 @@
     private HttpUtils() {
     }
     
+    public static SimpleDateFormat getHttpDateFormat() {
+        SimpleDateFormat dateFormat = 
+            new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US);
+        TimeZone tZone = TimeZone.getTimeZone("GMT");
+        dateFormat.setTimeZone(tZone);
+        return dateFormat;
+    }
+    
     public static URI toAbsoluteUri(URI u, Message message) { 
         if (!u.isAbsolute()) {
             HttpServletRequest httpRequest = 

Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/InjectionUtils.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/InjectionUtils.java?rev=743825&r1=743824&r2=743825&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/InjectionUtils.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/InjectionUtils.java Thu Feb 12 18:26:07 2009
@@ -132,18 +132,6 @@
         return (Class<?>)paramType.getActualTypeArguments()[0];
     }
     
-    public static Class<?> getActualType(Type genericType, int i) {
-        if (genericType == null 
-            || !ParameterizedType.class.isAssignableFrom(genericType.getClass())) {
-            return null;
-        }
-        ParameterizedType paramType = (ParameterizedType)genericType;
-        if (i < paramType.getActualTypeArguments().length) {
-            return (Class<?>)paramType.getActualTypeArguments()[i];
-        }
-        return null;
-    }
-    
     public static void injectThroughMethod(Object requestObject,
                                            Method method,
                                            Object parameterValue) {
@@ -514,4 +502,11 @@
             InjectionUtils.injectContextField(cri, f, o, value, true);
         }
     }
+    
+    public static boolean isPrimitive(Class<?> type) {
+        return type.isPrimitive() 
+            || Number.class.isAssignableFrom(type)
+            || Boolean.class.isAssignableFrom(type)
+            || String.class == type;
+    }
 }

Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/JAXRSUtils.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/JAXRSUtils.java?rev=743825&r1=743824&r2=743825&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/JAXRSUtils.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/JAXRSUtils.java Thu Feb 12 18:26:07 2009
@@ -28,6 +28,7 @@
 import java.lang.reflect.ParameterizedType;
 import java.lang.reflect.Type;
 import java.net.URLDecoder;
+import java.net.URLEncoder;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -597,24 +598,21 @@
     @SuppressWarnings("unchecked")
     private static Object processCookieParam(Message m, String cookieName, 
                               Class<?> pClass, Type genericType, String defaultValue) {
-        Map<String, List<String>> headers = 
-            (Map<String, List<String>>)m.get(Message.PROTOCOL_HEADERS);
-        // get the cookie with this name...
-        List<String> values = headers.get("Cookie");
-        String value = "";
-        if (values != null && values.get(0).contains(cookieName + '=')) {
-            value = values.get(0);
+        List<String> values = new HttpHeadersImpl(m).getRequestHeader(HttpHeaders.COOKIE);
+        String value = values != null && values.get(0).contains(cookieName + '=') ? values.get(0) 
+                       : defaultValue != null ? cookieName + '=' + defaultValue : null;
+        
+        if (value == null) {
+            return null;
         }
+        
+        Cookie c = Cookie.valueOf(value);
         if (pClass.isAssignableFrom(Cookie.class)) {
-            return Cookie.valueOf(value.length() == 0 ? defaultValue : value);
+            return c;
         }
         
         String basePath = HttpUtils.getOriginalAddress(m);
-        return value.length() > 0 ? InjectionUtils.handleParameter(value, 
-                                                                   pClass, 
-                                                                   ParameterType.COOKIE,
-                                                                   basePath) 
-                                  : defaultValue;
+        return InjectionUtils.handleParameter(c.getValue(), pClass, ParameterType.COOKIE, basePath);
     }
     
     public static <T> T createContextValue(Message m, Type genericType, Class<T> clazz) {
@@ -958,5 +956,16 @@
         return null;
         
     }
+    
+    public static String encode(boolean encoded, String value) {
+        if (!encoded) {
+            try {
+                value = URLEncoder.encode(value, "UTF-8");
+            } catch (UnsupportedEncodingException ex) {
+                // unlikely to happen
+            }
+        }
+        return value;
+    }
         
 }

Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/ParameterType.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/ParameterType.java?rev=743825&r1=743824&r2=743825&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/ParameterType.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/ParameterType.java Thu Feb 12 18:26:07 2009
@@ -28,5 +28,6 @@
     FORM,
     
     REQUEST_BODY,
+    CONTEXT,
     UNKNOWN
 }

Added: cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/client/WebClientTest.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/client/WebClientTest.java?rev=743825&view=auto
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/client/WebClientTest.java (added)
+++ cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/client/WebClientTest.java Thu Feb 12 18:26:07 2009
@@ -0,0 +1,105 @@
+/**
+ * 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;
+
+import java.net.URI;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+
+public class WebClientTest extends Assert {
+
+    @Test 
+    public void testBaseCurrentPath() {
+        assertEquals(URI.create("http://foo"), new WebClient("http://foo").getBaseURI());
+        assertEquals(URI.create("http://foo"), new WebClient("http://foo").getCurrentURI());
+    }
+    
+    @Test 
+    public void testNewBaseCurrentPath() {
+        WebClient wc = new WebClient("http://foo");
+        assertEquals(URI.create("http://foo"), wc.getBaseURI());
+        assertEquals(URI.create("http://foo"), wc.getCurrentURI());
+        wc.to("http://bar");
+        assertEquals(URI.create("http://bar"), wc.getBaseURI());
+        assertEquals(URI.create("http://bar"), wc.getCurrentURI());
+    }
+    
+    @Test 
+    public void testBaseCurrentPathAfterChange() {
+        WebClient wc = new WebClient(URI.create("http://foo"));
+        wc.path("bar").path("baz").matrix("m1", "m1value").query("q1", "q1value");
+        assertEquals(URI.create("http://foo"), wc.getBaseURI());
+        assertEquals(URI.create("http://foo/bar/baz;m1=m1value?q1=q1value"), wc.getCurrentURI());
+    }
+    
+    
+    @Test 
+    public void testBaseCurrentPathAfterCopy() {
+        WebClient wc = new WebClient(URI.create("http://foo"));
+        wc.path("bar").path("baz").matrix("m1", "m1value").query("q1", "q1value");
+        WebClient wc1 = new WebClient(wc);
+        assertEquals(URI.create("http://foo/bar/baz;m1=m1value?q1=q1value"), wc1.getBaseURI());
+        assertEquals(URI.create("http://foo/bar/baz;m1=m1value?q1=q1value"), wc1.getCurrentURI());
+    }
+    
+    @Test 
+    public void testHeaders() {
+        WebClient wc = new WebClient(URI.create("http://foo"));
+        wc.header("h1", "h1value").header("h2", "h2value");
+        assertEquals(1, wc.getHeaders().get("h1").size());
+        assertEquals("h1value", wc.getHeaders().getFirst("h1"));
+        assertEquals(1, wc.getHeaders().get("h2").size());
+        assertEquals("h2value", wc.getHeaders().getFirst("h2"));
+        wc.getHeaders().clear();
+        assertEquals(1, wc.getHeaders().get("h1").size());
+        assertEquals("h1value", wc.getHeaders().getFirst("h1"));
+        assertEquals(1, wc.getHeaders().get("h2").size());
+        assertEquals("h2value", wc.getHeaders().getFirst("h2"));
+        wc.reset();
+        assertTrue(wc.getHeaders().isEmpty());
+    }
+    
+    @Test
+    public void testBackFast() {
+        WebClient wc = new WebClient(URI.create("http://foo"));
+        wc.path("bar").path("baz").matrix("m1", "m1value");
+        assertEquals(URI.create("http://foo"), wc.getBaseURI());
+        assertEquals(URI.create("http://foo/bar/baz;m1=m1value"), wc.getCurrentURI());
+        wc.back(true);
+        assertEquals(URI.create("http://foo"), wc.getCurrentURI());
+    }
+    
+    @Test
+    public void testBack() {
+        WebClient wc = new WebClient(URI.create("http://foo"));
+        wc.path("bar").path("baz");
+        assertEquals(URI.create("http://foo"), wc.getBaseURI());
+        assertEquals(URI.create("http://foo/bar/baz"), wc.getCurrentURI());
+        wc.back(false);
+        assertEquals(URI.create("http://foo/bar"), wc.getCurrentURI());
+        wc.back(false);
+        assertEquals(URI.create("http://foo"), wc.getCurrentURI());
+        wc.back(false);
+        assertEquals(URI.create("http://foo"), wc.getCurrentURI());
+    }
+    
+}

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

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

Modified: cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/impl/UriBuilderImplTest.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/impl/UriBuilderImplTest.java?rev=743825&r1=743824&r2=743825&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/impl/UriBuilderImplTest.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/impl/UriBuilderImplTest.java Thu Feb 12 18:26:07 2009
@@ -46,6 +46,20 @@
         assertEquals("URI is not built correctly", uri, newUri);
     }
 
+    @Test
+    public void testReplacePath() throws Exception {
+        URI uri = new URI("http://foo/bar/baz;m1=m1value");
+        URI newUri = new UriBuilderImpl(uri).replacePath("/newpath").build();
+        assertEquals("URI is not built correctly", "http://foo/newpath", newUri.toString());
+    }
+    
+    @Test
+    public void testReplaceNullPath() throws Exception {
+        URI uri = new URI("http://foo/bar/baz;m1=m1value");
+        URI newUri = new UriBuilderImpl(uri).replacePath(null).build();
+        assertEquals("URI is not built correctly", "http://foo", newUri.toString());
+    }
+    
     @Test(expected = IllegalArgumentException.class)
     public void testUriNull() throws Exception {
         new UriBuilderImpl().uri(null);

Copied: cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/provider/FormEncodingProviderTest.java (from r739958, cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/provider/FormEncodingReaderProviderTest.java)
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/provider/FormEncodingProviderTest.java?p2=cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/provider/FormEncodingProviderTest.java&p1=cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/provider/FormEncodingReaderProviderTest.java&r1=739958&r2=743825&rev=743825&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/provider/FormEncodingReaderProviderTest.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/provider/FormEncodingProviderTest.java Thu Feb 12 18:26:07 2009
@@ -37,13 +37,13 @@
 import org.junit.Before;
 import org.junit.Test;
 
-public class FormEncodingReaderProviderTest extends Assert {
+public class FormEncodingProviderTest extends Assert {
 
-    private FormEncodingReaderProvider ferp;
+    private FormEncodingProvider ferp;
 
     @Before
     public void setUp() {
-        ferp = new FormEncodingReaderProvider();
+        ferp = new FormEncodingProvider();
     }
 
     @SuppressWarnings("unchecked")

Modified: cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/provider/ProviderFactoryTest.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/provider/ProviderFactoryTest.java?rev=743825&r1=743824&r2=743825&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/provider/ProviderFactoryTest.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/provider/ProviderFactoryTest.java Thu Feb 12 18:26:07 2009
@@ -121,17 +121,17 @@
     public void testSortEntityProviders() throws Exception {
         ProviderFactory pf = ProviderFactory.getInstance();
         pf.registerUserProvider(new TestStringProvider());
-        pf.registerUserProvider(new StringProvider());
+        pf.registerUserProvider(new PrimitiveTextProvider());
         
         List<ProviderInfo<MessageBodyReader>> readers = pf.getUserMessageReaders();
 
         assertTrue(indexOf(readers, TestStringProvider.class) 
-                   < indexOf(readers, StringProvider.class));
+                   < indexOf(readers, PrimitiveTextProvider.class));
         
         List<ProviderInfo<MessageBodyWriter>> writers = pf.getUserMessageWriters();
 
         assertTrue(indexOf(writers, TestStringProvider.class) 
-                   < indexOf(writers, StringProvider.class));
+                   < indexOf(writers, PrimitiveTextProvider.class));
         
         //REVISIT the compare algorithm
         //assertTrue(indexOf(providers, JSONProvider.class) < indexOf(providers, TestStringProvider.class));
@@ -170,7 +170,7 @@
     
     @Test
     public void testGetStringProvider() throws Exception {
-        verifyProvider(String.class, StringProvider.class, "text/html");
+        verifyProvider(String.class, PrimitiveTextProvider.class, "text/plain");
     }
     
     @Test
@@ -206,7 +206,7 @@
        
     @Test
     public void testGetStringProviderWildCard() throws Exception {
-        verifyProvider(String.class, StringProvider.class, "text/*");
+        verifyProvider(String.class, PrimitiveTextProvider.class, "text/*");
     }
     
     @Test