HTTPCLIENT-719: Clone support for HTTP request and cookie objects
git-svn-id: https://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk@659191 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
a9d307fa91
commit
5cd9d169f2
|
@ -1,6 +1,9 @@
|
|||
Changes since 4.0 Alpha 4
|
||||
-------------------
|
||||
|
||||
* [HTTPCLIENT-719] Clone support for HTTP request and cookie objects.
|
||||
Contributed by Oleg Kalnichevski <olegk at apache.org>
|
||||
|
||||
* [HTTPCLIENT-776] Fixed concurrency issues with AbstractPoolEntry.
|
||||
Contributed by Sam Berlin <sberlin at gmail.com>
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@ package org.apache.http.client.methods;
|
|||
import org.apache.http.Header;
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.HttpEntityEnclosingRequest;
|
||||
import org.apache.http.client.utils.CloneUtils;
|
||||
import org.apache.http.protocol.HTTP;
|
||||
|
||||
/**
|
||||
|
@ -66,5 +67,15 @@ abstract class HttpEntityEnclosingRequestBase
|
|||
Header expect = getFirstHeader(HTTP.EXPECT_DIRECTIVE);
|
||||
return expect != null && HTTP.EXPECT_CONTINUE.equalsIgnoreCase(expect.getValue());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Object clone() throws CloneNotSupportedException {
|
||||
HttpEntityEnclosingRequestBase clone =
|
||||
(HttpEntityEnclosingRequestBase) super.clone();
|
||||
if (this.entity != null) {
|
||||
clone.entity = (HttpEntity) CloneUtils.clone(this.entity);
|
||||
}
|
||||
return clone;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -38,10 +38,13 @@ import java.util.concurrent.locks.ReentrantLock;
|
|||
|
||||
import org.apache.http.ProtocolVersion;
|
||||
import org.apache.http.RequestLine;
|
||||
import org.apache.http.client.utils.CloneUtils;
|
||||
import org.apache.http.conn.ClientConnectionRequest;
|
||||
import org.apache.http.conn.ConnectionReleaseTrigger;
|
||||
import org.apache.http.message.AbstractHttpMessage;
|
||||
import org.apache.http.message.BasicRequestLine;
|
||||
import org.apache.http.message.HeaderGroup;
|
||||
import org.apache.http.params.HttpParams;
|
||||
import org.apache.http.params.HttpProtocolParams;
|
||||
|
||||
/**
|
||||
|
@ -54,9 +57,9 @@ import org.apache.http.params.HttpProtocolParams;
|
|||
* @since 4.0
|
||||
*/
|
||||
abstract class HttpRequestBase extends AbstractHttpMessage
|
||||
implements HttpUriRequest, AbortableHttpRequest {
|
||||
implements HttpUriRequest, AbortableHttpRequest, Cloneable {
|
||||
|
||||
private final Lock abortLock;
|
||||
private Lock abortLock;
|
||||
|
||||
private boolean aborted;
|
||||
|
||||
|
@ -159,5 +162,21 @@ abstract class HttpRequestBase extends AbstractHttpMessage
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isAborted() {
|
||||
return this.aborted;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object clone() throws CloneNotSupportedException {
|
||||
HttpRequestBase clone = (HttpRequestBase) super.clone();
|
||||
clone.abortLock = new ReentrantLock();
|
||||
clone.aborted = false;
|
||||
clone.releaseTrigger = null;
|
||||
clone.connRequest = null;
|
||||
clone.headergroup = (HeaderGroup) CloneUtils.clone(this.headergroup);
|
||||
clone.params = (HttpParams) CloneUtils.clone(this.params);
|
||||
return clone;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -61,4 +61,20 @@ public interface HttpUriRequest extends HttpRequest {
|
|||
*/
|
||||
URI getURI();
|
||||
|
||||
/**
|
||||
* Aborts execution of the request.
|
||||
*
|
||||
* @throws UnsupportedOperationException if the abort operation
|
||||
* is not supported / cannot be implemented.
|
||||
*/
|
||||
void abort() throws UnsupportedOperationException;
|
||||
|
||||
/**
|
||||
* Tests if the request execution has been aborted.
|
||||
*
|
||||
* @return <code>true</code> if the request execution has been aborted,
|
||||
* <code>false</code> otherwise.
|
||||
*/
|
||||
boolean isAborted();
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* $HeadURL:$
|
||||
* $Revision:$
|
||||
* $Date:$
|
||||
*
|
||||
* ====================================================================
|
||||
*
|
||||
* 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.
|
||||
* ====================================================================
|
||||
*
|
||||
* This software consists of voluntary contributions made by many
|
||||
* individuals on behalf of the Apache Software Foundation. For more
|
||||
* information on the Apache Software Foundation, please see
|
||||
* <http://www.apache.org/>.
|
||||
*
|
||||
*/
|
||||
package org.apache.http.client.utils;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* A collection of utilities to workaround limitations of Java clone framework.
|
||||
*/
|
||||
public class CloneUtils {
|
||||
|
||||
public static Object clone(final Object obj) throws CloneNotSupportedException {
|
||||
if (obj == null) {
|
||||
return null;
|
||||
}
|
||||
if (obj instanceof Cloneable) {
|
||||
Class<?> clazz = obj.getClass ();
|
||||
Method m;
|
||||
try {
|
||||
m = clazz.getMethod("clone", (Class[]) null);
|
||||
} catch (NoSuchMethodException ex) {
|
||||
throw new NoSuchMethodError(ex.getMessage());
|
||||
}
|
||||
try {
|
||||
return m.invoke(obj, (Object []) null);
|
||||
} catch (InvocationTargetException ex) {
|
||||
Throwable cause = ex.getCause();
|
||||
if (cause instanceof CloneNotSupportedException) {
|
||||
throw ((CloneNotSupportedException) cause);
|
||||
} else {
|
||||
throw new Error("Unexpected exception", cause);
|
||||
}
|
||||
} catch (IllegalAccessException ex) {
|
||||
throw new IllegalAccessError(ex.getMessage());
|
||||
}
|
||||
} else {
|
||||
throw new CloneNotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This class should not be instantiated.
|
||||
*/
|
||||
private CloneUtils() {
|
||||
}
|
||||
|
||||
}
|
|
@ -137,6 +137,14 @@ class RequestWrapper extends AbstractHttpMessage implements HttpUriRequest {
|
|||
return new BasicRequestLine(method, uritext, ver);
|
||||
}
|
||||
|
||||
public void abort() throws UnsupportedOperationException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public boolean isAborted() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public HttpRequest getOriginal() {
|
||||
return this.original;
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ import org.apache.http.cookie.SetCookie;
|
|||
*
|
||||
* @version $Revision$
|
||||
*/
|
||||
public class BasicClientCookie implements SetCookie, ClientCookie {
|
||||
public class BasicClientCookie implements SetCookie, ClientCookie, Cloneable {
|
||||
|
||||
/**
|
||||
* Default Constructor taking a name and a value. The value may be null.
|
||||
|
@ -311,6 +311,13 @@ public class BasicClientCookie implements SetCookie, ClientCookie {
|
|||
public boolean containsAttribute(final String name) {
|
||||
return this.attribs.get(name) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object clone() throws CloneNotSupportedException {
|
||||
BasicClientCookie clone = (BasicClientCookie) super.clone();
|
||||
clone.attribs = new HashMap<String, String>(this.attribs);
|
||||
return clone;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
|
@ -342,7 +349,7 @@ public class BasicClientCookie implements SetCookie, ClientCookie {
|
|||
private final String name;
|
||||
|
||||
/** Cookie attributes as specified by the origin server */
|
||||
private final Map<String, String> attribs;
|
||||
private Map<String, String> attribs;
|
||||
|
||||
/** Cookie value */
|
||||
private String value;
|
||||
|
|
|
@ -89,6 +89,13 @@ public class BasicClientCookie2 extends BasicClientCookie implements SetCookie2
|
|||
public boolean isExpired(final Date date) {
|
||||
return this.discard || super.isExpired(date);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object clone() throws CloneNotSupportedException {
|
||||
BasicClientCookie2 clone = (BasicClientCookie2) super.clone();
|
||||
clone.ports = this.ports.clone();
|
||||
return clone;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* $HeadURL:$
|
||||
* $Revision:$
|
||||
* $Date:$
|
||||
* $HeadURL$
|
||||
* $Revision$
|
||||
* $Date$
|
||||
* ====================================================================
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
|
@ -30,10 +30,15 @@
|
|||
|
||||
package org.apache.http.client.methods;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.apache.http.Header;
|
||||
import org.apache.http.HttpVersion;
|
||||
import org.apache.http.entity.InputStreamEntity;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.params.HttpProtocolParams;
|
||||
import org.apache.http.util.LangUtils;
|
||||
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestCase;
|
||||
|
@ -72,4 +77,67 @@ public class TestHttpRequestBase extends TestCase {
|
|||
assertEquals("/", httpget.getRequestLine().getUri());
|
||||
}
|
||||
|
||||
public void testCloneBasicRequests() throws Exception {
|
||||
HttpGet httpget = new HttpGet("http://host/path");
|
||||
httpget.addHeader("h1", "this header");
|
||||
httpget.addHeader("h2", "that header");
|
||||
httpget.addHeader("h3", "all sorts of headers");
|
||||
httpget.getParams().setParameter("p1", Integer.valueOf(1));
|
||||
httpget.getParams().setParameter("p2", "whatever");
|
||||
HttpGet clone = (HttpGet) httpget.clone();
|
||||
|
||||
assertEquals(httpget.getMethod(), clone.getMethod());
|
||||
assertEquals(httpget.getURI(), clone.getURI());
|
||||
|
||||
Header[] headers1 = httpget.getAllHeaders();
|
||||
Header[] headers2 = clone.getAllHeaders();
|
||||
|
||||
assertTrue(LangUtils.equals(headers1, headers2));
|
||||
assertTrue(httpget.getParams() != clone.getParams());
|
||||
|
||||
assertEquals(Integer.valueOf(1), clone.getParams().getParameter("p1"));
|
||||
assertEquals("whatever", clone.getParams().getParameter("p2"));
|
||||
assertEquals(null, clone.getParams().getParameter("p3"));
|
||||
}
|
||||
|
||||
public void testCloneEntityEnclosingRequests() throws Exception {
|
||||
HttpPost httppost = new HttpPost("http://host/path");
|
||||
httppost.addHeader("h1", "this header");
|
||||
httppost.addHeader("h2", "that header");
|
||||
httppost.addHeader("h3", "all sorts of headers");
|
||||
httppost.getParams().setParameter("p1", Integer.valueOf(1));
|
||||
httppost.getParams().setParameter("p2", "whatever");
|
||||
HttpPost clone = (HttpPost) httppost.clone();
|
||||
|
||||
assertEquals(httppost.getMethod(), clone.getMethod());
|
||||
assertEquals(httppost.getURI(), clone.getURI());
|
||||
|
||||
Header[] headers1 = httppost.getAllHeaders();
|
||||
Header[] headers2 = clone.getAllHeaders();
|
||||
|
||||
assertTrue(LangUtils.equals(headers1, headers2));
|
||||
assertTrue(httppost.getParams() != clone.getParams());
|
||||
|
||||
assertEquals(Integer.valueOf(1), clone.getParams().getParameter("p1"));
|
||||
assertEquals("whatever", clone.getParams().getParameter("p2"));
|
||||
assertEquals(null, clone.getParams().getParameter("p3"));
|
||||
|
||||
assertNull(clone.getEntity());
|
||||
|
||||
StringEntity e1 = new StringEntity("stuff");
|
||||
httppost.setEntity(e1);
|
||||
clone = (HttpPost) httppost.clone();
|
||||
assertTrue(clone.getEntity() instanceof StringEntity);
|
||||
assertFalse(clone.getEntity().equals(e1));
|
||||
|
||||
ByteArrayInputStream instream = new ByteArrayInputStream(new byte[] {});
|
||||
InputStreamEntity e2 = new InputStreamEntity(instream, -1);
|
||||
httppost.setEntity(e2);
|
||||
|
||||
try {
|
||||
httppost.clone();
|
||||
fail("CloneNotSupportedException should have been thrown");
|
||||
} catch (CloneNotSupportedException expected) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue