diff --git a/core/src/main/java/org/jclouds/View.java b/core/src/main/java/org/jclouds/View.java index 30f8863f84..08ed544c8e 100644 --- a/core/src/main/java/org/jclouds/View.java +++ b/core/src/main/java/org/jclouds/View.java @@ -16,6 +16,8 @@ */ package org.jclouds; +import java.io.Closeable; + import com.google.common.annotations.Beta; import com.google.common.reflect.TypeToken; @@ -68,4 +70,14 @@ public interface View { */ C unwrap() throws ClassCastException; + /** + * Unwraps the underlying api from this view. + * + * @param apiClass The class of the api to unwrap. + * @return The unwrapped api. + * + * @since 1.7 + */ + A unwrapApi(Class apiClass); + } diff --git a/core/src/main/java/org/jclouds/internal/BaseView.java b/core/src/main/java/org/jclouds/internal/BaseView.java index 38fbbfb410..250f49fe72 100644 --- a/core/src/main/java/org/jclouds/internal/BaseView.java +++ b/core/src/main/java/org/jclouds/internal/BaseView.java @@ -19,15 +19,19 @@ import static com.google.common.base.Objects.equal; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; +import java.io.Closeable; + import javax.inject.Singleton; import org.jclouds.Context; import org.jclouds.View; import org.jclouds.location.Provider; +import org.jclouds.rest.ApiContext; import com.google.common.base.Objects; import com.google.common.base.Objects.ToStringHelper; import com.google.common.collect.ForwardingObject; +import com.google.common.reflect.TypeParameter; import com.google.common.reflect.TypeToken; /** @@ -62,6 +66,17 @@ public abstract class BaseView extends ForwardingObject implements View { return (C) unwrap(getBackendType()); } + @Override + public A unwrapApi(Class apiClass) { + checkArgument(ApiContext.class.isAssignableFrom(backendType.getRawType()), + "backend type: %s should be an ApiContext", backendType); + TypeToken> contextToken = new TypeToken>(delegate().getClass()) { + private static final long serialVersionUID = 1L; + }.where(new TypeParameter() { + }, TypeToken.of(apiClass)); + return unwrap(contextToken).getApi(); + } + @Override protected Context delegate() { return backend; diff --git a/core/src/test/java/org/jclouds/internal/BaseViewTest.java b/core/src/test/java/org/jclouds/internal/BaseViewTest.java index 4270fdd278..2d82e3b380 100644 --- a/core/src/test/java/org/jclouds/internal/BaseViewTest.java +++ b/core/src/test/java/org/jclouds/internal/BaseViewTest.java @@ -17,19 +17,27 @@ package org.jclouds.internal; 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.reflect.Reflection2.typeToken; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotEquals; import static org.testng.Assert.fail; +import java.io.Closeable; +import java.io.IOException; + import org.jclouds.domain.Credentials; import org.jclouds.lifecycle.Closer; import org.jclouds.providers.ProviderMetadata; +import org.jclouds.rest.ApiContext; import org.jclouds.rest.Utils; import org.testng.annotations.Test; import com.google.common.base.Supplier; import com.google.common.base.Suppliers; +import com.google.common.reflect.TypeToken; /** * @author Adrian Cole @@ -66,6 +74,23 @@ public class BaseViewTest { } } + private static class DummyApi implements Closeable { + + @Override + public void close() throws IOException { + + } + } + + public class DummyView extends BaseView { + + protected DummyView(ApiContext context) { + super(context, new TypeToken>() { + private static final long serialVersionUID = 1L; + }); + } + } + public void testWaterTurnedIntoWine() { Wine wine = new Wine(); assertEquals(wine.getBackendType(), typeToken(Water.class)); @@ -83,5 +108,29 @@ public class BaseViewTest { assertEquals(e.getMessage(), "backend type: org.jclouds.internal.BaseViewTest$Water not assignable from org.jclouds.internal.BaseViewTest$PeanutButter"); } } - + + public void testCannotUnwrapIfNotApiContext() { + Wine wine = new Wine(); + try { + wine.unwrapApi(DummyApi.class); + fail(); + } catch (IllegalArgumentException e) { + assertEquals(e.getMessage(), "backend type: org.jclouds.internal.BaseViewTest$Water should be an ApiContext"); + } + } + + @SuppressWarnings("unchecked") + public void testUnwrapApi() { + DummyApi beer = new DummyApi(); + ApiContext beerContext = createMock(ApiContext.class); + expect(beerContext.getApi()).andReturn(beer); + replay(beerContext); + + DummyView bar = new DummyView(beerContext); + DummyApi result = bar.unwrapApi(DummyApi.class); + + assertEquals(result, beer); + verify(beerContext); + } + }