mirror of https://github.com/apache/jclouds.git
added new annotation @PartParam for multipart form support
This commit is contained in:
parent
fae1a1930e
commit
ab5e8b3ab4
|
@ -18,12 +18,6 @@
|
||||||
*/
|
*/
|
||||||
package org.jclouds.blobstore.binders;
|
package org.jclouds.blobstore.binders;
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
|
|
||||||
import javax.ws.rs.core.HttpHeaders;
|
import javax.ws.rs.core.HttpHeaders;
|
||||||
|
|
||||||
import org.jclouds.blobstore.domain.Blob;
|
import org.jclouds.blobstore.domain.Blob;
|
||||||
|
@ -32,9 +26,6 @@ import org.jclouds.http.MultipartForm;
|
||||||
import org.jclouds.http.MultipartForm.Part;
|
import org.jclouds.http.MultipartForm.Part;
|
||||||
import org.jclouds.rest.Binder;
|
import org.jclouds.rest.Binder;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableMultimap;
|
|
||||||
import com.google.common.collect.Multimap;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author Adrian Cole
|
* @author Adrian Cole
|
||||||
|
@ -45,36 +36,14 @@ public class BindBlobToMultipartForm implements Binder {
|
||||||
|
|
||||||
public void bindToRequest(HttpRequest request, Object payload) {
|
public void bindToRequest(HttpRequest request, Object payload) {
|
||||||
Blob object = (Blob) payload;
|
Blob object = (Blob) payload;
|
||||||
File file = new File(object.getMetadata().getName());
|
|
||||||
Multimap<String, String> partHeaders = ImmutableMultimap.of("Content-Disposition", String
|
|
||||||
.format("form-data; name=\"%s\"; filename=\"%s\"", file.getName(), file.getName()),
|
|
||||||
HttpHeaders.CONTENT_TYPE, checkNotNull(object.getMetadata().getContentType(),
|
|
||||||
"object.metadata.contentType()"));
|
|
||||||
Object data = checkNotNull(object.getPayload(), "object.getPayload()").getRawContent();
|
|
||||||
|
|
||||||
Part part;
|
Part part = Part.create(object.getMetadata().getName(), object.getPayload(), object
|
||||||
try {
|
.getMetadata().getContentType());
|
||||||
if (data instanceof byte[]) {
|
|
||||||
part = new Part(partHeaders, (byte[]) data);
|
|
||||||
} else if (data instanceof String) {
|
|
||||||
part = new Part(partHeaders, (String) data);
|
|
||||||
} else if (data instanceof File) {
|
|
||||||
part = new Part(partHeaders, (File) data);
|
|
||||||
} else if (data instanceof InputStream) {
|
|
||||||
part = new Part(partHeaders, (InputStream) data, object.getContentLength());
|
|
||||||
} else {
|
|
||||||
throw new IllegalArgumentException("type of part not supported: "
|
|
||||||
+ data.getClass().getCanonicalName() + "; " + object);
|
|
||||||
}
|
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
throw new IllegalArgumentException("file for part not found: " + object);
|
|
||||||
}
|
|
||||||
MultipartForm form = new MultipartForm(BOUNDARY, part);
|
MultipartForm form = new MultipartForm(BOUNDARY, part);
|
||||||
|
|
||||||
request.setPayload(form.getData());
|
request.setPayload(form.getData());
|
||||||
request.getHeaders().put(HttpHeaders.CONTENT_TYPE,
|
request.getHeaders().put(HttpHeaders.CONTENT_TYPE,
|
||||||
"multipart/form-data; boundary=" + BOUNDARY);
|
"multipart/form-data; boundary=" + BOUNDARY);
|
||||||
|
|
||||||
request.getHeaders().put(HttpHeaders.CONTENT_LENGTH, form.getSize() + "");
|
request.getHeaders().put(HttpHeaders.CONTENT_LENGTH, form.getSize() + "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,7 +62,7 @@ public class BindBlobToMultipartFormTest {
|
||||||
|
|
||||||
public void testSinglePart() throws IOException {
|
public void testSinglePart() throws IOException {
|
||||||
|
|
||||||
assertEquals(EXPECTS.length(), 131);
|
assertEquals(EXPECTS.length(), 113);
|
||||||
|
|
||||||
BindBlobToMultipartForm binder = new BindBlobToMultipartForm();
|
BindBlobToMultipartForm binder = new BindBlobToMultipartForm();
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@ public class BindBlobToMultipartFormTest {
|
||||||
|
|
||||||
assertEquals(Utils.toStringAndClose((InputStream) request.getPayload().getRawContent()),
|
assertEquals(Utils.toStringAndClose((InputStream) request.getPayload().getRawContent()),
|
||||||
EXPECTS);
|
EXPECTS);
|
||||||
assertEquals(request.getFirstHeaderOrNull(HttpHeaders.CONTENT_LENGTH), 131 + "");
|
assertEquals(request.getFirstHeaderOrNull(HttpHeaders.CONTENT_LENGTH), 113 + "");
|
||||||
|
|
||||||
assertEquals(request.getFirstHeaderOrNull(HttpHeaders.CONTENT_TYPE),
|
assertEquals(request.getFirstHeaderOrNull(HttpHeaders.CONTENT_TYPE),
|
||||||
"multipart/form-data; boundary=" + BOUNDRY);
|
"multipart/form-data; boundary=" + BOUNDRY);
|
||||||
|
@ -80,7 +80,7 @@ public class BindBlobToMultipartFormTest {
|
||||||
private static void addData(String boundary, String data, StringBuilder builder) {
|
private static void addData(String boundary, String data, StringBuilder builder) {
|
||||||
builder.append(boundary).append("\r\n");
|
builder.append(boundary).append("\r\n");
|
||||||
builder.append("Content-Disposition").append(": ").append(
|
builder.append("Content-Disposition").append(": ").append(
|
||||||
"form-data; name=\"hello\"; filename=\"hello\"").append("\r\n");
|
"form-data; name=\"hello\"").append("\r\n");
|
||||||
builder.append("Content-Type").append(": ").append("text/plain").append("\r\n");
|
builder.append("Content-Type").append(": ").append("text/plain").append("\r\n");
|
||||||
builder.append("\r\n");
|
builder.append("\r\n");
|
||||||
builder.append(data).append("\r\n");
|
builder.append(data).append("\r\n");
|
||||||
|
|
|
@ -18,18 +18,24 @@
|
||||||
*/
|
*/
|
||||||
package org.jclouds.http;
|
package org.jclouds.http;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
import java.io.IOException;
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
import org.jclouds.util.InputStreamChain;
|
import javax.annotation.Nullable;
|
||||||
import org.jclouds.util.Utils;
|
import javax.ws.rs.core.HttpHeaders;
|
||||||
|
|
||||||
|
import org.jclouds.http.payloads.FilePayload;
|
||||||
|
import org.jclouds.util.InputStreamChain;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableMultimap;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.google.common.collect.Multimap;
|
import com.google.common.collect.Multimap;
|
||||||
|
import com.google.common.collect.Multimaps;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -57,9 +63,9 @@ public class MultipartForm {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addData(Part part) {
|
private void addData(Part part) {
|
||||||
chain.addInputStream(part.getData());
|
chain.addInputStream(part.getContent());
|
||||||
chain.addAsInputStream(rn);
|
chain.addAsInputStream(rn);
|
||||||
size += part.getSize() + rn.length();
|
size += part.calculateSize() + rn.length();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addHeaders(String boundaryrn, Part part) {
|
private void addHeaders(String boundaryrn, Part part) {
|
||||||
|
@ -83,39 +89,112 @@ public class MultipartForm {
|
||||||
this("__redrose__", parts);
|
this("__redrose__", parts);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Part {
|
public static class Part implements Payload {
|
||||||
private final Multimap<String, String> headers;
|
private final Multimap<String, String> headers;
|
||||||
private final InputStream data;
|
private final Payload delegate;
|
||||||
private final long size;
|
|
||||||
|
|
||||||
public Part(Multimap<String, String> headers, InputStream data, long size) {
|
private static class PartMap extends LinkedHashMap<String, String> {
|
||||||
this.headers = headers;
|
|
||||||
this.data = data;
|
/** The serialVersionUID */
|
||||||
this.size = size;
|
private static final long serialVersionUID = -287387556008320212L;
|
||||||
|
|
||||||
|
static PartMap create(String name) {
|
||||||
|
PartMap map = new PartMap();
|
||||||
|
map.put("Content-Disposition", String.format("form-data; name=\"%s\"", checkNotNull(
|
||||||
|
name, "name")));
|
||||||
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Part(Multimap<String, String> headers, String data) {
|
static PartMap create(String name, String filename) {
|
||||||
this(headers, Utils.toInputStream(data), data.length());
|
PartMap map = new PartMap();
|
||||||
|
map.put("Content-Disposition", String.format("form-data; name=\"%s\"; filename=\"%s\"",
|
||||||
|
checkNotNull(name, "name"), checkNotNull(filename, "filename")));
|
||||||
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Part(Multimap<String, String> headers, File data) throws FileNotFoundException {
|
PartMap contentType(@Nullable String type) {
|
||||||
this(headers, new FileInputStream(data), data.length());
|
if (type != null)
|
||||||
|
put(HttpHeaders.CONTENT_TYPE, checkNotNull(type, "type"));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Part(Multimap<String, String> headers, byte[] data) {
|
private Part(PartMap map, Payload delegate) {
|
||||||
this(headers, new ByteArrayInputStream(data), data.length);
|
this.delegate = checkNotNull(delegate, "delegate");
|
||||||
|
this.headers = ImmutableMultimap.copyOf(Multimaps.forMap((checkNotNull(map, "headers"))));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Part create(String name, String value) {
|
||||||
|
return new Part(PartMap.create(name), Payloads.newStringPayload(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Part create(String name, Payload delegate, String contentType) {
|
||||||
|
return new Part(PartMap.create(name).contentType(contentType), delegate);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Part create(String name, FilePayload delegate, String contentType) {
|
||||||
|
return new Part(PartMap.create(name, delegate.getRawContent().getName()).contentType(
|
||||||
|
contentType), delegate);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Multimap<String, String> getHeaders() {
|
public Multimap<String, String> getHeaders() {
|
||||||
return headers;
|
return headers;
|
||||||
}
|
}
|
||||||
|
|
||||||
public InputStream getData() {
|
@Override
|
||||||
return data;
|
public Long calculateSize() {
|
||||||
|
return delegate.calculateSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getSize() {
|
@Override
|
||||||
return size;
|
public InputStream getContent() {
|
||||||
|
return delegate.getContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getRawContent() {
|
||||||
|
return delegate.getContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isRepeatable() {
|
||||||
|
return delegate.isRepeatable();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeTo(OutputStream outstream) throws IOException {
|
||||||
|
delegate.writeTo(outstream);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
final int prime = 31;
|
||||||
|
int result = 1;
|
||||||
|
result = prime * result + ((delegate == null) ? 0 : delegate.hashCode());
|
||||||
|
result = prime * result + ((headers == null) ? 0 : headers.hashCode());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj)
|
||||||
|
return true;
|
||||||
|
if (obj == null)
|
||||||
|
return false;
|
||||||
|
if (getClass() != obj.getClass())
|
||||||
|
return false;
|
||||||
|
Part other = (Part) obj;
|
||||||
|
if (delegate == null) {
|
||||||
|
if (other.delegate != null)
|
||||||
|
return false;
|
||||||
|
} else if (!delegate.equals(other.delegate))
|
||||||
|
return false;
|
||||||
|
if (headers == null) {
|
||||||
|
if (other.headers != null)
|
||||||
|
return false;
|
||||||
|
} else if (!headers.equals(other.headers))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,9 +24,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.Target;
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
import org.jclouds.http.MultipartForm.Part;
|
import javax.ws.rs.core.MediaType;
|
||||||
|
|
||||||
import com.google.common.base.Function;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Designates that this parameter will be bound to a multipart form.
|
* Designates that this parameter will be bound to a multipart form.
|
||||||
|
@ -36,17 +34,7 @@ import com.google.common.base.Function;
|
||||||
@Target(PARAMETER)
|
@Target(PARAMETER)
|
||||||
@Retention(RUNTIME)
|
@Retention(RUNTIME)
|
||||||
public @interface PartParam {
|
public @interface PartParam {
|
||||||
|
String name();
|
||||||
|
|
||||||
public static class ALREADY_PART implements Function<Object, Part> {
|
String contentType() default MediaType.TEXT_PLAIN;
|
||||||
|
|
||||||
@Override
|
|
||||||
public Part apply(Object from) {
|
|
||||||
return Part.class.cast(from);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* how to convert this to a part.
|
|
||||||
*/
|
|
||||||
Class<? extends Function<Object, Part>> value() default ALREADY_PART.class;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,6 +62,7 @@ import org.jclouds.http.HttpRequestFilter;
|
||||||
import org.jclouds.http.HttpResponse;
|
import org.jclouds.http.HttpResponse;
|
||||||
import org.jclouds.http.HttpUtils;
|
import org.jclouds.http.HttpUtils;
|
||||||
import org.jclouds.http.MultipartForm;
|
import org.jclouds.http.MultipartForm;
|
||||||
|
import org.jclouds.http.Payloads;
|
||||||
import org.jclouds.http.MultipartForm.Part;
|
import org.jclouds.http.MultipartForm.Part;
|
||||||
import org.jclouds.http.functions.CloseContentAndReturn;
|
import org.jclouds.http.functions.CloseContentAndReturn;
|
||||||
import org.jclouds.http.functions.ParseSax;
|
import org.jclouds.http.functions.ParseSax;
|
||||||
|
@ -102,7 +103,6 @@ import com.google.common.annotations.VisibleForTesting;
|
||||||
import com.google.common.base.Function;
|
import com.google.common.base.Function;
|
||||||
import com.google.common.base.Predicate;
|
import com.google.common.base.Predicate;
|
||||||
import com.google.common.collect.Collections2;
|
import com.google.common.collect.Collections2;
|
||||||
import com.google.common.collect.ImmutableMultimap;
|
|
||||||
import com.google.common.collect.Iterables;
|
import com.google.common.collect.Iterables;
|
||||||
import com.google.common.collect.LinkedHashMultimap;
|
import com.google.common.collect.LinkedHashMultimap;
|
||||||
import com.google.common.collect.LinkedListMultimap;
|
import com.google.common.collect.LinkedListMultimap;
|
||||||
|
@ -195,8 +195,7 @@ public class RestAnnotationProcessor<T> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Part apply(Entry<String, String> from) {
|
public Part apply(Entry<String, String> from) {
|
||||||
return new Part(ImmutableMultimap.of("Content-Disposition", String.format(
|
return Part.create(from.getKey(), from.getValue());
|
||||||
"form-data; name=\"%s\"", from.getKey())), from.getValue());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -1012,8 +1011,9 @@ public class RestAnnotationProcessor<T> {
|
||||||
.get(method);
|
.get(method);
|
||||||
for (Entry<Integer, Set<Annotation>> entry : indexToPartParam.entrySet()) {
|
for (Entry<Integer, Set<Annotation>> entry : indexToPartParam.entrySet()) {
|
||||||
for (Annotation key : entry.getValue()) {
|
for (Annotation key : entry.getValue()) {
|
||||||
PartParam extractor = (PartParam) key;
|
PartParam param = (PartParam) key;
|
||||||
Part part = injector.getInstance(extractor.value()).apply(args[entry.getKey()]);
|
Part part = Part.create(param.name(), Payloads.newPayload(args[entry.getKey()]), param
|
||||||
|
.contentType());
|
||||||
parts.add(part);
|
parts.add(part);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,19 +18,24 @@
|
||||||
*/
|
*/
|
||||||
package org.jclouds.http;
|
package org.jclouds.http;
|
||||||
|
|
||||||
|
import static org.easymock.EasyMock.expect;
|
||||||
|
import static org.easymock.classextension.EasyMock.createMock;
|
||||||
|
import static org.easymock.classextension.EasyMock.replay;
|
||||||
import static org.testng.Assert.assertEquals;
|
import static org.testng.Assert.assertEquals;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
|
||||||
import javax.ws.rs.core.HttpHeaders;
|
|
||||||
import javax.ws.rs.core.MediaType;
|
import javax.ws.rs.core.MediaType;
|
||||||
|
|
||||||
import org.jclouds.http.MultipartForm.Part;
|
import org.jclouds.http.MultipartForm.Part;
|
||||||
|
import org.jclouds.http.payloads.FilePayload;
|
||||||
|
import org.jclouds.http.payloads.StringPayload;
|
||||||
import org.jclouds.util.Utils;
|
import org.jclouds.util.Utils;
|
||||||
import org.testng.annotations.Test;
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableMultimap;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests parsing of a request
|
* Tests parsing of a request
|
||||||
*
|
*
|
||||||
|
@ -54,10 +59,47 @@ public class MultipartFormTest {
|
||||||
assertEquals(multipartForm.getSize(), 199);
|
assertEquals(multipartForm.getSize(), 199);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class MockFilePayload extends FilePayload {
|
||||||
|
|
||||||
|
private final StringPayload realPayload;
|
||||||
|
|
||||||
|
public MockFilePayload(String content) {
|
||||||
|
super(createMockFile(content));
|
||||||
|
this.realPayload = Payloads.newStringPayload(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static File createMockFile(String content) {
|
||||||
|
File file = createMock(File.class);
|
||||||
|
expect(file.exists()).andReturn(true);
|
||||||
|
expect(file.getName()).andReturn("testfile.txt");
|
||||||
|
replay(file);
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long calculateSize() {
|
||||||
|
return realPayload.calculateSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InputStream getContent() {
|
||||||
|
return realPayload.getContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isRepeatable() {
|
||||||
|
return realPayload.isRepeatable();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeTo(OutputStream outstream) throws IOException {
|
||||||
|
realPayload.writeTo(outstream);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private Part newPart(String data) {
|
private Part newPart(String data) {
|
||||||
return new MultipartForm.Part(ImmutableMultimap.of("Content-Disposition",
|
return Part.create("file", new MockFilePayload(data), MediaType.TEXT_PLAIN);
|
||||||
"form-data; name=\"file\"; filename=\"testfile.txt\"", HttpHeaders.CONTENT_TYPE,
|
|
||||||
MediaType.TEXT_PLAIN), data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addData(String boundary, String data, StringBuilder builder) {
|
private void addData(String boundary, String data, StringBuilder builder) {
|
||||||
|
|
|
@ -23,6 +23,7 @@ import static com.google.common.util.concurrent.MoreExecutors.sameThreadExecutor
|
||||||
import static org.testng.Assert.assertEquals;
|
import static org.testng.Assert.assertEquals;
|
||||||
import static org.testng.Assert.assertNull;
|
import static org.testng.Assert.assertNull;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
|
@ -98,6 +99,7 @@ import org.jclouds.rest.annotations.MapPayloadParam;
|
||||||
import org.jclouds.rest.annotations.MatrixParams;
|
import org.jclouds.rest.annotations.MatrixParams;
|
||||||
import org.jclouds.rest.annotations.OverrideRequestFilters;
|
import org.jclouds.rest.annotations.OverrideRequestFilters;
|
||||||
import org.jclouds.rest.annotations.ParamParser;
|
import org.jclouds.rest.annotations.ParamParser;
|
||||||
|
import org.jclouds.rest.annotations.PartParam;
|
||||||
import org.jclouds.rest.annotations.QueryParams;
|
import org.jclouds.rest.annotations.QueryParams;
|
||||||
import org.jclouds.rest.annotations.RequestFilters;
|
import org.jclouds.rest.annotations.RequestFilters;
|
||||||
import org.jclouds.rest.annotations.ResponseParser;
|
import org.jclouds.rest.annotations.ResponseParser;
|
||||||
|
@ -114,6 +116,7 @@ import org.testng.annotations.BeforeClass;
|
||||||
import org.testng.annotations.DataProvider;
|
import org.testng.annotations.DataProvider;
|
||||||
import org.testng.annotations.Test;
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import com.google.common.base.Charsets;
|
||||||
import com.google.common.base.Function;
|
import com.google.common.base.Function;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
@ -123,6 +126,7 @@ import com.google.common.collect.Iterables;
|
||||||
import com.google.common.collect.LinkedHashMultimap;
|
import com.google.common.collect.LinkedHashMultimap;
|
||||||
import com.google.common.collect.LinkedListMultimap;
|
import com.google.common.collect.LinkedListMultimap;
|
||||||
import com.google.common.collect.Multimap;
|
import com.google.common.collect.Multimap;
|
||||||
|
import com.google.common.io.Files;
|
||||||
import com.google.common.util.concurrent.ListenableFuture;
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
import com.google.inject.AbstractModule;
|
import com.google.inject.AbstractModule;
|
||||||
import com.google.inject.ConfigurationException;
|
import com.google.inject.ConfigurationException;
|
||||||
|
@ -612,6 +616,115 @@ public class RestAnnotationProcessorTest {
|
||||||
assertEquals(httpMethod.getPayload().toString(), expected);
|
assertEquals(httpMethod.getPayload().toString(), expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Endpoint(Localhost.class)
|
||||||
|
static interface TestMultipartForm {
|
||||||
|
@POST
|
||||||
|
public void withStringPart(@PartParam(name = "fooble") String path);
|
||||||
|
|
||||||
|
@POST
|
||||||
|
public void withParamStringPart(@FormParam("name") String name,
|
||||||
|
@PartParam(name = "file") String path);
|
||||||
|
|
||||||
|
@POST
|
||||||
|
public void withParamFilePart(@FormParam("name") String name,
|
||||||
|
@PartParam(name = "file") File path);
|
||||||
|
|
||||||
|
@POST
|
||||||
|
public void withParamFileBinaryPart(@FormParam("name") String name,
|
||||||
|
@PartParam(name = "file", contentType = MediaType.APPLICATION_OCTET_STREAM) File path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testMultipartWithStringPart() throws SecurityException, NoSuchMethodException,
|
||||||
|
IOException {
|
||||||
|
Method method = TestMultipartForm.class.getMethod("withStringPart", String.class);
|
||||||
|
GeneratedHttpRequest<TestMultipartForm> httpRequest = factory(TestMultipartForm.class)
|
||||||
|
.createRequest(method, "foobledata");
|
||||||
|
assertRequestLineEquals(httpRequest, "POST http://localhost:9999 HTTP/1.1");
|
||||||
|
assertHeadersEqual(httpRequest,
|
||||||
|
"Content-Length: 119\nContent-Type: multipart/form-data; boundary=--JCLOUDS--\n");
|
||||||
|
assertPayloadEquals(httpRequest,//
|
||||||
|
"----JCLOUDS--\r\n" + //
|
||||||
|
"Content-Disposition: form-data; name=\"fooble\"\r\n" + //
|
||||||
|
"Content-Type: text/plain\r\n" + //
|
||||||
|
"\r\n" + //
|
||||||
|
"foobledata\r\n" + //
|
||||||
|
"----JCLOUDS----\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testMultipartWithParamStringPart() throws SecurityException, NoSuchMethodException,
|
||||||
|
IOException {
|
||||||
|
Method method = TestMultipartForm.class.getMethod("withParamStringPart", String.class,
|
||||||
|
String.class);
|
||||||
|
GeneratedHttpRequest<TestMultipartForm> httpRequest = factory(TestMultipartForm.class)
|
||||||
|
.createRequest(method, "name", "foobledata");
|
||||||
|
assertRequestLineEquals(httpRequest, "POST http://localhost:9999 HTTP/1.1");
|
||||||
|
assertHeadersEqual(httpRequest,
|
||||||
|
"Content-Length: 185\nContent-Type: multipart/form-data; boundary=--JCLOUDS--\n");
|
||||||
|
assertPayloadEquals(httpRequest,//
|
||||||
|
"----JCLOUDS--\r\n" + //
|
||||||
|
"Content-Disposition: form-data; name=\"name\"\r\n" + //
|
||||||
|
"\r\n" + //
|
||||||
|
"name\r\n" + // /
|
||||||
|
"----JCLOUDS--\r\n" + //
|
||||||
|
"Content-Disposition: form-data; name=\"file\"\r\n" + //
|
||||||
|
"Content-Type: text/plain\r\n" + //
|
||||||
|
"\r\n" + //
|
||||||
|
"foobledata\r\n" + //
|
||||||
|
"----JCLOUDS----\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testMultipartWithParamFilePart() throws SecurityException, NoSuchMethodException,
|
||||||
|
IOException {
|
||||||
|
Method method = TestMultipartForm.class.getMethod("withParamFilePart", String.class,
|
||||||
|
File.class);
|
||||||
|
File file = File.createTempFile("foo", "bar");
|
||||||
|
Files.append("foobledata", file, Charsets.UTF_8);
|
||||||
|
file.deleteOnExit();
|
||||||
|
|
||||||
|
GeneratedHttpRequest<TestMultipartForm> httpRequest = factory(TestMultipartForm.class)
|
||||||
|
.createRequest(method, "name", file);
|
||||||
|
assertRequestLineEquals(httpRequest, "POST http://localhost:9999 HTTP/1.1");
|
||||||
|
assertHeadersEqual(httpRequest,
|
||||||
|
"Content-Length: 185\nContent-Type: multipart/form-data; boundary=--JCLOUDS--\n");
|
||||||
|
assertPayloadEquals(httpRequest,//
|
||||||
|
"----JCLOUDS--\r\n" + //
|
||||||
|
"Content-Disposition: form-data; name=\"name\"\r\n" + //
|
||||||
|
"\r\n" + //
|
||||||
|
"name\r\n" + // /
|
||||||
|
"----JCLOUDS--\r\n" + //
|
||||||
|
"Content-Disposition: form-data; name=\"file\"\r\n" + //
|
||||||
|
"Content-Type: text/plain\r\n" + //
|
||||||
|
"\r\n" + //
|
||||||
|
"foobledata\r\n" + //
|
||||||
|
"----JCLOUDS----\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testMultipartWithParamFileBinaryPart() throws SecurityException,
|
||||||
|
NoSuchMethodException, IOException {
|
||||||
|
Method method = TestMultipartForm.class.getMethod("withParamFileBinaryPart", String.class,
|
||||||
|
File.class);
|
||||||
|
File file = File.createTempFile("foo", "bar");
|
||||||
|
Files.write(new byte[] { 17, 26, 39, 40, 50 }, file);
|
||||||
|
file.deleteOnExit();
|
||||||
|
|
||||||
|
GeneratedHttpRequest<TestMultipartForm> httpRequest = factory(TestMultipartForm.class)
|
||||||
|
.createRequest(method, "name", file);
|
||||||
|
assertRequestLineEquals(httpRequest, "POST http://localhost:9999 HTTP/1.1");
|
||||||
|
assertHeadersEqual(httpRequest,
|
||||||
|
"Content-Length: 194\nContent-Type: multipart/form-data; boundary=--JCLOUDS--\n");
|
||||||
|
assertPayloadEquals(httpRequest,//
|
||||||
|
"----JCLOUDS--\r\n" + //
|
||||||
|
"Content-Disposition: form-data; name=\"name\"\r\n" + //
|
||||||
|
"\r\n" + //
|
||||||
|
"name\r\n" + // /
|
||||||
|
"----JCLOUDS--\r\n" + //
|
||||||
|
"Content-Disposition: form-data; name=\"file\"\r\n" + //
|
||||||
|
"Content-Type: application/octet-stream\r\n" + //
|
||||||
|
"\r\n" + //
|
||||||
|
"'(2\r\n" + //
|
||||||
|
"----JCLOUDS----\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
@Endpoint(Localhost.class)
|
@Endpoint(Localhost.class)
|
||||||
public class TestPut {
|
public class TestPut {
|
||||||
@PUT
|
@PUT
|
||||||
|
|
|
@ -164,7 +164,7 @@ public class PCSAsyncClientTest extends RestClientTest<PCSAsyncClient> {
|
||||||
|
|
||||||
assertRequestLineEquals(httpMethod, "POST http://localhost/mycontainer/contents HTTP/1.1");
|
assertRequestLineEquals(httpMethod, "POST http://localhost/mycontainer/contents HTTP/1.1");
|
||||||
assertHeadersEqual(httpMethod,
|
assertHeadersEqual(httpMethod,
|
||||||
"Content-Length: 131\nContent-Type: multipart/form-data; boundary=--JCLOUDS--\n");
|
"Content-Length: 113\nContent-Type: multipart/form-data; boundary=--JCLOUDS--\n");
|
||||||
assertPayloadEquals(httpMethod, BindBlobToMultipartFormTest.EXPECTS);
|
assertPayloadEquals(httpMethod, BindBlobToMultipartFormTest.EXPECTS);
|
||||||
|
|
||||||
assertResponseParserClassEquals(method, httpMethod,
|
assertResponseParserClassEquals(method, httpMethod,
|
||||||
|
|
|
@ -92,14 +92,14 @@
|
||||||
<category name="jclouds.headers">
|
<category name="jclouds.headers">
|
||||||
<priority value="DEBUG" />
|
<priority value="DEBUG" />
|
||||||
<appender-ref ref="ASYNCWIRE" />
|
<appender-ref ref="ASYNCWIRE" />
|
||||||
</category><!--
|
</category>
|
||||||
|
|
||||||
<category name="jclouds.wire">
|
<category name="jclouds.wire">
|
||||||
<priority value="DEBUG" />
|
<priority value="DEBUG" />
|
||||||
<appender-ref ref="ASYNCWIRE" />
|
<appender-ref ref="ASYNCWIRE" />
|
||||||
</category>
|
</category>
|
||||||
|
|
||||||
--><!-- ======================= -->
|
<!-- ======================= -->
|
||||||
<!-- Setup the Root category -->
|
<!-- Setup the Root category -->
|
||||||
<!-- ======================= -->
|
<!-- ======================= -->
|
||||||
|
|
||||||
|
|
|
@ -84,10 +84,10 @@ public class SDNAsyncClientTest extends RestClientTest<SDNAsyncClient> {
|
||||||
httpMethod,
|
httpMethod,
|
||||||
"POST http://uploader/Upload.ashx?output=json&destFolderPath=adriansmovies&uploadToken=token HTTP/1.1");
|
"POST http://uploader/Upload.ashx?output=json&destFolderPath=adriansmovies&uploadToken=token HTTP/1.1");
|
||||||
assertHeadersEqual(httpMethod,
|
assertHeadersEqual(httpMethod,
|
||||||
"Content-Length: 131\nContent-Type: multipart/form-data; boundary=--JCLOUDS--\n");
|
"Content-Length: 113\nContent-Type: multipart/form-data; boundary=--JCLOUDS--\n");
|
||||||
StringBuffer expects = new StringBuffer();
|
StringBuffer expects = new StringBuffer();
|
||||||
expects.append("----JCLOUDS--\r\n");
|
expects.append("----JCLOUDS--\r\n");
|
||||||
expects.append("Content-Disposition: form-data; name=\"hello\"; filename=\"hello\"\r\n");
|
expects.append("Content-Disposition: form-data; name=\"hello\"\r\n");
|
||||||
expects.append("Content-Type: text/plain\r\n\r\n");
|
expects.append("Content-Type: text/plain\r\n\r\n");
|
||||||
expects.append("hello\r\n");
|
expects.append("hello\r\n");
|
||||||
expects.append("----JCLOUDS----\r\n");
|
expects.append("----JCLOUDS----\r\n");
|
||||||
|
|
Loading…
Reference in New Issue