refactored internal code and tests to use FunctionalReflection

This commit is contained in:
Adrian Cole 2013-01-06 23:17:14 -08:00
parent bd9e998b12
commit 3089111621
127 changed files with 1618 additions and 2301 deletions

View File

@ -33,6 +33,7 @@ import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.functions.BlobToHttpGetOptions; import org.jclouds.blobstore.functions.BlobToHttpGetOptions;
import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpRequest;
import org.jclouds.http.options.GetOptions; import org.jclouds.http.options.GetOptions;
import org.jclouds.reflect.Invocation;
import org.jclouds.rest.internal.RestAnnotationProcessor; import org.jclouds.rest.internal.RestAnnotationProcessor;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
@ -53,9 +54,9 @@ public class AtmosBlobRequestSigner implements BlobRequestSigner {
private final Invokable<?, ?> createMethod; private final Invokable<?, ?> createMethod;
@Inject @Inject
public AtmosBlobRequestSigner(RestAnnotationProcessor.Factory processor, BlobToObject blobToObject, public AtmosBlobRequestSigner(RestAnnotationProcessor processor, BlobToObject blobToObject,
BlobToHttpGetOptions blob2ObjectGetOptions) throws SecurityException, NoSuchMethodException { BlobToHttpGetOptions blob2ObjectGetOptions) throws SecurityException, NoSuchMethodException {
this.processor = checkNotNull(processor, "processor").declaring(AtmosAsyncClient.class); this.processor = checkNotNull(processor, "processor");
this.blobToObject = checkNotNull(blobToObject, "blobToObject"); this.blobToObject = checkNotNull(blobToObject, "blobToObject");
this.blob2ObjectGetOptions = checkNotNull(blob2ObjectGetOptions, "blob2ObjectGetOptions"); this.blob2ObjectGetOptions = checkNotNull(blob2ObjectGetOptions, "blob2ObjectGetOptions");
this.getMethod = Invokable.from(AtmosAsyncClient.class.getMethod("readFile", String.class, GetOptions[].class)); this.getMethod = Invokable.from(AtmosAsyncClient.class.getMethod("readFile", String.class, GetOptions[].class));
@ -68,7 +69,8 @@ public class AtmosBlobRequestSigner implements BlobRequestSigner {
public HttpRequest signGetBlob(String container, String name) { public HttpRequest signGetBlob(String container, String name) {
checkNotNull(container, "container"); checkNotNull(container, "container");
checkNotNull(name, "name"); checkNotNull(name, "name");
return cleanRequest(processor.createRequest(getMethod, ImmutableList.<Object> of(getPath(container, name)))); return cleanRequest(processor.apply(Invocation.create(getMethod,
ImmutableList.<Object> of(getPath(container, name)))));
} }
@Override @Override
@ -80,8 +82,8 @@ public class AtmosBlobRequestSigner implements BlobRequestSigner {
public HttpRequest signPutBlob(String container, Blob blob) { public HttpRequest signPutBlob(String container, Blob blob) {
checkNotNull(container, "container"); checkNotNull(container, "container");
checkNotNull(blob, "blob"); checkNotNull(blob, "blob");
return cleanRequest(processor.createRequest(createMethod, return cleanRequest(processor.apply(Invocation.create(createMethod,
ImmutableList.<Object> of(container, blobToObject.apply(blob)))); ImmutableList.<Object> of(container, blobToObject.apply(blob)))));
} }
@Override @Override
@ -93,7 +95,8 @@ public class AtmosBlobRequestSigner implements BlobRequestSigner {
public HttpRequest signRemoveBlob(String container, String name) { public HttpRequest signRemoveBlob(String container, String name) {
checkNotNull(container, "container"); checkNotNull(container, "container");
checkNotNull(name, "name"); checkNotNull(name, "name");
return cleanRequest(processor.createRequest(deleteMethod, ImmutableList.<Object> of(getPath(container, name)))); return cleanRequest(processor.apply(Invocation.create(deleteMethod,
ImmutableList.<Object> of(getPath(container, name)))));
} }
private String getPath(String container, String name) { private String getPath(String container, String name) {
@ -104,8 +107,8 @@ public class AtmosBlobRequestSigner implements BlobRequestSigner {
public HttpRequest signGetBlob(String container, String name, org.jclouds.blobstore.options.GetOptions options) { public HttpRequest signGetBlob(String container, String name, org.jclouds.blobstore.options.GetOptions options) {
checkNotNull(container, "container"); checkNotNull(container, "container");
checkNotNull(name, "name"); checkNotNull(name, "name");
return cleanRequest(processor.createRequest(getMethod, return cleanRequest(processor.apply(Invocation.create(getMethod,
ImmutableList.of(getPath(container, name), blob2ObjectGetOptions.apply(checkNotNull(options, "options"))))); ImmutableList.of(getPath(container, name), blob2ObjectGetOptions.apply(checkNotNull(options, "options"))))));
} }
} }

View File

@ -79,7 +79,7 @@ public class ParseObjectFromHeadersAndHttpContent implements Function<HttpRespon
@Override @Override
public ParseObjectFromHeadersAndHttpContent setContext(HttpRequest request) { public ParseObjectFromHeadersAndHttpContent setContext(HttpRequest request) {
this.uri = request.getEndpoint(); this.uri = request.getEndpoint();
return setPath(GeneratedHttpRequest.class.cast(request).getArgs().get(0).toString()); return setPath(GeneratedHttpRequest.class.cast(request).getInvocation().getArgs().get(0).toString());
} }
private ParseObjectFromHeadersAndHttpContent setPath(String path) { private ParseObjectFromHeadersAndHttpContent setPath(String path) {

View File

@ -20,7 +20,6 @@ package org.jclouds.cloudsigma.binders;
import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import java.util.Map; import java.util.Map;
@ -58,7 +57,6 @@ public class BindCloneDriveOptionsToPlainTextString implements MapBinder {
checkArgument(checkNotNull(request, "request") instanceof GeneratedHttpRequest, checkArgument(checkNotNull(request, "request") instanceof GeneratedHttpRequest,
"this binder is only valid for GeneratedHttpRequests!"); "this binder is only valid for GeneratedHttpRequests!");
GeneratedHttpRequest gRequest = GeneratedHttpRequest.class.cast(request); GeneratedHttpRequest gRequest = GeneratedHttpRequest.class.cast(request);
checkState(gRequest.getArgs() != null, "args should be initialized at this point");
CloneDriveOptions options = findOptionsInArgsOrNull(gRequest); CloneDriveOptions options = findOptionsInArgsOrNull(gRequest);
if (options != null) { if (options != null) {
@ -76,7 +74,7 @@ public class BindCloneDriveOptionsToPlainTextString implements MapBinder {
} }
static CloneDriveOptions findOptionsInArgsOrNull(GeneratedHttpRequest gRequest) { static CloneDriveOptions findOptionsInArgsOrNull(GeneratedHttpRequest gRequest) {
for (Object arg : gRequest.getArgs()) { for (Object arg : gRequest.getInvocation().getArgs()) {
if (arg instanceof CloneDriveOptions) { if (arg instanceof CloneDriveOptions) {
return (CloneDriveOptions) arg; return (CloneDriveOptions) arg;
} else if (arg instanceof CloneDriveOptions[]) { } else if (arg instanceof CloneDriveOptions[]) {

View File

@ -18,64 +18,59 @@
*/ */
package org.jclouds.cloudsigma.binders; package org.jclouds.cloudsigma.binders;
import static org.easymock.EasyMock.createMock; import static org.testng.Assert.assertEquals;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
import java.io.IOException; import java.io.IOException;
import java.net.URI;
import java.util.List; import java.util.List;
import java.util.Map;
import org.jclouds.cloudsigma.options.CloneDriveOptions; import org.jclouds.cloudsigma.options.CloneDriveOptions;
import org.jclouds.io.MutableContentMetadata; import org.jclouds.reflect.Invocation;
import org.jclouds.io.Payload;
import org.jclouds.rest.internal.GeneratedHttpRequest; import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.reflect.Invokable;
import com.google.inject.Guice; import com.google.inject.Guice;
/** /**
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
@Test(groups = { "unit" }) @Test(groups = "unit")
public class BindCloneDriveOptionsToPlainTextStringTest { public class BindCloneDriveOptionsToPlainTextStringTest {
private static final BindCloneDriveOptionsToPlainTextString binder = Guice.createInjector().getInstance( private static final BindCloneDriveOptionsToPlainTextString binder = Guice.createInjector().getInstance(
BindCloneDriveOptionsToPlainTextString.class); BindCloneDriveOptionsToPlainTextString.class);
public void testDefault() throws IOException { public void testDefault() throws IOException {
assertInputAndArgsCreatesPayload(ImmutableMap.<String, Object>of("name", "newdrive"), ImmutableList.<Object> of(), String expected = "name newdrive";
"name newdrive"); GeneratedHttpRequest request = requestForArgs(ImmutableList.<Object> of());
Map<String, Object> map = ImmutableMap.<String, Object> of("name", "newdrive");
assertEquals(binder.bindToRequest(request, map).getPayload().getRawContent(), expected);
} }
public void testWithSize() throws IOException { public void testWithSize() throws IOException {
assertInputAndArgsCreatesPayload(ImmutableMap.<String, Object>of("name", "newdrive"), String expected = "name newdrive\nsize 1024";
ImmutableList.<Object> of(new CloneDriveOptions().size(1024)), "name newdrive\nsize 1024"); GeneratedHttpRequest request = requestForArgs(ImmutableList.<Object> of(new CloneDriveOptions().size(1024)));
Map<String, Object> map = ImmutableMap.<String, Object> of("name", "newdrive");
assertEquals(binder.bindToRequest(request, map).getPayload().getRawContent(), expected);
} }
protected void assertInputAndArgsCreatesPayload(ImmutableMap<String, Object> inputMap, List<Object> args, protected GeneratedHttpRequest requestForArgs(List<Object> args) {
String expected) { try {
GeneratedHttpRequest request = createMock(GeneratedHttpRequest.class); Invocation invocation = Invocation.create(Invokable.from(String.class.getDeclaredMethod("toString")), args);
expect(request.getArgs()).andReturn(args).atLeastOnce(); return GeneratedHttpRequest.builder().method("POST").endpoint(URI.create("http://localhost/key"))
request.setPayload(expected); .invocation(invocation).build();
Payload payload = createMock(Payload.class); } catch (SecurityException e) {
expect(request.getPayload()).andReturn(payload); throw Throwables.propagate(e);
MutableContentMetadata md = createMock(MutableContentMetadata.class); } catch (NoSuchMethodException e) {
expect(payload.getContentMetadata()).andReturn(md); throw Throwables.propagate(e);
md.setContentType("text/plain"); }
replay(request);
replay(payload);
replay(md);
binder.bindToRequest(request, inputMap);
verify(request);
verify(payload);
verify(md);
} }
} }

View File

@ -187,7 +187,7 @@ public class CreateVolumeResponseHandler extends ParseSax.HandlerForGeneratedReq
} }
public static String findAvailabilityZoneInArgsOrNull(GeneratedHttpRequest gRequest, Set<String> zones) { public static String findAvailabilityZoneInArgsOrNull(GeneratedHttpRequest gRequest, Set<String> zones) {
for (Object arg : gRequest.getArgs()) { for (Object arg : gRequest.getInvocation().getArgs()) {
if (arg instanceof String) { if (arg instanceof String) {
String zone = (String) arg; String zone = (String) arg;
if (zones.contains(zone)) if (zones.contains(zone))

View File

@ -18,9 +18,6 @@
*/ */
package org.jclouds.ec2.xml; package org.jclouds.ec2.xml;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import java.io.InputStream; import java.io.InputStream;
@ -28,11 +25,8 @@ import java.io.InputStream;
import org.jclouds.date.DateService; import org.jclouds.date.DateService;
import org.jclouds.ec2.domain.Attachment; import org.jclouds.ec2.domain.Attachment;
import org.jclouds.http.functions.ParseSax; import org.jclouds.http.functions.ParseSax;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
/** /**
* Tests behavior of {@code AttachmentHandler} * Tests behavior of {@code AttachmentHandler}
* *
@ -56,9 +50,6 @@ public class AttachmentHandlerTest extends BaseEC2HandlerTest {
} }
private void addDefaultRegionToHandler(ParseSax.HandlerWithResult<?> handler) { private void addDefaultRegionToHandler(ParseSax.HandlerWithResult<?> handler) {
GeneratedHttpRequest request = createMock(GeneratedHttpRequest.class);
expect(request.getArgs()).andReturn(ImmutableList.<Object> of());
replay(request);
handler.setContext(request); handler.setContext(request);
} }
} }

View File

@ -18,9 +18,6 @@
*/ */
package org.jclouds.ec2.xml; package org.jclouds.ec2.xml;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import java.io.InputStream; import java.io.InputStream;
@ -28,11 +25,8 @@ import java.io.InputStream;
import org.jclouds.date.DateService; import org.jclouds.date.DateService;
import org.jclouds.ec2.domain.BundleTask; import org.jclouds.ec2.domain.BundleTask;
import org.jclouds.http.functions.ParseSax; import org.jclouds.http.functions.ParseSax;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
/** /**
* Tests behavior of {@code BundleTaskHandler} * Tests behavior of {@code BundleTaskHandler}
* *
@ -71,9 +65,6 @@ public class BundleTaskHandlerTest extends BaseEC2HandlerTest {
} }
private void addDefaultRegionToHandler(ParseSax.HandlerWithResult<?> handler) { private void addDefaultRegionToHandler(ParseSax.HandlerWithResult<?> handler) {
GeneratedHttpRequest request = createMock(GeneratedHttpRequest.class);
expect(request.getArgs()).andReturn(ImmutableList.<Object>of());
replay(request);
handler.setContext(request); handler.setContext(request);
} }
} }

View File

@ -18,9 +18,6 @@
*/ */
package org.jclouds.ec2.xml; package org.jclouds.ec2.xml;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import java.io.InputStream; import java.io.InputStream;
@ -30,10 +27,8 @@ import org.jclouds.date.DateService;
import org.jclouds.ec2.domain.Attachment; import org.jclouds.ec2.domain.Attachment;
import org.jclouds.ec2.domain.Volume; import org.jclouds.ec2.domain.Volume;
import org.jclouds.http.functions.ParseSax; import org.jclouds.http.functions.ParseSax;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
/** /**
@ -62,9 +57,6 @@ public class CreateVolumeResponseHandlerTest extends BaseEC2HandlerTest {
} }
private void addDefaultRegionToHandler(ParseSax.HandlerWithResult<?> handler) { private void addDefaultRegionToHandler(ParseSax.HandlerWithResult<?> handler) {
GeneratedHttpRequest request = createMock(GeneratedHttpRequest.class);
expect(request.getArgs()).andReturn(ImmutableList.<Object>of()).atLeastOnce();
replay(request);
handler.setContext(request); handler.setContext(request);
} }
} }

View File

@ -18,9 +18,6 @@
*/ */
package org.jclouds.ec2.xml; package org.jclouds.ec2.xml;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import java.io.InputStream; import java.io.InputStream;
@ -29,7 +26,6 @@ import java.util.Set;
import org.jclouds.ec2.domain.PublicIpInstanceIdPair; import org.jclouds.ec2.domain.PublicIpInstanceIdPair;
import org.jclouds.http.functions.ParseSax; import org.jclouds.http.functions.ParseSax;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
@ -58,9 +54,6 @@ public class DescribeAddressesResponseHandlerTest extends BaseEC2HandlerTest {
} }
private void addDefaultRegionToHandler(ParseSax.HandlerWithResult<?> handler) { private void addDefaultRegionToHandler(ParseSax.HandlerWithResult<?> handler) {
GeneratedHttpRequest request = createMock(GeneratedHttpRequest.class);
expect(request.getArgs()).andReturn(ImmutableList.<Object>of()).atLeastOnce();
replay(request);
handler.setContext(request); handler.setContext(request);
} }
} }

View File

@ -18,9 +18,6 @@
*/ */
package org.jclouds.ec2.xml; package org.jclouds.ec2.xml;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import java.io.InputStream; import java.io.InputStream;
@ -28,10 +25,8 @@ import java.io.InputStream;
import org.jclouds.date.DateService; import org.jclouds.date.DateService;
import org.jclouds.ec2.domain.BundleTask; import org.jclouds.ec2.domain.BundleTask;
import org.jclouds.http.functions.ParseSax; import org.jclouds.http.functions.ParseSax;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
/** /**
@ -58,9 +53,6 @@ public class DescribeBundleTasksResponseHandlerTest extends BaseEC2HandlerTest {
} }
private void addDefaultRegionToHandler(ParseSax.HandlerWithResult<?> handler) { private void addDefaultRegionToHandler(ParseSax.HandlerWithResult<?> handler) {
GeneratedHttpRequest request = createMock(GeneratedHttpRequest.class);
expect(request.getArgs()).andReturn(ImmutableList.<Object>of());
replay(request);
handler.setContext(request); handler.setContext(request);
} }
} }

View File

@ -17,10 +17,6 @@
* under the License. * under the License.
*/ */
package org.jclouds.ec2.xml; package org.jclouds.ec2.xml;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import java.io.InputStream; import java.io.InputStream;
@ -28,10 +24,8 @@ import java.util.Set;
import org.jclouds.ec2.domain.KeyPair; import org.jclouds.ec2.domain.KeyPair;
import org.jclouds.http.functions.ParseSax; import org.jclouds.http.functions.ParseSax;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
/** /**
@ -56,9 +50,6 @@ public class DescribeKeyPairsResponseHandlerTest extends BaseEC2HandlerTest {
} }
private void addDefaultRegionToHandler(ParseSax.HandlerWithResult<?> handler) { private void addDefaultRegionToHandler(ParseSax.HandlerWithResult<?> handler) {
GeneratedHttpRequest request = createMock(GeneratedHttpRequest.class);
expect(request.getArgs()).andReturn(ImmutableList.<Object> of());
replay(request);
handler.setContext(request); handler.setContext(request);
} }
} }

View File

@ -18,9 +18,6 @@
*/ */
package org.jclouds.ec2.xml; package org.jclouds.ec2.xml;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import java.io.InputStream; import java.io.InputStream;
@ -30,10 +27,8 @@ import org.jclouds.ec2.domain.IpPermission;
import org.jclouds.ec2.domain.IpProtocol; import org.jclouds.ec2.domain.IpProtocol;
import org.jclouds.ec2.domain.SecurityGroup; import org.jclouds.ec2.domain.SecurityGroup;
import org.jclouds.http.functions.ParseSax; import org.jclouds.http.functions.ParseSax;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.collect.LinkedHashMultimap; import com.google.common.collect.LinkedHashMultimap;
@ -91,9 +86,6 @@ public class DescribeSecurityGroupsResponseHandlerTest extends BaseEC2HandlerTes
} }
private void addDefaultRegionToHandler(ParseSax.HandlerWithResult<?> handler) { private void addDefaultRegionToHandler(ParseSax.HandlerWithResult<?> handler) {
GeneratedHttpRequest request = createMock(GeneratedHttpRequest.class);
expect(request.getArgs()).andReturn(ImmutableList.<Object> of()).atLeastOnce();
replay(request);
handler.setContext(request); handler.setContext(request);
} }
} }

View File

@ -18,9 +18,6 @@
*/ */
package org.jclouds.ec2.xml; package org.jclouds.ec2.xml;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import java.io.InputStream; import java.io.InputStream;
@ -29,10 +26,8 @@ import java.util.Set;
import org.jclouds.date.DateService; import org.jclouds.date.DateService;
import org.jclouds.ec2.domain.Snapshot; import org.jclouds.ec2.domain.Snapshot;
import org.jclouds.http.functions.ParseSax; import org.jclouds.http.functions.ParseSax;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
/** /**
@ -61,9 +56,6 @@ public class DescribeSnapshotsResponseHandlerTest extends BaseEC2HandlerTest {
} }
private void addDefaultRegionToHandler(ParseSax.HandlerWithResult<?> handler) { private void addDefaultRegionToHandler(ParseSax.HandlerWithResult<?> handler) {
GeneratedHttpRequest request = createMock(GeneratedHttpRequest.class);
expect(request.getArgs()).andReturn(ImmutableList.<Object>of());
replay(request);
handler.setContext(request); handler.setContext(request);
} }
} }

View File

@ -18,9 +18,6 @@
*/ */
package org.jclouds.ec2.xml; package org.jclouds.ec2.xml;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import java.io.InputStream; import java.io.InputStream;
@ -30,10 +27,8 @@ import org.jclouds.date.DateService;
import org.jclouds.ec2.domain.Attachment; import org.jclouds.ec2.domain.Attachment;
import org.jclouds.ec2.domain.Volume; import org.jclouds.ec2.domain.Volume;
import org.jclouds.http.functions.ParseSax; import org.jclouds.http.functions.ParseSax;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
/** /**
@ -69,9 +64,6 @@ public class DescribeVolumesResponseHandlerTest extends BaseEC2HandlerTest {
} }
private void addDefaultRegionToHandler(ParseSax.HandlerWithResult<?> handler) { private void addDefaultRegionToHandler(ParseSax.HandlerWithResult<?> handler) {
GeneratedHttpRequest request = createMock(GeneratedHttpRequest.class);
expect(request.getArgs()).andReturn(ImmutableList.<Object>of()).atLeastOnce();
replay(request);
handler.setContext(request); handler.setContext(request);
} }
} }

View File

@ -18,9 +18,6 @@
*/ */
package org.jclouds.ec2.xml; package org.jclouds.ec2.xml;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import java.io.InputStream; import java.io.InputStream;
@ -30,11 +27,9 @@ import org.jclouds.date.DateService;
import org.jclouds.ec2.domain.InstanceState; import org.jclouds.ec2.domain.InstanceState;
import org.jclouds.ec2.domain.InstanceStateChange; import org.jclouds.ec2.domain.InstanceStateChange;
import org.jclouds.http.functions.ParseSax; import org.jclouds.http.functions.ParseSax;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.testng.annotations.BeforeTest; import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
/** /**
@ -95,9 +90,6 @@ public class InstanceStateChangeHandlerTest extends BaseEC2HandlerTest {
} }
private void addDefaultRegionToHandler(ParseSax.HandlerWithResult<?> handler) { private void addDefaultRegionToHandler(ParseSax.HandlerWithResult<?> handler) {
GeneratedHttpRequest request = createMock(GeneratedHttpRequest.class);
expect(request.getArgs()).andReturn(ImmutableList.<Object>of()).atLeastOnce();
replay(request);
handler.setContext(request); handler.setContext(request);
} }
} }

View File

@ -17,10 +17,6 @@
* under the License. * under the License.
*/ */
package org.jclouds.ec2.xml; package org.jclouds.ec2.xml;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import java.io.IOException; import java.io.IOException;
@ -29,11 +25,8 @@ import java.io.InputStream;
import org.jclouds.crypto.SshKeys; import org.jclouds.crypto.SshKeys;
import org.jclouds.ec2.domain.KeyPair; import org.jclouds.ec2.domain.KeyPair;
import org.jclouds.http.functions.ParseSax; import org.jclouds.http.functions.ParseSax;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
/** /**
* Tests behavior of {@code KeyPairResponseHandler} * Tests behavior of {@code KeyPairResponseHandler}
* *
@ -84,9 +77,6 @@ public class KeyPairResponseHandlerTest extends BaseEC2HandlerTest {
} }
private void addDefaultRegionToHandler(ParseSax.HandlerWithResult<?> handler) { private void addDefaultRegionToHandler(ParseSax.HandlerWithResult<?> handler) {
GeneratedHttpRequest request = createMock(GeneratedHttpRequest.class);
expect(request.getArgs()).andReturn(ImmutableList.<Object> of()).atLeastOnce();
replay(request);
handler.setContext(request); handler.setContext(request);
} }
} }

View File

@ -18,9 +18,6 @@
*/ */
package org.jclouds.ec2.xml; package org.jclouds.ec2.xml;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import java.io.InputStream; import java.io.InputStream;
@ -32,11 +29,9 @@ import org.jclouds.ec2.domain.Reservation;
import org.jclouds.ec2.domain.RootDeviceType; import org.jclouds.ec2.domain.RootDeviceType;
import org.jclouds.ec2.domain.RunningInstance; import org.jclouds.ec2.domain.RunningInstance;
import org.jclouds.http.functions.ParseSax; import org.jclouds.http.functions.ParseSax;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.testng.annotations.BeforeTest; import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
/** /**
@ -112,9 +107,6 @@ public class RunInstancesResponseHandlerTest extends BaseEC2HandlerTest {
} }
private void addDefaultRegionToHandler(ParseSax.HandlerWithResult<?> handler) { private void addDefaultRegionToHandler(ParseSax.HandlerWithResult<?> handler) {
GeneratedHttpRequest request = createMock(GeneratedHttpRequest.class);
expect(request.getArgs()).andReturn(ImmutableList.<Object> of()).atLeastOnce();
replay(request);
handler.setContext(request); handler.setContext(request);
} }
} }

View File

@ -18,9 +18,6 @@
*/ */
package org.jclouds.ec2.xml; package org.jclouds.ec2.xml;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import java.io.InputStream; import java.io.InputStream;
@ -28,11 +25,8 @@ import java.io.InputStream;
import org.jclouds.date.DateService; import org.jclouds.date.DateService;
import org.jclouds.ec2.domain.Snapshot; import org.jclouds.ec2.domain.Snapshot;
import org.jclouds.http.functions.ParseSax; import org.jclouds.http.functions.ParseSax;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
/** /**
* Tests behavior of {@code SnapshotHandler} * Tests behavior of {@code SnapshotHandler}
* *
@ -56,9 +50,6 @@ public class SnapshotHandlerTest extends BaseEC2HandlerTest {
} }
private void addDefaultRegionToHandler(ParseSax.HandlerWithResult<?> handler) { private void addDefaultRegionToHandler(ParseSax.HandlerWithResult<?> handler) {
GeneratedHttpRequest request = createMock(GeneratedHttpRequest.class);
expect(request.getArgs()).andReturn(ImmutableList.<Object>of()).atLeastOnce();
replay(request);
handler.setContext(request); handler.setContext(request);
} }
} }

View File

@ -20,7 +20,6 @@ package org.jclouds.openstack.keystone.v2_0.binders;
import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import java.util.Map; import java.util.Map;
@ -37,8 +36,8 @@ import org.jclouds.rest.internal.GeneratedHttpRequest;
import com.google.common.base.Predicates; import com.google.common.base.Predicates;
import com.google.common.base.Strings; import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
import com.google.common.collect.ImmutableMap.Builder; import com.google.common.collect.ImmutableMap.Builder;
import com.google.common.collect.Iterables;
/** /**
* *
@ -58,7 +57,7 @@ public class BindAuthToJsonPayload extends BindToJsonPayload implements MapBinde
} }
protected void addCredentialsInArgsOrNull(GeneratedHttpRequest gRequest, Builder<String, Object> builder) { protected void addCredentialsInArgsOrNull(GeneratedHttpRequest gRequest, Builder<String, Object> builder) {
for (Object arg : Iterables.filter(gRequest.getArgs(), Predicates.notNull())) { for (Object arg : Iterables.filter(gRequest.getInvocation().getArgs(), Predicates.notNull())) {
if (arg.getClass().isAnnotationPresent(CredentialType.class)) { if (arg.getClass().isAnnotationPresent(CredentialType.class)) {
builder.put(arg.getClass().getAnnotation(CredentialType.class).value(), arg); builder.put(arg.getClass().getAnnotation(CredentialType.class).value(), arg);
} }
@ -70,7 +69,6 @@ public class BindAuthToJsonPayload extends BindToJsonPayload implements MapBinde
checkArgument(checkNotNull(request, "request") instanceof GeneratedHttpRequest, checkArgument(checkNotNull(request, "request") instanceof GeneratedHttpRequest,
"this binder is only valid for GeneratedHttpRequests!"); "this binder is only valid for GeneratedHttpRequests!");
GeneratedHttpRequest gRequest = (GeneratedHttpRequest) request; GeneratedHttpRequest gRequest = (GeneratedHttpRequest) request;
checkState(gRequest.getArgs() != null, "args should be initialized at this point");
Builder<String, Object> builder = ImmutableMap.builder(); Builder<String, Object> builder = ImmutableMap.builder();
addCredentialsInArgsOrNull(gRequest, builder); addCredentialsInArgsOrNull(gRequest, builder);

View File

@ -19,26 +19,28 @@
package org.jclouds.openstack.v2_0.functions; package org.jclouds.openstack.v2_0.functions;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.Iterables.any;
import static org.jclouds.openstack.v2_0.predicates.ExtensionPredicates.namespaceOrAliasEquals;
import static org.jclouds.util.Optionals2.unwrapIfOptional;
import java.net.URI; import java.net.URI;
import java.util.List;
import java.util.Set; import java.util.Set;
import javax.inject.Inject; import javax.inject.Inject;
import org.jclouds.internal.ClassInvokerArgsAndReturnVal;
import org.jclouds.openstack.v2_0.domain.Extension; import org.jclouds.openstack.v2_0.domain.Extension;
import org.jclouds.openstack.v2_0.predicates.ExtensionPredicates; import org.jclouds.reflect.InvocationSuccess;
import org.jclouds.rest.functions.ImplicitOptionalConverter; import org.jclouds.rest.functions.ImplicitOptionalConverter;
import com.google.common.base.Optional; import com.google.common.base.Optional;
import com.google.common.cache.LoadingCache; import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Multimap; import com.google.common.collect.Multimap;
/** /**
* We use the annotation {@link org.jclouds.openstack.services.Extension} to * We use the annotation {@link org.jclouds.openstack.services.Extension} to bind a class that implements an extension
* bind a class that implements an extension API to an {@link Extension}. * API to an {@link Extension}.
* *
* @author Adrian Cole * @author Adrian Cole
* *
@ -50,33 +52,33 @@ public class PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensio
@Inject @Inject
public PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSet( public PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSet(
LoadingCache<String, Set<? extends Extension>> extensions, LoadingCache<String, Set<? extends Extension>> extensions, Multimap<URI, URI> aliases) {
Multimap<URI, URI> aliases) {
this.extensions = checkNotNull(extensions, "extensions"); this.extensions = checkNotNull(extensions, "extensions");
this.aliases = aliases == null ? ImmutableMultimap.<URI, URI> of() : ImmutableMultimap.copyOf(aliases); this.aliases = aliases == null ? ImmutableMultimap.<URI, URI> of() : ImmutableMultimap.copyOf(aliases);
} }
@Override @Override
public Optional<Object> apply(ClassInvokerArgsAndReturnVal input) { public Optional<Object> apply(InvocationSuccess input) {
Optional<org.jclouds.openstack.v2_0.services.Extension> ext = Optional.fromNullable(input.getClazz().getAnnotation( Class<?> target = unwrapIfOptional(input.getInvocation().getInvokable().getReturnType());
org.jclouds.openstack.v2_0.services.Extension.class)); Optional<org.jclouds.openstack.v2_0.services.Extension> ext = Optional.fromNullable(target
.getAnnotation(org.jclouds.openstack.v2_0.services.Extension.class));
if (ext.isPresent()) { if (ext.isPresent()) {
URI namespace = URI.create(ext.get().namespace()); URI namespace = URI.create(ext.get().namespace());
if (input.getArgs().isEmpty()) { List<Object> args = input.getInvocation().getArgs();
if (Iterables.any(extensions.getUnchecked(""), if (args.isEmpty()) {
ExtensionPredicates.namespaceOrAliasEquals(namespace, aliases.get(namespace)))) if (any(extensions.getUnchecked(""), namespaceOrAliasEquals(namespace, aliases.get(namespace))))
return Optional.of(input.getReturnVal()); return input.getResult();
} else if (input.getArgs().size() == 1) { } else if (args.size() == 1) {
if (Iterables.any(extensions.getUnchecked(checkNotNull(input.getArgs().get(0), "arg[0] in %s", input).toString()), String arg0 = checkNotNull(args.get(0), "arg[0] in %s", input).toString();
ExtensionPredicates.namespaceOrAliasEquals(namespace, aliases.get(namespace)))) if (any(extensions.getUnchecked(arg0), namespaceOrAliasEquals(namespace, aliases.get(namespace))))
return Optional.of(input.getReturnVal()); return input.getResult();
} else { } else {
throw new RuntimeException(String.format("expecting zero or one args %s", input)); throw new RuntimeException(String.format("expecting zero or one args %s", input));
} }
return Optional.absent(); return Optional.absent();
} else { } else {
// No extension annotation, should check whether to return absent // No extension annotation, should check whether to return absent
return Optional.of(input.getReturnVal()); return input.getResult();
} }
} }

View File

@ -3,12 +3,14 @@ package org.jclouds.openstack.v2_0.functions;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import java.net.URI; import java.net.URI;
import java.util.List;
import java.util.Set; import java.util.Set;
import org.jclouds.date.internal.SimpleDateFormatDateService; import org.jclouds.date.internal.SimpleDateFormatDateService;
import org.jclouds.internal.ClassInvokerArgsAndReturnVal;
import org.jclouds.openstack.v2_0.ServiceType; import org.jclouds.openstack.v2_0.ServiceType;
import org.jclouds.openstack.v2_0.domain.Extension; import org.jclouds.openstack.v2_0.domain.Extension;
import org.jclouds.reflect.Invocation;
import org.jclouds.reflect.InvocationSuccess;
import org.jclouds.rest.annotations.Delegate; import org.jclouds.rest.annotations.Delegate;
import org.testng.annotations.Test; import org.testng.annotations.Test;
@ -63,34 +65,31 @@ public class PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensio
} }
ClassInvokerArgsAndReturnVal getFloatingIPExtension() throws SecurityException, NoSuchMethodException { InvocationSuccess getFloatingIPExtension(List<Object> args) throws SecurityException, NoSuchMethodException {
return ClassInvokerArgsAndReturnVal return InvocationSuccess.create(Invocation.create(
.builder() Invokable.from(NovaAsyncApi.class.getDeclaredMethod("getFloatingIPExtensionForZone", String.class)),
.clazz(FloatingIPAsyncApi.class) args), "foo");
.invoker(
Invokable.from(NovaAsyncApi.class.getDeclaredMethod("getFloatingIPExtensionForZone", String.class)))
.args(ImmutableList.<Object> of("zone")).returnVal("foo").build();
} }
ClassInvokerArgsAndReturnVal getKeyPairExtension() throws SecurityException, NoSuchMethodException { InvocationSuccess getKeyPairExtension(List<Object> args) throws SecurityException, NoSuchMethodException {
return ClassInvokerArgsAndReturnVal.builder().clazz(KeyPairAsyncApi.class) return InvocationSuccess.create(Invocation.create(
.invoker(Invokable.from(NovaAsyncApi.class.getDeclaredMethod("getKeyPairExtensionForZone", String.class))) Invokable.from(NovaAsyncApi.class.getDeclaredMethod("getKeyPairExtensionForZone", String.class)),
.args(ImmutableList.<Object> of("zone")).returnVal("foo").build(); args), "foo");
} }
public void testPresentWhenExtensionsIncludeNamespaceFromAnnotationAbsentWhenNot() throws SecurityException, NoSuchMethodException { public void testPresentWhenExtensionsIncludeNamespaceFromAnnotationAbsentWhenNot() throws SecurityException, NoSuchMethodException {
assertEquals(whenExtensionsInZoneInclude("zone", keypairs, floatingIps).apply(getFloatingIPExtension()), Optional.of("foo")); assertEquals(whenExtensionsInZoneInclude("zone", keypairs, floatingIps).apply(getFloatingIPExtension(ImmutableList.<Object> of("zone"))), Optional.of("foo"));
assertEquals(whenExtensionsInZoneInclude("zone", keypairs, floatingIps).apply(getKeyPairExtension()), Optional.of("foo")); assertEquals(whenExtensionsInZoneInclude("zone", keypairs, floatingIps).apply(getKeyPairExtension(ImmutableList.<Object> of("zone"))), Optional.of("foo"));
assertEquals(whenExtensionsInZoneInclude("zone", keypairs).apply(getFloatingIPExtension()), Optional.absent()); assertEquals(whenExtensionsInZoneInclude("zone", keypairs).apply(getFloatingIPExtension(ImmutableList.<Object> of("zone"))), Optional.absent());
assertEquals(whenExtensionsInZoneInclude("zone", floatingIps).apply(getKeyPairExtension()), Optional.absent()); assertEquals(whenExtensionsInZoneInclude("zone", floatingIps).apply(getKeyPairExtension(ImmutableList.<Object> of("zone"))), Optional.absent());
} }
public void testZoneWithoutExtensionsReturnsAbsent() throws SecurityException, NoSuchMethodException { public void testZoneWithoutExtensionsReturnsAbsent() throws SecurityException, NoSuchMethodException {
assertEquals(whenExtensionsInZoneInclude("zone", floatingIps).apply( assertEquals(whenExtensionsInZoneInclude("zone", floatingIps).apply(
getFloatingIPExtension().toBuilder().args(ImmutableList.<Object> of("differentzone")).build()), Optional.absent()); getFloatingIPExtension(ImmutableList.<Object> of("differentzone"))), Optional.absent());
assertEquals(whenExtensionsInZoneInclude("zone", keypairs).apply( assertEquals(whenExtensionsInZoneInclude("zone", keypairs).apply(
getKeyPairExtension().toBuilder().args(ImmutableList.<Object> of("differentzone")).build()), Optional.absent()); getKeyPairExtension(ImmutableList.<Object> of("differentzone"))), Optional.absent());
} }
/** /**
@ -107,9 +106,9 @@ public class PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensio
.getNamespace()); .getNamespace());
assertEquals(whenExtensionsAndAliasesInZoneInclude("zone", ImmutableSet.of(keypairsWithDifferentNamespace), aliases).apply( assertEquals(whenExtensionsAndAliasesInZoneInclude("zone", ImmutableSet.of(keypairsWithDifferentNamespace), aliases).apply(
getKeyPairExtension()), Optional.of("foo")); getKeyPairExtension(ImmutableList.<Object> of("zone"))), Optional.of("foo"));
assertEquals(whenExtensionsAndAliasesInZoneInclude("zone", ImmutableSet.of(keypairsWithDifferentNamespace), aliases).apply( assertEquals(whenExtensionsAndAliasesInZoneInclude("zone", ImmutableSet.of(keypairsWithDifferentNamespace), aliases).apply(
getFloatingIPExtension()), Optional.absent()); getFloatingIPExtension(ImmutableList.<Object> of("zone"))), Optional.absent());
} }

View File

@ -20,6 +20,8 @@ package org.jclouds.openstack.nova.v2_0.binders;
import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Predicates.instanceOf;
import static com.google.common.collect.Iterables.find;
import java.util.Map; import java.util.Map;
@ -33,9 +35,7 @@ import org.jclouds.rest.MapBinder;
import org.jclouds.rest.binders.BindToJsonPayload; import org.jclouds.rest.binders.BindToJsonPayload;
import org.jclouds.rest.internal.GeneratedHttpRequest; import org.jclouds.rest.internal.GeneratedHttpRequest;
import com.google.common.base.Predicates;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
import com.google.common.collect.ImmutableMap.Builder; import com.google.common.collect.ImmutableMap.Builder;
/** /**
@ -63,7 +63,7 @@ public class BindSecurityGroupRuleToJsonPayload extends BindToJsonPayload implem
"this binder is only valid for GeneratedHttpRequests!"); "this binder is only valid for GeneratedHttpRequests!");
GeneratedHttpRequest gRequest = (GeneratedHttpRequest) request; GeneratedHttpRequest gRequest = (GeneratedHttpRequest) request;
Ingress ingress = Ingress.class.cast(Iterables.find(gRequest.getArgs(), Predicates.instanceOf(Ingress.class))); Ingress ingress = Ingress.class.cast(find(gRequest.getInvocation().getArgs(), instanceOf(Ingress.class)));
payload.put("ip_protocol", ingress.getIpProtocol().toString()); payload.put("ip_protocol", ingress.getIpProtocol().toString());
payload.put("from_port", ingress.getFromPort() + ""); payload.put("from_port", ingress.getFromPort() + "");
payload.put("to_port", ingress.getToPort() + ""); payload.put("to_port", ingress.getToPort() + "");

View File

@ -29,6 +29,7 @@ import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.functions.BlobToHttpGetOptions; import org.jclouds.blobstore.functions.BlobToHttpGetOptions;
import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpRequest;
import org.jclouds.http.options.GetOptions; import org.jclouds.http.options.GetOptions;
import org.jclouds.reflect.Invocation;
import org.jclouds.rest.internal.RestAnnotationProcessor; import org.jclouds.rest.internal.RestAnnotationProcessor;
import org.jclouds.s3.S3AsyncClient; import org.jclouds.s3.S3AsyncClient;
import org.jclouds.s3.blobstore.functions.BlobToObject; import org.jclouds.s3.blobstore.functions.BlobToObject;
@ -37,13 +38,14 @@ import org.jclouds.s3.options.PutObjectOptions;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.reflect.Invokable; import com.google.common.reflect.Invokable;
import com.google.common.reflect.TypeToken;
/** /**
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
@Singleton @Singleton
public class S3BlobRequestSigner implements BlobRequestSigner { public class S3BlobRequestSigner<T extends S3AsyncClient> implements BlobRequestSigner {
private final RestAnnotationProcessor processor; private final RestAnnotationProcessor processor;
private final BlobToObject blobToObject; private final BlobToObject blobToObject;
private final BlobToHttpGetOptions blob2HttpGetOptions; private final BlobToHttpGetOptions blob2HttpGetOptions;
@ -51,26 +53,30 @@ public class S3BlobRequestSigner implements BlobRequestSigner {
private final Invokable<?, ?> getMethod; private final Invokable<?, ?> getMethod;
private final Invokable<?, ?> deleteMethod; private final Invokable<?, ?> deleteMethod;
private final Invokable<?, ?> createMethod; private final Invokable<?, ?> createMethod;
private final Class<T> interfaceType;
@Inject @Inject
public S3BlobRequestSigner(RestAnnotationProcessor.Factory processor, BlobToObject blobToObject, public S3BlobRequestSigner(RestAnnotationProcessor processor, BlobToObject blobToObject,
BlobToHttpGetOptions blob2HttpGetOptions) throws SecurityException, NoSuchMethodException { BlobToHttpGetOptions blob2HttpGetOptions, Class<T> interfaceType) throws SecurityException,
this.processor = checkNotNull(processor, "processor").declaring(S3AsyncClient.class); NoSuchMethodException {
this.processor = checkNotNull(processor, "processor");
this.interfaceType = checkNotNull(interfaceType, "interfaceType");
this.blobToObject = checkNotNull(blobToObject, "blobToObject"); this.blobToObject = checkNotNull(blobToObject, "blobToObject");
this.blob2HttpGetOptions = checkNotNull(blob2HttpGetOptions, "blob2HttpGetOptions"); this.blob2HttpGetOptions = checkNotNull(blob2HttpGetOptions, "blob2HttpGetOptions");
this.getMethod = Invokable.from(S3AsyncClient.class.getMethod("getObject", String.class, String.class, this.getMethod = TypeToken.of(interfaceType).method(
GetOptions[].class)); interfaceType.getMethod("getObject", String.class, String.class, GetOptions[].class));
this.deleteMethod = Invokable.from(S3AsyncClient.class.getMethod("deleteObject", String.class, String.class)); this.deleteMethod = TypeToken.of(interfaceType).method(
this.createMethod = Invokable.from(S3AsyncClient.class.getMethod("putObject", String.class, S3Object.class, interfaceType.getMethod("deleteObject", String.class, String.class));
PutObjectOptions[].class)); this.createMethod = TypeToken.of(interfaceType).method(
interfaceType.getMethod("putObject", String.class, S3Object.class, PutObjectOptions[].class));
} }
@Override @Override
public HttpRequest signGetBlob(String container, String name) { public HttpRequest signGetBlob(String container, String name) {
checkNotNull(container, "container"); checkNotNull(container, "container");
checkNotNull(name, "name"); checkNotNull(name, "name");
return cleanRequest(processor.createRequest(getMethod, ImmutableList.<Object> of(container, name))); return cleanRequest(processor.apply(Invocation.create(interfaceType, getMethod,
ImmutableList.<Object> of(container, name))));
} }
@Override @Override
@ -82,8 +88,8 @@ public class S3BlobRequestSigner implements BlobRequestSigner {
public HttpRequest signPutBlob(String container, Blob blob) { public HttpRequest signPutBlob(String container, Blob blob) {
checkNotNull(container, "container"); checkNotNull(container, "container");
checkNotNull(blob, "blob"); checkNotNull(blob, "blob");
return cleanRequest(processor.createRequest(createMethod, return cleanRequest(processor.apply(Invocation.create(interfaceType, createMethod,
ImmutableList.<Object> of(container, blobToObject.apply(blob)))); ImmutableList.<Object> of(container, blobToObject.apply(blob)))));
} }
@Override @Override
@ -95,14 +101,15 @@ public class S3BlobRequestSigner implements BlobRequestSigner {
public HttpRequest signRemoveBlob(String container, String name) { public HttpRequest signRemoveBlob(String container, String name) {
checkNotNull(container, "container"); checkNotNull(container, "container");
checkNotNull(name, "name"); checkNotNull(name, "name");
return cleanRequest(processor.createRequest(deleteMethod, ImmutableList.<Object> of(container, name))); return cleanRequest(processor.apply(Invocation.create(interfaceType, deleteMethod,
ImmutableList.<Object> of(container, name))));
} }
@Override @Override
public HttpRequest signGetBlob(String container, String name, org.jclouds.blobstore.options.GetOptions options) { public HttpRequest signGetBlob(String container, String name, org.jclouds.blobstore.options.GetOptions options) {
checkNotNull(container, "container"); checkNotNull(container, "container");
checkNotNull(name, "name"); checkNotNull(name, "name");
return cleanRequest(processor.createRequest(getMethod, return cleanRequest(processor.apply(Invocation.create(interfaceType, getMethod,
ImmutableList.of(container, name, blob2HttpGetOptions.apply(checkNotNull(options, "options"))))); ImmutableList.of(container, name, blob2HttpGetOptions.apply(checkNotNull(options, "options"))))));
} }
} }

View File

@ -28,10 +28,12 @@ import org.jclouds.blobstore.BlobStore;
import org.jclouds.blobstore.attr.ConsistencyModel; import org.jclouds.blobstore.attr.ConsistencyModel;
import org.jclouds.blobstore.config.BlobStoreMapModule; import org.jclouds.blobstore.config.BlobStoreMapModule;
import org.jclouds.domain.Location; import org.jclouds.domain.Location;
import org.jclouds.s3.S3AsyncClient;
import org.jclouds.s3.S3Client; import org.jclouds.s3.S3Client;
import org.jclouds.s3.blobstore.S3AsyncBlobStore; import org.jclouds.s3.blobstore.S3AsyncBlobStore;
import org.jclouds.s3.blobstore.S3BlobRequestSigner; import org.jclouds.s3.blobstore.S3BlobRequestSigner;
import org.jclouds.s3.blobstore.S3BlobStore; import org.jclouds.s3.blobstore.S3BlobStore;
import org.jclouds.s3.blobstore.S3BlobStoreContext;
import org.jclouds.s3.blobstore.functions.LocationFromBucketName; import org.jclouds.s3.blobstore.functions.LocationFromBucketName;
import org.jclouds.s3.domain.AccessControlList; import org.jclouds.s3.domain.AccessControlList;
@ -57,9 +59,14 @@ public class S3BlobStoreContextModule extends AbstractModule {
bind(ConsistencyModel.class).toInstance(ConsistencyModel.EVENTUAL); bind(ConsistencyModel.class).toInstance(ConsistencyModel.EVENTUAL);
bind(AsyncBlobStore.class).to(S3AsyncBlobStore.class).in(Scopes.SINGLETON); bind(AsyncBlobStore.class).to(S3AsyncBlobStore.class).in(Scopes.SINGLETON);
bind(BlobStore.class).to(S3BlobStore.class).in(Scopes.SINGLETON); bind(BlobStore.class).to(S3BlobStore.class).in(Scopes.SINGLETON);
bind(BlobRequestSigner.class).to(S3BlobRequestSigner.class);
bind(new TypeLiteral<Function<String, Location>>() { bind(new TypeLiteral<Function<String, Location>>() {
}).to(LocationFromBucketName.class); }).to(LocationFromBucketName.class);
bindRequestSigner();
}
protected void bindRequestSigner() {
bind(BlobRequestSigner.class).to(new TypeLiteral<S3BlobRequestSigner<S3AsyncClient>>() {
});
} }
@Provides @Provides

View File

@ -59,7 +59,7 @@ public class BlobToObjectMetadata implements Function<BlobMetadata, MutableObjec
@Override @Override
public BlobToObjectMetadata setContext(HttpRequest request) { public BlobToObjectMetadata setContext(HttpRequest request) {
checkArgument(request instanceof GeneratedHttpRequest, "note this handler requires a GeneratedHttpRequest"); checkArgument(request instanceof GeneratedHttpRequest, "note this handler requires a GeneratedHttpRequest");
return setBucket(GeneratedHttpRequest.class.cast(request).getArgs().get(0).toString()); return setBucket(GeneratedHttpRequest.class.cast(request).getInvocation().getArgs().get(0).toString());
} }
private BlobToObjectMetadata setBucket(String bucket) { private BlobToObjectMetadata setBucket(String bucket) {

View File

@ -52,14 +52,13 @@ public class S3Utils {
"bucketName name must start with a number or letter and can only contain lowercase letters, numbers, periods (.), underscores (_), and dashes (-)"); "bucketName name must start with a number or letter and can only contain lowercase letters, numbers, periods (.), underscores (_), and dashes (-)");
checkArgument(bucketName.length() > 2 && bucketName.length() < 256, checkArgument(bucketName.length() > 2 && bucketName.length() < 256,
"bucketName name must be between 3 and 255 characters long"); "bucketName name must be between 3 and 255 characters long");
checkArgument(!IP_PATTERN.matcher(bucketName).matches(), checkArgument(!IP_PATTERN.matcher(bucketName).matches(), "bucketName name cannot be ip address style");
"bucketName name cannot be ip address style");
return bucketName; return bucketName;
} }
/** /**
* This implementation invokes {@link S3Client#deleteBucketIfEmpty} followed by * This implementation invokes {@link S3Client#deleteBucketIfEmpty} followed by {@link S3Client#bucketExists} until
* {@link S3Client#bucketExists} until it is true. * it is true.
*/ */
public static boolean deleteAndVerifyContainerGone(S3Client sync, String container) { public static boolean deleteAndVerifyContainerGone(S3Client sync, String container) {
sync.deleteBucketIfEmpty(container); sync.deleteBucketIfEmpty(container);
@ -78,9 +77,10 @@ public class S3Utils {
String bucketName = null; String bucketName = null;
for (int i = 0; i < request.getInvoker().getParameters().size(); i++) { for (int i = 0; i < request.getInvocation().getInvokable().getParameters().size(); i++) {
if (any(Arrays.asList(request.getInvoker().getParameters().get(i).getAnnotations()), ANNOTATIONTYPE_BUCKET)) { if (any(Arrays.asList(request.getInvocation().getInvokable().getParameters().get(i).getAnnotations()),
bucketName = (String) request.getArgs().get(i); ANNOTATIONTYPE_BUCKET)) {
bucketName = (String) request.getInvocation().getArgs().get(i);
break; break;
} }
} }

View File

@ -64,7 +64,7 @@ public class LocationConstraintHandler extends ParseSax.HandlerWithResult<String
@Override @Override
public LocationConstraintHandler setContext(HttpRequest request) { public LocationConstraintHandler setContext(HttpRequest request) {
super.setContext(request); super.setContext(request);
setBucket(GeneratedHttpRequest.class.cast(getRequest()).getArgs().get(0).toString()); setBucket(GeneratedHttpRequest.class.cast(getRequest()).getInvocation().getArgs().get(0).toString());
return this; return this;
} }

View File

@ -27,12 +27,14 @@ import static org.testng.Assert.assertFalse;
import org.jclouds.aws.AWSResponseException; import org.jclouds.aws.AWSResponseException;
import org.jclouds.aws.domain.AWSError; import org.jclouds.aws.domain.AWSError;
import org.jclouds.reflect.Invocation;
import org.jclouds.rest.internal.GeneratedHttpRequest; import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.jclouds.s3.S3Client; import org.jclouds.s3.S3Client;
import org.jclouds.s3.options.PutBucketOptions; import org.jclouds.s3.options.PutBucketOptions;
import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.collect.Lists;
import com.google.common.reflect.Invokable; import com.google.common.reflect.Invokable;
/** /**
@ -45,14 +47,12 @@ public class FalseIfBucketAlreadyOwnedByYouOrOperationAbortedWhenBucketExistsTes
@BeforeClass @BeforeClass
void setUp() throws SecurityException, NoSuchMethodException { void setUp() throws SecurityException, NoSuchMethodException {
putBucket = GeneratedHttpRequest putBucket = GeneratedHttpRequest.builder()
.builder()
.method("PUT") .method("PUT")
.endpoint("https://adriancole-blobstore113.s3.amazonaws.com/") .endpoint("https://adriancole-blobstore113.s3.amazonaws.com/")
.declaring(S3Client.class) .invocation(
.invoker(Invokable.from( Invocation.create(Invokable.from(S3Client.class.getMethod("putBucketInRegion", String.class,
S3Client.class.getMethod("putBucketInRegion", String.class, String.class, PutBucketOptions[].class))) String.class, PutBucketOptions[].class)), Lists.<Object> newArrayList(null, "bucket"))).build();
.args(new Object[] { null, "bucket" }).build();
} }
@Test @Test

View File

@ -40,7 +40,6 @@ import org.jclouds.blobstore.binders.BindMapToHeadersWithPrefix;
import org.jclouds.blobstore.domain.PageSet; import org.jclouds.blobstore.domain.PageSet;
import org.jclouds.http.functions.ParseETagHeader; import org.jclouds.http.functions.ParseETagHeader;
import org.jclouds.http.options.GetOptions; import org.jclouds.http.options.GetOptions;
import org.jclouds.openstack.filters.AuthenticateRequest;
import org.jclouds.openstack.swift.SwiftFallbacks.TrueOn404FalseOn409; import org.jclouds.openstack.swift.SwiftFallbacks.TrueOn404FalseOn409;
import org.jclouds.openstack.swift.binders.BindIterableToHeadersWithContainerDeleteMetadataPrefix; import org.jclouds.openstack.swift.binders.BindIterableToHeadersWithContainerDeleteMetadataPrefix;
import org.jclouds.openstack.swift.binders.BindMapToHeadersWithContainerMetadataPrefix; import org.jclouds.openstack.swift.binders.BindMapToHeadersWithContainerMetadataPrefix;
@ -60,12 +59,10 @@ import org.jclouds.openstack.swift.options.CreateContainerOptions;
import org.jclouds.openstack.swift.options.ListContainerOptions; import org.jclouds.openstack.swift.options.ListContainerOptions;
import org.jclouds.openstack.swift.reference.SwiftHeaders; import org.jclouds.openstack.swift.reference.SwiftHeaders;
import org.jclouds.rest.annotations.BinderParam; import org.jclouds.rest.annotations.BinderParam;
import org.jclouds.rest.annotations.Endpoint;
import org.jclouds.rest.annotations.Fallback; import org.jclouds.rest.annotations.Fallback;
import org.jclouds.rest.annotations.Headers; import org.jclouds.rest.annotations.Headers;
import org.jclouds.rest.annotations.ParamParser; import org.jclouds.rest.annotations.ParamParser;
import org.jclouds.rest.annotations.QueryParams; import org.jclouds.rest.annotations.QueryParams;
import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.ResponseParser; import org.jclouds.rest.annotations.ResponseParser;
import com.google.common.annotations.Beta; import com.google.common.annotations.Beta;
@ -79,8 +76,6 @@ import com.google.inject.Provides;
* @see <a href="http://www.rackspacecloud.com/cf-devguide-20090812.pdf" /> * @see <a href="http://www.rackspacecloud.com/cf-devguide-20090812.pdf" />
* @author Adrian Cole * @author Adrian Cole
*/ */
@RequestFilters(AuthenticateRequest.class)
@Endpoint(Storage.class)
public interface CommonSwiftAsyncClient { public interface CommonSwiftAsyncClient {
@Provides @Provides
SwiftObject newSwiftObject(); SwiftObject newSwiftObject();

View File

@ -45,6 +45,7 @@ import org.jclouds.openstack.swift.CommonSwiftAsyncClient;
import org.jclouds.openstack.swift.TemporaryUrlKey; import org.jclouds.openstack.swift.TemporaryUrlKey;
import org.jclouds.openstack.swift.blobstore.functions.BlobToObject; import org.jclouds.openstack.swift.blobstore.functions.BlobToObject;
import org.jclouds.openstack.swift.domain.SwiftObject; import org.jclouds.openstack.swift.domain.SwiftObject;
import org.jclouds.reflect.Invocation;
import org.jclouds.rest.internal.RestAnnotationProcessor; import org.jclouds.rest.internal.RestAnnotationProcessor;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
@ -53,6 +54,7 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.io.ByteProcessor; import com.google.common.io.ByteProcessor;
import com.google.common.reflect.Invokable; import com.google.common.reflect.Invokable;
import com.google.common.reflect.TypeToken;
import com.google.inject.Provider; import com.google.inject.Provider;
/** /**
@ -73,6 +75,7 @@ public class SwiftBlobSigner<T extends CommonSwiftAsyncClient> implements BlobRe
private final Invokable<?, ?> getMethod; private final Invokable<?, ?> getMethod;
private final Invokable<?, ?> deleteMethod; private final Invokable<?, ?> deleteMethod;
private final Invokable<?, ?> createMethod; private final Invokable<?, ?> createMethod;
private final Class<T> interfaceType;
/** /**
* create a signer for this subtype of swift * create a signer for this subtype of swift
@ -83,9 +86,10 @@ public class SwiftBlobSigner<T extends CommonSwiftAsyncClient> implements BlobRe
@Inject @Inject
protected SwiftBlobSigner(BlobToObject blobToObject, BlobToHttpGetOptions blob2HttpGetOptions, Crypto crypto, protected SwiftBlobSigner(BlobToObject blobToObject, BlobToHttpGetOptions blob2HttpGetOptions, Crypto crypto,
@TimeStamp Provider<Long> unixEpochTimestampProvider, @TimeStamp Provider<Long> unixEpochTimestampProvider,
@TemporaryUrlKey Supplier<String> temporaryUrlKeySupplier, RestAnnotationProcessor.Factory processor, @TemporaryUrlKey Supplier<String> temporaryUrlKeySupplier, RestAnnotationProcessor processor,
Class<T> clazz) throws SecurityException, NoSuchMethodException { Class<T> interfaceType) throws SecurityException, NoSuchMethodException {
this.processor = checkNotNull(processor, "processor").declaring(clazz); this.processor = checkNotNull(processor, "processor");
this.interfaceType = checkNotNull(interfaceType, "interfaceType");
this.crypto = checkNotNull(crypto, "crypto"); this.crypto = checkNotNull(crypto, "crypto");
this.unixEpochTimestampProvider = checkNotNull(unixEpochTimestampProvider, "unixEpochTimestampProvider"); this.unixEpochTimestampProvider = checkNotNull(unixEpochTimestampProvider, "unixEpochTimestampProvider");
@ -94,23 +98,28 @@ public class SwiftBlobSigner<T extends CommonSwiftAsyncClient> implements BlobRe
this.blobToObject = checkNotNull(blobToObject, "blobToObject"); this.blobToObject = checkNotNull(blobToObject, "blobToObject");
this.blob2HttpGetOptions = checkNotNull(blob2HttpGetOptions, "blob2HttpGetOptions"); this.blob2HttpGetOptions = checkNotNull(blob2HttpGetOptions, "blob2HttpGetOptions");
this.getMethod = Invokable.from(clazz.getMethod("getObject", String.class, String.class, GetOptions[].class)); this.getMethod = TypeToken.of(interfaceType).method(
this.deleteMethod = Invokable.from(clazz.getMethod("removeObject", String.class, String.class)); interfaceType.getMethod("getObject", String.class, String.class, GetOptions[].class));
this.createMethod = Invokable.from(clazz.getMethod("putObject", String.class, SwiftObject.class)); this.deleteMethod = TypeToken.of(interfaceType).method(
interfaceType.getMethod("removeObject", String.class, String.class));
this.createMethod = TypeToken.of(interfaceType).method(
interfaceType.getMethod("putObject", String.class, SwiftObject.class));
} }
@Override @Override
public HttpRequest signGetBlob(String container, String name) { public HttpRequest signGetBlob(String container, String name) {
checkNotNull(container, "container"); checkNotNull(container, "container");
checkNotNull(name, "name"); checkNotNull(name, "name");
return cleanRequest(processor.createRequest(getMethod, ImmutableList.<Object> of(container, name))); return cleanRequest(processor.apply(Invocation.create(interfaceType, getMethod,
ImmutableList.<Object> of(container, name))));
} }
@Override @Override
public HttpRequest signGetBlob(String container, String name, long timeInSeconds) { public HttpRequest signGetBlob(String container, String name, long timeInSeconds) {
checkNotNull(container, "container"); checkNotNull(container, "container");
checkNotNull(name, "name"); checkNotNull(name, "name");
HttpRequest request = processor.createRequest(getMethod, ImmutableList.<Object> of(container, name)); HttpRequest request = processor.apply(Invocation.create(interfaceType, getMethod,
ImmutableList.<Object> of(container, name)));
return cleanRequest(signForTemporaryAccess(request, timeInSeconds)); return cleanRequest(signForTemporaryAccess(request, timeInSeconds));
} }
@ -118,24 +127,24 @@ public class SwiftBlobSigner<T extends CommonSwiftAsyncClient> implements BlobRe
public HttpRequest signGetBlob(String container, String name, org.jclouds.blobstore.options.GetOptions options) { public HttpRequest signGetBlob(String container, String name, org.jclouds.blobstore.options.GetOptions options) {
checkNotNull(container, "container"); checkNotNull(container, "container");
checkNotNull(name, "name"); checkNotNull(name, "name");
return cleanRequest(processor.createRequest(getMethod, return cleanRequest(processor.apply(Invocation.create(interfaceType, getMethod,
ImmutableList.of(container, name, blob2HttpGetOptions.apply(checkNotNull(options, "options"))))); ImmutableList.of(container, name, blob2HttpGetOptions.apply(checkNotNull(options, "options"))))));
} }
@Override @Override
public HttpRequest signPutBlob(String container, Blob blob) { public HttpRequest signPutBlob(String container, Blob blob) {
checkNotNull(container, "container"); checkNotNull(container, "container");
checkNotNull(blob, "blob"); checkNotNull(blob, "blob");
return cleanRequest(processor.createRequest(createMethod, return cleanRequest(processor.apply(Invocation.create(interfaceType, createMethod,
ImmutableList.<Object> of(container, blobToObject.apply(blob)))); ImmutableList.<Object> of(container, blobToObject.apply(blob)))));
} }
@Override @Override
public HttpRequest signPutBlob(String container, Blob blob, long timeInSeconds) { public HttpRequest signPutBlob(String container, Blob blob, long timeInSeconds) {
checkNotNull(container, "container"); checkNotNull(container, "container");
checkNotNull(blob, "blob"); checkNotNull(blob, "blob");
HttpRequest request = processor.createRequest(createMethod, HttpRequest request = processor.apply(Invocation.create(interfaceType, createMethod,
ImmutableList.<Object> of(container, blobToObject.apply(blob))); ImmutableList.<Object> of(container, blobToObject.apply(blob))));
return cleanRequest(signForTemporaryAccess(request, timeInSeconds)); return cleanRequest(signForTemporaryAccess(request, timeInSeconds));
} }
@ -143,7 +152,8 @@ public class SwiftBlobSigner<T extends CommonSwiftAsyncClient> implements BlobRe
public HttpRequest signRemoveBlob(String container, String name) { public HttpRequest signRemoveBlob(String container, String name) {
checkNotNull(container, "container"); checkNotNull(container, "container");
checkNotNull(name, "name"); checkNotNull(name, "name");
return cleanRequest(processor.createRequest(deleteMethod, ImmutableList.<Object> of(container, name))); return cleanRequest(processor.apply(Invocation.create(interfaceType, deleteMethod,
ImmutableList.<Object> of(container, name))));
} }
private HttpRequest signForTemporaryAccess(HttpRequest request, long timeInSeconds) { private HttpRequest signForTemporaryAccess(HttpRequest request, long timeInSeconds) {

View File

@ -45,7 +45,7 @@ public class ParseContainerMetadataFromHeaders implements Function<HttpResponse,
private GeneratedHttpRequest request; private GeneratedHttpRequest request;
public ContainerMetadata apply(HttpResponse from) { public ContainerMetadata apply(HttpResponse from) {
return ContainerMetadata.builder().name(request.getArgs().get(0).toString()) return ContainerMetadata.builder().name(request.getInvocation().getArgs().get(0).toString())
.readACL(from.getFirstHeaderOrNull(SwiftHeaders.CONTAINER_READ)) .readACL(from.getFirstHeaderOrNull(SwiftHeaders.CONTAINER_READ))
.bytes(Long.valueOf(from.getFirstHeaderOrNull(SwiftHeaders.CONTAINER_BYTES_USED))) .bytes(Long.valueOf(from.getFirstHeaderOrNull(SwiftHeaders.CONTAINER_BYTES_USED)))
.count(Long.valueOf(from.getFirstHeaderOrNull(SwiftHeaders.CONTAINER_OBJECT_COUNT))) .count(Long.valueOf(from.getFirstHeaderOrNull(SwiftHeaders.CONTAINER_OBJECT_COUNT)))

View File

@ -73,7 +73,7 @@ public class ParseObjectInfoFromHeaders implements Function<HttpResponse, Mutabl
public ParseObjectInfoFromHeaders setContext(HttpRequest request) { public ParseObjectInfoFromHeaders setContext(HttpRequest request) {
blobMetadataParser.setContext(request); blobMetadataParser.setContext(request);
checkArgument(request instanceof GeneratedHttpRequest, "note this handler requires a GeneratedHttpRequest"); checkArgument(request instanceof GeneratedHttpRequest, "note this handler requires a GeneratedHttpRequest");
return setContainer(GeneratedHttpRequest.class.cast(request).getArgs().get(0).toString()); return setContainer(GeneratedHttpRequest.class.cast(request).getInvocation().getArgs().get(0).toString());
} }
private ParseObjectInfoFromHeaders setContainer(String container) { private ParseObjectInfoFromHeaders setContainer(String container) {

View File

@ -25,6 +25,7 @@ import static org.jclouds.http.Uris.uriBuilder;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.util.List;
import java.util.SortedSet; import java.util.SortedSet;
import javax.inject.Inject; import javax.inject.Inject;
@ -54,8 +55,10 @@ import com.google.inject.TypeLiteral;
public class ParseObjectInfoListFromJsonResponse extends ParseJson<PageSet<ObjectInfo>> implements public class ParseObjectInfoListFromJsonResponse extends ParseJson<PageSet<ObjectInfo>> implements
InvocationContext<ParseObjectInfoListFromJsonResponse> { InvocationContext<ParseObjectInfoListFromJsonResponse> {
private GeneratedHttpRequest request; private List<Object> args;
private String container; private String container;
private GeneratedHttpRequest request;
private ListContainerOptions options;
@Inject @Inject
public ParseObjectInfoListFromJsonResponse(Json json) { public ParseObjectInfoListFromJsonResponse(Json json) {
@ -64,13 +67,7 @@ public class ParseObjectInfoListFromJsonResponse extends ParseJson<PageSet<Objec
} }
public PageSet<ObjectInfo> apply(InputStream stream) { public PageSet<ObjectInfo> apply(InputStream stream) {
checkState(request != null, "request should be initialized at this point"); checkState(args != null, "request should be initialized at this point");
checkState(request.getArgs() != null, "request.getArgs() should be initialized at this point");
checkArgument(request.getArgs().get(0) instanceof String, "arg[0] must be a container name");
checkArgument(request.getArgs().get(1) instanceof ListContainerOptions[],
"arg[1] must be an array of ListContainerOptions");
ListContainerOptions[] optionsList = (ListContainerOptions[]) request.getArgs().get(1);
ListContainerOptions options = optionsList.length > 0 ? optionsList[0] : ListContainerOptions.NONE;
Type listType = new TypeToken<SortedSet<ObjectInfoImpl>>() { Type listType = new TypeToken<SortedSet<ObjectInfoImpl>>() {
}.getType(); }.getType();
@ -95,12 +92,13 @@ public class ParseObjectInfoListFromJsonResponse extends ParseJson<PageSet<Objec
@Override @Override
public ParseObjectInfoListFromJsonResponse setContext(HttpRequest request) { public ParseObjectInfoListFromJsonResponse setContext(HttpRequest request) {
checkArgument(request instanceof GeneratedHttpRequest, "note this handler requires a GeneratedHttpRequest"); checkArgument(request instanceof GeneratedHttpRequest, "note this handler requires a GeneratedHttpRequest");
this.request = (GeneratedHttpRequest) request; this.request = GeneratedHttpRequest.class.cast(request);
return setContainer(GeneratedHttpRequest.class.cast(request).getArgs().get(0).toString()); this.args = this.request.getInvocation().getArgs();
} checkArgument(args.get(0) instanceof String, "arg[0] must be a container name");
this.container = args.get(0).toString();
private ParseObjectInfoListFromJsonResponse setContainer(String container) { checkArgument(args.get(1) instanceof ListContainerOptions[], "arg[1] must be an array of ListContainerOptions");
this.container = container; ListContainerOptions[] optionsList = (ListContainerOptions[]) args.get(1);
this.options = optionsList.length > 0 ? optionsList[0] : ListContainerOptions.NONE;
return this; return this;
} }
} }

View File

@ -19,9 +19,6 @@
package org.jclouds.openstack.swift.domain.internal; package org.jclouds.openstack.swift.domain.internal;
import static com.google.common.io.BaseEncoding.base16; import static com.google.common.io.BaseEncoding.base16;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import java.io.InputStream; import java.io.InputStream;
@ -29,20 +26,15 @@ import java.net.URI;
import java.util.Set; import java.util.Set;
import org.jclouds.date.internal.SimpleDateFormatDateService; import org.jclouds.date.internal.SimpleDateFormatDateService;
import org.jclouds.json.config.GsonModule;
import org.jclouds.json.config.GsonModule.DateAdapter;
import org.jclouds.json.config.GsonModule.Iso8601DateAdapter;
import org.jclouds.openstack.swift.domain.ObjectInfo; import org.jclouds.openstack.swift.domain.ObjectInfo;
import org.jclouds.openstack.swift.functions.ParseObjectInfoListFromJsonResponse; import org.jclouds.openstack.swift.functions.ParseObjectInfoListFromJsonResponse;
import org.jclouds.openstack.swift.internal.BasePayloadTest;
import org.jclouds.openstack.swift.options.ListContainerOptions; import org.jclouds.openstack.swift.options.ListContainerOptions;
import org.jclouds.rest.internal.GeneratedHttpRequest; import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
/** /**
* Tests behavior of {@code ParseObjectInfoListFromJsonResponse} * Tests behavior of {@code ParseObjectInfoListFromJsonResponse}
@ -50,35 +42,26 @@ import com.google.inject.Injector;
* @author Adrian Cole * @author Adrian Cole
*/ */
@Test(groups = "unit") @Test(groups = "unit")
public class ParseObjectInfoListFromJsonResponseTest { public class ParseObjectInfoListFromJsonResponseTest extends BasePayloadTest {
Injector i = Guice.createInjector(new AbstractModule() {
@Override
protected void configure() {
bind(DateAdapter.class).to(Iso8601DateAdapter.class);
}
}, new GsonModule());
public void testApplyInputStream() { public void testApplyInputStream() {
InputStream is = getClass().getResourceAsStream("/test_list_container.json"); InputStream is = getClass().getResourceAsStream("/test_list_container.json");
Set<ObjectInfo> expects = ImmutableSet.<ObjectInfo> of(ObjectInfoImpl.builder().container("container").name( Set<ObjectInfo> expects = ImmutableSet
"test_obj_1").uri(URI.create("http://localhost/foo/test_obj_1")).hash( .<ObjectInfo> of(
base16().lowerCase().decode("4281c348eaf83e70ddce0e07221c3d28")).bytes(14l) ObjectInfoImpl.builder().container("container").name("test_obj_1")
.contentType("application/octet-stream").lastModified( .uri(URI.create("http://localhost/key/test_obj_1"))
new SimpleDateFormatDateService().iso8601DateParse("2009-02-03T05:26:32.612Z")).build(), .hash(base16().lowerCase().decode("4281c348eaf83e70ddce0e07221c3d28")).bytes(14l)
ObjectInfoImpl.builder().container("container").name("test_obj_2").uri( .contentType("application/octet-stream")
URI.create("http://localhost/foo/test_obj_2")).hash( .lastModified(new SimpleDateFormatDateService().iso8601DateParse("2009-02-03T05:26:32.612Z"))
base16().lowerCase().decode("b039efe731ad111bc1b0ef221c3849d0")).bytes(64l).contentType( .build(),
"application/octet-stream").lastModified( ObjectInfoImpl.builder().container("container").name("test_obj_2")
new SimpleDateFormatDateService().iso8601DateParse("2009-02-03T05:26:32.612Z")).build()); .uri(URI.create("http://localhost/key/test_obj_2"))
GeneratedHttpRequest request = createMock(GeneratedHttpRequest.class); .hash(base16().lowerCase().decode("b039efe731ad111bc1b0ef221c3849d0")).bytes(64l)
ListContainerOptions options = new ListContainerOptions(); .contentType("application/octet-stream")
expect(request.getEndpoint()).andReturn(URI.create("http://localhost/foo")).atLeastOnce(); .lastModified(new SimpleDateFormatDateService().iso8601DateParse("2009-02-03T05:26:32.612Z"))
expect(request.getArgs()).andReturn( .build());
ImmutableList.<Object> of("container", new ListContainerOptions[] { options })).atLeastOnce(); GeneratedHttpRequest request = requestForArgs(ImmutableList.<Object> of("container",
replay(request); new ListContainerOptions[] { new ListContainerOptions() }));
ParseObjectInfoListFromJsonResponse parser = i.getInstance(ParseObjectInfoListFromJsonResponse.class); ParseObjectInfoListFromJsonResponse parser = i.getInstance(ParseObjectInfoListFromJsonResponse.class);
parser.setContext(request); parser.setContext(request);
assertEquals(parser.apply(is).toString(), expects.toString()); assertEquals(parser.apply(is).toString(), expects.toString());

View File

@ -26,15 +26,13 @@ import java.util.Map;
import org.jclouds.http.HttpResponse; import org.jclouds.http.HttpResponse;
import org.jclouds.http.functions.ParseJson; import org.jclouds.http.functions.ParseJson;
import org.jclouds.json.config.GsonModule;
import org.jclouds.openstack.swift.domain.ContainerMetadata; import org.jclouds.openstack.swift.domain.ContainerMetadata;
import org.jclouds.openstack.swift.internal.BasePayloadTest;
import org.jclouds.util.Strings2; import org.jclouds.util.Strings2;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Key; import com.google.inject.Key;
import com.google.inject.TypeLiteral; import com.google.inject.TypeLiteral;
@ -44,8 +42,7 @@ import com.google.inject.TypeLiteral;
* @author Adrian Cole * @author Adrian Cole
*/ */
@Test(groups = "unit") @Test(groups = "unit")
public class ParseContainerListFromJsonResponseTest { public class ParseContainerListFromJsonResponseTest extends BasePayloadTest {
Injector i = Guice.createInjector(new GsonModule());
@Test @Test
public void testApplyInputStream() { public void testApplyInputStream() {

View File

@ -18,24 +18,15 @@
*/ */
package org.jclouds.openstack.swift.functions; package org.jclouds.openstack.swift.functions;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import java.net.URI;
import org.jclouds.http.HttpResponse; import org.jclouds.http.HttpResponse;
import org.jclouds.openstack.swift.domain.ContainerMetadata; import org.jclouds.openstack.swift.domain.ContainerMetadata;
import org.jclouds.openstack.swift.functions.ParseContainerMetadataFromHeaders; import org.jclouds.openstack.swift.internal.BasePayloadTest;
import org.jclouds.openstack.swift.reference.SwiftHeaders; import org.jclouds.openstack.swift.reference.SwiftHeaders;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
/** /**
* Tests behavior of {@code ParseContainerMetadataFromHeaders} * Tests behavior of {@code ParseContainerMetadataFromHeaders}
@ -43,22 +34,12 @@ import com.google.inject.Injector;
* @author Everett Toews * @author Everett Toews
*/ */
@Test(groups = "unit") @Test(groups = "unit")
public class ParseContainerMetadataFromHeadersTest { public class ParseContainerMetadataFromHeadersTest extends BasePayloadTest {
Injector i = Guice.createInjector(new AbstractModule() {
@Override
protected void configure() {
}
});
public void testParseContainerMetadataHeaders() { public void testParseContainerMetadataHeaders() {
ParseContainerMetadataFromHeaders parser = i.getInstance(ParseContainerMetadataFromHeaders.class); ParseContainerMetadataFromHeaders parser = i.getInstance(ParseContainerMetadataFromHeaders.class);
GeneratedHttpRequest request = createMock(GeneratedHttpRequest.class);
expect(request.getArgs()).andReturn(ImmutableList.<Object> of("container", "key")).atLeastOnce(); parser.setContext(requestForArgs(ImmutableList.<Object> of("container", "key")));
expect(request.getEndpoint()).andReturn(URI.create("http://localhost/test")).atLeastOnce();
replay(request);
parser.setContext(request);
HttpResponse response = HttpResponse.builder().statusCode(204).message("No Content").payload("") HttpResponse response = HttpResponse.builder().statusCode(204).message("No Content").payload("")
.addHeader(SwiftHeaders.CONTAINER_BYTES_USED, "42") .addHeader(SwiftHeaders.CONTAINER_BYTES_USED, "42")

View File

@ -18,25 +18,14 @@
*/ */
package org.jclouds.openstack.swift.functions; package org.jclouds.openstack.swift.functions;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertNotNull;
import java.net.URI;
import org.jclouds.Constants;
import org.jclouds.blobstore.reference.BlobStoreConstants;
import org.jclouds.http.HttpResponse; import org.jclouds.http.HttpResponse;
import org.jclouds.openstack.swift.domain.MutableObjectInfoWithMetadata; import org.jclouds.openstack.swift.domain.MutableObjectInfoWithMetadata;
import org.jclouds.rest.internal.GeneratedHttpRequest; import org.jclouds.openstack.swift.internal.BasePayloadTest;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.name.Names;
/** /**
* Tests behavior of {@code ParseContainerListFromJsonResponse} * Tests behavior of {@code ParseContainerListFromJsonResponse}
@ -44,26 +33,13 @@ import com.google.inject.name.Names;
* @author Adrian Cole * @author Adrian Cole
*/ */
@Test(groups = "unit") @Test(groups = "unit")
public class ParseObjectInfoFromHeadersTest { public class ParseObjectInfoFromHeadersTest extends BasePayloadTest {
Injector i = Guice.createInjector(new AbstractModule() {
@Override
protected void configure() {
bindConstant().annotatedWith(Names.named(BlobStoreConstants.PROPERTY_USER_METADATA_PREFIX)).to("sdf");
bindConstant().annotatedWith(Names.named(Constants.PROPERTY_API_VERSION)).to("1");
}
});
public void testEtagCaseIssue() { public void testEtagCaseIssue() {
ParseObjectInfoFromHeaders parser = i.getInstance(ParseObjectInfoFromHeaders.class); ParseObjectInfoFromHeaders parser = i.getInstance(ParseObjectInfoFromHeaders.class);
GeneratedHttpRequest request = createMock(GeneratedHttpRequest.class);
expect(request.getArgs()).andReturn(ImmutableList.<Object> of("container", "key")).atLeastOnce();
expect(request.getEndpoint()).andReturn(URI.create("http://localhost/test")).atLeastOnce(); parser.setContext(requestForArgs(ImmutableList.<Object> of("container", "key")));
replay(request);
parser.setContext(request);
HttpResponse response = HttpResponse.builder().statusCode(200).message("ok").payload("") HttpResponse response = HttpResponse.builder().statusCode(200).message("ok").payload("")
.addHeader("Last-Modified", "Fri, 12 Jun 2007 13:40:18 GMT") .addHeader("Last-Modified", "Fri, 12 Jun 2007 13:40:18 GMT")
.addHeader("Content-Length", "0") .addHeader("Content-Length", "0")

View File

@ -0,0 +1,57 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.jclouds.openstack.swift.internal;
import java.net.URI;
import java.util.List;
import org.jclouds.json.config.GsonModule;
import org.jclouds.json.config.GsonModule.DateAdapter;
import org.jclouds.json.config.GsonModule.Iso8601DateAdapter;
import org.jclouds.openstack.swift.SwiftApiMetadata;
import org.jclouds.reflect.Invocation;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.nnsoft.guice.rocoto.Rocoto;
import org.nnsoft.guice.rocoto.configuration.ConfigurationModule;
import com.google.common.base.Throwables;
import com.google.common.reflect.Invokable;
import com.google.inject.Guice;
import com.google.inject.Injector;
public class BasePayloadTest {
protected Injector i = Guice.createInjector(Rocoto.expandVariables(new ConfigurationModule() {
protected void bindConfigurations() {
bindProperties(new SwiftApiMetadata().getDefaultProperties());
bind(DateAdapter.class).to(Iso8601DateAdapter.class);
}
}), new GsonModule());
protected GeneratedHttpRequest requestForArgs(List<Object> args) {
try {
Invocation invocation = Invocation.create(Invokable.from(String.class.getDeclaredMethod("toString")), args);
return GeneratedHttpRequest.builder().method("POST").endpoint(URI.create("http://localhost/key"))
.invocation(invocation).build();
} catch (SecurityException e) {
throw Throwables.propagate(e);
} catch (NoSuchMethodException e) {
throw Throwables.propagate(e);
}
}
}

View File

@ -20,7 +20,6 @@ package org.jclouds.vcloud.binders;
import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_XML_NAMESPACE; import static org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_XML_NAMESPACE;
import static org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_XML_SCHEMA; import static org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_XML_SCHEMA;
@ -68,7 +67,6 @@ public class BindCaptureVAppParamsToXmlPayload implements MapBinder {
checkArgument(checkNotNull(request, "request") instanceof GeneratedHttpRequest, checkArgument(checkNotNull(request, "request") instanceof GeneratedHttpRequest,
"this binder is only valid for GeneratedHttpRequests!"); "this binder is only valid for GeneratedHttpRequests!");
GeneratedHttpRequest gRequest = (GeneratedHttpRequest) request; GeneratedHttpRequest gRequest = (GeneratedHttpRequest) request;
checkState(gRequest.getArgs() != null, "args should be initialized at this point");
String templateName = checkNotNull(postParams.remove("templateName"), "templateName").toString(); String templateName = checkNotNull(postParams.remove("templateName"), "templateName").toString();
String vApp = checkNotNull(postParams.remove("vApp"), "vApp").toString(); String vApp = checkNotNull(postParams.remove("vApp"), "vApp").toString();
@ -106,7 +104,7 @@ public class BindCaptureVAppParamsToXmlPayload implements MapBinder {
} }
protected CaptureVAppOptions findOptionsInArgsOrNull(GeneratedHttpRequest gRequest) { protected CaptureVAppOptions findOptionsInArgsOrNull(GeneratedHttpRequest gRequest) {
for (Object arg : gRequest.getArgs()) { for (Object arg : gRequest.getInvocation().getArgs()) {
if (arg instanceof CaptureVAppOptions) { if (arg instanceof CaptureVAppOptions) {
return (CaptureVAppOptions) arg; return (CaptureVAppOptions) arg;
} else if (arg instanceof CaptureVAppOptions[]) { } else if (arg instanceof CaptureVAppOptions[]) {

View File

@ -20,7 +20,6 @@ package org.jclouds.vcloud.binders;
import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_XML_NAMESPACE; import static org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_XML_NAMESPACE;
import static org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_XML_SCHEMA; import static org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_XML_SCHEMA;
@ -69,7 +68,6 @@ public class BindCatalogItemToXmlPayload implements MapBinder {
checkArgument(checkNotNull(request, "request") instanceof GeneratedHttpRequest, checkArgument(checkNotNull(request, "request") instanceof GeneratedHttpRequest,
"this binder is only valid for GeneratedHttpRequests!"); "this binder is only valid for GeneratedHttpRequests!");
GeneratedHttpRequest gRequest = (GeneratedHttpRequest) request; GeneratedHttpRequest gRequest = (GeneratedHttpRequest) request;
checkState(gRequest.getArgs() != null, "args should be initialized at this point");
String name = checkNotNull(postParams.get("name"), "name").toString(); String name = checkNotNull(postParams.get("name"), "name").toString();
URI entity = URI.create(checkNotNull(postParams.get("Entity"), "Entity").toString()); URI entity = URI.create(checkNotNull(postParams.get("Entity"), "Entity").toString());
@ -107,7 +105,7 @@ public class BindCatalogItemToXmlPayload implements MapBinder {
} }
protected CatalogItemOptions findOptionsInArgsOrNew(GeneratedHttpRequest gRequest) { protected CatalogItemOptions findOptionsInArgsOrNew(GeneratedHttpRequest gRequest) {
for (Object arg : gRequest.getArgs()) { for (Object arg : gRequest.getInvocation().getArgs()) {
if (arg instanceof CatalogItemOptions) { if (arg instanceof CatalogItemOptions) {
return CatalogItemOptions.class.cast(arg); return CatalogItemOptions.class.cast(arg);
} else if (arg.getClass().isArray()) { } else if (arg.getClass().isArray()) {

View File

@ -20,7 +20,6 @@ package org.jclouds.vcloud.binders;
import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_XML_NAMESPACE; import static org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_XML_NAMESPACE;
import static org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_XML_SCHEMA; import static org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_XML_SCHEMA;
@ -69,7 +68,6 @@ public abstract class BindCloneParamsToXmlPayload<O extends CloneOptions> implem
checkArgument(checkNotNull(request, "request") instanceof GeneratedHttpRequest, checkArgument(checkNotNull(request, "request") instanceof GeneratedHttpRequest,
"this binder is only valid for GeneratedHttpRequests!"); "this binder is only valid for GeneratedHttpRequests!");
GeneratedHttpRequest gRequest = (GeneratedHttpRequest) request; GeneratedHttpRequest gRequest = (GeneratedHttpRequest) request;
checkState(gRequest.getArgs() != null, "args should be initialized at this point");
String name = checkNotNull(postParams.get("name"), "name").toString(); String name = checkNotNull(postParams.get("name"), "name").toString();
String source = checkNotNull(postParams.get("Source"), "Source").toString(); String source = checkNotNull(postParams.get("Source"), "Source").toString();
boolean isSourceDelete = Boolean.parseBoolean((String) postParams.get("IsSourceDelete")); boolean isSourceDelete = Boolean.parseBoolean((String) postParams.get("IsSourceDelete"));
@ -110,7 +108,7 @@ public abstract class BindCloneParamsToXmlPayload<O extends CloneOptions> implem
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
protected O findOptionsInArgsOrNew(GeneratedHttpRequest gRequest) { protected O findOptionsInArgsOrNew(GeneratedHttpRequest gRequest) {
for (Object arg : gRequest.getArgs()) { for (Object arg : gRequest.getInvocation().getArgs()) {
if (getOptionClass().isInstance(arg)) { if (getOptionClass().isInstance(arg)) {
return (O) arg; return (O) arg;
} else if (arg.getClass().isArray()) { } else if (arg.getClass().isArray()) {

View File

@ -20,7 +20,6 @@ package org.jclouds.vcloud.binders;
import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.Iterables.transform; import static com.google.common.collect.Iterables.transform;
import static org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_XML_NAMESPACE; import static org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_XML_NAMESPACE;
import static org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_XML_SCHEMA; import static org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_XML_SCHEMA;
@ -92,7 +91,6 @@ public class BindInstantiateVAppTemplateParamsToXmlPayload implements MapBinder
checkArgument(checkNotNull(request, "request") instanceof GeneratedHttpRequest, checkArgument(checkNotNull(request, "request") instanceof GeneratedHttpRequest,
"this binder is only valid for GeneratedHttpRequests!"); "this binder is only valid for GeneratedHttpRequests!");
GeneratedHttpRequest gRequest = (GeneratedHttpRequest) request; GeneratedHttpRequest gRequest = (GeneratedHttpRequest) request;
checkState(gRequest.getArgs() != null, "args should be initialized at this point");
String name = checkNotNull(postParams.remove("name"), "name").toString(); String name = checkNotNull(postParams.remove("name"), "name").toString();
URI template = URI.create(checkNotNull(postParams.remove("template"), "template").toString()); URI template = URI.create(checkNotNull(postParams.remove("template"), "template").toString());
@ -203,7 +201,7 @@ public class BindInstantiateVAppTemplateParamsToXmlPayload implements MapBinder
} }
protected InstantiateVAppTemplateOptions findOptionsInArgsOrNull(GeneratedHttpRequest gRequest) { protected InstantiateVAppTemplateOptions findOptionsInArgsOrNull(GeneratedHttpRequest gRequest) {
for (Object arg : gRequest.getArgs()) { for (Object arg : gRequest.getInvocation().getArgs()) {
if (arg instanceof InstantiateVAppTemplateOptions) { if (arg instanceof InstantiateVAppTemplateOptions) {
return (InstantiateVAppTemplateOptions) arg; return (InstantiateVAppTemplateOptions) arg;
} else if (arg instanceof InstantiateVAppTemplateOptions[]) { } else if (arg instanceof InstantiateVAppTemplateOptions[]) {

View File

@ -18,26 +18,18 @@
*/ */
package org.jclouds.vcloud.binders; package org.jclouds.vcloud.binders;
import static org.easymock.EasyMock.createMock; import static org.testng.Assert.assertEquals;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
import java.io.IOException; import java.io.IOException;
import java.net.URI;
import java.util.Map; import java.util.Map;
import org.jclouds.rest.internal.GeneratedHttpRequest; import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.jclouds.vcloud.VCloudApiMetadata; import org.jclouds.vcloud.internal.BasePayloadTest;
import org.jclouds.vcloud.options.CatalogItemOptions; import org.jclouds.vcloud.options.CatalogItemOptions;
import org.nnsoft.guice.rocoto.Rocoto;
import org.nnsoft.guice.rocoto.configuration.ConfigurationModule;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.inject.Guice;
import com.google.inject.Injector;
/** /**
* Tests behavior of {@code BindCatalogItemToXmlPayload} * Tests behavior of {@code BindCatalogItemToXmlPayload}
@ -45,31 +37,19 @@ import com.google.inject.Injector;
* @author Adrian Cole * @author Adrian Cole
*/ */
@Test(groups = "unit") @Test(groups = "unit")
public class BindCatalogItemToXmlPayloadTest { public class BindCatalogItemToXmlPayloadTest extends BasePayloadTest {
Injector injector = Guice.createInjector(Rocoto.expandVariables(new ConfigurationModule() {
@Override
protected void bindConfigurations() {
bindProperties(new VCloudApiMetadata().getDefaultProperties());
}
}));
public void testDefault() throws IOException { public void testDefault() throws IOException {
String expected = "<CatalogItem xmlns=\"http://www.vmware.com/vcloud/v1\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" name=\"myname\" xsi:schemaLocation=\"http://www.vmware.com/vcloud/v1 http://vcloud.safesecureweb.com/ns/vcloud.xsd\"><Description>mydescription</Description><Entity href=\"http://fooentity\"/><Property key=\"foo\">bar</Property></CatalogItem>"; String expected = "<CatalogItem xmlns=\"http://www.vmware.com/vcloud/v1\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" name=\"myname\" xsi:schemaLocation=\"http://www.vmware.com/vcloud/v1 http://vcloud.safesecureweb.com/ns/vcloud.xsd\"><Description>mydescription</Description><Entity href=\"http://fooentity\"/><Property key=\"foo\">bar</Property></CatalogItem>";
GeneratedHttpRequest request = createMock(GeneratedHttpRequest.class); CatalogItemOptions options = CatalogItemOptions.Builder.description("mydescription").properties(
expect(request.getEndpoint()).andReturn(URI.create("http://localhost/key")).anyTimes(); ImmutableMap.of("foo", "bar"));
expect(request.getArgs()).andReturn( GeneratedHttpRequest request = requestForArgs(ImmutableList.<Object> of(options));
ImmutableList.<Object> of(CatalogItemOptions.Builder.description("mydescription").properties(
ImmutableMap.of("foo", "bar")))).anyTimes();
request.setPayload(expected);
replay(request);
BindCatalogItemToXmlPayload binder = injector.getInstance(BindCatalogItemToXmlPayload.class); BindCatalogItemToXmlPayload binder = injector.getInstance(BindCatalogItemToXmlPayload.class);
Map<String, Object> map = ImmutableMap.<String, Object> of("name", "myname", "Entity", "http://fooentity"); Map<String, Object> map = ImmutableMap.<String, Object> of("name", "myname", "Entity", "http://fooentity");
binder.bindToRequest(request, map); assertEquals(binder.bindToRequest(request, map).getPayload().getRawContent(), expected);
verify(request);
} }
} }

View File

@ -20,21 +20,15 @@ package org.jclouds.vcloud.binders;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import java.util.Properties;
import org.jclouds.rest.internal.GeneratedHttpRequest; import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.jclouds.util.Strings2; import org.jclouds.util.Strings2;
import org.jclouds.vcloud.VCloudApiMetadata; import org.jclouds.vcloud.internal.BasePayloadTest;
import org.jclouds.vcloud.options.CloneVAppOptions; import org.jclouds.vcloud.options.CloneVAppOptions;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMap.Builder; import com.google.common.collect.ImmutableMap.Builder;
import com.google.common.reflect.Invokable;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.name.Names;
/** /**
* Tests behavior of {@code BindCloneVAppParamsToXmlPayload} * Tests behavior of {@code BindCloneVAppParamsToXmlPayload}
@ -42,25 +36,14 @@ import com.google.inject.name.Names;
* @author Adrian Cole * @author Adrian Cole
*/ */
@Test(groups = "unit") @Test(groups = "unit")
public class BindCloneVAppParamsToXmlPayloadTest { public class BindCloneVAppParamsToXmlPayloadTest extends BasePayloadTest {
Injector injector = Guice.createInjector(new AbstractModule() {
@Override
protected void configure() {
Properties props = new VCloudApiMetadata().getDefaultProperties();
props.setProperty("jclouds.vcloud.xml.ns", "http://www.vmware.com/vcloud/v1");
props.setProperty("jclouds.vcloud.xml.schema", "http://vcloud.safesecureweb.com/ns/vcloud.xsd");
Names.bindProperties(binder(), props);
}
});
public void testWithDescriptionDeployOn() throws Exception { public void testWithDescriptionDeployOn() throws Exception {
String expected = Strings2.toStringAndClose(getClass().getResourceAsStream("/copyVApp.xml")); String expected = Strings2.toStringAndClose(getClass().getResourceAsStream("/copyVApp.xml"));
CloneVAppOptions options = new CloneVAppOptions().deploy().powerOn().description( CloneVAppOptions options = new CloneVAppOptions().deploy().powerOn().description(
"The description of the new vApp"); "The description of the new vApp");
GeneratedHttpRequest request = GeneratedHttpRequest.builder().method("POST").endpoint("http://localhost/key") GeneratedHttpRequest request = requestForArgs(ImmutableList.<Object> of(options));
.declaring(String.class).invoker(Invokable.from(String.class.getDeclaredMethod("toString"))).arg(options).build();
BindCloneVAppParamsToXmlPayload binder = injector.getInstance(BindCloneVAppParamsToXmlPayload.class); BindCloneVAppParamsToXmlPayload binder = injector.getInstance(BindCloneVAppParamsToXmlPayload.class);
@ -75,9 +58,7 @@ public class BindCloneVAppParamsToXmlPayloadTest {
CloneVAppOptions options = new CloneVAppOptions().deploy().powerOn().description( CloneVAppOptions options = new CloneVAppOptions().deploy().powerOn().description(
"The description of the new vApp"); "The description of the new vApp");
GeneratedHttpRequest request = GeneratedHttpRequest.builder().method("POST").endpoint("http://localhost/key") GeneratedHttpRequest request = requestForArgs(ImmutableList.<Object> of(options));
.declaring(String.class).invoker(Invokable.from(String.class.getDeclaredMethod("toString"))).arg(options).build();
BindCloneVAppParamsToXmlPayload binder = injector.getInstance(BindCloneVAppParamsToXmlPayload.class); BindCloneVAppParamsToXmlPayload binder = injector.getInstance(BindCloneVAppParamsToXmlPayload.class);
@ -90,10 +71,7 @@ public class BindCloneVAppParamsToXmlPayloadTest {
public void testDefault() throws Exception { public void testDefault() throws Exception {
String expected = Strings2.toStringAndClose(getClass().getResourceAsStream("/copyVApp-default.xml")); String expected = Strings2.toStringAndClose(getClass().getResourceAsStream("/copyVApp-default.xml"));
GeneratedHttpRequest request = requestForArgs(ImmutableList.<Object> of());
GeneratedHttpRequest request = GeneratedHttpRequest.builder().method("POST").endpoint("http://localhost/key")
.declaring(String.class).invoker(Invokable.from(String.class.getDeclaredMethod("toString"))).build();
BindCloneVAppParamsToXmlPayload binder = injector.getInstance(BindCloneVAppParamsToXmlPayload.class); BindCloneVAppParamsToXmlPayload binder = injector.getInstance(BindCloneVAppParamsToXmlPayload.class);

View File

@ -18,28 +18,19 @@
*/ */
package org.jclouds.vcloud.binders; package org.jclouds.vcloud.binders;
import static org.easymock.EasyMock.createMock; import static org.jclouds.util.Strings2.toStringAndClose;
import static org.easymock.EasyMock.expect; import static org.testng.Assert.assertEquals;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
import java.io.IOException; import java.io.IOException;
import java.net.URI;
import java.util.Properties;
import org.jclouds.rest.internal.GeneratedHttpRequest; import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.jclouds.util.Strings2; import org.jclouds.vcloud.internal.BasePayloadTest;
import org.jclouds.vcloud.VCloudApiMetadata;
import org.jclouds.vcloud.options.CloneVAppTemplateOptions; import org.jclouds.vcloud.options.CloneVAppTemplateOptions;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMap.Builder; import com.google.common.collect.ImmutableMap.Builder;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.name.Names;
/** /**
* Tests behavior of {@code BindCloneVAppTemplateParamsToXmlPayload} * Tests behavior of {@code BindCloneVAppTemplateParamsToXmlPayload}
@ -47,28 +38,13 @@ import com.google.inject.name.Names;
* @author Adrian Cole * @author Adrian Cole
*/ */
@Test(groups = "unit") @Test(groups = "unit")
public class BindCloneVAppTemplateParamsToXmlPayloadTest { public class BindCloneVAppTemplateParamsToXmlPayloadTest extends BasePayloadTest {
Injector injector = Guice.createInjector(new AbstractModule() {
@Override
protected void configure() {
Properties props = new Properties();
props.setProperty("jclouds.vcloud.xml.ns", "http://www.vmware.com/vcloud/v1");
props.setProperty("jclouds.vcloud.xml.schema", "http://vcloud.safesecureweb.com/ns/vcloud.xsd");
Names.bindProperties(binder(), new VCloudApiMetadata().getDefaultProperties());
}
});
public void testWithDescription() throws IOException { public void testWithDescription() throws IOException {
String expected = Strings2.toStringAndClose(getClass().getResourceAsStream("/copyVAppTemplate.xml")); String expected = toStringAndClose(getClass().getResourceAsStream("/copyVAppTemplate.xml"));
CloneVAppTemplateOptions options = new CloneVAppTemplateOptions() CloneVAppTemplateOptions options = new CloneVAppTemplateOptions()
.description("The description of the new vAppTemplate"); .description("The description of the new vAppTemplate");
GeneratedHttpRequest request = createMock(GeneratedHttpRequest.class); GeneratedHttpRequest request = requestForArgs(ImmutableList.<Object> of(options));
expect(request.getEndpoint()).andReturn(URI.create("http://localhost/key")).anyTimes();
expect(request.getArgs()).andReturn(ImmutableList.<Object> of(options)).atLeastOnce();
request.setPayload(expected);
replay(request);
BindCloneVAppTemplateParamsToXmlPayload binder = injector BindCloneVAppTemplateParamsToXmlPayload binder = injector
.getInstance(BindCloneVAppTemplateParamsToXmlPayload.class); .getInstance(BindCloneVAppTemplateParamsToXmlPayload.class);
@ -76,20 +52,16 @@ public class BindCloneVAppTemplateParamsToXmlPayloadTest {
Builder<String, Object> map = ImmutableMap.builder(); Builder<String, Object> map = ImmutableMap.builder();
map.put("name", "new-linux-server"); map.put("name", "new-linux-server");
map.put("Source", "https://vcenterprise.bluelock.com/api/v1.0/vAppTemplate/201"); map.put("Source", "https://vcenterprise.bluelock.com/api/v1.0/vAppTemplate/201");
binder.bindToRequest(request, map.build());
verify(request); assertEquals(binder.bindToRequest(request, map.build()).getPayload().getRawContent(), expected);
} }
public void testWithDescriptionSourceDelete() throws IOException { public void testWithDescriptionSourceDelete() throws IOException {
String expected = Strings2.toStringAndClose(getClass().getResourceAsStream("/moveVAppTemplate.xml")); String expected = toStringAndClose(getClass().getResourceAsStream("/moveVAppTemplate.xml"));
CloneVAppTemplateOptions options = new CloneVAppTemplateOptions() CloneVAppTemplateOptions options = new CloneVAppTemplateOptions()
.description("The description of the new vAppTemplate"); .description("The description of the new vAppTemplate");
GeneratedHttpRequest request = createMock(GeneratedHttpRequest.class); GeneratedHttpRequest request = requestForArgs(ImmutableList.<Object> of(options));
expect(request.getEndpoint()).andReturn(URI.create("http://localhost/key")).anyTimes();
expect(request.getArgs()).andReturn(ImmutableList.<Object> of(options)).atLeastOnce();
request.setPayload(expected);
replay(request);
BindCloneVAppTemplateParamsToXmlPayload binder = injector BindCloneVAppTemplateParamsToXmlPayload binder = injector
.getInstance(BindCloneVAppTemplateParamsToXmlPayload.class); .getInstance(BindCloneVAppTemplateParamsToXmlPayload.class);
@ -98,18 +70,14 @@ public class BindCloneVAppTemplateParamsToXmlPayloadTest {
map.put("name", "new-linux-server"); map.put("name", "new-linux-server");
map.put("Source", "https://vcenterprise.bluelock.com/api/v1.0/vAppTemplate/201"); map.put("Source", "https://vcenterprise.bluelock.com/api/v1.0/vAppTemplate/201");
map.put("IsSourceDelete", "true"); map.put("IsSourceDelete", "true");
binder.bindToRequest(request, map.build());
verify(request); assertEquals(binder.bindToRequest(request, map.build()).getPayload().getRawContent(), expected);
} }
public void testDefault() throws IOException { public void testDefault() throws IOException {
String expected = Strings2.toStringAndClose(getClass().getResourceAsStream("/copyVAppTemplate-default.xml")); String expected = toStringAndClose(getClass().getResourceAsStream("/copyVAppTemplate-default.xml"));
GeneratedHttpRequest request = createMock(GeneratedHttpRequest.class); GeneratedHttpRequest request = requestForArgs(ImmutableList.<Object> of());
expect(request.getEndpoint()).andReturn(URI.create("http://localhost/key")).anyTimes();
expect(request.getArgs()).andReturn(ImmutableList.<Object> of()).atLeastOnce();
request.setPayload(expected);
replay(request);
BindCloneVAppTemplateParamsToXmlPayload binder = injector BindCloneVAppTemplateParamsToXmlPayload binder = injector
.getInstance(BindCloneVAppTemplateParamsToXmlPayload.class); .getInstance(BindCloneVAppTemplateParamsToXmlPayload.class);
@ -117,7 +85,7 @@ public class BindCloneVAppTemplateParamsToXmlPayloadTest {
Builder<String, Object> map = ImmutableMap.builder(); Builder<String, Object> map = ImmutableMap.builder();
map.put("name", "my-vapptemplate"); map.put("name", "my-vapptemplate");
map.put("Source", "https://vcenterprise.bluelock.com/api/v1.0/vAppTemplate/4181"); map.put("Source", "https://vcenterprise.bluelock.com/api/v1.0/vAppTemplate/4181");
binder.bindToRequest(request, map.build());
verify(request); assertEquals(binder.bindToRequest(request, map.build()).getPayload().getRawContent(), expected);
} }
} }

View File

@ -18,24 +18,17 @@
*/ */
package org.jclouds.vcloud.binders; package org.jclouds.vcloud.binders;
import static org.easymock.EasyMock.createMock; import static org.testng.Assert.assertEquals;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
import java.io.IOException; import java.io.IOException;
import java.net.URI;
import java.util.Map; import java.util.Map;
import org.jclouds.rest.internal.GeneratedHttpRequest; import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.jclouds.vcloud.VCloudApiMetadata; import org.jclouds.vcloud.internal.BasePayloadTest;
import org.nnsoft.guice.rocoto.Rocoto;
import org.nnsoft.guice.rocoto.configuration.ConfigurationModule;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.google.inject.Guice;
import com.google.inject.Injector;
/** /**
* Tests behavior of {@code BindDeployVAppParamsToXmlPayload} * Tests behavior of {@code BindDeployVAppParamsToXmlPayload}
@ -43,44 +36,28 @@ import com.google.inject.Injector;
* @author Adrian Cole * @author Adrian Cole
*/ */
@Test(groups = "unit") @Test(groups = "unit")
public class BindDeployVAppParamsToXmlPayloadTest { public class BindDeployVAppParamsToXmlPayloadTest extends BasePayloadTest {
Injector injector = Guice.createInjector(Rocoto.expandVariables(new ConfigurationModule() {
@Override
protected void bindConfigurations() {
bindProperties(new VCloudApiMetadata().getDefaultProperties());
}
}));
public void testPowerOnTrue() throws IOException { public void testPowerOnTrue() throws IOException {
String expected = "<DeployVAppParams xmlns=\"http://www.vmware.com/vcloud/v1\" powerOn=\"true\"/>"; String expected = "<DeployVAppParams xmlns=\"http://www.vmware.com/vcloud/v1\" powerOn=\"true\"/>";
GeneratedHttpRequest request = createMock(GeneratedHttpRequest.class); GeneratedHttpRequest request = requestForArgs(ImmutableList.<Object> of());
expect(request.getEndpoint()).andReturn(URI.create("http://localhost/key")).anyTimes();
request.setPayload(expected);
replay(request);
BindDeployVAppParamsToXmlPayload binder = injector.getInstance(BindDeployVAppParamsToXmlPayload.class); BindDeployVAppParamsToXmlPayload binder = injector.getInstance(BindDeployVAppParamsToXmlPayload.class);
Map<String, Object> map = Maps.newHashMap(); Map<String, Object> map = Maps.newHashMap();
map.put("powerOn", "true"); map.put("powerOn", "true");
binder.bindToRequest(request, map); assertEquals(binder.bindToRequest(request, map).getPayload().getRawContent(), expected);
verify(request);
} }
public void testDefault() throws IOException { public void testDefault() throws IOException {
String expected = "<DeployVAppParams xmlns=\"http://www.vmware.com/vcloud/v1\"/>"; String expected = "<DeployVAppParams xmlns=\"http://www.vmware.com/vcloud/v1\"/>";
GeneratedHttpRequest request = createMock(GeneratedHttpRequest.class); GeneratedHttpRequest request = requestForArgs(ImmutableList.<Object> of());
expect(request.getEndpoint()).andReturn(URI.create("http://localhost/key")).anyTimes();
request.setPayload(expected);
replay(request);
BindDeployVAppParamsToXmlPayload binder = injector.getInstance(BindDeployVAppParamsToXmlPayload.class); BindDeployVAppParamsToXmlPayload binder = injector.getInstance(BindDeployVAppParamsToXmlPayload.class);
Map<String, Object> map = Maps.newHashMap(); Map<String, Object> map = Maps.newHashMap();
assertEquals(binder.bindToRequest(request, map).getPayload().getRawContent(), expected);
binder.bindToRequest(request, map);
verify(request);
} }
} }

View File

@ -19,11 +19,10 @@
package org.jclouds.vcloud.binders; package org.jclouds.vcloud.binders;
import static org.easymock.EasyMock.createMock; import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay; import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
import static org.jclouds.vcloud.options.InstantiateVAppTemplateOptions.Builder.addNetworkConfig; import static org.jclouds.vcloud.options.InstantiateVAppTemplateOptions.Builder.addNetworkConfig;
import static org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_DEFAULT_FENCEMODE; import static org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_DEFAULT_FENCEMODE;
import static org.testng.Assert.assertEquals;
import java.io.IOException; import java.io.IOException;
import java.net.URI; import java.net.URI;
@ -41,6 +40,7 @@ import org.jclouds.vcloud.domain.internal.ReferenceTypeImpl;
import org.jclouds.vcloud.domain.network.FenceMode; import org.jclouds.vcloud.domain.network.FenceMode;
import org.jclouds.vcloud.domain.network.NetworkConfig; import org.jclouds.vcloud.domain.network.NetworkConfig;
import org.jclouds.vcloud.endpoints.Network; import org.jclouds.vcloud.endpoints.Network;
import org.jclouds.vcloud.internal.BasePayloadTest;
import org.jclouds.vcloud.options.InstantiateVAppTemplateOptions; import org.jclouds.vcloud.options.InstantiateVAppTemplateOptions;
import org.nnsoft.guice.rocoto.Rocoto; import org.nnsoft.guice.rocoto.Rocoto;
import org.nnsoft.guice.rocoto.configuration.ConfigurationModule; import org.nnsoft.guice.rocoto.configuration.ConfigurationModule;
@ -66,7 +66,7 @@ import com.google.inject.Provides;
* @author Adrian Cole * @author Adrian Cole
*/ */
@Test(groups = "unit") @Test(groups = "unit")
public class BindInstantiateVAppTemplateParamsToXmlPayloadTest { public class BindInstantiateVAppTemplateParamsToXmlPayloadTest extends BasePayloadTest {
Injector createInjector(final URI vAppTemplate, final VAppTemplate value) { Injector createInjector(final URI vAppTemplate, final VAppTemplate value) {
return Guice.createInjector(Rocoto.expandVariables(new ConfigurationModule() { return Guice.createInjector(Rocoto.expandVariables(new ConfigurationModule() {
@ -109,15 +109,10 @@ public class BindInstantiateVAppTemplateParamsToXmlPayloadTest {
public void testDefault() throws IOException { public void testDefault() throws IOException {
URI templateUri = URI.create("https://vcenterprise.bluelock.com/api/v1.0/vAppTemplate/3"); URI templateUri = URI.create("https://vcenterprise.bluelock.com/api/v1.0/vAppTemplate/3");
VAppTemplate template = createMock(VAppTemplate.class); VAppTemplate template = createMock(VAppTemplate.class);
replay(template);
String expected = Strings2.toStringAndClose(getClass().getResourceAsStream("/instantiationparams.xml")); String expected = Strings2.toStringAndClose(getClass().getResourceAsStream("/instantiationparams.xml"));
GeneratedHttpRequest request = createMock(GeneratedHttpRequest.class); GeneratedHttpRequest request = requestForArgs(ImmutableList.<Object> of(new InstantiateVAppTemplateOptions()));
expect(request.getEndpoint()).andReturn(URI.create("http://localhost/key")).anyTimes();
expect(request.getArgs()).andReturn(ImmutableList.<Object> of(new InstantiateVAppTemplateOptions()))
.atLeastOnce();
request.setPayload(expected);
replay(request, template);
BindInstantiateVAppTemplateParamsToXmlPayload binder = createInjector(templateUri, template).getInstance( BindInstantiateVAppTemplateParamsToXmlPayload binder = createInjector(templateUri, template).getInstance(
BindInstantiateVAppTemplateParamsToXmlPayload.class); BindInstantiateVAppTemplateParamsToXmlPayload.class);
@ -125,24 +120,17 @@ public class BindInstantiateVAppTemplateParamsToXmlPayloadTest {
Map<String, Object> map = Maps.newHashMap(); Map<String, Object> map = Maps.newHashMap();
map.put("name", "my-vapp"); map.put("name", "my-vapp");
map.put("template", templateUri.toASCIIString()); map.put("template", templateUri.toASCIIString());
binder.bindToRequest(request, map); assertEquals(binder.bindToRequest(request, map).getPayload().getRawContent(), expected);
verify(request, template);
} }
public void testDescription() throws IOException { public void testDescription() throws IOException {
URI templateUri = URI.create("https://vcenterprise.bluelock.com/api/v1.0/vAppTemplate/3"); URI templateUri = URI.create("https://vcenterprise.bluelock.com/api/v1.0/vAppTemplate/3");
VAppTemplate template = createMock(VAppTemplate.class); VAppTemplate template = createMock(VAppTemplate.class);
replay(template);
String expected = Strings2.toStringAndClose(getClass() String expected = Strings2.toStringAndClose(getClass()
.getResourceAsStream("/instantiationparams-description.xml")); .getResourceAsStream("/instantiationparams-description.xml"));
GeneratedHttpRequest request = createMock(GeneratedHttpRequest.class); GeneratedHttpRequest request = requestForArgs(ImmutableList.<Object> of(new InstantiateVAppTemplateOptions().description("my foo")));
expect(request.getEndpoint()).andReturn(URI.create("http://localhost/key")).anyTimes();
expect(request.getArgs()).andReturn(
ImmutableList.<Object> of(new InstantiateVAppTemplateOptions().description("my foo"))).atLeastOnce();
request.setPayload(expected);
replay(request, template);
BindInstantiateVAppTemplateParamsToXmlPayload binder = createInjector(templateUri, template).getInstance( BindInstantiateVAppTemplateParamsToXmlPayload binder = createInjector(templateUri, template).getInstance(
BindInstantiateVAppTemplateParamsToXmlPayload.class); BindInstantiateVAppTemplateParamsToXmlPayload.class);
@ -150,22 +138,16 @@ public class BindInstantiateVAppTemplateParamsToXmlPayloadTest {
Map<String, Object> map = Maps.newHashMap(); Map<String, Object> map = Maps.newHashMap();
map.put("name", "my-vapp"); map.put("name", "my-vapp");
map.put("template", templateUri.toASCIIString()); map.put("template", templateUri.toASCIIString());
binder.bindToRequest(request, map); assertEquals(binder.bindToRequest(request, map).getPayload().getRawContent(), expected);
verify(request, template);
} }
public void testWhenTemplateDoesntExist() throws IOException { public void testWhenTemplateDoesntExist() throws IOException {
URI templateUri = URI.create("https://vcenterprise.bluelock.com/api/v1.0/vAppTemplate/3"); URI templateUri = URI.create("https://vcenterprise.bluelock.com/api/v1.0/vAppTemplate/3");
VAppTemplate template = createMock(VAppTemplate.class); VAppTemplate template = createMock(VAppTemplate.class);
replay(template);
String expected = Strings2.toStringAndClose(getClass().getResourceAsStream("/instantiationparams.xml")); String expected = Strings2.toStringAndClose(getClass().getResourceAsStream("/instantiationparams.xml"));
GeneratedHttpRequest request = createMock(GeneratedHttpRequest.class); GeneratedHttpRequest request = requestForArgs(ImmutableList.<Object> of());
expect(request.getEndpoint()).andReturn(URI.create("http://localhost/key")).anyTimes();
expect(request.getArgs()).andReturn(ImmutableList.<Object> of()).atLeastOnce();
request.setPayload(expected);
replay(request, template);
BindInstantiateVAppTemplateParamsToXmlPayload binder = createInjector(templateUri, template).getInstance( BindInstantiateVAppTemplateParamsToXmlPayload binder = createInjector(templateUri, template).getInstance(
BindInstantiateVAppTemplateParamsToXmlPayload.class); BindInstantiateVAppTemplateParamsToXmlPayload.class);
@ -173,52 +155,19 @@ public class BindInstantiateVAppTemplateParamsToXmlPayloadTest {
Map<String, Object> map = Maps.newHashMap(); Map<String, Object> map = Maps.newHashMap();
map.put("name", "my-vapp"); map.put("name", "my-vapp");
map.put("template", templateUri.toASCIIString()); map.put("template", templateUri.toASCIIString());
binder.bindToRequest(request, map); assertEquals(binder.bindToRequest(request, map).getPayload().getRawContent(), expected);
verify(request, template);
}
// TODO!!! figure out how to get this to work
@Test(enabled = false)
public void testWithProcessorMemoryDisk() throws IOException {
URI templateUri = URI.create("https://vcenterprise.bluelock.com/api/v1.0/vAppTemplate/3");
VAppTemplate template = null;
InstantiateVAppTemplateOptions options = new InstantiateVAppTemplateOptions();
String expected = Strings2.toStringAndClose(getClass().getResourceAsStream("/instantiationparams.xml"));
GeneratedHttpRequest request = createMock(GeneratedHttpRequest.class);
expect(request.getEndpoint()).andReturn(URI.create("http://localhost/key")).anyTimes();
expect(request.getArgs()).andReturn(ImmutableList.<Object> of(options)).atLeastOnce();
request.setPayload(expected);
replay(request);
BindInstantiateVAppTemplateParamsToXmlPayload binder = createInjector(templateUri, template).getInstance(
BindInstantiateVAppTemplateParamsToXmlPayload.class);
Map<String, Object> map = Maps.newHashMap();
map.put("name", "my-vapp");
map.put("template", "https://vcenterprise.bluelock.com/api/v1.0/vAppTemplate/3");
binder.bindToRequest(request, map);
verify(request);
} }
public void testWithNetworkNameFenceMode() throws IOException { public void testWithNetworkNameFenceMode() throws IOException {
URI templateUri = URI.create("https://vcenterprise.bluelock.com/api/v1.0/vAppTemplate/3"); URI templateUri = URI.create("https://vcenterprise.bluelock.com/api/v1.0/vAppTemplate/3");
VAppTemplate template = createMock(VAppTemplate.class); VAppTemplate template = createMock(VAppTemplate.class);
replay(template);
InstantiateVAppTemplateOptions options = addNetworkConfig(new NetworkConfig("aloha", URI InstantiateVAppTemplateOptions options = addNetworkConfig(new NetworkConfig("aloha", URI
.create("https://vcenterprise.bluelock.com/api/v1.0/network/1991"), FenceMode.NAT_ROUTED)); .create("https://vcenterprise.bluelock.com/api/v1.0/network/1991"), FenceMode.NAT_ROUTED));
String expected = Strings2.toStringAndClose(getClass().getResourceAsStream("/instantiationparams-network.xml")); String expected = Strings2.toStringAndClose(getClass().getResourceAsStream("/instantiationparams-network.xml"));
GeneratedHttpRequest request = requestForArgs(ImmutableList.<Object> of(options));
GeneratedHttpRequest request = createMock(GeneratedHttpRequest.class);
expect(request.getEndpoint()).andReturn(URI.create("http://localhost/key")).anyTimes();
expect(request.getArgs()).andReturn(ImmutableList.<Object> of(options)).atLeastOnce();
request.setPayload(expected);
replay(request, template);
BindInstantiateVAppTemplateParamsToXmlPayload binder = createInjector(templateUri, template).getInstance( BindInstantiateVAppTemplateParamsToXmlPayload binder = createInjector(templateUri, template).getInstance(
BindInstantiateVAppTemplateParamsToXmlPayload.class); BindInstantiateVAppTemplateParamsToXmlPayload.class);
@ -227,7 +176,6 @@ public class BindInstantiateVAppTemplateParamsToXmlPayloadTest {
map.put("name", "my-vapp"); map.put("name", "my-vapp");
map.put("template", "https://vcenterprise.bluelock.com/api/v1.0/vAppTemplate/3"); map.put("template", "https://vcenterprise.bluelock.com/api/v1.0/vAppTemplate/3");
binder.bindToRequest(request, map); assertEquals(binder.bindToRequest(request, map).getPayload().getRawContent(), expected);
verify(request, template);
} }
} }

View File

@ -24,17 +24,13 @@ import java.io.IOException;
import java.net.URI; import java.net.URI;
import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpRequest;
import org.jclouds.vcloud.VCloudApiMetadata;
import org.jclouds.vcloud.domain.NetworkConnection; import org.jclouds.vcloud.domain.NetworkConnection;
import org.jclouds.vcloud.domain.NetworkConnectionSection; import org.jclouds.vcloud.domain.NetworkConnectionSection;
import org.jclouds.vcloud.domain.network.IpAddressAllocationMode; import org.jclouds.vcloud.domain.network.IpAddressAllocationMode;
import org.nnsoft.guice.rocoto.Rocoto; import org.jclouds.vcloud.internal.BasePayloadTest;
import org.nnsoft.guice.rocoto.configuration.ConfigurationModule;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.inject.Guice;
import com.google.inject.Injector;
/** /**
* Tests behavior of {@code BindNetworkConnectionSectionToXmlPayload} * Tests behavior of {@code BindNetworkConnectionSectionToXmlPayload}
@ -42,14 +38,7 @@ import com.google.inject.Injector;
* @author Adrian Cole * @author Adrian Cole
*/ */
@Test(groups = "unit", testName = "BindNetworkConnectionSectionToXmlPayloadTest") @Test(groups = "unit", testName = "BindNetworkConnectionSectionToXmlPayloadTest")
public class BindNetworkConnectionSectionToXmlPayloadTest { public class BindNetworkConnectionSectionToXmlPayloadTest extends BasePayloadTest {
Injector injector = Guice.createInjector(Rocoto.expandVariables(new ConfigurationModule() {
@Override
protected void bindConfigurations() {
bindProperties(new VCloudApiMetadata().getDefaultProperties());
}
}));
public void testWithIpAllocationModeNONE() throws IOException { public void testWithIpAllocationModeNONE() throws IOException {

View File

@ -18,24 +18,17 @@
*/ */
package org.jclouds.vcloud.binders; package org.jclouds.vcloud.binders;
import static org.easymock.EasyMock.createMock; import static org.testng.Assert.assertEquals;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
import java.io.IOException; import java.io.IOException;
import java.net.URI;
import java.util.Map; import java.util.Map;
import org.jclouds.rest.internal.GeneratedHttpRequest; import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.jclouds.vcloud.VCloudApiMetadata; import org.jclouds.vcloud.internal.BasePayloadTest;
import org.nnsoft.guice.rocoto.Rocoto;
import org.nnsoft.guice.rocoto.configuration.ConfigurationModule;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.google.inject.Guice;
import com.google.inject.Injector;
/** /**
* Tests behavior of {@code BindUndeployVAppParamsToXmlPayload} * Tests behavior of {@code BindUndeployVAppParamsToXmlPayload}
@ -43,44 +36,28 @@ import com.google.inject.Injector;
* @author Adrian Cole * @author Adrian Cole
*/ */
@Test(groups = "unit") @Test(groups = "unit")
public class BindUndeployVAppParamsToXmlPayloadTest { public class BindUndeployVAppParamsToXmlPayloadTest extends BasePayloadTest {
Injector injector = Guice.createInjector(Rocoto.expandVariables(new ConfigurationModule() {
@Override
protected void bindConfigurations() {
bindProperties(new VCloudApiMetadata().getDefaultProperties());
}
}));
public void testSaveStateTrue() throws IOException { public void testSaveStateTrue() throws IOException {
String expected = "<UndeployVAppParams xmlns=\"http://www.vmware.com/vcloud/v1\" saveState=\"true\"/>"; String expected = "<UndeployVAppParams xmlns=\"http://www.vmware.com/vcloud/v1\" saveState=\"true\"/>";
GeneratedHttpRequest request = createMock(GeneratedHttpRequest.class); GeneratedHttpRequest request = requestForArgs(ImmutableList.<Object> of());
expect(request.getEndpoint()).andReturn(URI.create("http://localhost/key")).anyTimes();
request.setPayload(expected);
replay(request);
BindUndeployVAppParamsToXmlPayload binder = injector.getInstance(BindUndeployVAppParamsToXmlPayload.class); BindUndeployVAppParamsToXmlPayload binder = injector.getInstance(BindUndeployVAppParamsToXmlPayload.class);
Map<String, Object> map = Maps.newHashMap(); Map<String, Object> map = Maps.newHashMap();
map.put("saveState", "true"); map.put("saveState", "true");
binder.bindToRequest(request, map); assertEquals(binder.bindToRequest(request, map).getPayload().getRawContent(), expected);
verify(request);
} }
public void testDefault() throws IOException { public void testDefault() throws IOException {
String expected = "<UndeployVAppParams xmlns=\"http://www.vmware.com/vcloud/v1\"/>"; String expected = "<UndeployVAppParams xmlns=\"http://www.vmware.com/vcloud/v1\"/>";
GeneratedHttpRequest request = createMock(GeneratedHttpRequest.class); GeneratedHttpRequest request = requestForArgs(ImmutableList.<Object> of());
expect(request.getEndpoint()).andReturn(URI.create("http://localhost/key")).anyTimes();
request.setPayload(expected);
replay(request);
BindUndeployVAppParamsToXmlPayload binder = injector.getInstance(BindUndeployVAppParamsToXmlPayload.class); BindUndeployVAppParamsToXmlPayload binder = injector.getInstance(BindUndeployVAppParamsToXmlPayload.class);
Map<String, Object> map = Maps.newHashMap(); Map<String, Object> map = Maps.newHashMap();
assertEquals(binder.bindToRequest(request, map).getPayload().getRawContent(), expected);
binder.bindToRequest(request, map);
verify(request);
} }
} }

View File

@ -0,0 +1,54 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.jclouds.vcloud.internal;
import java.net.URI;
import java.util.List;
import org.jclouds.reflect.Invocation;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.jclouds.vcloud.VCloudApiMetadata;
import org.nnsoft.guice.rocoto.Rocoto;
import org.nnsoft.guice.rocoto.configuration.ConfigurationModule;
import com.google.common.base.Throwables;
import com.google.common.reflect.Invokable;
import com.google.inject.Guice;
import com.google.inject.Injector;
public class BasePayloadTest {
protected Injector injector = Guice.createInjector(Rocoto.expandVariables(new ConfigurationModule() {
protected void bindConfigurations() {
bindProperties(new VCloudApiMetadata().getDefaultProperties());
}
}));
protected GeneratedHttpRequest requestForArgs(List<Object> args) {
try {
Invocation invocation = Invocation.create(Invokable.from(String.class.getDeclaredMethod("toString")), args);
return GeneratedHttpRequest.builder().method("POST").endpoint(URI.create("http://localhost/key"))
.invocation(invocation).build();
} catch (SecurityException e) {
throw Throwables.propagate(e);
} catch (NoSuchMethodException e) {
throw Throwables.propagate(e);
}
}
}

View File

@ -20,6 +20,7 @@ package org.jclouds.blobstore.util;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@ -60,12 +61,13 @@ public class BlobStoreUtils {
public static String getNameFor(GeneratedHttpRequest request) { public static String getNameFor(GeneratedHttpRequest request) {
checkNotNull(request, "request"); checkNotNull(request, "request");
List<Object> args = request.getInvocation().getArgs();
// assume first params are container and key // assume first params are container and key
if (request.getArgs().size() >= 2 && request.getArgs().get(0) instanceof String if (args.size() >= 2 && args.get(0) instanceof String
&& request.getArgs().get(1) instanceof String) { && args.get(1) instanceof String) {
return request.getArgs().get(1).toString(); return args.get(1).toString();
} else if (request.getArgs().size() >= 1 && request.getArgs().get(0) instanceof String) { } else if (args.size() >= 1 && args.get(0) instanceof String) {
Matcher matcher = keyFromContainer.matcher(request.getArgs().get(0).toString()); Matcher matcher = keyFromContainer.matcher(args.get(0).toString());
if (matcher.find()) if (matcher.find())
return matcher.group(1); return matcher.group(1);
} }

View File

@ -27,16 +27,20 @@ import static org.jclouds.blobstore.util.BlobStoreUtils.getNameFor;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import java.net.URI; import java.net.URI;
import java.util.List;
import org.jclouds.blobstore.AsyncBlobStore; import org.jclouds.blobstore.AsyncBlobStore;
import org.jclouds.blobstore.domain.Blob; import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.MutableBlobMetadata; import org.jclouds.blobstore.domain.MutableBlobMetadata;
import org.jclouds.reflect.Invocation;
import org.jclouds.rest.Providers; import org.jclouds.rest.Providers;
import org.jclouds.rest.internal.GeneratedHttpRequest; import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.common.reflect.Invokable;
/** /**
* Tests behavior of {@code BlobStoreUtils} * Tests behavior of {@code BlobStoreUtils}
@ -121,30 +125,28 @@ public class BlobStoreUtilsTest {
} }
public void testGetKeyForAzureS3AndRackspace() { public void testGetKeyForAzureS3AndRackspace() {
GeneratedHttpRequest request = requestForEndpointAndArgs(
GeneratedHttpRequest request = createMock(GeneratedHttpRequest.class); "https://jclouds.blob.core.windows.net/adriancole-blobstore0/five",
ImmutableList.<Object> of("adriancole-blobstore0", "five"));
expect(request.getEndpoint()).andReturn(
URI.create("https://jclouds.blob.core.windows.net/adriancole-blobstore0/five"));
expect(request.getArgs()).andReturn(ImmutableList.<Object> of("adriancole-blobstore0", "five")).atLeastOnce();
replay(request);
assertEquals(getNameFor(request), "five"); assertEquals(getNameFor(request), "five");
} }
public void testGetKeyForAtmos() { public void testGetKeyForAtmos() {
GeneratedHttpRequest request = requestForEndpointAndArgs(
GeneratedHttpRequest request = createMock(GeneratedHttpRequest.class); "https://storage4.clouddrive.com/v1/MossoCloudFS_dc1f419c-5059-4c87-a389-3f2e33a77b22/adriancole-blobstore0/four",
ImmutableList.<Object> of("adriancole-blobstore0/four"));
expect(request.getEndpoint())
.andReturn(
URI.create("https://storage4.clouddrive.com/v1/MossoCloudFS_dc1f419c-5059-4c87-a389-3f2e33a77b22/adriancole-blobstore0/four"));
expect(request.getArgs()).andReturn(ImmutableList.<Object> of("adriancole-blobstore0/four")).atLeastOnce();
replay(request);
assertEquals(getNameFor(request), "four"); assertEquals(getNameFor(request), "four");
} }
GeneratedHttpRequest requestForEndpointAndArgs(String endpoint, List<Object> args) {
try {
Invocation invocation = Invocation.create(Invokable.from(String.class.getDeclaredMethod("toString")), args);
return GeneratedHttpRequest.builder().method("POST").endpoint(URI.create(endpoint)).invocation(invocation)
.build();
} catch (SecurityException e) {
throw Throwables.propagate(e);
} catch (NoSuchMethodException e) {
throw Throwables.propagate(e);
}
}
} }

View File

@ -213,7 +213,7 @@ public class AWSUtils {
} }
public static String findRegionInArgsOrNull(GeneratedHttpRequest gRequest) { public static String findRegionInArgsOrNull(GeneratedHttpRequest gRequest) {
for (Object arg : gRequest.getArgs()) { for (Object arg : gRequest.getInvocation().getArgs()) {
if (arg instanceof String) { if (arg instanceof String) {
String regionName = (String) arg; String regionName = (String) arg;
// TODO regions may not be amazon regions! // TODO regions may not be amazon regions!

View File

@ -68,7 +68,6 @@ public class BindCloneVAppParamsToXmlPayload implements MapBinder {
checkArgument(checkNotNull(request, "request") instanceof GeneratedHttpRequest, checkArgument(checkNotNull(request, "request") instanceof GeneratedHttpRequest,
"this binder is only valid for GeneratedHttpRequests!"); "this binder is only valid for GeneratedHttpRequests!");
GeneratedHttpRequest gRequest = (GeneratedHttpRequest) request; GeneratedHttpRequest gRequest = (GeneratedHttpRequest) request;
checkState(gRequest.getArgs() != null, "args should be initialized at this point");
String newName = checkNotNull(postParams.remove("newName"), "newName").toString(); String newName = checkNotNull(postParams.remove("newName"), "newName").toString();
String vApp = checkNotNull(postParams.remove("vApp"), "vApp").toString(); String vApp = checkNotNull(postParams.remove("vApp"), "vApp").toString();
@ -108,7 +107,7 @@ public class BindCloneVAppParamsToXmlPayload implements MapBinder {
} }
protected CloneVAppOptions findOptionsInArgsOrNull(GeneratedHttpRequest gRequest) { protected CloneVAppOptions findOptionsInArgsOrNull(GeneratedHttpRequest gRequest) {
for (Object arg : gRequest.getArgs()) { for (Object arg : gRequest.getInvocation().getArgs()) {
if (arg instanceof CloneVAppOptions) { if (arg instanceof CloneVAppOptions) {
return (CloneVAppOptions) arg; return (CloneVAppOptions) arg;
} else if (arg instanceof CloneVAppOptions[]) { } else if (arg instanceof CloneVAppOptions[]) {

View File

@ -87,7 +87,6 @@ public class BindInstantiateVAppTemplateParamsToXmlPayload implements MapBinder
checkArgument(checkNotNull(request, "request") instanceof GeneratedHttpRequest, checkArgument(checkNotNull(request, "request") instanceof GeneratedHttpRequest,
"this binder is only valid for GeneratedHttpRequests!"); "this binder is only valid for GeneratedHttpRequests!");
GeneratedHttpRequest gRequest = (GeneratedHttpRequest) request; GeneratedHttpRequest gRequest = (GeneratedHttpRequest) request;
checkState(gRequest.getArgs() != null, "args should be initialized at this point");
String name = checkNotNull(postParams.remove("name"), "name").toString(); String name = checkNotNull(postParams.remove("name"), "name").toString();
String template = checkNotNull(postParams.remove("template"), "template").toString(); String template = checkNotNull(postParams.remove("template"), "template").toString();
@ -174,7 +173,7 @@ public class BindInstantiateVAppTemplateParamsToXmlPayload implements MapBinder
protected InstantiateVAppTemplateOptions findOptionsInArgsOrNull(GeneratedHttpRequest gRequest) { protected InstantiateVAppTemplateOptions findOptionsInArgsOrNull(GeneratedHttpRequest gRequest) {
InstantiateVAppTemplateOptions options = null; InstantiateVAppTemplateOptions options = null;
for (Object arg : gRequest.getArgs()) { for (Object arg : gRequest.getInvocation().getArgs()) {
if (arg instanceof InstantiateVAppTemplateOptions) { if (arg instanceof InstantiateVAppTemplateOptions) {
options = (InstantiateVAppTemplateOptions) arg; options = (InstantiateVAppTemplateOptions) arg;
} else if (arg instanceof InstantiateVAppTemplateOptions[]) { } else if (arg instanceof InstantiateVAppTemplateOptions[]) {

View File

@ -82,8 +82,6 @@ public class BindVAppConfigurationToXmlPayload implements MapBinder, Function<Ob
checkArgument(checkNotNull(request, "request") instanceof GeneratedHttpRequest, checkArgument(checkNotNull(request, "request") instanceof GeneratedHttpRequest,
"this binder is only valid for GeneratedHttpRequests!"); "this binder is only valid for GeneratedHttpRequests!");
GeneratedHttpRequest gRequest = (GeneratedHttpRequest) request; GeneratedHttpRequest gRequest = (GeneratedHttpRequest) request;
checkState(gRequest.getArgs() != null, "args should be initialized at this point");
VApp vApp = checkNotNull(findVAppInArgsOrNull(gRequest), "vApp"); VApp vApp = checkNotNull(findVAppInArgsOrNull(gRequest), "vApp");
checkArgument(vApp.getStatus() == Status.OFF, "vApp must be off!"); checkArgument(vApp.getStatus() == Status.OFF, "vApp must be off!");
VAppConfiguration configuration = checkNotNull(findConfigInArgsOrNull(gRequest), "config"); VAppConfiguration configuration = checkNotNull(findConfigInArgsOrNull(gRequest), "config");
@ -182,7 +180,7 @@ public class BindVAppConfigurationToXmlPayload implements MapBinder, Function<Ob
} }
protected VApp findVAppInArgsOrNull(GeneratedHttpRequest gRequest) { protected VApp findVAppInArgsOrNull(GeneratedHttpRequest gRequest) {
for (Object arg : gRequest.getArgs()) { for (Object arg : gRequest.getInvocation().getArgs()) {
if (arg instanceof VApp) { if (arg instanceof VApp) {
return (VApp) arg; return (VApp) arg;
} else if (arg instanceof VApp[]) { } else if (arg instanceof VApp[]) {
@ -194,7 +192,7 @@ public class BindVAppConfigurationToXmlPayload implements MapBinder, Function<Ob
} }
protected VAppConfiguration findConfigInArgsOrNull(GeneratedHttpRequest gRequest) { protected VAppConfiguration findConfigInArgsOrNull(GeneratedHttpRequest gRequest) {
for (Object arg : gRequest.getArgs()) { for (Object arg : gRequest.getInvocation().getArgs()) {
if (arg instanceof VAppConfiguration) { if (arg instanceof VAppConfiguration) {
return (VAppConfiguration) arg; return (VAppConfiguration) arg;
} else if (arg instanceof VAppConfiguration[]) { } else if (arg instanceof VAppConfiguration[]) {

View File

@ -48,7 +48,7 @@ public class KeyPairByNameHandler extends ParseSax.HandlerForGeneratedRequestWit
@Override @Override
public KeyPair getResult() { public KeyPair getResult() {
final String name = getRequest().getArgs().get(1).toString(); final String name = getRequest().getInvocation().getArgs().get(1).toString();
try { try {
return Iterables.find(handler.getResult(), new Predicate<KeyPair>() { return Iterables.find(handler.getResult(), new Predicate<KeyPair>() {
@ -59,7 +59,8 @@ public class KeyPairByNameHandler extends ParseSax.HandlerForGeneratedRequestWit
}); });
} catch (NoSuchElementException e) { } catch (NoSuchElementException e) {
logger.debug("keypair %s/%s not found in %s", getRequest().getArgs().get(0), name, handler.getResult()); logger.debug("keypair %s/%s not found in %s", getRequest().getInvocation().getArgs().get(0), name,
handler.getResult());
return null; return null;
} }
} }

View File

@ -64,11 +64,9 @@ public class BindAddNodeServiceToXmlPayloadTest {
}); });
public void testApplyInputStream() throws IOException { public void testApplyInputStream() throws IOException {
String expected = Strings2.toStringAndClose(getClass().getResourceAsStream( String expected = Strings2.toStringAndClose(getClass().getResourceAsStream("/CreateNodeService-test.xml"));
"/CreateNodeService-test.xml"));
HttpRequest request = HttpRequest.builder().method("GET").endpoint("http://test").build(); HttpRequest request = HttpRequest.builder().method("GET").endpoint("http://test").build();
BindAddNodeServiceToXmlPayload binder = injector BindAddNodeServiceToXmlPayload binder = injector.getInstance(BindAddNodeServiceToXmlPayload.class);
.getInstance(BindAddNodeServiceToXmlPayload.class);
Map<String, Object> map = Maps.newHashMap(); Map<String, Object> map = Maps.newHashMap();
map.put("name", "Node for Jim"); map.put("name", "Node for Jim");
@ -76,8 +74,6 @@ public class BindAddNodeServiceToXmlPayloadTest {
map.put("port", "80"); map.put("port", "80");
map.put("enabled", "false"); map.put("enabled", "false");
map.put("description", "Some test node"); map.put("description", "Some test node");
binder.bindToRequest(request, map); assertEquals(binder.bindToRequest(request, map).getPayload().getRawContent(), expected);
assertEquals(request.getPayload().getRawContent(), expected);
} }
} }

View File

@ -24,13 +24,14 @@ import java.util.Map;
import java.util.Properties; import java.util.Properties;
import org.jclouds.rest.internal.GeneratedHttpRequest; import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.jclouds.trmk.vcloud_0_8.internal.BasePayloadTest;
import org.jclouds.trmk.vcloud_0_8.internal.TerremarkVCloudApiMetadata; import org.jclouds.trmk.vcloud_0_8.internal.TerremarkVCloudApiMetadata;
import org.jclouds.trmk.vcloud_0_8.options.CloneVAppOptions; import org.jclouds.trmk.vcloud_0_8.options.CloneVAppOptions;
import org.jclouds.util.Strings2; import org.jclouds.util.Strings2;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.google.common.reflect.Invokable;
import com.google.inject.AbstractModule; import com.google.inject.AbstractModule;
import com.google.inject.Guice; import com.google.inject.Guice;
import com.google.inject.Injector; import com.google.inject.Injector;
@ -42,7 +43,7 @@ import com.google.inject.name.Names;
* @author Adrian Cole * @author Adrian Cole
*/ */
@Test(groups = "unit") @Test(groups = "unit")
public class BindCloneVAppParamsToXmlPayloadTest { public class BindCloneVAppParamsToXmlPayloadTest extends BasePayloadTest {
Injector injector = Guice.createInjector(new AbstractModule() { Injector injector = Guice.createInjector(new AbstractModule() {
@Override @Override
@ -59,9 +60,7 @@ public class BindCloneVAppParamsToXmlPayloadTest {
CloneVAppOptions options = new CloneVAppOptions().deploy().powerOn().withDescription( CloneVAppOptions options = new CloneVAppOptions().deploy().powerOn().withDescription(
"The description of the new vApp"); "The description of the new vApp");
GeneratedHttpRequest request = GeneratedHttpRequest.builder().method("POST").endpoint("http://localhost/key") GeneratedHttpRequest request = requestForArgs(ImmutableList.<Object> of(options));
.declaring(String.class).invoker(Invokable.from(String.class.getDeclaredMethod("toString"))).arg(options).build();
BindCloneVAppParamsToXmlPayload binder = injector.getInstance(BindCloneVAppParamsToXmlPayload.class); BindCloneVAppParamsToXmlPayload binder = injector.getInstance(BindCloneVAppParamsToXmlPayload.class);
@ -74,8 +73,7 @@ public class BindCloneVAppParamsToXmlPayloadTest {
public void testDefault() throws Exception { public void testDefault() throws Exception {
String expected = Strings2.toStringAndClose(getClass().getResourceAsStream("/cloneVApp-default.xml")); String expected = Strings2.toStringAndClose(getClass().getResourceAsStream("/cloneVApp-default.xml"));
GeneratedHttpRequest request = GeneratedHttpRequest.builder().method("POST").endpoint("http://localhost/key") GeneratedHttpRequest request = requestForArgs(ImmutableList.<Object> of());
.declaring(String.class).invoker(Invokable.from(String.class.getDeclaredMethod("toString"))).build();
BindCloneVAppParamsToXmlPayload binder = injector.getInstance(BindCloneVAppParamsToXmlPayload.class); BindCloneVAppParamsToXmlPayload binder = injector.getInstance(BindCloneVAppParamsToXmlPayload.class);

View File

@ -18,9 +18,7 @@
*/ */
package org.jclouds.trmk.vcloud_0_8.binders; package org.jclouds.trmk.vcloud_0_8.binders;
import static org.easymock.EasyMock.createMock; import static org.testng.Assert.assertEquals;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import java.io.IOException; import java.io.IOException;
import java.net.URI; import java.net.URI;
@ -32,6 +30,7 @@ import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.jclouds.trmk.vcloud_0_8.domain.ReferenceType; import org.jclouds.trmk.vcloud_0_8.domain.ReferenceType;
import org.jclouds.trmk.vcloud_0_8.domain.internal.ReferenceTypeImpl; import org.jclouds.trmk.vcloud_0_8.domain.internal.ReferenceTypeImpl;
import org.jclouds.trmk.vcloud_0_8.endpoints.Network; import org.jclouds.trmk.vcloud_0_8.endpoints.Network;
import org.jclouds.trmk.vcloud_0_8.internal.BasePayloadTest;
import org.jclouds.trmk.vcloud_0_8.internal.TerremarkVCloudApiMetadata; import org.jclouds.trmk.vcloud_0_8.internal.TerremarkVCloudApiMetadata;
import org.jclouds.trmk.vcloud_0_8.options.InstantiateVAppTemplateOptions; import org.jclouds.trmk.vcloud_0_8.options.InstantiateVAppTemplateOptions;
import org.jclouds.trmk.vcloud_0_8.options.InstantiateVAppTemplateOptions.NetworkConfig; import org.jclouds.trmk.vcloud_0_8.options.InstantiateVAppTemplateOptions.NetworkConfig;
@ -42,11 +41,8 @@ import org.testng.annotations.Test;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
import com.google.common.base.Suppliers; import com.google.common.base.Suppliers;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
import com.google.inject.Guice; import com.google.inject.Guice;
import com.google.inject.Injector; import com.google.inject.Injector;
import com.google.inject.Provides; import com.google.inject.Provides;
@ -57,7 +53,7 @@ import com.google.inject.Provides;
* @author Adrian Cole * @author Adrian Cole
*/ */
@Test(groups = "unit") @Test(groups = "unit")
public class BindInstantiateVAppTemplateParamsToXmlPayloadTest { public class BindInstantiateVAppTemplateParamsToXmlPayloadTest extends BasePayloadTest {
Injector injector = Guice.createInjector(Rocoto.expandVariables(new ConfigurationModule() { Injector injector = Guice.createInjector(Rocoto.expandVariables(new ConfigurationModule() {
@Override @Override
@ -78,17 +74,10 @@ public class BindInstantiateVAppTemplateParamsToXmlPayloadTest {
String expected = Strings2.toStringAndClose(getClass().getResourceAsStream( String expected = Strings2.toStringAndClose(getClass().getResourceAsStream(
"/InstantiateVAppTemplateParams-options-test.xml")); "/InstantiateVAppTemplateParams-options-test.xml"));
Multimap<String, String> headers = Multimaps.synchronizedMultimap(HashMultimap.<String, String> create());
GeneratedHttpRequest request = createMock(GeneratedHttpRequest.class); GeneratedHttpRequest request = requestForArgs(ImmutableList.<Object> of(InstantiateVAppTemplateOptions.Builder
expect(request.getEndpoint()).andReturn(URI.create("http://localhost/key")).anyTimes(); .processorCount(2).memory(512).inGroup("group").withPassword("password").inRow("row")
expect(request.getArgs()).andReturn( .addNetworkConfig(new NetworkConfig(URI.create("http://network")))));
ImmutableList.<Object> of(InstantiateVAppTemplateOptions.Builder.processorCount(2).memory(512)
.inGroup("group").withPassword("password").inRow("row")
.addNetworkConfig(new NetworkConfig(URI.create("http://network"))))).atLeastOnce();
expect(request.getFirstHeaderOrNull("Content-Type")).andReturn("application/unknown").atLeastOnce();
expect(request.getHeaders()).andReturn(headers).atLeastOnce();
request.setPayload(expected);
replay(request);
BindInstantiateVAppTemplateParamsToXmlPayload binder = injector BindInstantiateVAppTemplateParamsToXmlPayload binder = injector
.getInstance(BindInstantiateVAppTemplateParamsToXmlPayload.class); .getInstance(BindInstantiateVAppTemplateParamsToXmlPayload.class);
@ -96,7 +85,7 @@ public class BindInstantiateVAppTemplateParamsToXmlPayloadTest {
Map<String, Object> map = Maps.newHashMap(); Map<String, Object> map = Maps.newHashMap();
map.put("name", "name"); map.put("name", "name");
map.put("template", "https://vcloud/vAppTemplate/3"); map.put("template", "https://vcloud/vAppTemplate/3");
binder.bindToRequest(request, map); assertEquals(binder.bindToRequest(request, map).getPayload().getRawContent(), expected);
} }
} }

View File

@ -18,11 +18,8 @@
*/ */
package org.jclouds.trmk.vcloud_0_8.binders; package org.jclouds.trmk.vcloud_0_8.binders;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
import static org.jclouds.trmk.vcloud_0_8.domain.VAppConfiguration.Builder.changeNameTo; import static org.jclouds.trmk.vcloud_0_8.domain.VAppConfiguration.Builder.changeNameTo;
import static org.testng.Assert.assertEquals;
import java.io.IOException; import java.io.IOException;
import java.net.URI; import java.net.URI;
@ -35,6 +32,7 @@ import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.jclouds.trmk.vcloud_0_8.domain.Status; import org.jclouds.trmk.vcloud_0_8.domain.Status;
import org.jclouds.trmk.vcloud_0_8.domain.VAppConfiguration; import org.jclouds.trmk.vcloud_0_8.domain.VAppConfiguration;
import org.jclouds.trmk.vcloud_0_8.domain.internal.VAppImpl; import org.jclouds.trmk.vcloud_0_8.domain.internal.VAppImpl;
import org.jclouds.trmk.vcloud_0_8.internal.BasePayloadTest;
import org.jclouds.trmk.vcloud_0_8.internal.TerremarkVCloudApiMetadata; import org.jclouds.trmk.vcloud_0_8.internal.TerremarkVCloudApiMetadata;
import org.jclouds.util.Strings2; import org.jclouds.util.Strings2;
import org.nnsoft.guice.rocoto.Rocoto; import org.nnsoft.guice.rocoto.Rocoto;
@ -54,7 +52,7 @@ import com.google.inject.Injector;
* @author Adrian Cole * @author Adrian Cole
*/ */
@Test(groups = "unit") @Test(groups = "unit")
public class BindVAppConfigurationToXmlPayloadTest { public class BindVAppConfigurationToXmlPayloadTest extends BasePayloadTest {
Injector injector = Guice.createInjector(Rocoto.expandVariables(new ConfigurationModule() { Injector injector = Guice.createInjector(Rocoto.expandVariables(new ConfigurationModule() {
@Override @Override
@ -80,17 +78,11 @@ public class BindVAppConfigurationToXmlPayloadTest {
VAppConfiguration config = new VAppConfiguration().changeNameTo("roberto"); VAppConfiguration config = new VAppConfiguration().changeNameTo("roberto");
GeneratedHttpRequest request = createMock(GeneratedHttpRequest.class); GeneratedHttpRequest request = requestForArgs(ImmutableList.<Object> of(vApp, config));
expect(request.getEndpoint()).andReturn(URI.create("http://localhost/key")).anyTimes();
expect(request.getArgs()).andReturn(ImmutableList.<Object> of(vApp, config)).atLeastOnce();
request.setPayload(expected);
replay(request);
BindVAppConfigurationToXmlPayload binder = injector.getInstance(BindVAppConfigurationToXmlPayload.class); BindVAppConfigurationToXmlPayload binder = injector.getInstance(BindVAppConfigurationToXmlPayload.class);
Map<String, Object> map = Maps.newHashMap(); Map<String, Object> map = Maps.newHashMap();
binder.bindToRequest(request, map); assertEquals(binder.bindToRequest(request, map).getPayload().getRawContent(), expected);
verify(request);
} }
public void testRemoveDisk() throws IOException { public void testRemoveDisk() throws IOException {
@ -116,17 +108,12 @@ public class BindVAppConfigurationToXmlPayloadTest {
VAppConfiguration config = new VAppConfiguration().deleteDiskWithAddressOnParent(1); VAppConfiguration config = new VAppConfiguration().deleteDiskWithAddressOnParent(1);
GeneratedHttpRequest request = createMock(GeneratedHttpRequest.class); GeneratedHttpRequest request = requestForArgs(ImmutableList.<Object> of(vApp, config));
expect(request.getEndpoint()).andReturn(URI.create("http://localhost/key")).anyTimes();
expect(request.getArgs()).andReturn(ImmutableList.<Object> of(vApp, config)).atLeastOnce();
request.setPayload(expected);
replay(request);
BindVAppConfigurationToXmlPayload binder = injector.getInstance(BindVAppConfigurationToXmlPayload.class); BindVAppConfigurationToXmlPayload binder = injector.getInstance(BindVAppConfigurationToXmlPayload.class);
Map<String, Object> map = Maps.newHashMap(); Map<String, Object> map = Maps.newHashMap();
binder.bindToRequest(request, map); assertEquals(binder.bindToRequest(request, map).getPayload().getRawContent(), expected);
verify(request);
} }
public void testChangeAll() throws IOException { public void testChangeAll() throws IOException {
@ -145,17 +132,12 @@ public class BindVAppConfigurationToXmlPayloadTest {
VAppConfiguration config = changeNameTo("eduardo").changeMemoryTo(1536).changeProcessorCountTo(1).addDisk( VAppConfiguration config = changeNameTo("eduardo").changeMemoryTo(1536).changeProcessorCountTo(1).addDisk(
25 * 1048576).addDisk(25 * 1048576); 25 * 1048576).addDisk(25 * 1048576);
GeneratedHttpRequest request = createMock(GeneratedHttpRequest.class); GeneratedHttpRequest request = requestForArgs(ImmutableList.<Object> of(vApp, config));
expect(request.getEndpoint()).andReturn(URI.create("http://localhost/key")).anyTimes();
expect(request.getArgs()).andReturn(ImmutableList.<Object> of(vApp, config)).atLeastOnce();
request.setPayload(expected);
replay(request);
BindVAppConfigurationToXmlPayload binder = injector.getInstance(BindVAppConfigurationToXmlPayload.class); BindVAppConfigurationToXmlPayload binder = injector.getInstance(BindVAppConfigurationToXmlPayload.class);
Map<String, Object> map = Maps.newHashMap(); Map<String, Object> map = Maps.newHashMap();
binder.bindToRequest(request, map); assertEquals(binder.bindToRequest(request, map).getPayload().getRawContent(), expected);
verify(request);
} }
public void testChangeCPUCountTo4() throws IOException { public void testChangeCPUCountTo4() throws IOException {
@ -172,17 +154,12 @@ public class BindVAppConfigurationToXmlPayloadTest {
VAppConfiguration config = new VAppConfiguration().changeProcessorCountTo(4); VAppConfiguration config = new VAppConfiguration().changeProcessorCountTo(4);
GeneratedHttpRequest request = createMock(GeneratedHttpRequest.class); GeneratedHttpRequest request = requestForArgs(ImmutableList.<Object> of(vApp, config));
expect(request.getEndpoint()).andReturn(URI.create("http://localhost/key")).anyTimes();
expect(request.getArgs()).andReturn(ImmutableList.<Object> of(vApp, config)).atLeastOnce();
request.setPayload(expected);
replay(request);
BindVAppConfigurationToXmlPayload binder = injector.getInstance(BindVAppConfigurationToXmlPayload.class); BindVAppConfigurationToXmlPayload binder = injector.getInstance(BindVAppConfigurationToXmlPayload.class);
Map<String, Object> map = Maps.newHashMap(); Map<String, Object> map = Maps.newHashMap();
binder.bindToRequest(request, map); assertEquals(binder.bindToRequest(request, map).getPayload().getRawContent(), expected);
verify(request);
} }
public void testChangeMemoryTo1536() throws IOException { public void testChangeMemoryTo1536() throws IOException {
@ -201,16 +178,11 @@ public class BindVAppConfigurationToXmlPayloadTest {
VAppConfiguration config = new VAppConfiguration().changeMemoryTo(1536); VAppConfiguration config = new VAppConfiguration().changeMemoryTo(1536);
GeneratedHttpRequest request = createMock(GeneratedHttpRequest.class); GeneratedHttpRequest request = requestForArgs(ImmutableList.<Object> of(vApp, config));
expect(request.getEndpoint()).andReturn(URI.create("http://localhost/key")).anyTimes();
expect(request.getArgs()).andReturn(ImmutableList.<Object> of(vApp, config)).atLeastOnce();
request.setPayload(expected);
replay(request);
BindVAppConfigurationToXmlPayload binder = injector.getInstance(BindVAppConfigurationToXmlPayload.class); BindVAppConfigurationToXmlPayload binder = injector.getInstance(BindVAppConfigurationToXmlPayload.class);
Map<String, Object> map = Maps.newHashMap(); Map<String, Object> map = Maps.newHashMap();
binder.bindToRequest(request, map); assertEquals(binder.bindToRequest(request, map).getPayload().getRawContent(), expected);
verify(request);
} }
} }

View File

@ -0,0 +1,43 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.jclouds.trmk.vcloud_0_8.internal;
import java.net.URI;
import java.util.List;
import org.jclouds.reflect.Invocation;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import com.google.common.base.Throwables;
import com.google.common.reflect.Invokable;
public class BasePayloadTest {
protected GeneratedHttpRequest requestForArgs(List<Object> args) {
try {
Invocation invocation = Invocation.create(Invokable.from(String.class.getDeclaredMethod("toString")), args);
return GeneratedHttpRequest.builder().method("POST").endpoint(URI.create("http://localhost/key"))
.invocation(invocation).build();
} catch (SecurityException e) {
throw Throwables.propagate(e);
} catch (NoSuchMethodException e) {
throw Throwables.propagate(e);
}
}
}

View File

@ -18,17 +18,14 @@
*/ */
package org.jclouds.trmk.vcloud_0_8.xml; package org.jclouds.trmk.vcloud_0_8.xml;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNull;
import java.io.InputStream; import java.io.InputStream;
import java.net.URI; import java.net.URI;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import org.jclouds.http.functions.BaseHandlerTest; import org.jclouds.http.functions.BaseHandlerTest;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.jclouds.trmk.vcloud_0_8.domain.KeyPair; import org.jclouds.trmk.vcloud_0_8.domain.KeyPair;
import org.testng.annotations.Test; import org.testng.annotations.Test;
@ -59,15 +56,11 @@ public class KeyPairByNameHandlerTest extends BaseHandlerTest {
KeyPair result = factory.create( KeyPair result = factory.create(
addOrgAndNameToHandler(injector.getInstance(KeyPairByNameHandler.class), "org", "monster")).parse(is); addOrgAndNameToHandler(injector.getInstance(KeyPairByNameHandler.class), "org", "monster")).parse(is);
assertEquals(result, null); assertNull(result);
} }
private static KeyPairByNameHandler addOrgAndNameToHandler(KeyPairByNameHandler handler, String org, String name) { private KeyPairByNameHandler addOrgAndNameToHandler(KeyPairByNameHandler handler, String org, String name) {
GeneratedHttpRequest request = createMock(GeneratedHttpRequest.class); handler.setContext(requestForArgs(ImmutableList.<Object> of(org, name)));
expect(request.getArgs()).andReturn(ImmutableList.<Object> of(org, name)).anyTimes();
replay(request);
handler.setContext(request);
return handler; return handler;
} }
} }

View File

@ -24,34 +24,33 @@ import static com.google.common.base.Preconditions.checkState;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.Arrays; import java.util.Arrays;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named; import javax.inject.Named;
import org.jclouds.internal.ClassInvokerArgs; import org.jclouds.internal.ForwardInvocationToInterface;
import org.jclouds.internal.ClassInvokerArgsAndReturnVal;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.jclouds.reflect.AbstractInvocationHandler; import org.jclouds.reflect.FunctionalReflection;
import org.jclouds.reflect.Invocation;
import org.jclouds.reflect.Invocation.Result;
import org.jclouds.reflect.InvocationSuccess;
import org.jclouds.rest.annotations.Delegate; import org.jclouds.rest.annotations.Delegate;
import org.jclouds.rest.internal.AsyncRestClientProxy;
import org.jclouds.util.Optionals2; import org.jclouds.util.Optionals2;
import org.jclouds.util.Throwables2;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.base.Optional; import com.google.common.base.Optional;
import com.google.common.base.Throwables;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.reflect.Invokable; import com.google.common.reflect.Invokable;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import com.google.inject.ProvisionException;
import com.google.inject.assistedinject.Assisted; import com.google.inject.assistedinject.Assisted;
/** /**
@ -59,130 +58,174 @@ import com.google.inject.assistedinject.Assisted;
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
public final class SyncProxy extends AbstractInvocationHandler { public final class SyncProxy implements Function<Invocation, Result> {
public static interface Factory { public static interface Factory {
/** /**
* @param declaring * @param declaring
* type of the interface where all methods match those of {@code async} except the return values are * type of the interface where all invokeds match those of {@code async} except the return values are
* dereferenced * dereferenced
* @param async * @param async
* object whose interface matched {@code declaring} except all methods return {@link ListenableFuture} * object whose interface matched {@code declaring} except all invokeds return {@link ListenableFuture}
* @return blocking invocation handler * @return blocking invocation handler
*/ */
SyncProxy create(Class<?> declaring, Object async); SyncProxy create(Class<?> declaring, Object async);
} }
/**
* CreateClientForCaller is parameterized, so clients it creates aren't singletons. For example,
* CreateClientForCaller satisfies a call like this:
* {@code context.getProviderSpecificContext().getApi().getOrgClientForName(name)}
*
* @author Adrian Cole
*/
public static class CreateClientForCaller implements Function<ForwardInvocationToInterface, Object> {
private final SyncProxy.Factory factory;
private final AsyncRestClientProxy.Caller.Factory asyncFactory;
@Inject
private CreateClientForCaller(SyncProxy.Factory factory, AsyncRestClientProxy.Caller.Factory asyncFactory) {
this.factory = factory;
this.asyncFactory = asyncFactory;
}
@Override
public Object apply(ForwardInvocationToInterface from) {
Object asyncClient = FunctionalReflection.newProxy(from.getInterfaceType(),
asyncFactory.caller(from.getInvocation(), from.getInterfaceType()));
checkState(asyncClient != null, "configuration error, sync client for " + from + " not found");
Class<?> type = Optionals2.unwrapIfOptional(from.getInvocation().getInvokable().getReturnType());
return FunctionalReflection.newProxy(type, factory.create(type, asyncClient));
}
}
@Resource @Resource
private Logger logger = Logger.NULL; private Logger logger = Logger.NULL;
private final Function<ClassInvokerArgsAndReturnVal, Optional<Object>> optionalConverter; private final Function<InvocationSuccess, Optional<Object>> optionalConverter;
private final Object delegate; private final Object delegate;
private final Class<?> declaring; private final Class<?> declaring;
private final Map<Invokable<?, ?>, Invokable<Object, ListenableFuture<?>>> methodMap; private final Map<Invokable<?, ?>, Invokable<Object, ListenableFuture<?>>> invokedMap;
private final Map<Invokable<?, ?>, Invokable<Object, ?>> syncMethodMap; private final Map<Invokable<?, ?>, Invokable<Object, ?>> syncMethodMap;
private final Map<Invokable<?, ?>, Optional<Long>> timeoutMap; private final Map<Invokable<?, ?>, Optional<Long>> timeoutMap;
private final LoadingCache<ClassInvokerArgs, Object> delegateMap; private final Function<ForwardInvocationToInterface, Object> createClientForCaller;
private final Map<Class<?>, Class<?>> sync2Async; private final Map<Class<?>, Class<?>> sync2Async;
private static final Set<Method> objectMethods = ImmutableSet.copyOf(Object.class.getMethods()); private static final Set<Method> objectMethods = ImmutableSet.copyOf(Object.class.getMethods());
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Inject @Inject
@VisibleForTesting @VisibleForTesting
SyncProxy(Function<ClassInvokerArgsAndReturnVal, Optional<Object>> optionalConverter, SyncProxy(Function<InvocationSuccess, Optional<Object>> optionalConverter,
@Named("sync") LoadingCache<ClassInvokerArgs, Object> delegateMap, Map<Class<?>, Class<?>> sync2Async, Function<ForwardInvocationToInterface, Object> createClientForCaller, Map<Class<?>, Class<?>> sync2Async,
@Named("TIMEOUTS") Map<String, Long> timeouts, @Assisted Class<?> declaring, @Assisted Object async) @Named("TIMEOUTS") Map<String, Long> timeouts, @Assisted Class<?> declaring, @Assisted Object async)
throws SecurityException, NoSuchMethodException { throws SecurityException, NoSuchMethodException {
this.optionalConverter = optionalConverter; this.optionalConverter = optionalConverter;
this.delegateMap = delegateMap; this.createClientForCaller = createClientForCaller;
this.delegate = async; this.delegate = async;
this.declaring = declaring; this.declaring = declaring;
this.sync2Async = ImmutableMap.copyOf(sync2Async); this.sync2Async = ImmutableMap.copyOf(sync2Async);
ImmutableMap.Builder<Invokable<?, ?>, Invokable<Object, ListenableFuture<?>>> methodMapBuilder = ImmutableMap.builder(); ImmutableMap.Builder<Invokable<?, ?>, Invokable<Object, ListenableFuture<?>>> invokedMapBuilder = ImmutableMap
.builder();
ImmutableMap.Builder<Invokable<?, ?>, Invokable<Object, ?>> syncMethodMapBuilder = ImmutableMap.builder(); ImmutableMap.Builder<Invokable<?, ?>, Invokable<Object, ?>> syncMethodMapBuilder = ImmutableMap.builder();
for (Method method : declaring.getMethods()) { for (Method invoked : declaring.getMethods()) {
if (!objectMethods.contains(method)) { if (!objectMethods.contains(invoked)) {
Method delegatedMethod = delegate.getClass().getMethod(method.getName(), method.getParameterTypes()); Method delegatedMethod = delegate.getClass().getMethod(invoked.getName(), invoked.getParameterTypes());
if (!Arrays.equals(delegatedMethod.getExceptionTypes(), method.getExceptionTypes())) if (!Arrays.equals(delegatedMethod.getExceptionTypes(), invoked.getExceptionTypes()))
throw new IllegalArgumentException(String.format( throw new IllegalArgumentException(String.format(
"method %s has different typed exceptions than delegated method %s", method, delegatedMethod)); "invoked %s has different typed exceptions than delegated invoked %s", invoked, delegatedMethod));
if (delegatedMethod.getReturnType().isAssignableFrom(ListenableFuture.class)) { if (delegatedMethod.getReturnType().isAssignableFrom(ListenableFuture.class)) {
methodMapBuilder.put(Invokable.from(method), Invokable.class.cast(Invokable.from(delegatedMethod))); invokedMapBuilder.put(Invokable.from(invoked), Invokable.class.cast(Invokable.from(delegatedMethod)));
} else { } else {
syncMethodMapBuilder.put(Invokable.from(method), Invokable.class.cast(Invokable.from(delegatedMethod))); syncMethodMapBuilder.put(Invokable.from(invoked), Invokable.class.cast(Invokable.from(delegatedMethod)));
} }
} }
} }
methodMap = methodMapBuilder.build(); invokedMap = invokedMapBuilder.build();
syncMethodMap = syncMethodMapBuilder.build(); syncMethodMap = syncMethodMapBuilder.build();
ImmutableMap.Builder<Invokable<?, ?>, Optional<Long>> timeoutMapBuilder = ImmutableMap.builder(); ImmutableMap.Builder<Invokable<?, ?>, Optional<Long>> timeoutMapBuilder = ImmutableMap.builder();
for (Invokable<?, ?> method : methodMap.keySet()) { for (Invokable<?, ?> invoked : invokedMap.keySet()) {
timeoutMapBuilder.put(method, timeoutInNanos(method, timeouts)); timeoutMapBuilder.put(invoked, timeoutInNanos(invoked, timeouts));
} }
timeoutMap = timeoutMapBuilder.build(); timeoutMap = timeoutMapBuilder.build();
} }
public Class<?> getDeclaring() { @Override
return declaring; public Result apply(Invocation invocation) {
if (invocation.getInvokable().isAnnotationPresent(Delegate.class))
return forwardToDelegate(invocation);
if (syncMethodMap.containsKey(invocation.getInvokable()))
return invokeOnDelegate(invocation);
return invokeFutureAndBlock(invocation);
} }
@Override private Result forwardToDelegate(Invocation invocation) {
protected Object handleInvocation(Object proxy, Invokable<?, ?> method, List<Object> args) throws Throwable { Class<?> returnType = Optionals2.unwrapIfOptional(invocation.getInvokable().getReturnType());
if (method.isAnnotationPresent(Delegate.class)) {
Class<?> syncClass = Optionals2.returnTypeOrTypeOfOptional(method);
// get the return type of the asynchronous class associated with this client // get the return type of the asynchronous class associated with this client
// ex. FloatingIPClient is associated with FloatingIPAsyncClient // ex. FloatingIPClient is associated with FloatingIPAsyncClient
Class<?> asyncClass = sync2Async.get(syncClass); Class<?> asyncClass = sync2Async.get(returnType);
checkState(asyncClass != null, "please configure corresponding async class for " + syncClass checkState(asyncClass != null, "please configure corresponding async class for %s in your RestClientModule",
+ " in your RestClientModule"); returnType);
// pass any parameters necessary to get a relevant instance of that async class // pass any parameters necessary to get a relevant instance of that async class
// ex. getClientForRegion("north") might return an instance whose endpoint is // ex. getClientForRegion("north") might return an instance whose endpoint is
// different that "south" // different that "south"
ClassInvokerArgs cma = ClassInvokerArgs.builder().clazz(asyncClass).invoker(method).args(args).build(); ForwardInvocationToInterface cma = ForwardInvocationToInterface.create(invocation, asyncClass);
Object returnVal = delegateMap.get(cma); Object result = createClientForCaller.apply(cma);
if (Optionals2.isReturnTypeOptional(method)){ if (Optionals2.isReturnTypeOptional(invocation.getInvokable())) {
ClassInvokerArgsAndReturnVal cmar = ClassInvokerArgsAndReturnVal.builder().fromClassInvokerArgs(cma) result = optionalConverter.apply(InvocationSuccess.create(invocation, result));
.returnVal(returnVal).build();
return optionalConverter.apply(cmar);
} }
return returnVal; return Result.success(result);
} else if (syncMethodMap.containsKey(method)) { }
private Result invokeFutureAndBlock(Invocation invocation) {
try { try {
return syncMethodMap.get(method).invoke(delegate, args.toArray()); Invokable<Object, ListenableFuture<?>> asyncMethod = invokedMap.get(invocation.getInvokable());
ListenableFuture<?> future = asyncMethod.invoke(delegate, invocation.getArgs().toArray());
Optional<Long> timeoutNanos = timeoutMap.get(invocation.getInvokable());
return block(future, timeoutNanos);
} catch (InvocationTargetException e) { } catch (InvocationTargetException e) {
throw Throwables.propagate(e.getCause()); return Result.fail(e);
} catch (IllegalAccessException e) {
return Result.fail(e);
} }
} else { }
private Result block(ListenableFuture<?> future, Optional<Long> timeoutNanos) {
try { try {
Optional<Long> timeoutNanos = timeoutMap.get(method);
Invokable<Object, ListenableFuture<?>> asyncMethod = methodMap.get(method);
String name = asyncMethod.getDeclaringClass().getSimpleName() + "." + asyncMethod.getName();
ListenableFuture<?> future = asyncMethod.invoke(delegate, args.toArray());
if (timeoutNanos.isPresent()) { if (timeoutNanos.isPresent()) {
logger.debug(">> blocking on %s for %s", name, timeoutNanos); logger.debug(">> blocking on %s for %s", future, timeoutNanos);
return future.get(timeoutNanos.get(), TimeUnit.NANOSECONDS); return Result.success(future.get(timeoutNanos.get(), TimeUnit.NANOSECONDS));
} else {
logger.debug(">> blocking on %s", future);
return Result.success(future.get());
} }
logger.debug(">> blocking on %s", name);
return future.get();
} catch (ProvisionException e) {
throw Throwables2.returnFirstExceptionIfInListOrThrowStandardExceptionOrCause(method.getExceptionTypes(), e);
} catch (ExecutionException e) { } catch (ExecutionException e) {
throw Throwables2.returnFirstExceptionIfInListOrThrowStandardExceptionOrCause(method.getExceptionTypes(), e); return Result.fail(e.getCause());
} catch (Exception e) { } catch (InterruptedException e) {
throw Throwables2.returnFirstExceptionIfInListOrThrowStandardExceptionOrCause(method.getExceptionTypes(), e); return Result.fail(e); // TODO: should we kill the future?
} catch (TimeoutException e) {
return Result.fail(e);
} }
} }
private Result invokeOnDelegate(Invocation invocation) {
Invokable<Object, ?> toInvoke = syncMethodMap.get(invocation.getInvokable());
try {
return Result.success(toInvoke.invoke(delegate, invocation.getArgs().toArray()));
} catch (InvocationTargetException e) {
return Result.fail(e);
} catch (IllegalAccessException e) {
return Result.fail(e);
}
} }
// override timeout by values configured in properties(in ms) // override timeout by values configured in properties(in ms)
private Optional<Long> timeoutInNanos(Invokable<?, ?> method, Map<String, Long> timeouts) { private Optional<Long> timeoutInNanos(Invokable<?, ?> invoked, Map<String, Long> timeouts) {
String className = declaring.getSimpleName(); String className = declaring.getSimpleName();
Optional<Long> timeoutMillis = fromNullable(timeouts.get(className + "." + method.getName())) Optional<Long> timeoutMillis = fromNullable(timeouts.get(className + "." + invoked.getName())).or(
.or(fromNullable(timeouts.get(className))) fromNullable(timeouts.get(className))).or(fromNullable(timeouts.get("default")));
.or(fromNullable(timeouts.get("default")));
if (timeoutMillis.isPresent()) if (timeoutMillis.isPresent())
return Optional.of(TimeUnit.MILLISECONDS.toNanos(timeoutMillis.get())); return Optional.of(TimeUnit.MILLISECONDS.toNanos(timeoutMillis.get()));
return Optional.absent(); return Optional.absent();
@ -190,6 +233,6 @@ public final class SyncProxy extends AbstractInvocationHandler {
@Override @Override
public String toString() { public String toString() {
return "blocking invocation handler for: " + delegate.getClass().getSimpleName(); return String.format("%s->%s", declaring.getClass().getSimpleName(), delegate.getClass().getSimpleName());
} }
} }

View File

@ -23,6 +23,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
import org.jclouds.rest.internal.GeneratedHttpRequest; import org.jclouds.rest.internal.GeneratedHttpRequest;
import com.google.common.base.Objects; import com.google.common.base.Objects;
import com.google.common.reflect.Invokable;
/** /**
* Command whose endpoint is an http service. * Command whose endpoint is an http service.
@ -131,11 +132,12 @@ public class HttpCommand {
@Override @Override
public String toString() { public String toString() {
if (request instanceof GeneratedHttpRequest) if (request instanceof GeneratedHttpRequest) {
return String.format("[method=%s.%s, request=%s]", GeneratedHttpRequest.class.cast(request).getDeclaring() GeneratedHttpRequest gRequest = GeneratedHttpRequest.class.cast(request);
.getSimpleName(), GeneratedHttpRequest.class.cast(request).getInvoker().getName(), request return String.format("[method=%s.%s, request=%s]",
.getRequestLine()); gRequest.getInvocation().getInterfaceType().getSimpleName(), gRequest.getInvocation().getInvokable()
else .getName(), gRequest.getRequestLine());
}
return "[request=" + request.getRequestLine() + "]"; return "[request=" + request.getRequestLine() + "]";
} }

View File

@ -212,7 +212,7 @@ public class ParseSax<T> implements Function<HttpResponse, T>, InvocationContext
@Override @Override
public HandlerForGeneratedRequestWithResult<T> setContext(HttpRequest request) { public HandlerForGeneratedRequestWithResult<T> setContext(HttpRequest request) {
checkArgument(request instanceof GeneratedHttpRequest, "note this handler requires a GeneratedHttpRequest"); checkArgument(checkNotNull(request, "request") instanceof GeneratedHttpRequest, "note this handler requires a GeneratedHttpRequest");
super.setContext(request); super.setContext(request);
return this; return this;
} }

View File

@ -1,149 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.jclouds.internal;
import static com.google.common.base.Objects.equal;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.List;
import com.google.common.base.Objects;
import com.google.common.base.Objects.ToStringHelper;
import com.google.common.collect.ImmutableList;
import com.google.common.reflect.Invokable;
/**
*
* @author Adrian Cole
*/
public class ClassInvokerArgs {
public static Builder<?> builder() {
return new ConcreteBuilder();
}
public Builder<?> toBuilder() {
return builder().fromClassInvokerArgs(this);
}
private static class ConcreteBuilder extends Builder<ConcreteBuilder> {
}
public abstract static class Builder<B extends Builder<B>> {
private Class<?> clazz;
private Invokable<?, ?> invoker;
private List<Object> args = ImmutableList.of();
@SuppressWarnings("unchecked")
protected B self() {
return (B) this;
}
/**
* @see ClassInvokerArgs#getClazz()
*/
public B clazz(Class<?> clazz) {
this.clazz = clazz;
return self();
}
/**
* @see ClassInvokerArgs#getInvoker()
*/
public B invoker(Invokable<?, ?> invoker) {
this.invoker = invoker;
return self();
}
/**
* @see ClassInvokerArgs#getArgs()
*/
public B args(List<Object> args) {
this.args = args;
return self();
}
public ClassInvokerArgs build() {
return new ClassInvokerArgs(this);
}
public B fromClassInvokerArgs(ClassInvokerArgs in) {
return clazz(in.getClazz()).invoker(in.getInvoker()).args(in.getArgs());
}
}
private final Class<?> clazz;
private final Invokable<?, ?> invoker;
private final List<Object> args;
public ClassInvokerArgs(Builder<?> builder) {
this(builder.clazz, builder.invoker, builder.args);
}
/**
* @param args as these represent parameters, can contain nulls
*/
public ClassInvokerArgs(Class<?> clazz, Invokable<?, ?> invoker, List<Object> args) {
this.clazz = checkNotNull(clazz, "clazz");
this.invoker = checkNotNull(invoker, "invoker");
this.args = checkNotNull(args, "args");
}
/**
* not necessarily the declaring class of the invoker.
*/
public Class<?> getClazz() {
return clazz;
}
public Invokable<?, ?> getInvoker() {
return invoker;
}
/**
* @param args as these represent parameters, can contain nulls
*/
public List<Object> getArgs() {
return args;
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
ClassInvokerArgs that = ClassInvokerArgs.class.cast(o);
return equal(this.clazz, that.clazz) && equal(this.invoker, that.invoker) && equal(this.args, that.args);
}
@Override
public int hashCode() {
return Objects.hashCode(clazz, invoker, args);
}
@Override
public String toString() {
return string().toString();
}
protected ToStringHelper string() {
return Objects.toStringHelper("").omitNullValues().add("clazz", clazz).add("invoker", invoker)
.add("args", args.size() != 0 ? args : null);
}
}

View File

@ -1,101 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.jclouds.internal;
import static com.google.common.base.Objects.equal;
import java.util.List;
import com.google.common.base.Objects;
import com.google.common.base.Objects.ToStringHelper;
import com.google.common.reflect.Invokable;
/**
*
* @author Adrian Cole
*/
public final class ClassInvokerArgsAndReturnVal extends ClassInvokerArgs {
public static Builder builder() {
return new Builder();
}
public Builder toBuilder() {
return builder().fromClassInvokerArgsAndReturnVal(this);
}
public final static class Builder extends ClassInvokerArgs.Builder<Builder> {
private Object returnVal;
/**
* @see ClassInvokerArgsAndReturnVal#getReturnVal()
*/
public Builder returnVal(Object returnVal) {
this.returnVal = returnVal;
return this;
}
@Override
public ClassInvokerArgsAndReturnVal build() {
return new ClassInvokerArgsAndReturnVal(this);
}
public Builder fromClassInvokerArgsAndReturnVal(ClassInvokerArgsAndReturnVal in) {
return fromClassInvokerArgs(in).returnVal(in.getReturnVal());
}
}
private final Object returnVal;
private ClassInvokerArgsAndReturnVal(Class<?> clazz, Invokable<?, ?> invoker, List<Object> args, Object returnVal) {
super(clazz, invoker, args);
this.returnVal = returnVal;
}
private ClassInvokerArgsAndReturnVal(Builder builder) {
super(builder);
this.returnVal = builder.returnVal;
}
public Object getReturnVal() {
return returnVal;
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
ClassInvokerArgsAndReturnVal that = ClassInvokerArgsAndReturnVal.class.cast(o);
return super.equals(that) && equal(this.returnVal, that.returnVal);
}
@Override
public int hashCode() {
return Objects.hashCode(super.hashCode(), returnVal);
}
@Override
public ToStringHelper string() {
return super.string().add("returnVal", returnVal);
}
}

View File

@ -0,0 +1,84 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.jclouds.internal;
import static com.google.common.base.Objects.equal;
import static com.google.common.base.Preconditions.checkNotNull;
import org.jclouds.reflect.Invocation;
import com.google.common.annotations.Beta;
import com.google.common.base.Objects;
import com.google.common.base.Objects.ToStringHelper;
/**
* internal type to {@link SyncProxy} which is likely to be removed
*
* @author Adrian Cole
*/
@Beta
public final class ForwardInvocationToInterface {
/**
* @param interfaceType
* {@link #getInterfaceType()}
*/
public static ForwardInvocationToInterface create(Invocation invocation, Class<?> interfaceType) {
return new ForwardInvocationToInterface(invocation, interfaceType);
}
private final Invocation invocation;
private final Class<?> interfaceType;
private ForwardInvocationToInterface(Invocation invocation, Class<?> interfaceType) {
this.invocation = checkNotNull(invocation, "invocation");
this.interfaceType = checkNotNull(interfaceType, "interfaceType");
}
public Invocation getInvocation() {
return invocation;
}
public Class<?> getInterfaceType() {
return interfaceType;
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
ForwardInvocationToInterface that = ForwardInvocationToInterface.class.cast(o);
return equal(this.invocation, that.invocation) && equal(this.interfaceType, that.interfaceType);
}
@Override
public int hashCode() {
return Objects.hashCode(invocation, interfaceType);
}
@Override
public String toString() {
return string().toString();
}
protected ToStringHelper string() {
return Objects.toStringHelper("").omitNullValues().add("invocation", invocation).add("interfaceType", interfaceType);
}
}

View File

@ -32,7 +32,6 @@ import javax.inject.Singleton;
import org.jclouds.collect.Memoized; import org.jclouds.collect.Memoized;
import org.jclouds.domain.Location; import org.jclouds.domain.Location;
import org.jclouds.internal.ClassInvokerArgsAndReturnVal;
import org.jclouds.location.Iso3166; import org.jclouds.location.Iso3166;
import org.jclouds.location.Provider; import org.jclouds.location.Provider;
import org.jclouds.location.Region; import org.jclouds.location.Region;
@ -49,6 +48,7 @@ import org.jclouds.location.suppliers.RegionIdToZoneIdsSupplier;
import org.jclouds.location.suppliers.RegionIdsSupplier; import org.jclouds.location.suppliers.RegionIdsSupplier;
import org.jclouds.location.suppliers.ZoneIdToURISupplier; import org.jclouds.location.suppliers.ZoneIdToURISupplier;
import org.jclouds.location.suppliers.ZoneIdsSupplier; import org.jclouds.location.suppliers.ZoneIdsSupplier;
import org.jclouds.reflect.InvocationSuccess;
import org.jclouds.rest.AuthorizationException; import org.jclouds.rest.AuthorizationException;
import org.jclouds.rest.functions.ImplicitOptionalConverter; import org.jclouds.rest.functions.ImplicitOptionalConverter;
import org.jclouds.rest.suppliers.MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier; import org.jclouds.rest.suppliers.MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier;
@ -73,7 +73,7 @@ public class LocationModule extends AbstractModule {
@Override @Override
protected void configure() { protected void configure() {
bind(new TypeLiteral<Function<ClassInvokerArgsAndReturnVal, Optional<Object>>>(){}).to(ImplicitOptionalConverter.class); bind(new TypeLiteral<Function<InvocationSuccess, Optional<Object>>>(){}).to(ImplicitOptionalConverter.class);
} }
@Provides @Provides

View File

@ -1,58 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.jclouds.reflect;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import com.google.common.annotations.Beta;
import com.google.common.base.Predicates;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.reflect.Invokable;
/**
* Like {@link com.google.common.reflect.AbstractInvocationHandler}, except you process {@link Invokable} and
* {@link List} as opposed to {@link Method} and arg arrays.
*
* @author Adrian Cole
* @since 1.6
*/
@Beta
public abstract class AbstractInvocationHandler extends com.google.common.reflect.AbstractInvocationHandler {
/**
* @param args
* note that this can contain nulls, as method arguments can be null.
* @see com.google.common.reflect.AbstractInvocationHandler#invoke(Object, Method, Object[])
*/
protected abstract Object handleInvocation(Object proxy, Invokable<?, ?> method, List<Object> args) throws Throwable;
@Override
protected Object handleInvocation(Object proxy, Method method, Object[] argv) throws Throwable {
List<Object> args = Arrays.asList(argv);
if (Iterables.all(args, Predicates.notNull()))
args = ImmutableList.copyOf(args);
else
args = Collections.unmodifiableList(args);
return handleInvocation(proxy, Invokable.from(method), args);
}
}

View File

@ -26,12 +26,12 @@ import java.util.List;
import javax.inject.Inject; import javax.inject.Inject;
import org.jclouds.predicates.Validator; import org.jclouds.predicates.Validator;
import org.jclouds.reflect.Invocation;
import org.jclouds.rest.annotations.ParamValidators; import org.jclouds.rest.annotations.ParamValidators;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.reflect.Invokable;
import com.google.common.reflect.Parameter; import com.google.common.reflect.Parameter;
import com.google.inject.Injector; import com.google.inject.Injector;
@ -70,14 +70,13 @@ public class InputParamValidator {
* @throws IllegalStateException * @throws IllegalStateException
* if validation failed * if validation failed
*/ */
public void validateMethodParametersOrThrow(Invokable<?, ?> method, List<Object> args) { public void validateMethodParametersOrThrow(Invocation invocation) {
try { try {
performMethodValidation(checkNotNull(method, "method"), args); performMethodValidation(checkNotNull(invocation, "invocation"));
performParameterValidation(method.getParameters(), args); performParameterValidation(invocation);
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
throw new IllegalArgumentException(String.format("Validation on '%s#%s' didn't pass for arguments: " throw new IllegalArgumentException(String.format("Validation on '%s' didn't pass:%n Reason: %s.", invocation,
+ "%s. %n Reason: %s.", method.getDeclaringClass().getName(), method.getName(), args, e.getMessage()), e);
e.getMessage()));
} }
} }
@ -90,14 +89,14 @@ public class InputParamValidator {
* @param args * @param args
* method's parameters * method's parameters
*/ */
private void performMethodValidation(Invokable<?, ?> method, List<Object> args) { private void performMethodValidation(Invocation invocation) {
ParamValidators paramValidatorsAnnotation = method.getAnnotation(ParamValidators.class); ParamValidators paramValidatorsAnnotation = invocation.getInvokable().getAnnotation(ParamValidators.class);
if (paramValidatorsAnnotation == null) if (paramValidatorsAnnotation == null)
return; // by contract return; // by contract
List<Validator<?>> methodValidators = getValidatorsFromAnnotation(paramValidatorsAnnotation); List<Validator<?>> methodValidators = getValidatorsFromAnnotation(paramValidatorsAnnotation);
runPredicatesAgainstArgs(methodValidators, args); runPredicatesAgainstArgs(methodValidators, invocation.getArgs());
} }
/** /**
@ -109,8 +108,8 @@ public class InputParamValidator {
* @param args * @param args
* arguments that correspond to the array of annotations * arguments that correspond to the array of annotations
*/ */
private void performParameterValidation(List<Parameter> parameters, List<Object> args) { private void performParameterValidation(Invocation invocation) {
for (Parameter param : filter(parameters, new Predicate<Parameter>() { for (Parameter param : filter(invocation.getInvokable().getParameters(), new Predicate<Parameter>() {
public boolean apply(Parameter in) { public boolean apply(Parameter in) {
return in.isAnnotationPresent(ParamValidators.class); return in.isAnnotationPresent(ParamValidators.class);
} }
@ -119,7 +118,8 @@ public class InputParamValidator {
if (annotation == null) if (annotation == null)
continue; continue;
List<Validator<?>> parameterValidators = getValidatorsFromAnnotation(annotation); List<Validator<?>> parameterValidators = getValidatorsFromAnnotation(annotation);
runPredicatesAgainstArg(parameterValidators, args.get(param.hashCode()));// TODO position guava issue 1243 // TODO position guava issue 1243
runPredicatesAgainstArg(parameterValidators, invocation.getArgs().get(param.hashCode()));
} }
} }

View File

@ -32,6 +32,8 @@ import org.jclouds.rest.MapBinder;
import org.jclouds.rest.annotations.Payload; import org.jclouds.rest.annotations.Payload;
import org.jclouds.rest.internal.GeneratedHttpRequest; import org.jclouds.rest.internal.GeneratedHttpRequest;
import com.google.common.reflect.Invokable;
/** /**
* *
* @author Adrian Cole * @author Adrian Cole
@ -44,9 +46,10 @@ public class BindMapToStringPayload implements MapBinder {
public <R extends HttpRequest> R bindToRequest(R request, Map<String, Object> postParams) { public <R extends HttpRequest> R bindToRequest(R request, Map<String, Object> postParams) {
checkNotNull(postParams, "postParams"); checkNotNull(postParams, "postParams");
GeneratedHttpRequest r = GeneratedHttpRequest.class.cast(checkNotNull(request, "request")); GeneratedHttpRequest r = GeneratedHttpRequest.class.cast(checkNotNull(request, "request"));
checkArgument(r.getInvoker().isAnnotationPresent(Payload.class), Invokable<?, ?> invoked = r.getInvocation().getInvokable();
"method %s must have @Payload annotation to use this binder", r.getInvoker()); checkArgument(invoked.isAnnotationPresent(Payload.class),
String payload = r.getInvoker().getAnnotation(Payload.class).value(); "method %s must have @Payload annotation to use this binder", invoked);
String payload = invoked.getAnnotation(Payload.class).value();
if (postParams.size() > 0) { if (postParams.size() > 0) {
payload = urlDecode(expand(payload, postParams)); payload = urlDecode(expand(payload, postParams));
} }

View File

@ -18,13 +18,11 @@
*/ */
package org.jclouds.rest.config; package org.jclouds.rest.config;
import static com.google.common.reflect.Reflection.newProxy;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.jclouds.reflect.FunctionalReflection;
import org.jclouds.rest.internal.AsyncRestClientProxy; import org.jclouds.rest.internal.AsyncRestClientProxy;
import org.jclouds.rest.internal.AsyncRestClientProxy.Factory;
import com.google.inject.Provider; import com.google.inject.Provider;
import com.google.inject.TypeLiteral; import com.google.inject.TypeLiteral;
@ -36,11 +34,11 @@ import com.google.inject.TypeLiteral;
@Singleton @Singleton
public class AsyncClientProvider<A> implements Provider<A> { public class AsyncClientProvider<A> implements Provider<A> {
private final Class<? super A> asyncClientType; private final Class<? super A> asyncClientType;
private final Factory factory; private final AsyncRestClientProxy proxy;
@Inject @Inject
private AsyncClientProvider(AsyncRestClientProxy.Factory factory, TypeLiteral<A> asyncClientType) { private AsyncClientProvider(AsyncRestClientProxy proxy, TypeLiteral<A> asyncClientType) {
this.factory = factory; this.proxy = proxy;
this.asyncClientType = asyncClientType.getRawType(); this.asyncClientType = asyncClientType.getRawType();
} }
@ -48,7 +46,7 @@ public class AsyncClientProvider<A> implements Provider<A> {
@Override @Override
@Singleton @Singleton
public A get() { public A get() {
return (A) newProxy(asyncClientType, factory.declaring(asyncClientType)); return (A) FunctionalReflection.newProxy(asyncClientType, proxy);
} }
} }

View File

@ -18,12 +18,11 @@
*/ */
package org.jclouds.rest.config; package org.jclouds.rest.config;
import static com.google.common.reflect.Reflection.newProxy;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.jclouds.concurrent.internal.SyncProxy; import org.jclouds.concurrent.internal.SyncProxy;
import org.jclouds.reflect.FunctionalReflection;
import com.google.inject.Provider; import com.google.inject.Provider;
@ -50,6 +49,6 @@ public class ClientProvider<S, A> implements Provider<S> {
@Override @Override
@Singleton @Singleton
public S get() { public S get() {
return newProxy(syncClientType, factory.create(syncClientType, asyncClient)); return FunctionalReflection.newProxy(syncClientType, factory.create(syncClientType, asyncClient));
} }
} }

View File

@ -29,10 +29,11 @@ import javax.inject.Named;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.jclouds.concurrent.internal.SyncProxy; import org.jclouds.concurrent.internal.SyncProxy;
import org.jclouds.concurrent.internal.SyncProxy.CreateClientForCaller;
import org.jclouds.functions.IdentityFunction; import org.jclouds.functions.IdentityFunction;
import org.jclouds.http.functions.config.SaxParserModule; import org.jclouds.http.functions.config.SaxParserModule;
import org.jclouds.internal.ClassInvokerArgs;
import org.jclouds.internal.FilterStringsBoundToInjectorByName; import org.jclouds.internal.FilterStringsBoundToInjectorByName;
import org.jclouds.internal.ForwardInvocationToInterface;
import org.jclouds.json.config.GsonModule; import org.jclouds.json.config.GsonModule;
import org.jclouds.location.config.LocationModule; import org.jclouds.location.config.LocationModule;
import org.jclouds.rest.AuthorizationException; import org.jclouds.rest.AuthorizationException;
@ -40,8 +41,6 @@ import org.jclouds.rest.HttpAsyncClient;
import org.jclouds.rest.HttpClient; import org.jclouds.rest.HttpClient;
import org.jclouds.rest.binders.BindToJsonPayloadWrappedWith; import org.jclouds.rest.binders.BindToJsonPayloadWrappedWith;
import org.jclouds.rest.internal.AsyncRestClientProxy; import org.jclouds.rest.internal.AsyncRestClientProxy;
import org.jclouds.rest.internal.CreateAsyncClientForCaller;
import org.jclouds.rest.internal.CreateClientForCaller;
import org.jclouds.rest.internal.RestAnnotationProcessor; import org.jclouds.rest.internal.RestAnnotationProcessor;
import org.jclouds.util.Maps2; import org.jclouds.util.Maps2;
import org.jclouds.util.Predicates2; import org.jclouds.util.Predicates2;
@ -49,8 +48,6 @@ import org.jclouds.util.Predicates2;
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.base.Supplier; import com.google.common.base.Supplier;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.google.common.util.concurrent.Atomics; import com.google.common.util.concurrent.Atomics;
@ -84,8 +81,8 @@ public class RestModule extends AbstractModule {
install(new SaxParserModule()); install(new SaxParserModule());
install(new GsonModule()); install(new GsonModule());
install(new FactoryModuleBuilder().build(BindToJsonPayloadWrappedWith.Factory.class)); install(new FactoryModuleBuilder().build(BindToJsonPayloadWrappedWith.Factory.class));
install(new FactoryModuleBuilder().build(RestAnnotationProcessor.Factory.class)); install(new FactoryModuleBuilder().build(RestAnnotationProcessor.Caller.Factory.class));
install(new FactoryModuleBuilder().build(AsyncRestClientProxy.Factory.class)); install(new FactoryModuleBuilder().build(AsyncRestClientProxy.Caller.Factory.class));
bind(IdentityFunction.class).toInstance(IdentityFunction.INSTANCE); bind(IdentityFunction.class).toInstance(IdentityFunction.INSTANCE);
install(new FactoryModuleBuilder().build(SyncProxy.Factory.class)); install(new FactoryModuleBuilder().build(SyncProxy.Factory.class));
bindClientAndAsyncClient(binder(), HttpClient.class, HttpAsyncClient.class); bindClientAndAsyncClient(binder(), HttpClient.class, HttpAsyncClient.class);
@ -94,6 +91,10 @@ public class RestModule extends AbstractModule {
}).toInstance(authException); }).toInstance(authException);
bind(new TypeLiteral<Function<Predicate<String>, Map<String, String>>>() { bind(new TypeLiteral<Function<Predicate<String>, Map<String, String>>>() {
}).to(FilterStringsBoundToInjectorByName.class); }).to(FilterStringsBoundToInjectorByName.class);
bind(new TypeLiteral<Function<Predicate<String>, Map<String, String>>>() {
}).to(FilterStringsBoundToInjectorByName.class);
bind(new TypeLiteral<Function<ForwardInvocationToInterface, Object>>() {
}).to(CreateClientForCaller.class);
installLocations(); installLocations();
} }
@ -120,19 +121,4 @@ public class RestModule extends AbstractModule {
}); });
} }
@Provides
@Singleton
@Named("async")
LoadingCache<ClassInvokerArgs, Object> provideAsyncDelegateMap(CreateAsyncClientForCaller createAsyncClientForCaller) {
return CacheBuilder.newBuilder().build(createAsyncClientForCaller);
}
@Provides
@Singleton
@Named("sync")
LoadingCache<ClassInvokerArgs, Object> provideSyncDelegateMap(CreateClientForCaller createClientForCaller) {
return CacheBuilder.newBuilder().build(createClientForCaller);
}
} }

View File

@ -18,7 +18,7 @@
*/ */
package org.jclouds.rest.functions; package org.jclouds.rest.functions;
import org.jclouds.internal.ClassInvokerArgsAndReturnVal; import org.jclouds.reflect.InvocationSuccess;
import com.google.common.annotations.Beta; import com.google.common.annotations.Beta;
import com.google.common.base.Optional; import com.google.common.base.Optional;
@ -31,8 +31,8 @@ import com.google.common.base.Optional;
public class AlwaysPresentImplicitOptionalConverter implements ImplicitOptionalConverter { public class AlwaysPresentImplicitOptionalConverter implements ImplicitOptionalConverter {
@Override @Override
public Optional<Object> apply(ClassInvokerArgsAndReturnVal input) { public Optional<Object> apply(InvocationSuccess input) {
return Optional.of(input.getReturnVal()); return input.getResult();
} }
} }

View File

@ -18,7 +18,9 @@
*/ */
package org.jclouds.rest.functions; package org.jclouds.rest.functions;
import org.jclouds.internal.ClassInvokerArgsAndReturnVal; import org.jclouds.reflect.InvocationSuccess;
import org.jclouds.rest.annotations.ApiVersion;
import org.jclouds.rest.annotations.SinceApiVersion;
import org.jclouds.rest.config.RestClientModule; import org.jclouds.rest.config.RestClientModule;
import com.google.common.annotations.Beta; import com.google.common.annotations.Beta;
@ -39,19 +41,19 @@ import com.google.inject.ImplementedBy;
* } * }
* </pre> * </pre>
* *
* The input object of type {@link ClassInvokerArgsAndReturnVal} will include the * The input object of type {@link InvocationSuccess} will include the
* following. * following.
* <ol> * <ol>
* <li>the class declaring the method that returns optional: * <li>the class declaring the method that returns optional:
* {@link ClassInvokerArgsAndReturnVal#getClazz}; in the example above, * {@link InvocationSuccess#getClazz}; in the example above,
* {@code MyCloud}</li> * {@code MyCloud}</li>
* <li>the method returning the optional: * <li>the method returning the optional:
* {@link ClassInvokerArgsAndReturnVal#getMethod}; in the example above, * {@link InvocationSuccess#getMethod}; in the example above,
* {@code getKeyPairExtensionForRegion}</li> * {@code getKeyPairExtensionForRegion}</li>
* <li>the args passed to that method at runtime: * <li>the args passed to that method at runtime:
* {@link ClassInvokerArgsAndReturnVal#getArgs}; for example {@code North}</li> * {@link InvocationSuccess#getArgs}; for example {@code North}</li>
* <li>the rest client to be enclosed in the optional, should you choose to * <li>the rest client to be enclosed in the optional, should you choose to
* return it: {@link ClassInvokerArgsAndReturnVal#getReturnVal}; in the example * return it: {@link InvocationSuccess#getReturnVal}; in the example
* above, an implementation of {@code KeyPairClient}</li> * above, an implementation of {@code KeyPairClient}</li>
* </ol> * </ol>
* *
@ -80,6 +82,6 @@ import com.google.inject.ImplementedBy;
*/ */
@Beta @Beta
@ImplementedBy(PresentWhenApiVersionLexicographicallyAtOrAfterSinceApiVersion.class) @ImplementedBy(PresentWhenApiVersionLexicographicallyAtOrAfterSinceApiVersion.class)
public interface ImplicitOptionalConverter extends Function<ClassInvokerArgsAndReturnVal, Optional<Object>> { public interface ImplicitOptionalConverter extends Function<InvocationSuccess, Optional<Object>> {
} }

View File

@ -19,11 +19,12 @@
package org.jclouds.rest.functions; package org.jclouds.rest.functions;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.util.Optionals2.unwrapIfOptional;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.jclouds.internal.ClassInvokerArgsAndReturnVal; import org.jclouds.reflect.InvocationSuccess;
import org.jclouds.rest.annotations.ApiVersion; import org.jclouds.rest.annotations.ApiVersion;
import org.jclouds.rest.annotations.SinceApiVersion; import org.jclouds.rest.annotations.SinceApiVersion;
@ -43,7 +44,7 @@ import com.google.common.cache.LoadingCache;
public class PresentWhenApiVersionLexicographicallyAtOrAfterSinceApiVersion implements ImplicitOptionalConverter { public class PresentWhenApiVersionLexicographicallyAtOrAfterSinceApiVersion implements ImplicitOptionalConverter {
@VisibleForTesting @VisibleForTesting
static final class Loader extends CacheLoader<ClassInvokerArgsAndReturnVal, Optional<Object>> { static final class Loader extends CacheLoader<InvocationSuccess, Optional<Object>> {
private final String apiVersion; private final String apiVersion;
@Inject @Inject
@ -52,22 +53,22 @@ public class PresentWhenApiVersionLexicographicallyAtOrAfterSinceApiVersion impl
} }
@Override @Override
public Optional<Object> load(ClassInvokerArgsAndReturnVal input) { public Optional<Object> load(InvocationSuccess input) {
Optional<SinceApiVersion> sinceApiVersion = Optional.fromNullable(input.getClazz().getAnnotation( Class<?> target = unwrapIfOptional(input.getInvocation().getInvokable().getReturnType());
SinceApiVersion.class)); Optional<SinceApiVersion> sinceApiVersion = Optional.fromNullable(target.getAnnotation(SinceApiVersion.class));
if (sinceApiVersion.isPresent()) { if (sinceApiVersion.isPresent()) {
String since = sinceApiVersion.get().value(); String since = sinceApiVersion.get().value();
if (since.compareTo(apiVersion) <= 0) if (since.compareTo(apiVersion) <= 0)
return Optional.of(input.getReturnVal()); return input.getResult();
return Optional.absent(); return Optional.absent();
} else { } else {
// No SinceApiVersion annotation, so return present // No SinceApiVersion annotation, so return present
return Optional.of(input.getReturnVal()); return input.getResult();
} }
} }
} }
private final LoadingCache<ClassInvokerArgsAndReturnVal, Optional<Object>> lookupCache; private final LoadingCache<InvocationSuccess, Optional<Object>> lookupCache;
@Inject @Inject
protected PresentWhenApiVersionLexicographicallyAtOrAfterSinceApiVersion(@ApiVersion String apiVersion) { protected PresentWhenApiVersionLexicographicallyAtOrAfterSinceApiVersion(@ApiVersion String apiVersion) {
@ -76,7 +77,7 @@ public class PresentWhenApiVersionLexicographicallyAtOrAfterSinceApiVersion impl
} }
@Override @Override
public Optional<Object> apply(ClassInvokerArgsAndReturnVal input) { public Optional<Object> apply(InvocationSuccess input) {
return lookupCache.getUnchecked(input); return lookupCache.getUnchecked(input);
} }

View File

@ -19,6 +19,9 @@
package org.jclouds.rest.internal; package org.jclouds.rest.internal;
import static com.google.common.base.Functions.compose; import static com.google.common.base.Functions.compose;
import static com.google.common.base.Objects.equal;
import static com.google.common.base.Predicates.in;
import static com.google.common.base.Predicates.not;
import static com.google.common.base.Throwables.propagate; import static com.google.common.base.Throwables.propagate;
import static com.google.common.collect.Iterables.any; import static com.google.common.collect.Iterables.any;
import static com.google.common.collect.Iterables.find; import static com.google.common.collect.Iterables.find;
@ -31,7 +34,7 @@ import static javax.ws.rs.core.MediaType.APPLICATION_XML;
import static org.jclouds.concurrent.Futures.makeListenable; import static org.jclouds.concurrent.Futures.makeListenable;
import static org.jclouds.http.HttpUtils.tryFindHttpMethod; import static org.jclouds.http.HttpUtils.tryFindHttpMethod;
import static org.jclouds.util.Optionals2.isReturnTypeOptional; import static org.jclouds.util.Optionals2.isReturnTypeOptional;
import static org.jclouds.util.Optionals2.returnTypeOrTypeOfOptional; import static org.jclouds.util.Optionals2.unwrapIfOptional;
import static org.jclouds.util.Throwables2.getFirstThrowableOfType; import static org.jclouds.util.Throwables2.getFirstThrowableOfType;
import java.io.InputStream; import java.io.InputStream;
@ -41,7 +44,6 @@ import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.lang.reflect.WildcardType; import java.lang.reflect.WildcardType;
import java.net.URI; import java.net.URI;
import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
@ -73,11 +75,12 @@ import org.jclouds.http.functions.ReturnInputStream;
import org.jclouds.http.functions.ReturnStringIf2xx; import org.jclouds.http.functions.ReturnStringIf2xx;
import org.jclouds.http.functions.ReturnTrueIf2xx; import org.jclouds.http.functions.ReturnTrueIf2xx;
import org.jclouds.http.functions.UnwrapOnlyJsonValue; import org.jclouds.http.functions.UnwrapOnlyJsonValue;
import org.jclouds.internal.ClassInvokerArgs;
import org.jclouds.internal.ClassInvokerArgsAndReturnVal;
import org.jclouds.json.internal.GsonWrapper; import org.jclouds.json.internal.GsonWrapper;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.jclouds.reflect.AbstractInvocationHandler; import org.jclouds.reflect.FunctionalReflection;
import org.jclouds.reflect.Invocation;
import org.jclouds.reflect.Invocation.Result;
import org.jclouds.reflect.InvocationSuccess;
import org.jclouds.rest.AuthorizationException; import org.jclouds.rest.AuthorizationException;
import org.jclouds.rest.InvocationContext; import org.jclouds.rest.InvocationContext;
import org.jclouds.rest.annotations.Delegate; import org.jclouds.rest.annotations.Delegate;
@ -95,7 +98,6 @@ import com.google.common.base.Function;
import com.google.common.base.Objects; import com.google.common.base.Objects;
import com.google.common.base.Optional; import com.google.common.base.Optional;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader; import com.google.common.cache.CacheLoader;
@ -103,7 +105,6 @@ import com.google.common.cache.LoadingCache;
import com.google.common.collect.FluentIterable; import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import com.google.common.reflect.Invokable; import com.google.common.reflect.Invokable;
import com.google.common.reflect.Parameter; import com.google.common.reflect.Parameter;
import com.google.common.reflect.TypeToken; import com.google.common.reflect.TypeToken;
@ -123,49 +124,36 @@ import com.google.inject.assistedinject.Assisted;
* <p/> * <p/>
* Particularly, this code delegates calls to other things. * Particularly, this code delegates calls to other things.
* <ol> * <ol>
* <li>if the method has a {@link Provides} annotation, it responds via a {@link Injector} lookup</li> * <li>if the invoked has a {@link Provides} annotation, it responds via a {@link Injector} lookup</li>
* <li>if the method has a {@link Delegate} annotation, it responds with an instance of interface set in returnVal, * <li>if the invoked has a {@link Delegate} annotation, it responds with an instance of interface set in returnVal,
* adding the current JAXrs annotations to whatever are on that class.</li> * adding the current JAXrs annotations to whatever are on that class.</li>
* <ul> * <ul>
* <li>ex. if the method with {@link Delegate} has a {@code Path} annotation, and the returnval interface also has * <li>ex. if the invoked with {@link Delegate} has a {@code Path} annotation, and the returnval interface also has
* {@code Path}, these values are combined.</li> * {@code Path}, these values are combined.</li>
* </ul> * </ul>
* <li>if {@link RestAnnotationProcessor#delegationMap} contains a mapping for this, and the returnVal is properly * <li>if {@link RestAnnotationProcessor#delegationMap} contains a mapping for this, and the returnVal is properly
* assigned as a {@link ListenableFuture}, it responds with an http implementation.</li> * assigned as a {@link ListenableFuture}, it responds with an http implementation.</li>
* <li>otherwise a RuntimeException is thrown with a message including: * <li>otherwise a RuntimeException is thrown with a message including:
* {@code method is intended solely to set constants}</li> * {@code invoked is intended solely to set constants}</li>
* </ol> * </ol>
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
@Singleton @Singleton
public abstract class AsyncRestClientProxy extends AbstractInvocationHandler { public class AsyncRestClientProxy implements Function<Invocation, Result> {
public static interface Factory {
Declaring declaring(Class<?> declaring);
Caller caller(ClassInvokerArgs caller);
}
public final static class Declaring extends AsyncRestClientProxy {
@Inject
private Declaring(Injector injector, Function<ClassInvokerArgsAndReturnVal, Optional<Object>> optionalConverter,
HttpCommandExecutorService http, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService userThreads,
@Named("async") LoadingCache<ClassInvokerArgs, Object> delegateMap, RestAnnotationProcessor.Factory rap,
ParseSax.Factory parserFactory, @Assisted Class<?> declaring) {
super(injector, optionalConverter, http, userThreads, delegateMap, rap.declaring(declaring), parserFactory,
declaring);
}
}
public final static class Caller extends AsyncRestClientProxy { public final static class Caller extends AsyncRestClientProxy {
public static interface Factory {
Caller caller(Invocation caller, Class<?> interfaceType);
}
@Inject @Inject
private Caller(Injector injector, Function<ClassInvokerArgsAndReturnVal, Optional<Object>> optionalConverter, private Caller(Injector injector, Function<InvocationSuccess, Optional<Object>> optionalConverter,
HttpCommandExecutorService http, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService userThreads, HttpCommandExecutorService http, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService userThreads,
@Named("async") LoadingCache<ClassInvokerArgs, Object> delegateMap, RestAnnotationProcessor.Factory rap, Caller.Factory factory, RestAnnotationProcessor.Caller.Factory rap, ParseSax.Factory parserFactory,
ParseSax.Factory parserFactory, @Assisted ClassInvokerArgs caller) { @Assisted Invocation caller) {
super(injector, optionalConverter, http, userThreads, delegateMap, rap.caller(caller), parserFactory, caller super(injector, optionalConverter, http, userThreads, factory, rap.caller(caller), parserFactory);
.getClazz());
} }
} }
@ -175,18 +163,16 @@ public abstract class AsyncRestClientProxy extends AbstractInvocationHandler {
private final Injector injector; private final Injector injector;
private final HttpCommandExecutorService http; private final HttpCommandExecutorService http;
private final ExecutorService userThreads; private final ExecutorService userThreads;
private final Function<ClassInvokerArgsAndReturnVal, Optional<Object>> optionalConverter; private final Function<InvocationSuccess, Optional<Object>> optionalConverter;
private final LoadingCache<ClassInvokerArgs, Object> delegateMap; private final Caller.Factory factory;
private final RestAnnotationProcessor annotationProcessor; private final RestAnnotationProcessor annotationProcessor;
private final ParseSax.Factory parserFactory; private final ParseSax.Factory parserFactory;
private final Class<?> declaring;
private static final LoadingCache<Class<?>, Set<Integer>> delegationMapCache = CacheBuilder.newBuilder().build( private static final LoadingCache<Class<?>, Set<InterfaceNameAndParameters>> delegationMapCache = CacheBuilder
new CacheLoader<Class<?>, Set<Integer>>() { .newBuilder().build(new CacheLoader<Class<?>, Set<InterfaceNameAndParameters>>() {
public Set<Integer> load(Class<?> declaring) throws ExecutionException { public Set<InterfaceNameAndParameters> load(final Class<?> interfaceType) throws ExecutionException {
FluentIterable<Invokable<?, ?>> methodsToProcess = FluentIterable return FluentIterable.from(ImmutableSet.copyOf(interfaceType.getMethods()))
.from(ImmutableSet.copyOf(declaring.getMethods())) .filter(not(in(ImmutableSet.copyOf(Object.class.getMethods()))))
.filter(Predicates.not(Predicates.in(ImmutableSet.copyOf(Object.class.getMethods()))))
.transform(new Function<Method, Invokable<?, ?>>() { .transform(new Function<Method, Invokable<?, ?>>() {
public Invokable<?, ?> apply(Method in) { public Invokable<?, ?> apply(Method in) {
return Invokable.from(in); return Invokable.from(in);
@ -204,86 +190,97 @@ public abstract class AsyncRestClientProxy extends AbstractInvocationHandler {
public boolean apply(Invokable<?, ?> in) { public boolean apply(Invokable<?, ?> in) {
return in.getReturnType().getRawType().isAssignableFrom(ListenableFuture.class); return in.getReturnType().getRawType().isAssignableFrom(ListenableFuture.class);
} }
}).transform(new Function<Invokable<?, ?>, InterfaceNameAndParameters>() {
}); public InterfaceNameAndParameters apply(Invokable<?, ?> in) {
return Maps.uniqueIndex(methodsToProcess, HashSignatureExceptReturnVal.INSTANCE).keySet(); return new InterfaceNameAndParameters(interfaceType, in.getName(), in.getParameters());
}
}).toSet();
} }
}); });
private static enum HashSignatureExceptReturnVal implements Function<Invokable<?, ?>, Integer> { private static final class InterfaceNameAndParameters {
INSTANCE; private final Class<?> interfaceType;
public Integer apply(Invokable<?, ?> in) { private final String name;
int parametersTypeHashCode = hashParameterTypes(in); private final int parametersTypeHashCode;
return Objects.hashCode(in.getDeclaringClass(), in.getName(), parametersTypeHashCode);
}
}
private static int hashParameterTypes(Invokable<?, ?> in) { private InterfaceNameAndParameters(Class<?> interfaceType, String name, ImmutableList<Parameter> parameters) {
this.interfaceType = interfaceType;
this.name = name;
int parametersTypeHashCode = 0; int parametersTypeHashCode = 0;
for (Parameter param : in.getParameters()) for (Parameter param : parameters)
parametersTypeHashCode += param.getType().hashCode(); parametersTypeHashCode += param.getType().hashCode();
return parametersTypeHashCode; this.parametersTypeHashCode = parametersTypeHashCode;
} }
public int hashCode() {
return Objects.hashCode(interfaceType, name, parametersTypeHashCode);
}
private AsyncRestClientProxy(Injector injector, @Override
Function<ClassInvokerArgsAndReturnVal, Optional<Object>> optionalConverter, HttpCommandExecutorService http, public boolean equals(Object o) {
ExecutorService userThreads, LoadingCache<ClassInvokerArgs, Object> delegateMap, if (this == o)
RestAnnotationProcessor annotationProcessor, ParseSax.Factory parserFactory, Class<?> declaring) { return true;
if (o == null || getClass() != o.getClass())
return false;
InterfaceNameAndParameters that = InterfaceNameAndParameters.class.cast(o);
return equal(this.interfaceType, that.interfaceType) && equal(this.name, that.name)
&& equal(this.parametersTypeHashCode, that.parametersTypeHashCode);
}
}
@Inject
private AsyncRestClientProxy(Injector injector, Function<InvocationSuccess, Optional<Object>> optionalConverter,
HttpCommandExecutorService http, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService userThreads,
Caller.Factory factory, RestAnnotationProcessor annotationProcessor, ParseSax.Factory parserFactory) {
this.injector = injector; this.injector = injector;
this.optionalConverter = optionalConverter; this.optionalConverter = optionalConverter;
this.http = http; this.http = http;
this.userThreads = userThreads; this.userThreads = userThreads;
this.delegateMap = delegateMap; this.factory = factory;
this.annotationProcessor = annotationProcessor; this.annotationProcessor = annotationProcessor;
this.parserFactory = parserFactory; this.parserFactory = parserFactory;
this.declaring = declaring;
} }
private static final Predicate<Annotation> isQualifierPresent = new Predicate<Annotation>() { private static final Predicate<Annotation> isQualifierPresent = new Predicate<Annotation>() {
@Override
public boolean apply(Annotation input) { public boolean apply(Annotation input) {
return input.annotationType().isAnnotationPresent(Qualifier.class); return input.annotationType().isAnnotationPresent(Qualifier.class);
} }
}; };
@Override @Override
protected Object handleInvocation(Object proxy, Invokable<?, ?> method, List<Object> args) throws Throwable { public Result apply(Invocation invocation) {
if (method.isAnnotationPresent(Provides.class)) { if (invocation.getInvokable().isAnnotationPresent(Provides.class)) {
return lookupValueFromGuice(method); return Result.success(lookupValueFromGuice(invocation.getInvokable()));
} else if (method.isAnnotationPresent(Delegate.class)) { } else if (invocation.getInvokable().isAnnotationPresent(Delegate.class)) {
return propagateContextToDelegate(method, args); return Result.success(propagateContextToDelegate(invocation));
} else if (isAsyncOrDelegate(method)) { } else if (isAsyncOrDelegate(invocation)) {
return createListenableFutureForHttpRequestMappedToMethodAndArgs(method, args); return Result.success(createListenableFutureForHttpRequestMappedToMethodAndArgs(invocation));
} else { } else {
throw new RuntimeException(String.format("Method is not annotated as either http or provider method: %s", return Result.fail(new IllegalStateException(String.format(
method)); "Method is not annotated as either http or provider invoked: %s", invocation.getInvokable())));
} }
} }
private boolean isAsyncOrDelegate(Invokable<?, ?> method) { private boolean isAsyncOrDelegate(Invocation invocation) {
return delegationMapCache.getUnchecked(declaring).contains(HashSignatureExceptReturnVal.INSTANCE.apply(method)); return delegationMapCache.getUnchecked(invocation.getInterfaceType()).contains(
new InterfaceNameAndParameters(invocation.getInterfaceType(), invocation.getInvokable().getName(),
invocation.getInvokable().getParameters()));
} }
private Object propagateContextToDelegate(Invokable<?, ?> method, List<Object> args) throws ExecutionException { private Object propagateContextToDelegate(Invocation invocation) {
Class<?> asyncClass = returnTypeOrTypeOfOptional(method); Class<?> returnType = unwrapIfOptional(invocation.getInvokable().getReturnType());
ClassInvokerArgs cma = ClassInvokerArgs.builder().clazz(asyncClass).invoker(method).args(args).build(); Object result = FunctionalReflection.newProxy(returnType, factory.caller(invocation, returnType));
Object returnVal = delegateMap.get(cma); if (isReturnTypeOptional(invocation.getInvokable())) {
if (isReturnTypeOptional(method)) { return optionalConverter.apply(InvocationSuccess.create(invocation, result));
ClassInvokerArgsAndReturnVal cmar = ClassInvokerArgsAndReturnVal.builder().fromClassInvokerArgs(cma)
.returnVal(returnVal).build();
return optionalConverter.apply(cmar);
} }
return returnVal; return result;
} }
private Object lookupValueFromGuice(Invokable<?, ?> method) { private Object lookupValueFromGuice(Invokable<?, ?> invoked) {
try { try {
Type genericReturnType = method.getReturnType().getType(); Type genericReturnType = invoked.getReturnType().getType();
try { try {
Annotation qualifier = find(ImmutableList.copyOf(method.getAnnotations()), isQualifierPresent); Annotation qualifier = find(ImmutableList.copyOf(invoked.getAnnotations()), isQualifierPresent);
return getInstanceOfTypeWithQualifier(genericReturnType, qualifier); return getInstanceOfTypeWithQualifier(genericReturnType, qualifier);
} catch (ProvisionException e) { } catch (ProvisionException e) {
throw propagate(e.getCause()); throw propagate(e.getCause());
@ -336,19 +333,20 @@ public abstract class AsyncRestClientProxy extends AbstractInvocationHandler {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@VisibleForTesting @VisibleForTesting
static Function<HttpResponse, ?> createResponseParser(ParseSax.Factory parserFactory, Injector injector, static Function<HttpResponse, ?> createResponseParser(ParseSax.Factory parserFactory, Injector injector,
Invokable<?, ?> method, HttpRequest request) { Invocation invocation, HttpRequest request) {
Function<HttpResponse, ?> transformer; Function<HttpResponse, ?> transformer;
Class<? extends HandlerWithResult<?>> handler = getSaxResponseParserClassOrNull(method); Class<? extends HandlerWithResult<?>> handler = getSaxResponseParserClassOrNull(invocation.getInvokable());
if (handler != null) { if (handler != null) {
transformer = parserFactory.create(injector.getInstance(handler)); transformer = parserFactory.create(injector.getInstance(handler));
} else { } else {
transformer = getTransformerForMethod(method, injector); transformer = getTransformerForMethod(invocation, injector);
} }
if (transformer instanceof InvocationContext<?>) { if (transformer instanceof InvocationContext<?>) {
((InvocationContext<?>) transformer).setContext(request); ((InvocationContext<?>) transformer).setContext(request);
} }
if (method.isAnnotationPresent(Transform.class)) { if (invocation.getInvokable().isAnnotationPresent(Transform.class)) {
Function<?, ?> wrappingTransformer = injector.getInstance(method.getAnnotation(Transform.class).value()); Function<?, ?> wrappingTransformer = injector.getInstance(invocation.getInvokable()
.getAnnotation(Transform.class).value());
if (wrappingTransformer instanceof InvocationContext<?>) { if (wrappingTransformer instanceof InvocationContext<?>) {
((InvocationContext<?>) wrappingTransformer).setContext(request); ((InvocationContext<?>) wrappingTransformer).setContext(request);
} }
@ -357,8 +355,8 @@ public abstract class AsyncRestClientProxy extends AbstractInvocationHandler {
return transformer; return transformer;
} }
private static Class<? extends HandlerWithResult<?>> getSaxResponseParserClassOrNull(Invokable<?, ?> method) { private static Class<? extends HandlerWithResult<?>> getSaxResponseParserClassOrNull(Invokable<?, ?> invoked) {
XMLResponseParser annotation = method.getAnnotation(XMLResponseParser.class); XMLResponseParser annotation = invoked.getAnnotation(XMLResponseParser.class);
if (annotation != null) { if (annotation != null) {
return annotation.value(); return annotation.value();
} }
@ -368,40 +366,40 @@ public abstract class AsyncRestClientProxy extends AbstractInvocationHandler {
// TODO: refactor this out of here // TODO: refactor this out of here
@VisibleForTesting @VisibleForTesting
@SuppressWarnings({ "rawtypes", "unchecked" }) @SuppressWarnings({ "rawtypes", "unchecked" })
public static Function<HttpResponse, ?> getTransformerForMethod(Invokable<?, ?> method, Injector injector) { public static Function<HttpResponse, ?> getTransformerForMethod(Invocation invocation, Injector injector) {
Invokable<?, ?> invoked = invocation.getInvokable();
Function<HttpResponse, ?> transformer; Function<HttpResponse, ?> transformer;
if (method.isAnnotationPresent(SelectJson.class)) { if (invoked.isAnnotationPresent(SelectJson.class)) {
Type returnVal = getReturnTypeFor(method.getReturnType()); Type returnVal = getReturnTypeFor(invoked.getReturnType());
if (method.isAnnotationPresent(OnlyElement.class)) if (invoked.isAnnotationPresent(OnlyElement.class))
returnVal = newParameterizedType(Set.class, returnVal); returnVal = newParameterizedType(Set.class, returnVal);
transformer = new ParseFirstJsonValueNamed(injector.getInstance(GsonWrapper.class), transformer = new ParseFirstJsonValueNamed(injector.getInstance(GsonWrapper.class),
TypeLiteral.get(returnVal), method.getAnnotation(SelectJson.class).value()); TypeLiteral.get(returnVal), invoked.getAnnotation(SelectJson.class).value());
if (method.isAnnotationPresent(OnlyElement.class)) if (invoked.isAnnotationPresent(OnlyElement.class))
transformer = compose(new OnlyElementOrNull(), transformer); transformer = compose(new OnlyElementOrNull(), transformer);
} else { } else {
transformer = injector.getInstance(getParserOrThrowException(method)); transformer = injector.getInstance(getParserOrThrowException(invocation));
} }
return transformer; return transformer;
} }
private ListenableFuture<?> createListenableFutureForHttpRequestMappedToMethodAndArgs(Invokable<?, ?> invoker, private ListenableFuture<?> createListenableFutureForHttpRequestMappedToMethodAndArgs(Invocation invocation) {
List<Object> args) { String name = invocation.getInterfaceType().getSimpleName() + "." + invocation.getInvokable().getName();
String name = invoker.getDeclaringClass().getSimpleName() + "." + invoker.getName();
logger.trace(">> converting %s", name); logger.trace(">> converting %s", name);
FutureFallback<?> fallback = fallbacks.getUnchecked(invoker); FutureFallback<?> fallback = fallbacks.getUnchecked(invocation.getInvokable());
// in case there is an exception creating the request, we should at least pass in args // in case there is an exception creating the request, we should at least pass in args
if (fallback instanceof InvocationContext) { if (fallback instanceof InvocationContext) {
InvocationContext.class.cast(fallback).setContext((HttpRequest) null); InvocationContext.class.cast(fallback).setContext((HttpRequest) null);
} }
ListenableFuture<?> result; ListenableFuture<?> result;
try { try {
GeneratedHttpRequest request = annotationProcessor.createRequest(invoker, args); GeneratedHttpRequest request = annotationProcessor.apply(invocation);
if (fallback instanceof InvocationContext) { if (fallback instanceof InvocationContext) {
InvocationContext.class.cast(fallback).setContext(request); InvocationContext.class.cast(fallback).setContext(request);
} }
logger.trace("<< converted %s to %s", name, request.getRequestLine()); logger.trace("<< converted %s to %s", name, request.getRequestLine());
Function<HttpResponse, ?> transformer = createResponseParser(parserFactory, injector, invoker, request); Function<HttpResponse, ?> transformer = createResponseParser(parserFactory, injector, invocation, request);
logger.trace("<< response from %s is parsed by %s", name, transformer.getClass().getSimpleName()); logger.trace("<< response from %s is parsed by %s", name, transformer.getClass().getSimpleName());
logger.debug(">> invoking %s", name); logger.debug(">> invoking %s", name);
@ -422,7 +420,7 @@ public abstract class AsyncRestClientProxy extends AbstractInvocationHandler {
@Override @Override
public String toString() { public String toString() {
return "Client Proxy for :" + declaring.getName(); return String.format("async->http");
} }
private final LoadingCache<Invokable<?, ?>, FutureFallback<?>> fallbacks = CacheBuilder.newBuilder().build( private final LoadingCache<Invokable<?, ?>, FutureFallback<?>> fallbacks = CacheBuilder.newBuilder().build(
@ -460,57 +458,57 @@ public abstract class AsyncRestClientProxy extends AbstractInvocationHandler {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@VisibleForTesting @VisibleForTesting
static Key<? extends Function<HttpResponse, ?>> getParserOrThrowException(Invokable<?, ?> method) { static Key<? extends Function<HttpResponse, ?>> getParserOrThrowException(Invocation invocation) {
Invokable<?, ?> invoked = invocation.getInvokable();
ResponseParser annotation = method.getAnnotation(ResponseParser.class); ResponseParser annotation = invoked.getAnnotation(ResponseParser.class);
if (annotation == null) { if (annotation == null) {
if (method.getReturnType().equals(void.class) || method.getReturnType().equals(futureVoidLiteral)) { if (invoked.getReturnType().equals(void.class) || invoked.getReturnType().equals(futureVoidLiteral)) {
return Key.get(ReleasePayloadAndReturn.class); return Key.get(ReleasePayloadAndReturn.class);
} else if (method.getReturnType().equals(boolean.class) || method.getReturnType().equals(Boolean.class) } else if (invoked.getReturnType().equals(boolean.class) || invoked.getReturnType().equals(Boolean.class)
|| method.getReturnType().equals(futureBooleanLiteral)) { || invoked.getReturnType().equals(futureBooleanLiteral)) {
return Key.get(ReturnTrueIf2xx.class); return Key.get(ReturnTrueIf2xx.class);
} else if (method.getReturnType().equals(InputStream.class) } else if (invoked.getReturnType().equals(InputStream.class)
|| method.getReturnType().equals(futureInputStreamLiteral)) { || invoked.getReturnType().equals(futureInputStreamLiteral)) {
return Key.get(ReturnInputStream.class); return Key.get(ReturnInputStream.class);
} else if (method.getReturnType().equals(HttpResponse.class) } else if (invoked.getReturnType().equals(HttpResponse.class)
|| method.getReturnType().equals(futureHttpResponseLiteral)) { || invoked.getReturnType().equals(futureHttpResponseLiteral)) {
return Key.get(Class.class.cast(IdentityFunction.class)); return Key.get(Class.class.cast(IdentityFunction.class));
} else if (RestAnnotationProcessor.getAcceptHeaders(method).contains(APPLICATION_JSON)) { } else if (RestAnnotationProcessor.getAcceptHeaders(invocation).contains(APPLICATION_JSON)) {
return getJsonParserKeyForMethod(method); return getJsonParserKeyForMethod(invoked);
} else if (RestAnnotationProcessor.getAcceptHeaders(method).contains(APPLICATION_XML) } else if (RestAnnotationProcessor.getAcceptHeaders(invocation).contains(APPLICATION_XML)
|| method.isAnnotationPresent(JAXBResponseParser.class)) { || invoked.isAnnotationPresent(JAXBResponseParser.class)) {
return getJAXBParserKeyForMethod(method); return getJAXBParserKeyForMethod(invoked);
} else if (method.getReturnType().equals(String.class) || method.getReturnType().equals(futureStringLiteral)) { } else if (invoked.getReturnType().equals(String.class) || invoked.getReturnType().equals(futureStringLiteral)) {
return Key.get(ReturnStringIf2xx.class); return Key.get(ReturnStringIf2xx.class);
} else if (method.getReturnType().equals(URI.class) || method.getReturnType().equals(futureURILiteral)) { } else if (invoked.getReturnType().equals(URI.class) || invoked.getReturnType().equals(futureURILiteral)) {
return Key.get(ParseURIFromListOrLocationHeaderIf20x.class); return Key.get(ParseURIFromListOrLocationHeaderIf20x.class);
} else { } else {
throw new IllegalStateException("You must specify a ResponseParser annotation on: " + method.toString()); throw new IllegalStateException("You must specify a ResponseParser annotation on: " + invoked.toString());
} }
} }
return Key.get(annotation.value()); return Key.get(annotation.value());
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private static Key<? extends Function<HttpResponse, ?>> getJAXBParserKeyForMethod(Invokable<?, ?> method) { private static Key<? extends Function<HttpResponse, ?>> getJAXBParserKeyForMethod(Invokable<?, ?> invoked) {
Optional<Type> configuredReturnVal = Optional.absent(); Optional<Type> configuredReturnVal = Optional.absent();
if (method.isAnnotationPresent(JAXBResponseParser.class)) { if (invoked.isAnnotationPresent(JAXBResponseParser.class)) {
Type configuredClass = method.getAnnotation(JAXBResponseParser.class).value(); Type configuredClass = invoked.getAnnotation(JAXBResponseParser.class).value();
configuredReturnVal = configuredClass.equals(NullType.class) ? Optional.<Type> absent() : Optional configuredReturnVal = configuredClass.equals(NullType.class) ? Optional.<Type> absent() : Optional
.<Type> of(configuredClass); .<Type> of(configuredClass);
} }
Type returnVal = configuredReturnVal.or(getReturnTypeFor(method.getReturnType())); Type returnVal = configuredReturnVal.or(getReturnTypeFor(invoked.getReturnType()));
Type parserType = newParameterizedType(ParseXMLWithJAXB.class, returnVal); Type parserType = newParameterizedType(ParseXMLWithJAXB.class, returnVal);
return (Key<? extends Function<HttpResponse, ?>>) Key.get(parserType); return (Key<? extends Function<HttpResponse, ?>>) Key.get(parserType);
} }
@SuppressWarnings({ "unchecked" }) @SuppressWarnings({ "unchecked" })
private static Key<? extends Function<HttpResponse, ?>> getJsonParserKeyForMethod(Invokable<?, ?> method) { private static Key<? extends Function<HttpResponse, ?>> getJsonParserKeyForMethod(Invokable<?, ?> invoked) {
ParameterizedType parserType; ParameterizedType parserType;
if (method.isAnnotationPresent(Unwrap.class)) { if (invoked.isAnnotationPresent(Unwrap.class)) {
parserType = newParameterizedType(UnwrapOnlyJsonValue.class, getReturnTypeFor(method.getReturnType())); parserType = newParameterizedType(UnwrapOnlyJsonValue.class, getReturnTypeFor(invoked.getReturnType()));
} else { } else {
parserType = newParameterizedType(ParseJson.class, getReturnTypeFor(method.getReturnType())); parserType = newParameterizedType(ParseJson.class, getReturnTypeFor(invoked.getReturnType()));
} }
return (Key<? extends Function<HttpResponse, ?>>) Key.get(parserType); return (Key<? extends Function<HttpResponse, ?>>) Key.get(parserType);
} }
@ -527,4 +525,5 @@ public abstract class AsyncRestClientProxy extends AbstractInvocationHandler {
} }
return returnVal; return returnVal;
} }
} }

View File

@ -1,41 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.jclouds.rest.internal;
import static com.google.common.reflect.Reflection.newProxy;
import org.jclouds.internal.ClassInvokerArgs;
import org.jclouds.rest.internal.AsyncRestClientProxy.Factory;
import com.google.common.cache.CacheLoader;
import com.google.inject.Inject;
public final class CreateAsyncClientForCaller extends CacheLoader<ClassInvokerArgs, Object> {
private final Factory factory;
@Inject
private CreateAsyncClientForCaller(AsyncRestClientProxy.Factory factory) {
this.factory = factory;
}
@Override
public Object load(ClassInvokerArgs from) {
return newProxy(from.getClazz(), factory.caller(from));
}
}

View File

@ -1,64 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.jclouds.rest.internal;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.reflect.Reflection.newProxy;
import java.util.Map;
import javax.inject.Inject;
import javax.inject.Named;
import org.jclouds.concurrent.internal.SyncProxy;
import org.jclouds.internal.ClassInvokerArgs;
import org.jclouds.util.Optionals2;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
/**
* CreateClientForCaller is parameterized, so clients it creates aren't singletons. For example, CreateClientForCaller
* satisfies a call like this: {@code context.getProviderSpecificContext().getApi().getOrgClientForName(name)}
*
* @author Adrian Cole
*/
public class CreateClientForCaller extends CacheLoader<ClassInvokerArgs, Object> {
private final SyncProxy.Factory factory;
private final LoadingCache<ClassInvokerArgs, Object> asyncMap;
private final Map<Class<?>, Class<?>> sync2Async;
@Inject
private CreateClientForCaller(SyncProxy.Factory factory,
@Named("async") LoadingCache<ClassInvokerArgs, Object> asyncMap, Map<Class<?>, Class<?>> sync2Async) {
this.factory = factory;
this.asyncMap = asyncMap;
this.sync2Async = sync2Async;
}
@Override
public Object load(ClassInvokerArgs from) {
Class<?> syncClass = Optionals2.returnTypeOrTypeOfOptional(from.getInvoker());
Class<?> asyncClass = sync2Async.get(syncClass);
checkState(asyncClass != null, "configuration error, sync class " + syncClass + " not mapped to an async class");
Object asyncClient = asyncMap.getUnchecked(from);
checkState(asyncClient != null, "configuration error, sync client for " + from + " not found");
return newProxy(syncClass, factory.create(syncClass, asyncClient));
}
}

View File

@ -21,28 +21,22 @@ package org.jclouds.rest.internal;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import java.net.URI; import java.net.URI;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpRequestFilter; import org.jclouds.http.HttpRequestFilter;
import org.jclouds.internal.ClassInvokerArgs;
import org.jclouds.io.Payload; import org.jclouds.io.Payload;
import org.jclouds.javax.annotation.Nullable; import org.jclouds.javax.annotation.Nullable;
import org.jclouds.reflect.Invocation;
import com.google.common.base.Optional; import com.google.common.base.Optional;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap; import com.google.common.collect.Multimap;
import com.google.common.reflect.Invokable;
/** /**
* Represents a request generated from annotations * Represents a request generated from annotations
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
// TODO: get rid of all the mock tests so that this can be made final public final class GeneratedHttpRequest extends HttpRequest {
public class GeneratedHttpRequest extends HttpRequest {
public static Builder builder() { public static Builder builder() {
return new Builder(); return new Builder();
} }
@ -51,70 +45,34 @@ public class GeneratedHttpRequest extends HttpRequest {
return new Builder().fromGeneratedHttpRequest(this); return new Builder().fromGeneratedHttpRequest(this);
} }
public static class Builder extends HttpRequest.Builder<Builder> { public final static class Builder extends HttpRequest.Builder<Builder> {
protected Class<?> declaring; protected Invocation invocation;
protected Invokable<?, ?> invoker; protected Optional<Invocation> caller = Optional.absent();
// args can be null, so cannot use immutable list
protected List<Object> args = Lists.newArrayList();
protected Optional<ClassInvokerArgs> caller = Optional.absent();
/** /**
* @see GeneratedHttpRequest#getDeclaring() * @see GeneratedHttpRequest#getInvocation()
*/ */
public Builder declaring(Class<?> declaring) { public Builder invocation(Invocation invocation) {
this.declaring = checkNotNull(declaring, "declaring"); this.invocation = checkNotNull(invocation, "invocation");
return this;
}
/**
* @see GeneratedHttpRequest#getInvoker()
*/
public Builder invoker(Invokable<?, ?> invoker) {
this.invoker = checkNotNull(invoker, "invoker");
return this;
}
/**
* @see GeneratedHttpRequest#getArgs()
*/
public Builder args(Iterable<Object> args) {
this.args = Lists.newArrayList(checkNotNull(args, "args"));
return this;
}
/**
* @see GeneratedHttpRequest#getArgs()
*/
public Builder args(@Nullable Object[] args) {
return args(Arrays.asList(args != null ? args : new Object[] {}));
}
/**
* @see GeneratedHttpRequest#getArgs()
*/
public Builder arg(@Nullable Object arg) {
this.args.add(arg);
return this; return this;
} }
/** /**
* @see GeneratedHttpRequest#getCaller() * @see GeneratedHttpRequest#getCaller()
*/ */
public Builder caller(@Nullable ClassInvokerArgs caller) { public Builder caller(@Nullable Invocation caller) {
this.caller = Optional.fromNullable(caller); this.caller = Optional.fromNullable(caller);
return this; return this;
} }
public GeneratedHttpRequest build() { public GeneratedHttpRequest build() {
return new GeneratedHttpRequest(method, endpoint, headers.build(), payload, declaring, invoker, args, return new GeneratedHttpRequest(method, endpoint, headers.build(), payload, invocation, filters.build(),
filters.build(), caller); caller);
} }
public Builder fromGeneratedHttpRequest(GeneratedHttpRequest in) { public Builder fromGeneratedHttpRequest(GeneratedHttpRequest in) {
return super.fromHttpRequest(in) return super.fromHttpRequest(in)
.declaring(in.getDeclaring()) .invocation(in.invocation)
.invoker(in.invoker)
.args(in.getArgs())
.caller(in.getCaller().orNull()); .caller(in.getCaller().orNull());
} }
@ -124,35 +82,25 @@ public class GeneratedHttpRequest extends HttpRequest {
} }
} }
private final Class<?> declaring; private final Invocation invocation;
private final Invokable<?, ?> invoker; private final Optional<Invocation> caller;
private final List<Object> args;
private final Optional<ClassInvokerArgs> caller;
protected GeneratedHttpRequest(String method, URI endpoint, Multimap<String, String> headers, protected GeneratedHttpRequest(String method, URI endpoint, Multimap<String, String> headers,
@Nullable Payload payload, Class<?> declaring, Invokable<?, ?> invoker, @Nullable Payload payload, Invocation invocation, Iterable<HttpRequestFilter> filters,
List<Object> args, Iterable<HttpRequestFilter> filters, Optional<ClassInvokerArgs> caller) { Optional<Invocation> caller) {
super(method, endpoint, headers, payload, filters); super(method, endpoint, headers, payload, filters);
this.declaring = checkNotNull(declaring, "declaring"); this.invocation = checkNotNull(invocation, "invocation");
this.invoker = checkNotNull(invoker, "invoker");
// TODO make immutable. ImmutableList.of() doesn't accept nulls
this.args = Collections.unmodifiableList(checkNotNull(args, "args"));
this.caller = checkNotNull(caller, "caller"); this.caller = checkNotNull(caller, "caller");
} }
public Class<?> getDeclaring() { /**
return declaring; * what was interpreted to create this request
*/
public Invocation getInvocation() {
return invocation;
} }
public Invokable<?,?> getInvoker() { public Optional<Invocation> getCaller() {
return invoker;
}
public List<Object> getArgs() {
return args;
}
public Optional<ClassInvokerArgs> getCaller() {
return caller; return caller;
} }
} }

View File

@ -17,6 +17,7 @@
* under the License. * under the License.
*/ */
package org.jclouds.rest.internal; package org.jclouds.rest.internal;
import static com.google.common.base.Functions.toStringFunction; import static com.google.common.base.Functions.toStringFunction;
import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
@ -67,7 +68,6 @@ import org.jclouds.http.HttpRequestFilter;
import org.jclouds.http.HttpUtils; import org.jclouds.http.HttpUtils;
import org.jclouds.http.Uris.UriBuilder; import org.jclouds.http.Uris.UriBuilder;
import org.jclouds.http.options.HttpRequestOptions; import org.jclouds.http.options.HttpRequestOptions;
import org.jclouds.internal.ClassInvokerArgs;
import org.jclouds.io.ContentMetadataCodec; import org.jclouds.io.ContentMetadataCodec;
import org.jclouds.io.Payload; import org.jclouds.io.Payload;
import org.jclouds.io.PayloadEnclosing; import org.jclouds.io.PayloadEnclosing;
@ -77,6 +77,7 @@ import org.jclouds.io.payloads.Part;
import org.jclouds.io.payloads.Part.PartOptions; import org.jclouds.io.payloads.Part.PartOptions;
import org.jclouds.javax.annotation.Nullable; import org.jclouds.javax.annotation.Nullable;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.jclouds.reflect.Invocation;
import org.jclouds.rest.Binder; import org.jclouds.rest.Binder;
import org.jclouds.rest.InputParamValidator; import org.jclouds.rest.InputParamValidator;
import org.jclouds.rest.annotations.ApiVersion; import org.jclouds.rest.annotations.ApiVersion;
@ -127,34 +128,25 @@ import com.google.inject.TypeLiteral;
import com.google.inject.assistedinject.Assisted; import com.google.inject.assistedinject.Assisted;
/** /**
* Creates http methods based on annotations on a class or interface. * Creates http invocation.getInvoked()s based on annotations on a class or interface.
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
public abstract class RestAnnotationProcessor { public class RestAnnotationProcessor implements Function<Invocation, GeneratedHttpRequest> {
public static interface Factory {
Declaring declaring(Class<?> declaring);
Caller caller(ClassInvokerArgs caller);
}
public static final class Declaring extends RestAnnotationProcessor {
@Inject
private Declaring(Injector injector, @ApiVersion String apiVersion, @BuildVersion String buildVersion,
HttpUtils utils, ContentMetadataCodec contentMetadataCodec, InputParamValidator inputParamValidator,
@Assisted Class<?> declaring) {
super(injector, apiVersion, buildVersion, utils, contentMetadataCodec, inputParamValidator, declaring);
}
}
public static final class Caller extends RestAnnotationProcessor { public static final class Caller extends RestAnnotationProcessor {
private final ClassInvokerArgs caller;
public static interface Factory {
Caller caller(Invocation caller);
}
private final Invocation caller;
@Inject @Inject
private Caller(Injector injector, @ApiVersion String apiVersion, @BuildVersion String buildVersion, private Caller(Injector injector, @ApiVersion String apiVersion, @BuildVersion String buildVersion,
HttpUtils utils, ContentMetadataCodec contentMetadataCodec, InputParamValidator inputParamValidator, HttpUtils utils, ContentMetadataCodec contentMetadataCodec, InputParamValidator inputParamValidator,
@Assisted ClassInvokerArgs caller) { @Assisted Invocation caller) {
super(injector, apiVersion, buildVersion, utils, contentMetadataCodec, inputParamValidator, caller.getClazz()); super(injector, apiVersion, buildVersion, utils, contentMetadataCodec, inputParamValidator);
this.caller = caller; this.caller = caller;
} }
@ -164,29 +156,22 @@ public abstract class RestAnnotationProcessor {
} }
@Override @Override
protected Optional<URI> findEndpoint(Invokable<?,?> method, List<Object> args) { protected Optional<URI> findEndpoint(Invocation invocation) {
Optional<URI> endpoint = getEndpointFor(caller.getInvoker(), caller.getArgs()); Optional<URI> endpoint = getEndpointFor(caller);
if (endpoint.isPresent()) if (endpoint.isPresent())
logger.trace("using endpoint %s from caller %s for %s", endpoint, caller, cma(method, args)); logger.trace("using endpoint %s from caller %s for %s", endpoint, caller, invocation);
else else
endpoint = super.findEndpoint(method, args); endpoint = super.findEndpoint(invocation);
return endpoint; return endpoint;
} }
@Override @Override
protected Multimap<String, Object> addPathAndGetTokens(Class<?> clazz, Invokable<?,?> method, List<Object> args, protected Multimap<String, Object> addPathAndGetTokens(Invocation invocation, UriBuilder uriBuilder) {
UriBuilder uriBuilder) { return ImmutableMultimap.<String, Object> builder().putAll(super.addPathAndGetTokens(caller, uriBuilder))
Class<?> callerClass = caller.getInvoker().getDeclaringClass(); .putAll(super.addPathAndGetTokens(invocation, uriBuilder)).build();
return ImmutableMultimap.<String, Object> builder()
.putAll(super.addPathAndGetTokens(callerClass, caller.getInvoker(), caller.getArgs(), uriBuilder))
.putAll(super.addPathAndGetTokens(clazz, method, args, uriBuilder)).build();
} }
} }
protected ClassInvokerArgs cma(Invokable<?,?> method, List<Object> args) {
return logger.isTraceEnabled() ? new ClassInvokerArgs(method.getDeclaringClass(), method, args) : null;
}
@Resource @Resource
protected Logger logger = Logger.NULL; protected Logger logger = Logger.NULL;
@ -197,7 +182,6 @@ public abstract class RestAnnotationProcessor {
} }
}; };
private final Class<?> declaring;
private final Injector injector; private final Injector injector;
private final HttpUtils utils; private final HttpUtils utils;
private final ContentMetadataCodec contentMetadataCodec; private final ContentMetadataCodec contentMetadataCodec;
@ -205,47 +189,52 @@ public abstract class RestAnnotationProcessor {
private final String buildVersion; private final String buildVersion;
private final InputParamValidator inputParamValidator; private final InputParamValidator inputParamValidator;
private RestAnnotationProcessor(Injector injector, String apiVersion, String buildVersion, @Inject
HttpUtils utils, ContentMetadataCodec contentMetadataCodec, private RestAnnotationProcessor(Injector injector, @ApiVersion String apiVersion, @BuildVersion String buildVersion,
InputParamValidator inputParamValidator, Class<?> declaring) { HttpUtils utils, ContentMetadataCodec contentMetadataCodec, InputParamValidator inputParamValidator) {
this.injector = injector; this.injector = injector;
this.utils = utils; this.utils = utils;
this.contentMetadataCodec = contentMetadataCodec; this.contentMetadataCodec = contentMetadataCodec;
this.apiVersion = apiVersion; this.apiVersion = apiVersion;
this.buildVersion = buildVersion; this.buildVersion = buildVersion;
this.inputParamValidator = inputParamValidator; this.inputParamValidator = inputParamValidator;
this.declaring = declaring;
} }
public GeneratedHttpRequest createRequest(Invokable<?, ?> invoker, List<Object> args) { /**
checkNotNull(invoker, "invoker"); * Note this is dangerous as it cannot pass the inheriting class! Using this when subclassing interfaces may result
checkNotNull(args, "args"); * in lost data.
inputParamValidator.validateMethodParametersOrThrow(invoker, args); */
@Deprecated
public GeneratedHttpRequest createRequest(Invokable<?, ?> invokable, List<Object> args) {
return apply(Invocation.create(invokable, args));
}
@Override
public GeneratedHttpRequest apply(Invocation invocation) {
checkNotNull(invocation, "invocation");
inputParamValidator.validateMethodParametersOrThrow(invocation);
Optional<URI> endpoint = Optional.absent(); Optional<URI> endpoint = Optional.absent();
HttpRequest r = findOrNull(args, HttpRequest.class); HttpRequest r = findOrNull(invocation.getArgs(), HttpRequest.class);
if (r != null) { if (r != null) {
endpoint = Optional.fromNullable(r.getEndpoint()); endpoint = Optional.fromNullable(r.getEndpoint());
if (endpoint.isPresent()) if (endpoint.isPresent())
logger.trace("using endpoint %s from args for %s", endpoint, cma(invoker, args)); logger.trace("using endpoint %s from invocation.getArgs() for %s", endpoint, invocation);
} else { } else {
endpoint = findEndpoint(invoker, args); endpoint = findEndpoint(invocation);
} }
if (!endpoint.isPresent()) if (!endpoint.isPresent())
throw new NoSuchElementException(format("no endpoint found for %s", cma(invoker, args))); throw new NoSuchElementException(format("no endpoint found for %s", invocation));
GeneratedHttpRequest.Builder requestBuilder = requestBuilder(); GeneratedHttpRequest.Builder requestBuilder = requestBuilder();
if (r != null) { if (r != null) {
requestBuilder.fromHttpRequest(r); requestBuilder.fromHttpRequest(r);
} else { } else {
requestBuilder.method(tryFindHttpMethod(invoker).get()); requestBuilder.method(tryFindHttpMethod(invocation.getInvokable()).get());
} }
requestBuilder.declaring(declaring) requestBuilder.invocation(invocation).filters(getFiltersIfAnnotated(invocation));
.invoker(invoker)
.args(args)
.filters(getFiltersIfAnnotated(invoker));
Multimap<String, Object> tokenValues = LinkedHashMultimap.create(); Multimap<String, Object> tokenValues = LinkedHashMultimap.create();
@ -254,18 +243,18 @@ public abstract class RestAnnotationProcessor {
UriBuilder uriBuilder = uriBuilder(endpoint.get().toString()); // URI template in rfc6570 form UriBuilder uriBuilder = uriBuilder(endpoint.get().toString()); // URI template in rfc6570 form
overridePathEncoding(uriBuilder, invoker); overridePathEncoding(uriBuilder, invocation);
tokenValues.putAll(addPathAndGetTokens(declaring, invoker, args, uriBuilder)); tokenValues.putAll(addPathAndGetTokens(invocation, uriBuilder));
Multimap<String, Object> formParams = addFormParams(tokenValues, invoker, args); Multimap<String, Object> formParams = addFormParams(tokenValues, invocation);
Multimap<String, Object> queryParams = addQueryParams(tokenValues, invoker, args); Multimap<String, Object> queryParams = addQueryParams(tokenValues, invocation);
Multimap<String, String> headers = buildHeaders(tokenValues, invoker, args); Multimap<String, String> headers = buildHeaders(tokenValues, invocation);
if (r != null) if (r != null)
headers.putAll(r.getHeaders()); headers.putAll(r.getHeaders());
if (shouldAddHostHeader(invoker)) { if (shouldAddHostHeader(invocation)) {
StringBuilder hostHeader = new StringBuilder(endpoint.get().getHost()); StringBuilder hostHeader = new StringBuilder(endpoint.get().getHost());
if (endpoint.get().getPort() != -1) if (endpoint.get().getPort() != -1)
hostHeader.append(":").append(endpoint.get().getPort()); hostHeader.append(":").append(endpoint.get().getPort());
@ -273,7 +262,7 @@ public abstract class RestAnnotationProcessor {
} }
Payload payload = null; Payload payload = null;
for(HttpRequestOptions options : findOptionsIn(invoker, args)) { for (HttpRequestOptions options : findOptionsIn(invocation)) {
injector.injectMembers(options);// TODO test case injector.injectMembers(options);// TODO test case
for (Entry<String, String> header : options.buildRequestHeaders().entries()) { for (Entry<String, String> header : options.buildRequestHeaders().entries()) {
headers.put(header.getKey(), replaceTokens(header.getValue(), tokenValues)); headers.put(header.getKey(), replaceTokens(header.getValue(), tokenValues));
@ -303,13 +292,13 @@ public abstract class RestAnnotationProcessor {
requestBuilder.endpoint(uriBuilder.build(convertUnsafe(tokenValues))); requestBuilder.endpoint(uriBuilder.build(convertUnsafe(tokenValues)));
if (payload == null) { if (payload == null) {
PayloadEnclosing payloadEnclosing = findOrNull(args, PayloadEnclosing.class); PayloadEnclosing payloadEnclosing = findOrNull(invocation.getArgs(), PayloadEnclosing.class);
payload = (payloadEnclosing != null) ? payloadEnclosing.getPayload() : findOrNull(args, Payload.class); payload = (payloadEnclosing != null) ? payloadEnclosing.getPayload() : findOrNull(invocation.getArgs(),
Payload.class);
} }
List<? extends Part> parts = getParts(invoker, args, ImmutableMultimap.<String, Object> builder() List<? extends Part> parts = getParts(invocation, ImmutableMultimap.<String, Object> builder()
.putAll(tokenValues) .putAll(tokenValues).putAll(formParams).build());
.putAll(formParams).build());
if (parts.size() > 0) { if (parts.size() > 0) {
if (formParams.size() > 0) { if (formParams.size() > 0) {
@ -328,11 +317,11 @@ public abstract class RestAnnotationProcessor {
} }
GeneratedHttpRequest request = requestBuilder.build(); GeneratedHttpRequest request = requestBuilder.build();
org.jclouds.rest.MapBinder mapBinder = getMapPayloadBinderOrNull(invoker, args); org.jclouds.rest.MapBinder mapBinder = getMapPayloadBinderOrNull(invocation);
if (mapBinder != null) { if (mapBinder != null) {
Map<String, Object> mapParams = buildPayloadParams(invoker, args); Map<String, Object> mapParams = buildPayloadParams(invocation);
if (invoker.isAnnotationPresent(PayloadParams.class)) { if (invocation.getInvokable().isAnnotationPresent(PayloadParams.class)) {
PayloadParams params = invoker.getAnnotation(PayloadParams.class); PayloadParams params = invocation.getInvokable().getAnnotation(PayloadParams.class);
addMapPayload(mapParams, params, headers); addMapPayload(mapParams, params, headers);
} }
request = mapBinder.bindToRequest(request, mapParams); request = mapBinder.bindToRequest(request, mapParams);
@ -347,7 +336,7 @@ public abstract class RestAnnotationProcessor {
return request; return request;
} }
private <T> T findOrNull(Iterable<Object> args, Class<T> clazz) { private static <T> T findOrNull(Iterable<Object> args, Class<T> clazz) {
return clazz.cast(tryFind(args, instanceOf(clazz)).orNull()); return clazz.cast(tryFind(args, instanceOf(clazz)).orNull());
} }
@ -363,12 +352,13 @@ public abstract class RestAnnotationProcessor {
return GeneratedHttpRequest.builder(); return GeneratedHttpRequest.builder();
} }
private void overridePathEncoding(UriBuilder uriBuilder, Invokable<?, ?> method) { private void overridePathEncoding(UriBuilder uriBuilder, Invocation invocation) {
if (declaring.isAnnotationPresent(SkipEncoding.class)) { if (invocation.getInterfaceType().isAnnotationPresent(SkipEncoding.class)) {
uriBuilder.skipPathEncoding(Chars.asList(declaring.getAnnotation(SkipEncoding.class).value())); uriBuilder.skipPathEncoding(Chars.asList(invocation.getInterfaceType().getAnnotation(SkipEncoding.class)
.value()));
} }
if (method.isAnnotationPresent(SkipEncoding.class)) { if (invocation.getInvokable().isAnnotationPresent(SkipEncoding.class)) {
uriBuilder.skipPathEncoding(Chars.asList(method.getAnnotation(SkipEncoding.class).value())); uriBuilder.skipPathEncoding(Chars.asList(invocation.getInvokable().getAnnotation(SkipEncoding.class).value()));
} }
} }
@ -383,63 +373,59 @@ public abstract class RestAnnotationProcessor {
} }
} }
protected Optional<URI> findEndpoint(Invokable<?,?> method, List<Object> args) { protected Optional<URI> findEndpoint(Invocation invocation) {
ClassInvokerArgs cma = cma(method, args); Optional<URI> endpoint = getEndpointFor(invocation);
Optional<URI> endpoint = getEndpointFor(method, args);
if (endpoint.isPresent()) if (endpoint.isPresent())
logger.trace("using endpoint %s for %s", endpoint, cma); logger.trace("using endpoint %s for %s", endpoint, invocation);
if (!endpoint.isPresent()) { if (!endpoint.isPresent()) {
logger.trace("looking up default endpoint for %s", cma); logger.trace("looking up default endpoint for %s", invocation);
endpoint = Optional.fromNullable(injector.getInstance( endpoint = Optional.fromNullable(injector.getInstance(
Key.get(uriSupplierLiteral, org.jclouds.location.Provider.class)).get()); Key.get(uriSupplierLiteral, org.jclouds.location.Provider.class)).get());
if (endpoint.isPresent()) if (endpoint.isPresent())
logger.trace("using default endpoint %s for %s", endpoint, cma); logger.trace("using default endpoint %s for %s", endpoint, invocation);
} }
return endpoint; return endpoint;
} }
protected Multimap<String, Object> addPathAndGetTokens(Class<?> clazz, Invokable<?, ?> method, List<Object> args, protected Multimap<String, Object> addPathAndGetTokens(Invocation invocation, UriBuilder uriBuilder) {
UriBuilder uriBuilder) { if (invocation.getInterfaceType().isAnnotationPresent(Path.class))
if (clazz.isAnnotationPresent(Path.class)) uriBuilder.appendPath(invocation.getInterfaceType().getAnnotation(Path.class).value());
uriBuilder.appendPath(clazz.getAnnotation(Path.class).value()); if (invocation.getInvokable().isAnnotationPresent(Path.class))
if (method.isAnnotationPresent(Path.class)) uriBuilder.appendPath(invocation.getInvokable().getAnnotation(Path.class).value());
uriBuilder.appendPath(method.getAnnotation(Path.class).value()); return getPathParamKeyValues(invocation);
return getPathParamKeyValues(method, args);
} }
private Multimap<String, Object> addFormParams(Multimap<String, ?> tokenValues, Invokable<?, ?> method, private Multimap<String, Object> addFormParams(Multimap<String, ?> tokenValues, Invocation invocation) {
List<Object> args) {
Multimap<String, Object> formMap = LinkedListMultimap.create(); Multimap<String, Object> formMap = LinkedListMultimap.create();
if (declaring.isAnnotationPresent(FormParams.class)) { if (invocation.getInterfaceType().isAnnotationPresent(FormParams.class)) {
FormParams form = declaring.getAnnotation(FormParams.class); FormParams form = invocation.getInterfaceType().getAnnotation(FormParams.class);
addForm(formMap, form, tokenValues); addForm(formMap, form, tokenValues);
} }
if (method.isAnnotationPresent(FormParams.class)) { if (invocation.getInvokable().isAnnotationPresent(FormParams.class)) {
FormParams form = method.getAnnotation(FormParams.class); FormParams form = invocation.getInvokable().getAnnotation(FormParams.class);
addForm(formMap, form, tokenValues); addForm(formMap, form, tokenValues);
} }
for (Entry<String, Object> form : getFormParamKeyValues(method, args).entries()) { for (Entry<String, Object> form : getFormParamKeyValues(invocation).entries()) {
formMap.put(form.getKey(), replaceTokens(form.getValue().toString(), tokenValues)); formMap.put(form.getKey(), replaceTokens(form.getValue().toString(), tokenValues));
} }
return formMap; return formMap;
} }
private Multimap<String, Object> addQueryParams(Multimap<String, ?> tokenValues, Invokable<?, ?> method, private Multimap<String, Object> addQueryParams(Multimap<String, ?> tokenValues, Invocation invocation) {
List<Object> args) {
Multimap<String, Object> queryMap = LinkedListMultimap.create(); Multimap<String, Object> queryMap = LinkedListMultimap.create();
if (declaring.isAnnotationPresent(QueryParams.class)) { if (invocation.getInterfaceType().isAnnotationPresent(QueryParams.class)) {
QueryParams query = declaring.getAnnotation(QueryParams.class); QueryParams query = invocation.getInterfaceType().getAnnotation(QueryParams.class);
addQuery(queryMap, query, tokenValues); addQuery(queryMap, query, tokenValues);
} }
if (method.isAnnotationPresent(QueryParams.class)) { if (invocation.getInvokable().isAnnotationPresent(QueryParams.class)) {
QueryParams query = method.getAnnotation(QueryParams.class); QueryParams query = invocation.getInvokable().getAnnotation(QueryParams.class);
addQuery(queryMap, query, tokenValues); addQuery(queryMap, query, tokenValues);
} }
for (Entry<String, Object> query : getQueryParamKeyValues(method, args).entries()) { for (Entry<String, Object> query : getQueryParamKeyValues(invocation).entries()) {
queryMap.put(query.getKey(), replaceTokens(query.getValue().toString(), tokenValues)); queryMap.put(query.getKey(), replaceTokens(query.getValue().toString(), tokenValues));
} }
return queryMap; return queryMap;
@ -478,47 +464,53 @@ public abstract class RestAnnotationProcessor {
} }
} }
private List<HttpRequestFilter> getFiltersIfAnnotated(Invokable<?,?> method) { private List<HttpRequestFilter> getFiltersIfAnnotated(Invocation invocation) {
List<HttpRequestFilter> filters = newArrayList(); List<HttpRequestFilter> filters = newArrayList();
if (declaring.isAnnotationPresent(RequestFilters.class)) { if (invocation.getInterfaceType().isAnnotationPresent(RequestFilters.class)) {
for (Class<? extends HttpRequestFilter> clazz : declaring.getAnnotation(RequestFilters.class).value()) { for (Class<? extends HttpRequestFilter> clazz : invocation.getInterfaceType()
.getAnnotation(RequestFilters.class).value()) {
HttpRequestFilter instance = injector.getInstance(clazz); HttpRequestFilter instance = injector.getInstance(clazz);
filters.add(instance); filters.add(instance);
logger.trace("adding filter %s from annotation on %s", instance, declaring.getName()); logger.trace("adding filter %s from annotation on %s", instance, invocation.getInterfaceType().getName());
} }
} }
if (method.isAnnotationPresent(RequestFilters.class)) { if (invocation.getInvokable().isAnnotationPresent(RequestFilters.class)) {
if (method.isAnnotationPresent(OverrideRequestFilters.class)) if (invocation.getInvokable().isAnnotationPresent(OverrideRequestFilters.class))
filters.clear(); filters.clear();
for (Class<? extends HttpRequestFilter> clazz : method.getAnnotation(RequestFilters.class).value()) { for (Class<? extends HttpRequestFilter> clazz : invocation.getInvokable().getAnnotation(RequestFilters.class)
.value()) {
HttpRequestFilter instance = injector.getInstance(clazz); HttpRequestFilter instance = injector.getInstance(clazz);
filters.add(instance); filters.add(instance);
logger.trace("adding filter %s from annotation on %s", instance, method.getName()); logger.trace("adding filter %s from annotation on %s", instance, invocation.getInvokable().getName());
} }
} }
return filters; return filters;
} }
@VisibleForTesting @VisibleForTesting
static URI getEndpointInParametersOrNull(Invokable<?,?> method, List<Object> args, Injector injector) { static URI getEndpointInParametersOrNull(Invocation invocation, Injector injector) {
Collection<Parameter> endpointParams = parametersWithAnnotation(method, EndpointParam.class); Collection<Parameter> endpointParams = parametersWithAnnotation(invocation.getInvokable(), EndpointParam.class);
if (endpointParams.isEmpty()) if (endpointParams.isEmpty())
return null; return null;
checkState(endpointParams.size() == 1, "method %s has too many EndpointParam annotations", method); checkState(endpointParams.size() == 1, "invocation.getInvoked() %s has too many EndpointParam annotations",
invocation.getInvokable());
Parameter endpointParam = get(endpointParams, 0); Parameter endpointParam = get(endpointParams, 0);
Function<Object, URI> parser = injector.getInstance(endpointParam.getAnnotation(EndpointParam.class).parser()); Function<Object, URI> parser = injector.getInstance(endpointParam.getAnnotation(EndpointParam.class).parser());
int position = endpointParam.hashCode();// guava issue 1243 int position = endpointParam.hashCode();// guava issue 1243
try { try {
URI returnVal = parser.apply(args.get(position)); URI returnVal = parser.apply(invocation.getArgs().get(position));
checkArgument(returnVal != null, format("endpoint for [%s] not configured for %s", position, method)); checkArgument(returnVal != null,
format("endpoint for [%s] not configured for %s", position, invocation.getInvokable()));
return returnVal; return returnVal;
} catch (NullPointerException e) { } catch (NullPointerException e) {
throw new IllegalArgumentException(format("argument at index %d on method %s was null", position, method), e); throw new IllegalArgumentException(format("argument at index %d on invocation.getInvoked() %s was null",
position, invocation.getInvokable()), e);
} }
} }
private static Collection<Parameter> parametersWithAnnotation(Invokable<?, ?> method, final Class<? extends Annotation> annotationType) { private static Collection<Parameter> parametersWithAnnotation(Invokable<?, ?> invokable,
return filter(method.getParameters(), new Predicate<Parameter>() { final Class<? extends Annotation> annotationType) {
return filter(invokable.getParameters(), new Predicate<Parameter>() {
public boolean apply(Parameter in) { public boolean apply(Parameter in) {
return in.isAnnotationPresent(annotationType); return in.isAnnotationPresent(annotationType);
} }
@ -528,16 +520,16 @@ public abstract class RestAnnotationProcessor {
private static final TypeLiteral<Supplier<URI>> uriSupplierLiteral = new TypeLiteral<Supplier<URI>>() { private static final TypeLiteral<Supplier<URI>> uriSupplierLiteral = new TypeLiteral<Supplier<URI>>() {
}; };
protected Optional<URI> getEndpointFor(Invokable<?,?> method, List<Object> args) { protected Optional<URI> getEndpointFor(Invocation invocation) {
URI endpoint = getEndpointInParametersOrNull(method, args, injector); URI endpoint = getEndpointInParametersOrNull(invocation, injector);
if (endpoint == null) { if (endpoint == null) {
Endpoint annotation; Endpoint annotation;
if (method.isAnnotationPresent(Endpoint.class)) { if (invocation.getInvokable().isAnnotationPresent(Endpoint.class)) {
annotation = method.getAnnotation(Endpoint.class); annotation = invocation.getInvokable().getAnnotation(Endpoint.class);
} else if (method.getDeclaringClass().isAnnotationPresent(Endpoint.class)) { } else if (invocation.getInterfaceType().isAnnotationPresent(Endpoint.class)) {
annotation = method.getDeclaringClass().getAnnotation(Endpoint.class); annotation = invocation.getInterfaceType().getAnnotation(Endpoint.class);
} else { } else {
logger.trace("no annotations on class or method: %s", method); logger.trace("no annotations on class or invocation.getInvoked(): %s", invocation.getInvokable());
return Optional.absent(); return Optional.absent();
} }
endpoint = injector.getInstance(Key.get(uriSupplierLiteral, annotation.value())).get(); endpoint = injector.getInstance(Key.get(uriSupplierLiteral, annotation.value())).get();
@ -557,9 +549,9 @@ public abstract class RestAnnotationProcessor {
return withHost.resolve(original); return withHost.resolve(original);
} }
private org.jclouds.rest.MapBinder getMapPayloadBinderOrNull(Invokable<?,?> method, List<Object> args) { private org.jclouds.rest.MapBinder getMapPayloadBinderOrNull(Invocation invocation) {
if (args != null) { if (invocation.getArgs() != null) {
for (Object arg : args) { for (Object arg : invocation.getArgs()) {
if (arg instanceof Object[]) { if (arg instanceof Object[]) {
Object[] postBinders = (Object[]) arg; Object[] postBinders = (Object[]) arg;
if (postBinders.length == 0) { if (postBinders.length == 0) {
@ -571,8 +563,9 @@ public abstract class RestAnnotationProcessor {
} }
} else { } else {
if (postBinders[0] instanceof org.jclouds.rest.MapBinder) { if (postBinders[0] instanceof org.jclouds.rest.MapBinder) {
throw new IllegalArgumentException("we currently do not support multiple varargs postBinders in: " throw new IllegalArgumentException(
+ method.getName()); "we currently do not support multiple varinvocation.getArgs() postBinders in: "
+ invocation.getInvokable().getName());
} }
} }
} else if (arg instanceof org.jclouds.rest.MapBinder) { } else if (arg instanceof org.jclouds.rest.MapBinder) {
@ -582,25 +575,28 @@ public abstract class RestAnnotationProcessor {
} }
} }
} }
if (method.isAnnotationPresent(MapBinder.class)) { if (invocation.getInvokable().isAnnotationPresent(MapBinder.class)) {
return injector.getInstance(method.getAnnotation(MapBinder.class).value()); return injector.getInstance(invocation.getInvokable().getAnnotation(MapBinder.class).value());
} else if (method.isAnnotationPresent(org.jclouds.rest.annotations.Payload.class)) { } else if (invocation.getInvokable().isAnnotationPresent(org.jclouds.rest.annotations.Payload.class)) {
return injector.getInstance(BindMapToStringPayload.class); return injector.getInstance(BindMapToStringPayload.class);
} else if (method.isAnnotationPresent(WrapWith.class)) { } else if (invocation.getInvokable().isAnnotationPresent(WrapWith.class)) {
return injector.getInstance(BindToJsonPayloadWrappedWith.Factory.class).create( return injector.getInstance(BindToJsonPayloadWrappedWith.Factory.class).create(
method.getAnnotation(WrapWith.class).value()); invocation.getInvokable().getAnnotation(WrapWith.class).value());
} }
return null; return null;
} }
private boolean shouldAddHostHeader(Invokable<?, ?> method) { private boolean shouldAddHostHeader(Invocation invocation) {
return (declaring.isAnnotationPresent(VirtualHost.class) || method.isAnnotationPresent(VirtualHost.class)); return (invocation.getInterfaceType().isAnnotationPresent(VirtualHost.class) || invocation.getInvokable()
.isAnnotationPresent(VirtualHost.class));
} }
private GeneratedHttpRequest decorateRequest(GeneratedHttpRequest request) throws NegativeArraySizeException { private GeneratedHttpRequest decorateRequest(GeneratedHttpRequest request) throws NegativeArraySizeException {
Set<Parameter> binderOrWrapWith = ImmutableSet.copyOf(concat(parametersWithAnnotation(request.getInvoker(), BinderParam.class), Invocation invocation = request.getInvocation();
parametersWithAnnotation(request.getInvoker(), WrapWith.class))); List<Object> args = request.getInvocation().getArgs();
Set<Parameter> binderOrWrapWith = ImmutableSet.copyOf(concat(
parametersWithAnnotation(invocation.getInvokable(), BinderParam.class),
parametersWithAnnotation(invocation.getInvokable(), WrapWith.class)));
OUTER: for (Parameter entry : binderOrWrapWith) { OUTER: for (Parameter entry : binderOrWrapWith) {
int position = entry.hashCode(); int position = entry.hashCode();
boolean shouldBreak = false; boolean shouldBreak = false;
@ -610,18 +606,19 @@ public abstract class RestAnnotationProcessor {
else else
binder = injector.getInstance(BindToJsonPayloadWrappedWith.Factory.class).create( binder = injector.getInstance(BindToJsonPayloadWrappedWith.Factory.class).create(
entry.getAnnotation(WrapWith.class).value()); entry.getAnnotation(WrapWith.class).value());
Object arg = request.getArgs().size() >= position + 1 ? request.getArgs().get(position) : null; Object arg = args.size() >= position + 1 ? args.get(position) : null;
if (request.getArgs().size() >= position + 1 && arg != null) { if (args.size() >= position + 1 && arg != null) {
Class<?> parameterType = entry.getType().getRawType(); Class<?> parameterType = entry.getType().getRawType();
Class<? extends Object> argType = arg.getClass(); Class<? extends Object> argType = arg.getClass();
if (!argType.isArray() && parameterType.isArray()) { // TODO && varargs guava issue 1244 if (!argType.isArray() && parameterType.isArray()) { // TODO && varinvocation.getArgs() guava issue 1244
int arrayLength = request.getArgs().size() - request.getInvoker().getParameters().size() + 1; int arrayLength = args.size() - invocation.getInvokable().getParameters().size() + 1;
if (arrayLength == 0) if (arrayLength == 0)
break OUTER; break OUTER;
arg = (Object[]) Array.newInstance(arg.getClass(), arrayLength); arg = (Object[]) Array.newInstance(arg.getClass(), arrayLength);
System.arraycopy(request.getArgs().toArray(), position, arg, 0, arrayLength); System.arraycopy(args.toArray(), position, arg, 0, arrayLength);
shouldBreak = true; shouldBreak = true;
} else if (argType.isArray() && parameterType.isArray()) { // TODO && varargs guava issue 1244 } else if (argType.isArray() && parameterType.isArray()) { // TODO && varinvocation.getArgs() guava issue
// 1244
} else { } else {
if (arg.getClass().isArray()) { if (arg.getClass().isArray()) {
Object[] payloadArray = (Object[]) arg; Object[] payloadArray = (Object[]) arg;
@ -634,24 +631,24 @@ public abstract class RestAnnotationProcessor {
if (shouldBreak) if (shouldBreak)
break OUTER; break OUTER;
} else { } else {
if (position + 1 == request.getInvoker().getParameters().size() && entry.getType().isArray()) if (position + 1 == invocation.getInvokable().getParameters().size() && entry.getType().isArray())
continue OUTER; // TODO should only skip on null when varargs: guava issue 1244 continue OUTER; // TODO should only skip on null when varinvocation.getArgs(): guava issue 1244
if (entry.isAnnotationPresent(Nullable.class)) { if (entry.isAnnotationPresent(Nullable.class)) {
continue OUTER; continue OUTER;
} }
checkNotNull(arg, request.getInvoker().getName() + " parameter " + (position + 1)); checkNotNull(arg, invocation.getInvokable().getName() + " parameter " + (position + 1));
} }
} }
return request; return request;
} }
private static final LoadingCache<Invokable<?, ?>, Set<Integer>> methodToIndexesOfOptions = CacheBuilder.newBuilder().build( private static final LoadingCache<Invokable<?, ?>, Set<Integer>> invokableToIndexesOfOptions = CacheBuilder
new CacheLoader<Invokable<?, ?>, Set<Integer>>() { .newBuilder().build(new CacheLoader<Invokable<?, ?>, Set<Integer>>() {
@Override @Override
public Set<Integer> load(Invokable<?, ?> method) { public Set<Integer> load(Invokable<?, ?> invokable) {
Builder<Integer> toReturn = ImmutableSet.builder(); Builder<Integer> toReturn = ImmutableSet.builder();
for (Parameter param : method.getParameters()) { for (Parameter param : invokable.getParameters()) {
Class<?> type = param.getType().getRawType(); Class<?> type = param.getType().getRawType();
if (HttpRequestOptions.class.isAssignableFrom(type) if (HttpRequestOptions.class.isAssignableFrom(type)
|| HttpRequestOptions[].class.isAssignableFrom(type)) || HttpRequestOptions[].class.isAssignableFrom(type))
@ -661,20 +658,20 @@ public abstract class RestAnnotationProcessor {
} }
}); });
private Set<HttpRequestOptions> findOptionsIn(Invokable<?,?> method, List<Object> args) { private Set<HttpRequestOptions> findOptionsIn(Invocation invocation) {
ImmutableSet.Builder<HttpRequestOptions> result = ImmutableSet.builder(); ImmutableSet.Builder<HttpRequestOptions> result = ImmutableSet.builder();
for (int index : methodToIndexesOfOptions.getUnchecked(method)) { for (int index : invokableToIndexesOfOptions.getUnchecked(invocation.getInvokable())) {
if (args.size() >= index + 1) {// accommodate varargs if (invocation.getArgs().size() >= index + 1) {// accommodate varinvocation.getArgs()
if (args.get(index) instanceof Object[]) { if (invocation.getArgs().get(index) instanceof Object[]) {
for (Object option : (Object[]) args.get(index)) { for (Object option : (Object[]) invocation.getArgs().get(index)) {
if (option instanceof HttpRequestOptions) { if (option instanceof HttpRequestOptions) {
result.add((HttpRequestOptions) option); result.add((HttpRequestOptions) option);
} }
} }
} else { } else {
for (; index < args.size(); index++) { for (; index < invocation.getArgs().size(); index++) {
if (args.get(index) instanceof HttpRequestOptions) { if (invocation.getArgs().get(index) instanceof HttpRequestOptions) {
result.add((HttpRequestOptions) args.get(index)); result.add((HttpRequestOptions) invocation.getArgs().get(index));
} }
} }
} }
@ -683,58 +680,57 @@ public abstract class RestAnnotationProcessor {
return result.build(); return result.build();
} }
private Multimap<String, String> buildHeaders(Multimap<String, ?> tokenValues, Invokable<?, ?> method, private Multimap<String, String> buildHeaders(Multimap<String, ?> tokenValues, Invocation invocation) {
List<Object> args) {
Multimap<String, String> headers = LinkedHashMultimap.create(); Multimap<String, String> headers = LinkedHashMultimap.create();
addHeaderIfAnnotationPresentOnMethod(headers, method, tokenValues); addHeaderIfAnnotationPresentOnMethod(headers, invocation, tokenValues);
for (Parameter headerParam : parametersWithAnnotation(method, HeaderParam.class)) { for (Parameter headerParam : parametersWithAnnotation(invocation.getInvokable(), HeaderParam.class)) {
Annotation key = headerParam.getAnnotation(HeaderParam.class); Annotation key = headerParam.getAnnotation(HeaderParam.class);
String value = args.get(headerParam.hashCode()).toString(); // TODO position guava issue 1243 String value = invocation.getArgs().get(headerParam.hashCode()).toString(); // TODO position guava issue 1243
value = replaceTokens(value, tokenValues); value = replaceTokens(value, tokenValues);
headers.put(((HeaderParam) key).value(), value); headers.put(((HeaderParam) key).value(), value);
} }
addProducesIfPresentOnTypeOrMethod(headers, method); addProducesIfPresentOnTypeOrMethod(headers, invocation);
addConsumesIfPresentOnTypeOrMethod(headers, method); addConsumesIfPresentOnTypeOrMethod(headers, invocation);
return headers; return headers;
} }
private void addConsumesIfPresentOnTypeOrMethod(Multimap<String, String> headers, Invokable<?,?> method) { private static void addConsumesIfPresentOnTypeOrMethod(Multimap<String, String> headers, Invocation invocation) {
Set<String> accept = getAcceptHeaders(method); Set<String> accept = getAcceptHeaders(invocation);
if (!accept.isEmpty()) if (!accept.isEmpty())
headers.replaceValues(ACCEPT, accept); headers.replaceValues(ACCEPT, accept);
} }
// TODO: refactor this out // TODO: refactor this out
static Set<String> getAcceptHeaders(Invokable<?, ?> method) { static Set<String> getAcceptHeaders(Invocation invocation) {
Optional<Consumes> accept = Optional.fromNullable(method.getAnnotation(Consumes.class)).or( Optional<Consumes> accept = Optional.fromNullable(invocation.getInvokable().getAnnotation(Consumes.class)).or(
Optional.fromNullable(method.getDeclaringClass().getAnnotation(Consumes.class))); Optional.fromNullable(invocation.getInterfaceType().getAnnotation(Consumes.class)));
return (accept.isPresent()) ? ImmutableSet.copyOf(accept.get().value()) : ImmutableSet.<String> of(); return (accept.isPresent()) ? ImmutableSet.copyOf(accept.get().value()) : ImmutableSet.<String> of();
} }
private void addProducesIfPresentOnTypeOrMethod(Multimap<String, String> headers, Invokable<?,?> method) { private static void addProducesIfPresentOnTypeOrMethod(Multimap<String, String> headers, Invocation invocation) {
if (declaring.isAnnotationPresent(Produces.class)) { if (invocation.getInterfaceType().isAnnotationPresent(Produces.class)) {
Produces header = declaring.getAnnotation(Produces.class); Produces header = invocation.getInterfaceType().getAnnotation(Produces.class);
headers.replaceValues(CONTENT_TYPE, asList(header.value())); headers.replaceValues(CONTENT_TYPE, asList(header.value()));
} }
if (method.isAnnotationPresent(Produces.class)) { if (invocation.getInvokable().isAnnotationPresent(Produces.class)) {
Produces header = method.getAnnotation(Produces.class); Produces header = invocation.getInvokable().getAnnotation(Produces.class);
headers.replaceValues(CONTENT_TYPE, asList(header.value())); headers.replaceValues(CONTENT_TYPE, asList(header.value()));
} }
} }
private void addHeaderIfAnnotationPresentOnMethod(Multimap<String, String> headers, Invokable<?,?> method, private static void addHeaderIfAnnotationPresentOnMethod(Multimap<String, String> headers, Invocation invocation,
Multimap<String, ?> tokenValues) { Multimap<String, ?> tokenValues) {
if (declaring.isAnnotationPresent(Headers.class)) { if (invocation.getInterfaceType().isAnnotationPresent(Headers.class)) {
Headers header = declaring.getAnnotation(Headers.class); Headers header = invocation.getInterfaceType().getAnnotation(Headers.class);
addHeader(headers, header, tokenValues); addHeader(headers, header, tokenValues);
} }
if (method.isAnnotationPresent(Headers.class)) { if (invocation.getInvokable().isAnnotationPresent(Headers.class)) {
Headers header = method.getAnnotation(Headers.class); Headers header = invocation.getInvokable().getAnnotation(Headers.class);
addHeader(headers, header, tokenValues); addHeader(headers, header, tokenValues);
} }
} }
private void addHeader(Multimap<String, String> headers, Headers header, Multimap<String, ?> tokenValues) { private static void addHeader(Multimap<String, String> headers, Headers header, Multimap<String, ?> tokenValues) {
for (int i = 0; i < header.keys().length; i++) { for (int i = 0; i < header.keys().length; i++) {
String value = header.values()[i]; String value = header.values()[i];
value = replaceTokens(value, tokenValues); value = replaceTokens(value, tokenValues);
@ -742,16 +738,16 @@ public abstract class RestAnnotationProcessor {
} }
} }
private List<Part> getParts(Invokable<?, ?> method, List<Object> args, Multimap<String, ?> tokenValues) { private static List<Part> getParts(Invocation invocation, Multimap<String, ?> tokenValues) {
ImmutableList.Builder<Part> parts = ImmutableList.<Part> builder(); ImmutableList.Builder<Part> parts = ImmutableList.<Part> builder();
for (Parameter param : parametersWithAnnotation(method, PartParam.class)) { for (Parameter param : parametersWithAnnotation(invocation.getInvokable(), PartParam.class)) {
PartParam partParam = param.getAnnotation(PartParam.class); PartParam partParam = param.getAnnotation(PartParam.class);
PartOptions options = new PartOptions(); PartOptions options = new PartOptions();
if (!PartParam.NO_CONTENT_TYPE.equals(partParam.contentType())) if (!PartParam.NO_CONTENT_TYPE.equals(partParam.contentType()))
options.contentType(partParam.contentType()); options.contentType(partParam.contentType());
if (!PartParam.NO_FILENAME.equals(partParam.filename())) if (!PartParam.NO_FILENAME.equals(partParam.filename()))
options.filename(replaceTokens(partParam.filename(), tokenValues)); options.filename(replaceTokens(partParam.filename(), tokenValues));
Object arg = args.get(param.hashCode()); // TODO position guava issue 1243 Object arg = invocation.getArgs().get(param.hashCode()); // TODO position guava issue 1243
checkNotNull(arg, partParam.name()); checkNotNull(arg, partParam.name());
Part part = Part.create(partParam.name(), newPayload(arg), options); Part part = Part.create(partParam.name(), newPayload(arg), options);
parts.add(part); parts.add(part);
@ -759,12 +755,12 @@ public abstract class RestAnnotationProcessor {
return parts.build(); return parts.build();
} }
private Multimap<String, Object> getPathParamKeyValues(Invokable<?, ?> method, List<Object> args) { private Multimap<String, Object> getPathParamKeyValues(Invocation invocation) {
Multimap<String, Object> pathParamValues = LinkedHashMultimap.create(); Multimap<String, Object> pathParamValues = LinkedHashMultimap.create();
for (Parameter param : parametersWithAnnotation(method, PathParam.class)) { for (Parameter param : parametersWithAnnotation(invocation.getInvokable(), PathParam.class)) {
PathParam pathParam = param.getAnnotation(PathParam.class); PathParam pathParam = param.getAnnotation(PathParam.class);
String paramKey = pathParam.value(); String paramKey = pathParam.value();
Optional<?> paramValue = getParamValue(method, args, param.getAnnotation(ParamParser.class), param.hashCode(), Optional<?> paramValue = getParamValue(invocation, param.getAnnotation(ParamParser.class), param.hashCode(),
paramKey); // TODO position guava issue 1243 paramKey); // TODO position guava issue 1243
if (paramValue.isPresent()) if (paramValue.isPresent())
pathParamValues.put(paramKey, paramValue.get().toString()); pathParamValues.put(paramKey, paramValue.get().toString());
@ -772,29 +768,29 @@ public abstract class RestAnnotationProcessor {
return pathParamValues; return pathParamValues;
} }
private Optional<?> getParamValue(Invokable<?,?> method, List<Object> args, @Nullable ParamParser extractor, private Optional<?> getParamValue(Invocation invocation, @Nullable ParamParser extractor, int argIndex,
int argIndex, String paramKey) { String paramKey) {
Object arg = args.get(argIndex); Object arg = invocation.getArgs().get(argIndex);
if (extractor != null && checkPresentOrNullable(method, paramKey, argIndex, arg)) { if (extractor != null && checkPresentOrNullable(invocation, paramKey, argIndex, arg)) {
arg = injector.getInstance(extractor.value()).apply(arg); // ParamParsers can deal with nullable parameters arg = injector.getInstance(extractor.value()).apply(arg); // ParamParsers can deal with nullable parameters
} }
checkPresentOrNullable(method, paramKey, argIndex, arg); checkPresentOrNullable(invocation, paramKey, argIndex, arg);
return Optional.fromNullable(arg); return Optional.fromNullable(arg);
} }
private static boolean checkPresentOrNullable(Invokable<?,?> method, String paramKey, int argIndex, Object arg) { private static boolean checkPresentOrNullable(Invocation invocation, String paramKey, int argIndex, Object arg) {
if (arg == null && !method.getParameters().get(argIndex).isAnnotationPresent(Nullable.class)) if (arg == null && !invocation.getInvokable().getParameters().get(argIndex).isAnnotationPresent(Nullable.class))
throw new NullPointerException(format("param{%s} for method %s.%s", paramKey, method throw new NullPointerException(format("param{%s} for invocation %s.%s", paramKey, invocation
.getDeclaringClass().getSimpleName(), method.getName())); .getInterfaceType().getSimpleName(), invocation.getInvokable().getName()));
return true; return true;
} }
private Multimap<String, Object> getFormParamKeyValues(Invokable<?,?> method, List<Object> args) { private Multimap<String, Object> getFormParamKeyValues(Invocation invocation) {
Multimap<String, Object> formParamValues = LinkedHashMultimap.create(); Multimap<String, Object> formParamValues = LinkedHashMultimap.create();
for (Parameter param : parametersWithAnnotation(method, FormParam.class)) { for (Parameter param : parametersWithAnnotation(invocation.getInvokable(), FormParam.class)) {
FormParam formParam = param.getAnnotation(FormParam.class); FormParam formParam = param.getAnnotation(FormParam.class);
String paramKey = formParam.value(); String paramKey = formParam.value();
Optional<?> paramValue = getParamValue(method, args, param.getAnnotation(ParamParser.class), param.hashCode(), Optional<?> paramValue = getParamValue(invocation, param.getAnnotation(ParamParser.class), param.hashCode(),
paramKey); // TODO position guava issue 1243 paramKey); // TODO position guava issue 1243
if (paramValue.isPresent()) if (paramValue.isPresent())
formParamValues.put(paramKey, paramValue.get().toString()); formParamValues.put(paramKey, paramValue.get().toString());
@ -802,12 +798,12 @@ public abstract class RestAnnotationProcessor {
return formParamValues; return formParamValues;
} }
private Multimap<String, Object> getQueryParamKeyValues(Invokable<?,?> method, List<Object> args) { private Multimap<String, Object> getQueryParamKeyValues(Invocation invocation) {
Multimap<String, Object> queryParamValues = LinkedHashMultimap.create(); Multimap<String, Object> queryParamValues = LinkedHashMultimap.create();
for (Parameter param : parametersWithAnnotation(method, QueryParam.class)) { for (Parameter param : parametersWithAnnotation(invocation.getInvokable(), QueryParam.class)) {
QueryParam queryParam = param.getAnnotation(QueryParam.class); QueryParam queryParam = param.getAnnotation(QueryParam.class);
String paramKey = queryParam.value(); String paramKey = queryParam.value();
Optional<?> paramValue = getParamValue(method, args, param.getAnnotation(ParamParser.class), param.hashCode(), Optional<?> paramValue = getParamValue(invocation, param.getAnnotation(ParamParser.class), param.hashCode(),
paramKey); // TODO position guava issue 1243 paramKey); // TODO position guava issue 1243
if (paramValue.isPresent()) if (paramValue.isPresent())
if (paramValue.get() instanceof Iterable) { if (paramValue.get() instanceof Iterable) {
@ -821,12 +817,12 @@ public abstract class RestAnnotationProcessor {
return queryParamValues; return queryParamValues;
} }
private Map<String, Object> buildPayloadParams(Invokable<?,?> method, List<Object> args) { private Map<String, Object> buildPayloadParams(Invocation invocation) {
Map<String, Object> payloadParamValues = Maps.newLinkedHashMap(); Map<String, Object> payloadParamValues = Maps.newLinkedHashMap();
for (Parameter param : parametersWithAnnotation(method, PayloadParam.class)) { for (Parameter param : parametersWithAnnotation(invocation.getInvokable(), PayloadParam.class)) {
PayloadParam payloadParam = param.getAnnotation(PayloadParam.class); PayloadParam payloadParam = param.getAnnotation(PayloadParam.class);
String paramKey = payloadParam.value(); String paramKey = payloadParam.value();
Optional<?> paramValue = getParamValue(method, args, param.getAnnotation(ParamParser.class), param.hashCode(), Optional<?> paramValue = getParamValue(invocation, param.getAnnotation(ParamParser.class), param.hashCode(),
paramKey); // TODO position guava issue 1243 paramKey); // TODO position guava issue 1243
if (paramValue.isPresent()) if (paramValue.isPresent())
payloadParamValues.put(paramKey, paramValue.get()); payloadParamValues.put(paramKey, paramValue.get());

View File

@ -31,23 +31,17 @@ import com.google.common.reflect.TypeToken;
* @author Adrian Cole * @author Adrian Cole
*/ */
public class Optionals2 { public class Optionals2 {
public static Class<?> returnTypeOrTypeOfOptional(Invokable<?, ?> method) { public static Class<?> unwrapIfOptional(TypeToken<?> type) {
TypeToken<?> type = method.getReturnType(); if (type.getRawType().isAssignableFrom(Optional.class)) {
return returnTypeOrTypeOfOptional(type.getRawType(), type.getType()); ParameterizedType futureType = ParameterizedType.class.cast(type.getType());
}
private static Class<?> returnTypeOrTypeOfOptional(Class<?> syncClass, Type genericType) {
if (syncClass.isAssignableFrom(Optional.class)) {
ParameterizedType futureType = ParameterizedType.class.cast(genericType);
// TODO: error checking in case this is a type, not a class. // TODO: error checking in case this is a type, not a class.
Type t = futureType.getActualTypeArguments()[0]; Type t = futureType.getActualTypeArguments()[0];
if (t instanceof WildcardType) { if (t instanceof WildcardType) {
t = ((WildcardType) t).getUpperBounds()[0]; t = ((WildcardType) t).getUpperBounds()[0];
} }
syncClass = Class.class.cast(t); return Class.class.cast(t);
} else {
} }
return syncClass; return type.getRawType();
} }
public static boolean isReturnTypeOptional(Invokable<?, ?> method) { public static boolean isReturnTypeOptional(Invokable<?, ?> method) {

View File

@ -33,7 +33,6 @@ import org.jclouds.rest.ResourceNotFoundException;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.base.Throwables;
import com.google.common.reflect.TypeToken; import com.google.common.reflect.TypeToken;
import com.google.inject.CreationException; import com.google.inject.CreationException;
import com.google.inject.ProvisionException; import com.google.inject.ProvisionException;
@ -119,32 +118,6 @@ public class Throwables2 {
return null; return null;
} }
// Note this needs to be kept up-to-date with all top-level exceptions jclouds works against
@SuppressWarnings( { "unchecked", "rawtypes" })
public static Exception returnFirstExceptionIfInListOrThrowStandardExceptionOrCause(Iterable<TypeToken<? extends Throwable>> throwables,
Exception exception) throws Exception {
for (TypeToken<? extends Throwable> type : throwables) {
Throwable throwable = getFirstThrowableOfType(exception, (Class<Throwable>) type.getRawType());
if (throwable != null) {
return (Exception) throwable;
}
}
for (Class<Exception> propagatableExceptionType : new Class[] { IllegalStateException.class,
AssertionError.class, UnsupportedOperationException.class, IllegalArgumentException.class,
AuthorizationException.class, ResourceNotFoundException.class, InsufficientResourcesException.class,
HttpResponseException.class }) {
Throwable throwable = getFirstThrowableOfType(exception, propagatableExceptionType);
if (throwable != null) {
if (throwable instanceof AssertionError)
throw (AssertionError) throwable;
else
throw (Exception) throwable;
}
}
Throwables.propagateIfPossible(exception.getCause(), Exception.class);
throw exception;
}
public static <T> T propagateAuthorizationOrOriginalException(Exception e) { public static <T> T propagateAuthorizationOrOriginalException(Exception e) {
AuthorizationException aex = getFirstThrowableOfType(e, AuthorizationException.class); AuthorizationException aex = getFirstThrowableOfType(e, AuthorizationException.class);
if (aex != null) if (aex != null)
@ -154,4 +127,24 @@ public class Throwables2 {
return null; return null;
} }
// Note this needs to be kept up-to-date with all top-level exceptions jclouds works against
@SuppressWarnings("unchecked")
public static void propagateIfPossible(Throwable exception, Iterable<TypeToken<? extends Throwable>> throwables)
throws Throwable {
for (TypeToken<? extends Throwable> type : throwables) {
Throwable throwable = Throwables2.getFirstThrowableOfType(exception, (Class<Throwable>) type.getRawType());
if (throwable != null) {
throw throwable;
}
}
for (Class<Exception> propagatableExceptionType : new Class[] { IllegalStateException.class,
AssertionError.class, UnsupportedOperationException.class, IllegalArgumentException.class,
AuthorizationException.class, ResourceNotFoundException.class, InsufficientResourcesException.class,
HttpResponseException.class }) {
Throwable throwable = Throwables2.getFirstThrowableOfType(exception, propagatableExceptionType);
if (throwable != null) {
throw throwable;
}
}
}
} }

View File

@ -18,7 +18,6 @@
*/ */
package org.jclouds.concurrent.internal; package org.jclouds.concurrent.internal;
import static com.google.common.reflect.Reflection.newProxy;
import static org.easymock.EasyMock.createMock; import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect; import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay; import static org.easymock.EasyMock.replay;
@ -29,7 +28,8 @@ import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
import org.jclouds.internal.ClassInvokerArgs; import org.jclouds.internal.ForwardInvocationToInterface;
import org.jclouds.reflect.FunctionalReflection;
import org.jclouds.rest.functions.AlwaysPresentImplicitOptionalConverter; import org.jclouds.rest.functions.AlwaysPresentImplicitOptionalConverter;
import org.testng.annotations.BeforeMethod; import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test; import org.testng.annotations.Test;
@ -73,14 +73,12 @@ public class SyncProxyTest {
Sync withOverride = syncProxyForTimeouts(ImmutableMap.of("default", 250L)); Sync withOverride = syncProxyForTimeouts(ImmutableMap.of("default", 250L));
assertEquals(withOverride.get(), "foo"); assertEquals(withOverride.get(), "foo");
verify(future); verify(future);
} }
public void testWithClassPropTimeout() throws Exception { public void testWithClassPropTimeout() throws Exception {
Sync withOverride = syncProxyForTimeouts(ImmutableMap.of("default", 50L, "Sync", 250L)); Sync withOverride = syncProxyForTimeouts(ImmutableMap.of("default", 50L, "Sync", 250L));
assertEquals(withOverride.get(), "foo"); assertEquals(withOverride.get(), "foo");
verify(future); verify(future);
} }
public void testWithMethodPropTimeout() throws Exception { public void testWithMethodPropTimeout() throws Exception {
@ -99,16 +97,13 @@ public class SyncProxyTest {
assertEquals(noOverrides.get(), "foo"); assertEquals(noOverrides.get(), "foo");
verify(future); verify(future);
} }
private Sync syncProxyForTimeouts(ImmutableMap<String, Long> timeouts) throws NoSuchMethodException { private Sync syncProxyForTimeouts(ImmutableMap<String, Long> timeouts) throws NoSuchMethodException {
LoadingCache<ClassInvokerArgs, Object> cache = CacheBuilder.newBuilder().build( LoadingCache<ForwardInvocationToInterface, Object> cache = CacheBuilder.newBuilder().build(
CacheLoader.from(Functions.<Object> constant(null))); CacheLoader.from(Functions.<Object> constant(null)));
return newProxy( return FunctionalReflection.newProxy(Sync.class, new SyncProxy(new AlwaysPresentImplicitOptionalConverter(),
Sync.class, cache, ImmutableMap.<Class<?>, Class<?>> of(Sync.class, Async.class), timeouts, Sync.class, new Async()));
new SyncProxy(new AlwaysPresentImplicitOptionalConverter(), cache, ImmutableMap.<Class<?>, Class<?>> of(
Sync.class, Async.class), timeouts, Sync.class, new Async()));
} }
} }

View File

@ -18,11 +18,18 @@
*/ */
package org.jclouds.http.functions; package org.jclouds.http.functions;
import static com.google.common.base.Throwables.propagate;
import java.util.List;
import org.jclouds.http.functions.config.SaxParserModule; import org.jclouds.http.functions.config.SaxParserModule;
import org.jclouds.reflect.Invocation;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.testng.annotations.AfterTest; import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeTest; import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
import com.google.common.reflect.Invokable;
import com.google.inject.Guice; import com.google.inject.Guice;
import com.google.inject.Injector; import com.google.inject.Injector;
@ -30,11 +37,12 @@ import com.google.inject.Injector;
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
@Test(groups = "unit")
public class BaseHandlerTest { public class BaseHandlerTest {
protected Injector injector = null; protected Injector injector = null;
protected ParseSax.Factory factory; protected ParseSax.Factory factory;
protected GeneratedHttpRequest request;
private Invocation toString;
@BeforeTest @BeforeTest
protected void setUpInjector() { protected void setUpInjector() {
@ -43,10 +51,27 @@ public class BaseHandlerTest {
assert factory != null; assert factory != null;
} }
@BeforeTest
protected void setUpRequest() {
try {
toString = Invocation.create(Invokable.from(String.class.getDeclaredMethod("toString")), ImmutableList.of());
} catch (SecurityException e) {
throw propagate(e);
} catch (NoSuchMethodException e) {
throw propagate(e);
}
request = GeneratedHttpRequest.builder().method("POST").endpoint("http://localhost/key").invocation(toString)
.build();
}
@AfterTest @AfterTest
protected void tearDownInjector() { protected void tearDownInjector() {
factory = null; factory = null;
injector = null; injector = null;
} }
protected GeneratedHttpRequest requestForArgs(List<Object> args) {
return GeneratedHttpRequest.builder().method("POST").endpoint("http://localhost/key")
.invocation(Invocation.create(toString.getInvokable(), args)).build();
}
} }

View File

@ -167,7 +167,7 @@ public class BackoffLimitedRetryHandlerTest {
} }
private final RestAnnotationProcessor processor = BaseJettyTest.newBuilder(8100, new Properties()).buildInjector() private final RestAnnotationProcessor processor = BaseJettyTest.newBuilder(8100, new Properties()).buildInjector()
.getInstance(RestAnnotationProcessor.Factory.class).declaring(IntegrationTestAsyncClient.class); .getInstance(RestAnnotationProcessor.class);
private HttpCommand createCommand() throws SecurityException, NoSuchMethodException { private HttpCommand createCommand() throws SecurityException, NoSuchMethodException {
Invokable<?, Object> method = Invokable.from(IntegrationTestAsyncClient.class.getMethod("download", String.class)); Invokable<?, Object> method = Invokable.from(IntegrationTestAsyncClient.class.getMethod("download", String.class));

View File

@ -78,11 +78,12 @@ public class TrackingJavaUrlHttpCommandExecutorService extends JavaUrlHttpComman
} }
public static Invokable<?, ?> getInvokerOfRequest(HttpCommand commandInvoked) { public static Invokable<?, ?> getInvokerOfRequest(HttpCommand commandInvoked) {
return GeneratedHttpRequest.class.cast(commandInvoked.getCurrentRequest()).getInvoker(); return GeneratedHttpRequest.class.cast(commandInvoked.getCurrentRequest()).getInvocation().getInvokable();
} }
public static List<Object> getArgsForRequestAtIndex(final Collection<HttpCommand> commandsInvoked, int index) { public static List<Object> getArgsForRequestAtIndex(final Collection<HttpCommand> commandsInvoked, int index) {
return GeneratedHttpRequest.class.cast(Iterables.get(commandsInvoked, index).getCurrentRequest()).getArgs(); return GeneratedHttpRequest.class.cast(Iterables.get(commandsInvoked, index).getCurrentRequest()).getInvocation()
.getArgs();
} }
@Inject @Inject

View File

@ -31,11 +31,13 @@ import org.jclouds.http.HttpResponse;
import org.jclouds.io.Payload; import org.jclouds.io.Payload;
import org.jclouds.io.Payloads; import org.jclouds.io.Payloads;
import org.jclouds.json.config.GsonModule; import org.jclouds.json.config.GsonModule;
import org.jclouds.reflect.Invocation;
import org.jclouds.rest.internal.AsyncRestClientProxy; import org.jclouds.rest.internal.AsyncRestClientProxy;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.base.Throwables; import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableList;
import com.google.common.reflect.Invokable; import com.google.common.reflect.Invokable;
import com.google.inject.Guice; import com.google.inject.Guice;
import com.google.inject.Injector; import com.google.inject.Injector;
@ -57,7 +59,7 @@ public abstract class BaseParserTest<T, G> {
protected Function<HttpResponse, T> parser(Injector i) { protected Function<HttpResponse, T> parser(Injector i) {
try { try {
return (Function<HttpResponse, T>) AsyncRestClientProxy.getTransformerForMethod( return (Function<HttpResponse, T>) AsyncRestClientProxy.getTransformerForMethod(
Invokable.from(getClass().getMethod("expected")), i); Invocation.create(Invokable.from(getClass().getMethod("expected")), ImmutableList.of()), i);
} catch (Exception e) { } catch (Exception e) {
throw Throwables.propagate(e); throw Throwables.propagate(e);
} }

View File

@ -1,66 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.jclouds.reflect;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertNull;
import static org.testng.Assert.assertTrue;
import java.io.IOException;
import java.util.List;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
import com.google.common.reflect.Invokable;
import com.google.common.reflect.Reflection;
/**
*
* @author Adrian Cole
*/
@Test
public class AbstractInvocationHandlerTest {
@Test(expectedExceptions = UnsupportedOperationException.class)
public void testNullArgsAreAllowedAndUnmodifiable() throws IOException {
Reflection.newProxy(Appendable.class, new AbstractInvocationHandler() {
protected Object handleInvocation(Object proxy, Invokable<?, ?> method, List<Object> args) throws Throwable {
assertNotNull(args);
assertNull(args.get(0));
args.add("foo");
throw new AssertionError("shouldn't be able to mutate the list!");
}
}).append(null);
}
@Test(expectedExceptions = UnsupportedOperationException.class)
public void testImmutableListWhenArgsAreNotNull() throws IOException {
Reflection.newProxy(Appendable.class, new AbstractInvocationHandler() {
protected Object handleInvocation(Object proxy, Invokable<?, ?> method, List<Object> args) throws Throwable {
assertNotNull(args);
assertTrue(args instanceof ImmutableList);
assertEquals(args.get(0), "foo");
args.add("bar");
throw new AssertionError("shouldn't be able to mutate the list!");
}
}).append("foo");
}
}

View File

@ -26,6 +26,7 @@ import org.jclouds.http.IntegrationTestAsyncClient;
import org.jclouds.http.IntegrationTestClient; import org.jclouds.http.IntegrationTestClient;
import org.jclouds.predicates.validators.AllLowerCaseValidator; import org.jclouds.predicates.validators.AllLowerCaseValidator;
import org.jclouds.providers.AnonymousProviderMetadata; import org.jclouds.providers.AnonymousProviderMetadata;
import org.jclouds.reflect.Invocation;
import org.jclouds.rest.annotations.ParamValidators; import org.jclouds.rest.annotations.ParamValidators;
import org.jclouds.rest.internal.RestAnnotationProcessor; import org.jclouds.rest.internal.RestAnnotationProcessor;
import org.testng.TestException; import org.testng.TestException;
@ -62,7 +63,6 @@ public class InputParamValidatorTest {
"allParamsValidated", String.class, String.class)); "allParamsValidated", String.class, String.class));
Invokable<?, ?> oneParamValidatedMethod = Invokable.from(InputParamValidatorForm.class.getMethod( Invokable<?, ?> oneParamValidatedMethod = Invokable.from(InputParamValidatorForm.class.getMethod(
"oneParamValidated", String.class, String.class)); "oneParamValidated", String.class, String.class));
RestAnnotationProcessor restAnnotationProcessor = factory(InputParamValidatorForm.class);
restAnnotationProcessor.createRequest(allParamsValidatedMethod, ImmutableList.<Object> of("blah", "blah")); restAnnotationProcessor.createRequest(allParamsValidatedMethod, ImmutableList.<Object> of("blah", "blah"));
restAnnotationProcessor.createRequest(oneParamValidatedMethod, ImmutableList.<Object> of("blah", "blah")); restAnnotationProcessor.createRequest(oneParamValidatedMethod, ImmutableList.<Object> of("blah", "blah"));
@ -98,15 +98,13 @@ public class InputParamValidatorTest {
@Test(expectedExceptions = ClassCastException.class) @Test(expectedExceptions = ClassCastException.class)
public void testWrongPredicateTypeLiteral() throws Exception { public void testWrongPredicateTypeLiteral() throws Exception {
Invokable<?, ?> method = Invokable.from(WrongValidator.class.getMethod("method", Integer.class)); Invocation invocation = Invocation.create(Invokable.from(WrongValidator.class.getMethod("method", Integer.class)),
new InputParamValidator(injector).validateMethodParametersOrThrow(method, ImmutableList.<Object> of(55)); ImmutableList.<Object> of(55));
} new InputParamValidator(injector).validateMethodParametersOrThrow(invocation);
private RestAnnotationProcessor factory(Class<?> clazz) {
return injector.getInstance(RestAnnotationProcessor.Factory.class).declaring(clazz);
} }
Injector injector; Injector injector;
RestAnnotationProcessor restAnnotationProcessor;
@BeforeClass @BeforeClass
void setupFactory() { void setupFactory() {
@ -114,7 +112,7 @@ public class InputParamValidatorTest {
.newBuilder( .newBuilder(
AnonymousProviderMetadata.forClientMappedToAsyncClientOnEndpoint(IntegrationTestClient.class, IntegrationTestAsyncClient.class, AnonymousProviderMetadata.forClientMappedToAsyncClientOnEndpoint(IntegrationTestClient.class, IntegrationTestAsyncClient.class,
"http://localhost:9999")).buildInjector(); "http://localhost:9999")).buildInjector();
restAnnotationProcessor = injector.getInstance(RestAnnotationProcessor.class);
} }
} }

View File

@ -25,6 +25,7 @@ import java.io.File;
import javax.ws.rs.PathParam; import javax.ws.rs.PathParam;
import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpRequest;
import org.jclouds.reflect.Invocation;
import org.jclouds.rest.annotations.Payload; import org.jclouds.rest.annotations.Payload;
import org.jclouds.rest.annotations.PayloadParam; import org.jclouds.rest.annotations.PayloadParam;
import org.jclouds.rest.internal.GeneratedHttpRequest; import org.jclouds.rest.internal.GeneratedHttpRequest;
@ -55,7 +56,7 @@ public class BindMapToStringPayloadTest {
public void testCorrect() throws SecurityException, NoSuchMethodException { public void testCorrect() throws SecurityException, NoSuchMethodException {
Invokable<?, Object> testPayload = Invokable.from(TestPayload.class.getMethod("testPayload", String.class)); Invokable<?, Object> testPayload = Invokable.from(TestPayload.class.getMethod("testPayload", String.class));
GeneratedHttpRequest request = GeneratedHttpRequest.builder() GeneratedHttpRequest request = GeneratedHttpRequest.builder()
.declaring(TestPayload.class).invoker(testPayload).args(ImmutableList.<Object> of("robot")) .invocation(Invocation.create(testPayload, ImmutableList.<Object> of("robot")))
.method("POST").endpoint("http://localhost").build(); .method("POST").endpoint("http://localhost").build();
GeneratedHttpRequest newRequest = binder() GeneratedHttpRequest newRequest = binder()
@ -69,7 +70,7 @@ public class BindMapToStringPayloadTest {
public void testDecodes() throws SecurityException, NoSuchMethodException { public void testDecodes() throws SecurityException, NoSuchMethodException {
Invokable<?, Object> testPayload = Invokable.from(TestPayload.class.getMethod("changeAdminPass", String.class)); Invokable<?, Object> testPayload = Invokable.from(TestPayload.class.getMethod("changeAdminPass", String.class));
GeneratedHttpRequest request = GeneratedHttpRequest.builder() GeneratedHttpRequest request = GeneratedHttpRequest.builder()
.declaring(TestPayload.class).invoker(testPayload).args(ImmutableList.<Object> of("foo")) .invocation(Invocation.create(testPayload, ImmutableList.<Object> of("foo")))
.method("POST").endpoint("http://localhost").build(); .method("POST").endpoint("http://localhost").build();
GeneratedHttpRequest newRequest = binder() GeneratedHttpRequest newRequest = binder()
@ -83,7 +84,7 @@ public class BindMapToStringPayloadTest {
public void testMustHavePayloadAnnotation() throws SecurityException, NoSuchMethodException { public void testMustHavePayloadAnnotation() throws SecurityException, NoSuchMethodException {
Invokable<?, Object> noPayload = Invokable.from(TestPayload.class.getMethod("noPayload", String.class)); Invokable<?, Object> noPayload = Invokable.from(TestPayload.class.getMethod("noPayload", String.class));
GeneratedHttpRequest request = GeneratedHttpRequest.builder() GeneratedHttpRequest request = GeneratedHttpRequest.builder()
.declaring(TestPayload.class).invoker(noPayload).args(ImmutableList.<Object> of("robot")) .invocation(Invocation.create(noPayload, ImmutableList.<Object> of("robot")))
.method("POST").endpoint("http://localhost").build(); .method("POST").endpoint("http://localhost").build();
binder().bindToRequest(request, ImmutableMap.<String,Object>of("fooble", "robot")); binder().bindToRequest(request, ImmutableMap.<String,Object>of("fooble", "robot"));
} }

View File

@ -25,7 +25,8 @@ import static org.testng.Assert.assertTrue;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.jclouds.internal.ClassInvokerArgsAndReturnVal; import org.jclouds.reflect.Invocation;
import org.jclouds.reflect.InvocationSuccess;
import org.jclouds.rest.annotations.Delegate; import org.jclouds.rest.annotations.Delegate;
import org.jclouds.rest.annotations.SinceApiVersion; import org.jclouds.rest.annotations.SinceApiVersion;
import org.jclouds.rest.functions.PresentWhenApiVersionLexicographicallyAtOrAfterSinceApiVersion.Loader; import org.jclouds.rest.functions.PresentWhenApiVersionLexicographicallyAtOrAfterSinceApiVersion.Loader;
@ -122,7 +123,7 @@ public class PresentWhenApiVersionLexicographicallyAtOrAfterSinceApiVersionTest
} }
public void testCacheIsFasterWhenNoAnnotationPresent() { public void testCacheIsFasterWhenNoAnnotationPresent() {
ClassInvokerArgsAndReturnVal keyPairApi = getKeyPairApi(); InvocationSuccess keyPairApi = getKeyPairApi();
ImplicitOptionalConverter fn = forApiVersion("2011-07-15"); ImplicitOptionalConverter fn = forApiVersion("2011-07-15");
Stopwatch watch = new Stopwatch().start(); Stopwatch watch = new Stopwatch().start();
fn.apply(keyPairApi); fn.apply(keyPairApi);
@ -136,7 +137,7 @@ public class PresentWhenApiVersionLexicographicallyAtOrAfterSinceApiVersionTest
} }
public void testCacheIsFasterWhenAnnotationPresent() { public void testCacheIsFasterWhenAnnotationPresent() {
ClassInvokerArgsAndReturnVal floatingIpApi = getKeyPairApi(); InvocationSuccess floatingIpApi = getKeyPairApi();
ImplicitOptionalConverter fn = forApiVersion("2011-07-15"); ImplicitOptionalConverter fn = forApiVersion("2011-07-15");
Stopwatch watch = new Stopwatch().start(); Stopwatch watch = new Stopwatch().start();
fn.apply(floatingIpApi); fn.apply(floatingIpApi);
@ -150,23 +151,23 @@ public class PresentWhenApiVersionLexicographicallyAtOrAfterSinceApiVersionTest
} }
ClassInvokerArgsAndReturnVal getFloatingIPApi() { InvocationSuccess getFloatingIPApi() {
return getApi("Tag", TagAsyncApi.class); return getApi("Tag", TagAsyncApi.class);
} }
ClassInvokerArgsAndReturnVal getKeyPairApi() { InvocationSuccess getKeyPairApi() {
return getApi("KeyPair", KeyPairAsyncApi.class); return getApi("KeyPair", KeyPairAsyncApi.class);
} }
ClassInvokerArgsAndReturnVal getVpcApi() { InvocationSuccess getVpcApi() {
return getApi("Vpc", VpcAsyncApi.class); return getApi("Vpc", VpcAsyncApi.class);
} }
ClassInvokerArgsAndReturnVal getApi(String name, Class<?> type) { InvocationSuccess getApi(String name, Class<?> target) {
try { try {
return ClassInvokerArgsAndReturnVal.builder().clazz(type) return InvocationSuccess.create(Invocation.create(
.invoker(Invokable.from(EC2AsyncApi.class.getDeclaredMethod("get" + name + "ApiForRegion", String.class))) Invokable.from(EC2AsyncApi.class.getDeclaredMethod("get" + name + "ApiForRegion", String.class)),
.args(ImmutableList.<Object> of("region")).returnVal("present").build(); ImmutableList.<Object> of("region")), "present");
} catch (Exception e) { } catch (Exception e) {
throw propagate(e); throw propagate(e);
} }

View File

@ -33,7 +33,6 @@ import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.reflect.TypeToken;
import com.google.inject.Binder; import com.google.inject.Binder;
import com.google.inject.Injector; import com.google.inject.Injector;
import com.google.inject.Module; import com.google.inject.Module;
@ -64,9 +63,7 @@ public abstract class BaseAsyncApiTest<T> extends BaseRestApiTest {
protected void setupFactory() throws IOException { protected void setupFactory() throws IOException {
injector = createInjector(); injector = createInjector();
parserFactory = injector.getInstance(ParseSax.Factory.class); parserFactory = injector.getInstance(ParseSax.Factory.class);
processor = injector.getInstance(RestAnnotationProcessor.Factory.class).declaring(new TypeToken<T>(getClass()) { processor = injector.getInstance(RestAnnotationProcessor.class);
private static final long serialVersionUID = 1L;
}.getRawType());
} }
protected String identity = "identity"; protected String identity = "identity";

View File

@ -40,11 +40,13 @@ import org.jclouds.http.config.ConfiguresHttpCommandExecutorService;
import org.jclouds.http.functions.ParseSax; import org.jclouds.http.functions.ParseSax;
import org.jclouds.io.MutableContentMetadata; import org.jclouds.io.MutableContentMetadata;
import org.jclouds.javax.annotation.Nullable; import org.jclouds.javax.annotation.Nullable;
import org.jclouds.reflect.Invocation;
import org.jclouds.rest.annotations.Fallback; import org.jclouds.rest.annotations.Fallback;
import org.jclouds.rest.annotations.XMLResponseParser; import org.jclouds.rest.annotations.XMLResponseParser;
import org.jclouds.util.Strings2; import org.jclouds.util.Strings2;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Multimap; import com.google.common.collect.Multimap;
import com.google.common.collect.SortedSetMultimap; import com.google.common.collect.SortedSetMultimap;
import com.google.common.collect.TreeMultimap; import com.google.common.collect.TreeMultimap;
@ -176,11 +178,8 @@ public abstract class BaseRestApiTest {
} }
protected void assertResponseParserClassEquals(Invokable<?, ?> method, HttpRequest request, @Nullable Class<?> parserClass) { protected void assertResponseParserClassEquals(Invokable<?, ?> method, HttpRequest request, @Nullable Class<?> parserClass) {
assertEquals(AsyncRestClientProxy.createResponseParser(parserFactory, injector, method, request).getClass(), parserClass); assertEquals(
AsyncRestClientProxy.createResponseParser(parserFactory, injector,
Invocation.create(method, ImmutableList.of()), request).getClass(), parserClass);
} }
protected RestAnnotationProcessor factory(Class<?> clazz) {
return injector.getInstance(RestAnnotationProcessor.Factory.class).declaring(clazz);
}
} }

View File

@ -40,26 +40,26 @@ public class Optionals2Test {
} }
public void testReturnTypeOrTypeOfOptionalWhenOptional() throws SecurityException, NoSuchMethodException { public void testReturnTypeOrTypeOfOptionalWhenOptional() throws SecurityException, NoSuchMethodException {
Invokable<?, ?> method = Invokable.from(Test.class.getMethod("getOptional")); Invokable<?, ?> invoked = Invokable.from(Test.class.getMethod("getOptional"));
assertEquals(Optionals2.returnTypeOrTypeOfOptional(method), String.class); assertEquals(Optionals2.unwrapIfOptional(invoked.getReturnType()), String.class);
} }
public void testReturnTypeOrTypeOfOptionalWhenNotOptional() throws SecurityException, NoSuchMethodException { public void testReturnTypeOrTypeOfOptionalWhenNotOptional() throws SecurityException, NoSuchMethodException {
Invokable<?, ?> method = Invokable.from(Test.class.getMethod("getNotOptional")); Invokable<?, ?> invoked = Invokable.from(Test.class.getMethod("getNotOptional"));
assertEquals(Optionals2.returnTypeOrTypeOfOptional(method), String.class); assertEquals(Optionals2.unwrapIfOptional(invoked.getReturnType()), String.class);
} }
public void testIsReturnTypeOptionalWhenOptional() throws SecurityException, NoSuchMethodException { public void testIsReturnTypeOptionalWhenOptional() throws SecurityException, NoSuchMethodException {
Invokable<?, ?> method = Invokable.from(Test.class.getMethod("getOptional")); Invokable<?, ?> invoked = Invokable.from(Test.class.getMethod("getOptional"));
assertTrue(Optionals2.isReturnTypeOptional(method)); assertTrue(Optionals2.isReturnTypeOptional(invoked));
} }
public void testIsReturnTypeOptionalWhenNotOptional() throws SecurityException, NoSuchMethodException { public void testIsReturnTypeOptionalWhenNotOptional() throws SecurityException, NoSuchMethodException {
Invokable<?, ?> method = Invokable.from(Test.class.getMethod("getNotOptional")); Invokable<?, ?> invoked = Invokable.from(Test.class.getMethod("getNotOptional"));
assertFalse(Optionals2.isReturnTypeOptional(method)); assertFalse(Optionals2.isReturnTypeOptional(invoked));
} }
} }

View File

@ -21,7 +21,7 @@ package org.jclouds.util;
import static org.easymock.EasyMock.createMock; import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.createNiceMock; import static org.easymock.EasyMock.createNiceMock;
import static org.jclouds.util.Throwables2.getFirstThrowableOfType; import static org.jclouds.util.Throwables2.getFirstThrowableOfType;
import static org.jclouds.util.Throwables2.returnFirstExceptionIfInListOrThrowStandardExceptionOrCause; import static org.jclouds.util.Throwables2.propagateIfPossible;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import java.io.IOException; import java.io.IOException;
@ -52,7 +52,6 @@ import com.google.inject.spi.Message;
@Test @Test
public class Throwables2Test { public class Throwables2Test {
public void testGetFirstThrowableOfTypeSubclass() { public void testGetFirstThrowableOfTypeSubclass() {
SocketException aex = createMock(SocketException.class); SocketException aex = createMock(SocketException.class);
assertEquals(getFirstThrowableOfType(aex, IOException.class), aex); assertEquals(getFirstThrowableOfType(aex, IOException.class), aex);
@ -90,7 +89,6 @@ public class Throwables2Test {
assertEquals(getFirstThrowableOfType(pex, AuthorizationException.class), null); assertEquals(getFirstThrowableOfType(pex, AuthorizationException.class), null);
} }
public void testGetCauseCreation() { public void testGetCauseCreation() {
AuthorizationException aex = createMock(AuthorizationException.class); AuthorizationException aex = createMock(AuthorizationException.class);
Message message = new Message(ImmutableList.of(), "test", aex); Message message = new Message(ImmutableList.of(), "test", aex);
@ -146,132 +144,125 @@ public class Throwables2Test {
assertEquals(getFirstThrowableOfType(pex, AuthorizationException.class), null); assertEquals(getFirstThrowableOfType(pex, AuthorizationException.class), null);
} }
@Test @Test(expectedExceptions = TestException.class)
public void testReturnExceptionThatsInList() throws Exception { public void testPropagateExceptionThatsInList() throws Throwable {
Exception e = new TestException(); Exception e = new TestException();
assertEquals( propagateIfPossible(e, ImmutableSet.<TypeToken<? extends Throwable>> of(TypeToken.of(TestException.class)));
returnFirstExceptionIfInListOrThrowStandardExceptionOrCause(
ImmutableSet.<TypeToken<? extends Throwable>> of(TypeToken.of(TestException.class)), e), e);
assertEquals(
returnFirstExceptionIfInListOrThrowStandardExceptionOrCause(
ImmutableSet.<TypeToken<? extends Throwable>> of(TypeToken.of(TestException.class)),
new RuntimeException(e)), e);
} }
@Test(expectedExceptions = TestException.class) @Test(expectedExceptions = TestException.class)
public void testThrowExceptionNotInList() throws Exception { public void testPropagateWrappedExceptionThatsInList() throws Throwable {
Exception e = new TestException(); Exception e = new TestException();
returnFirstExceptionIfInListOrThrowStandardExceptionOrCause(ImmutableSet.<TypeToken<? extends Throwable>> of(), e); propagateIfPossible(new RuntimeException(e),
ImmutableSet.<TypeToken<? extends Throwable>> of(TypeToken.of(TestException.class)));
}
public void testPropagateIfPossibleDoesnThrowExceptionNotInList() throws Throwable {
Exception e = new TestException();
propagateIfPossible(e, ImmutableSet.<TypeToken<? extends Throwable>> of());
} }
@Test(expectedExceptions = IllegalStateException.class) @Test(expectedExceptions = IllegalStateException.class)
public void testPropagateStandardExceptionIllegalStateException() throws Exception { public void testPropagateStandardExceptionIllegalStateException() throws Throwable {
Exception e = new IllegalStateException(); Exception e = new IllegalStateException();
returnFirstExceptionIfInListOrThrowStandardExceptionOrCause(ImmutableSet.<TypeToken<? extends Throwable>> of(), propagateIfPossible(new RuntimeException(e), ImmutableSet.<TypeToken<? extends Throwable>> of());
new RuntimeException(e));
} }
@Test(expectedExceptions = IllegalArgumentException.class) @Test(expectedExceptions = IllegalArgumentException.class)
public void testPropagateStandardExceptionIllegalArgumentException() throws Exception { public void testPropagateStandardExceptionIllegalArgumentException() throws Throwable {
Exception e = new IllegalArgumentException(); Exception e = new IllegalArgumentException();
returnFirstExceptionIfInListOrThrowStandardExceptionOrCause(ImmutableSet.<TypeToken<? extends Throwable>> of(), propagateIfPossible(new RuntimeException(e), ImmutableSet.<TypeToken<? extends Throwable>> of());
new RuntimeException(e));
} }
@Test(expectedExceptions = UnsupportedOperationException.class) @Test(expectedExceptions = UnsupportedOperationException.class)
public void testPropagateStandardExceptionUnsupportedOperationException() throws Exception { public void testPropagateStandardExceptionUnsupportedOperationException() throws Throwable {
Exception e = new UnsupportedOperationException(); Exception e = new UnsupportedOperationException();
returnFirstExceptionIfInListOrThrowStandardExceptionOrCause(ImmutableSet.<TypeToken<? extends Throwable>> of(), propagateIfPossible(new RuntimeException(e), ImmutableSet.<TypeToken<? extends Throwable>> of());
new RuntimeException(e));
} }
@Test(expectedExceptions = AssertionError.class) @Test(expectedExceptions = AssertionError.class)
public void testPropagateStandardExceptionAssertionError() throws Exception { public void testPropagateStandardExceptionAssertionError() throws Throwable {
AssertionError e = new AssertionError(); AssertionError e = new AssertionError();
returnFirstExceptionIfInListOrThrowStandardExceptionOrCause(ImmutableSet.<TypeToken<? extends Throwable>> of(), propagateIfPossible(new RuntimeException(e), ImmutableSet.<TypeToken<? extends Throwable>> of());
new RuntimeException(e));
} }
@Test(expectedExceptions = AuthorizationException.class) @Test(expectedExceptions = AuthorizationException.class)
public void testPropagateStandardExceptionAuthorizationException() throws Exception { public void testPropagateStandardExceptionAuthorizationException() throws Throwable {
Exception e = new AuthorizationException(); Exception e = new AuthorizationException();
returnFirstExceptionIfInListOrThrowStandardExceptionOrCause(ImmutableSet.<TypeToken<? extends Throwable>> of(), propagateIfPossible(new RuntimeException(e), ImmutableSet.<TypeToken<? extends Throwable>> of());
new RuntimeException(e));
} }
@Test(expectedExceptions = AuthorizationException.class) @Test(expectedExceptions = AuthorizationException.class)
public void testPropagateProvisionExceptionAuthorizationException() throws Exception { public void testPropagateProvisionExceptionAuthorizationException() throws Throwable {
Exception e = new AuthorizationException(); Exception e = new AuthorizationException();
returnFirstExceptionIfInListOrThrowStandardExceptionOrCause(ImmutableSet.<TypeToken<? extends Throwable>> of(), propagateIfPossible(
new ProvisionException(ImmutableSet.of(new Message(ImmutableList.of(), "Error in custom provider", e)))); new ProvisionException(ImmutableSet.of(new Message(ImmutableList.of(), "Error in custom provider", e))),
ImmutableSet.<TypeToken<? extends Throwable>> of());
} }
@Test(expectedExceptions = AuthorizationException.class) @Test(expectedExceptions = AuthorizationException.class)
public void testPropagateCreationExceptionAuthorizationException() throws Exception { public void testPropagateCreationExceptionAuthorizationException() throws Throwable {
Exception e = new AuthorizationException(); Exception e = new AuthorizationException();
returnFirstExceptionIfInListOrThrowStandardExceptionOrCause(ImmutableSet.<TypeToken<? extends Throwable>> of(), propagateIfPossible(
new CreationException(ImmutableSet.of(new Message(ImmutableList.of(), "Error in custom provider", e)))); new CreationException(ImmutableSet.of(new Message(ImmutableList.of(), "Error in custom provider", e))),
ImmutableSet.<TypeToken<? extends Throwable>> of());
} }
@Test(expectedExceptions = InsufficientResourcesException.class) @Test(expectedExceptions = InsufficientResourcesException.class)
public void testPropagateStandardExceptionInsufficientResourcesException() throws Exception { public void testPropagateStandardExceptionInsufficientResourcesException() throws Throwable {
Exception e = new InsufficientResourcesException(); Exception e = new InsufficientResourcesException();
returnFirstExceptionIfInListOrThrowStandardExceptionOrCause(ImmutableSet.<TypeToken<? extends Throwable>> of(), propagateIfPossible(new RuntimeException(e), ImmutableSet.<TypeToken<? extends Throwable>> of());
new RuntimeException(e));
} }
@Test(expectedExceptions = ResourceNotFoundException.class) @Test(expectedExceptions = ResourceNotFoundException.class)
public void testPropagateStandardExceptionResourceNotFoundException() throws Exception { public void testPropagateStandardExceptionResourceNotFoundException() throws Throwable {
Exception e = new ResourceNotFoundException(); Exception e = new ResourceNotFoundException();
returnFirstExceptionIfInListOrThrowStandardExceptionOrCause(ImmutableSet.<TypeToken<? extends Throwable>> of(), propagateIfPossible(new RuntimeException(e), ImmutableSet.<TypeToken<? extends Throwable>> of());
new RuntimeException(e));
} }
@Test(expectedExceptions = IllegalStateException.class) @Test(expectedExceptions = IllegalStateException.class)
public void testPropagateStandardExceptionIllegalStateExceptionNestedInHttpResponseException() throws Exception { public void testPropagateStandardExceptionIllegalStateExceptionNestedInHttpResponseException() throws Throwable {
Exception e = new IllegalStateException(); Exception e = new IllegalStateException();
returnFirstExceptionIfInListOrThrowStandardExceptionOrCause(ImmutableSet.<TypeToken<? extends Throwable>> of(), propagateIfPossible(new HttpResponseException("goo", createNiceMock(HttpCommand.class), null, e),
new HttpResponseException("goo", createNiceMock(HttpCommand.class), null, e)); ImmutableSet.<TypeToken<? extends Throwable>> of());
} }
@Test(expectedExceptions = IllegalArgumentException.class) @Test(expectedExceptions = IllegalArgumentException.class)
public void testPropagateStandardExceptionIllegalArgumentExceptionNestedInHttpResponseException() throws Exception { public void testPropagateStandardExceptionIllegalArgumentExceptionNestedInHttpResponseException() throws Throwable {
Exception e = new IllegalArgumentException(); Exception e = new IllegalArgumentException();
returnFirstExceptionIfInListOrThrowStandardExceptionOrCause(ImmutableSet.<TypeToken<? extends Throwable>> of(), propagateIfPossible(new HttpResponseException("goo", createNiceMock(HttpCommand.class), null, e),
new HttpResponseException("goo", createNiceMock(HttpCommand.class), null, e)); ImmutableSet.<TypeToken<? extends Throwable>> of());
} }
@Test(expectedExceptions = UnsupportedOperationException.class) @Test(expectedExceptions = UnsupportedOperationException.class)
public void testPropagateStandardExceptionUnsupportedOperationExceptionNestedInHttpResponseException() public void testPropagateStandardExceptionUnsupportedOperationExceptionNestedInHttpResponseException()
throws Exception { throws Throwable {
Exception e = new UnsupportedOperationException(); Exception e = new UnsupportedOperationException();
returnFirstExceptionIfInListOrThrowStandardExceptionOrCause(ImmutableSet.<TypeToken<? extends Throwable>> of(), propagateIfPossible(new HttpResponseException("goo", createNiceMock(HttpCommand.class), null, e),
new HttpResponseException("goo", createNiceMock(HttpCommand.class), null, e)); ImmutableSet.<TypeToken<? extends Throwable>> of());
} }
@Test(expectedExceptions = AuthorizationException.class) @Test(expectedExceptions = AuthorizationException.class)
public void testPropagateStandardExceptionAuthorizationExceptionNestedInHttpResponseException() throws Exception { public void testPropagateStandardExceptionAuthorizationExceptionNestedInHttpResponseException() throws Throwable {
Exception e = new AuthorizationException(); Exception e = new AuthorizationException();
returnFirstExceptionIfInListOrThrowStandardExceptionOrCause(ImmutableSet.<TypeToken<? extends Throwable>> of(), propagateIfPossible(new HttpResponseException("goo", createNiceMock(HttpCommand.class), null, e),
new HttpResponseException("goo", createNiceMock(HttpCommand.class), null, e)); ImmutableSet.<TypeToken<? extends Throwable>> of());
} }
@Test(expectedExceptions = ResourceNotFoundException.class) @Test(expectedExceptions = ResourceNotFoundException.class)
public void testPropagateStandardExceptionResourceNotFoundExceptionNestedInHttpResponseException() throws Exception { public void testPropagateStandardExceptionResourceNotFoundExceptionNestedInHttpResponseException() throws Throwable {
Exception e = new ResourceNotFoundException(); Exception e = new ResourceNotFoundException();
returnFirstExceptionIfInListOrThrowStandardExceptionOrCause(ImmutableSet.<TypeToken<? extends Throwable>> of(), propagateIfPossible(new HttpResponseException("goo", createNiceMock(HttpCommand.class), null, e),
new HttpResponseException("goo", createNiceMock(HttpCommand.class), null, e)); ImmutableSet.<TypeToken<? extends Throwable>> of());
} }
@Test(expectedExceptions = HttpResponseException.class) @Test(expectedExceptions = HttpResponseException.class)
public void testPropagateStandardExceptionHttpResponseException() throws Exception { public void testPropagateStandardExceptionHttpResponseException() throws Throwable {
Exception e = new HttpResponseException("goo", createNiceMock(HttpCommand.class), null); Exception e = new HttpResponseException("goo", createNiceMock(HttpCommand.class), null);
returnFirstExceptionIfInListOrThrowStandardExceptionOrCause(ImmutableSet.<TypeToken<? extends Throwable>> of(), propagateIfPossible(new RuntimeException(e), ImmutableSet.<TypeToken<? extends Throwable>> of());
new RuntimeException(e));
} }
static class TestException extends Exception { static class TestException extends Exception {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
} }
} }

Some files were not shown because too many files have changed in this diff Show More