Issue 690:Update to guava 10.0rc2 and change from MapMaker to CacheBuilder

This commit is contained in:
Adrian Cole 2011-09-22 00:23:29 -07:00
parent d039fe7d96
commit 4cd94489c9
61 changed files with 1236 additions and 864 deletions

View File

@ -25,9 +25,6 @@ import static org.jclouds.tools.ant.taskdefs.compute.ComputeTaskUtils.ipOrEmptyS
import java.io.IOException;
import java.net.URI;
import java.util.Map;
import org.jclouds.javax.annotation.Nullable;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
@ -43,10 +40,12 @@ import org.jclouds.compute.domain.Template;
import org.jclouds.compute.predicates.NodePredicates;
import org.jclouds.domain.Location;
import org.jclouds.http.HttpUtils;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.util.CredentialUtils;
import com.google.common.base.CaseFormat;
import com.google.common.base.Splitter;
import com.google.common.cache.Cache;
import com.google.common.collect.Iterables;
import com.google.inject.Provider;
@ -56,7 +55,7 @@ import com.google.inject.Provider;
*/
public class ComputeTask extends Task {
private final Map<URI, ComputeServiceContext> computeMap;
private final Cache<URI, ComputeServiceContext> computeMap;
private String provider;
private String actions;
private NodeElement nodeElement;
@ -72,7 +71,7 @@ public class ComputeTask extends Task {
}
};
public ComputeTask(@Nullable Map<URI, ComputeServiceContext> computeMap) {
public ComputeTask(@Nullable Cache<URI, ComputeServiceContext> computeMap) {
this.computeMap = computeMap != null ? computeMap : buildComputeMap(projectProvider);
}
@ -88,7 +87,7 @@ public class ComputeTask extends Task {
* makes a connection to the compute service and invokes
*/
public void execute() throws BuildException {
ComputeServiceContext context = computeMap.get(HttpUtils.createUri(provider));
ComputeServiceContext context = computeMap.getUnchecked(HttpUtils.createUri(provider));
try {
for (String action : Splitter.on(',').split(actions)) {

View File

@ -22,7 +22,6 @@ import static org.jclouds.rest.RestContextFactory.getPropertiesFromResource;
import java.io.IOException;
import java.net.URI;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Properties;
import java.util.Set;
@ -43,11 +42,12 @@ import org.jclouds.ssh.jsch.config.JschSshClientModule;
import org.jclouds.tools.ant.logging.config.AntLoggingModule;
import com.google.common.base.Charsets;
import com.google.common.base.Function;
import com.google.common.base.Splitter;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.MapMaker;
import com.google.common.io.Files;
import com.google.inject.Module;
import com.google.inject.Provider;
@ -67,12 +67,12 @@ public class ComputeTaskUtils {
* allows access to the ant project to retrieve default properties needed for compute
* providers.
*/
static Map<URI, ComputeServiceContext> buildComputeMap(final Provider<Project> projectProvider) {
return new MapMaker().makeComputingMap(new Function<URI, ComputeServiceContext>() {
static Cache<URI, ComputeServiceContext> buildComputeMap(final Provider<Project> projectProvider) {
return CacheBuilder.newBuilder().build(new CacheLoader<URI, ComputeServiceContext>() {
@SuppressWarnings("unchecked")
@Override
public ComputeServiceContext apply(URI from) {
public ComputeServiceContext load(URI from) {
Properties props = getPropertiesFromResource("/rest.properties");
props.putAll(projectProvider.get().getProperties());
// adding the properties to the factory will allow us to pass

View File

@ -68,6 +68,7 @@ import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.base.Supplier;
import com.google.common.cache.Cache;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableMultimap.Builder;
import com.google.common.collect.ImmutableSet;
@ -78,8 +79,8 @@ import com.google.common.collect.ImmutableSet;
@Singleton
public class EC2ComputeService extends BaseComputeService {
private final EC2Client ec2Client;
private final Map<RegionAndName, KeyPair> credentialsMap;
private final Map<RegionAndName, String> securityGroupMap;
private final Cache<RegionAndName, KeyPair> credentialsMap;
private final Cache<RegionAndName, String> securityGroupMap;
@Inject
protected EC2ComputeService(ComputeServiceContext context, Map<String, Credentials> credentialStore,
@ -96,7 +97,7 @@ public class EC2ComputeService extends BaseComputeService {
RunScriptOnNode.Factory runScriptOnNodeFactory, InitAdminAccess initAdminAccess,
PersistNodeCredentials persistNodeCredentials, Timeouts timeouts,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor, EC2Client ec2Client,
Map<RegionAndName, KeyPair> credentialsMap, @Named("SECURITY") Map<RegionAndName, String> securityGroupMap) {
Cache<RegionAndName, KeyPair> credentialsMap, @Named("SECURITY") Cache<RegionAndName, String> securityGroupMap) {
super(context, credentialStore, images, sizes, locations, listNodesStrategy, getNodeMetadataStrategy,
runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, startNodeStrategy, stopNodeStrategy,
templateBuilderProvider, templateOptionsProvider, nodeRunning, nodeTerminated, nodeSuspended,
@ -116,7 +117,7 @@ public class EC2ComputeService extends BaseComputeService {
try {
ec2Client.getSecurityGroupServices().deleteSecurityGroupInRegion(region, groupName);
// TODO: test this clear happens
securityGroupMap.remove(new RegionNameAndIngressRules(region, groupName, null, false));
securityGroupMap.invalidate(new RegionNameAndIngressRules(region, groupName, null, false));
logger.debug("<< deleted securityGroup(%s)", groupName);
} catch (IllegalStateException e) {
logger.debug("<< inUse securityGroup(%s)", groupName);
@ -142,7 +143,7 @@ public class EC2ComputeService extends BaseComputeService {
logger.debug(">> deleting keyPair(%s)", keyPair.getKeyName());
ec2Client.getKeyPairServices().deleteKeyPairInRegion(region, keyPair.getKeyName());
// TODO: test this clear happens
credentialsMap.remove(new RegionAndName(region, keyPair.getKeyName()));
credentialsMap.invalidate(new RegionAndName(region, keyPair.getKeyName()));
logger.debug("<< deleted keyPair(%s)", keyPair.getKeyName());
}
}

View File

@ -22,8 +22,6 @@ import static com.google.common.collect.Iterables.toArray;
import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL;
import static org.jclouds.ec2.reference.EC2Constants.PROPERTY_EC2_AMI_OWNERS;
import java.util.Map;
import javax.inject.Named;
import javax.inject.Singleton;
@ -37,6 +35,7 @@ import org.jclouds.rest.suppliers.MemoizedRetryOnTimeOutButNotOnAuthorizationExc
import com.google.common.base.Splitter;
import com.google.common.base.Supplier;
import com.google.common.cache.Cache;
import com.google.inject.Provides;
/**
@ -59,12 +58,12 @@ public class EC2ComputeServiceContextModule extends BaseComputeServiceContextMod
@Provides
@Singleton
protected Supplier<Map<RegionAndName, ? extends Image>> provideRegionAndNameToImageSupplierCache(
protected Supplier<Cache<RegionAndName, ? extends Image>> provideRegionAndNameToImageSupplierCache(
@Named(PROPERTY_SESSION_INTERVAL) long seconds, final RegionAndNameToImageSupplier supplier) {
return new MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier<Map<RegionAndName, ? extends Image>>(
authException, seconds, new Supplier<Map<RegionAndName, ? extends Image>>() {
return new MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier<Cache<RegionAndName, ? extends Image>>(
authException, seconds, new Supplier<Cache<RegionAndName, ? extends Image>>() {
@Override
public Map<RegionAndName, ? extends Image> get() {
public Cache<RegionAndName, ? extends Image> get() {
return supplier.get();
}
});

View File

@ -18,8 +18,6 @@
*/
package org.jclouds.ec2.compute.config;
import static com.google.common.collect.Maps.newLinkedHashMap;
import java.security.SecureRandom;
import java.util.Map;
@ -39,7 +37,6 @@ import org.jclouds.ec2.EC2AsyncClient;
import org.jclouds.ec2.EC2Client;
import org.jclouds.ec2.compute.EC2ComputeService;
import org.jclouds.ec2.compute.domain.RegionAndName;
import org.jclouds.ec2.compute.domain.RegionNameAndIngressRules;
import org.jclouds.ec2.compute.functions.CreateSecurityGroupIfNeeded;
import org.jclouds.ec2.compute.functions.CreateUniqueKeyPair;
import org.jclouds.ec2.compute.functions.CredentialsForInstance;
@ -55,8 +52,11 @@ import org.jclouds.rest.internal.RestContextImpl;
import com.google.common.base.Function;
import com.google.common.base.Supplier;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.MapMaker;
import com.google.common.collect.Maps;
import com.google.inject.AbstractModule;
import com.google.inject.Provides;
import com.google.inject.Scopes;
@ -69,11 +69,11 @@ import com.google.inject.TypeLiteral;
public class EC2ComputeServiceDependenciesModule extends AbstractModule {
public static final Map<InstanceState, NodeState> instanceToNodeState = ImmutableMap
.<InstanceState, NodeState> builder().put(InstanceState.PENDING, NodeState.PENDING).put(
InstanceState.RUNNING, NodeState.RUNNING).put(InstanceState.SHUTTING_DOWN, NodeState.PENDING).put(
InstanceState.TERMINATED, NodeState.TERMINATED).put(InstanceState.STOPPING, NodeState.PENDING)
.put(InstanceState.STOPPED, NodeState.SUSPENDED).put(InstanceState.UNRECOGNIZED, NodeState.UNRECOGNIZED)
.build();
.<InstanceState, NodeState> builder().put(InstanceState.PENDING, NodeState.PENDING)
.put(InstanceState.RUNNING, NodeState.RUNNING).put(InstanceState.SHUTTING_DOWN, NodeState.PENDING)
.put(InstanceState.TERMINATED, NodeState.TERMINATED).put(InstanceState.STOPPING, NodeState.PENDING)
.put(InstanceState.STOPPED, NodeState.SUSPENDED).put(InstanceState.UNRECOGNIZED, NodeState.UNRECOGNIZED)
.build();
@Singleton
@Provides
@ -88,13 +88,13 @@ public class EC2ComputeServiceDependenciesModule extends AbstractModule {
bind(ComputeService.class).to(EC2ComputeService.class);
bind(new TypeLiteral<Function<RunningInstance, NodeMetadata>>() {
}).to(RunningInstanceToNodeMetadata.class);
bind(new TypeLiteral<Function<RunningInstance, Credentials>>() {
bind(new TypeLiteral<CacheLoader<RunningInstance, Credentials>>() {
}).to(CredentialsForInstance.class);
bind(new TypeLiteral<Function<RegionNameAndIngressRules, String>>() {
bind(new TypeLiteral<CacheLoader<RegionAndName, String>>() {
}).to(CreateSecurityGroupIfNeeded.class);
bind(new TypeLiteral<Function<RegionAndName, KeyPair>>() {
bind(new TypeLiteral<CacheLoader<RegionAndName, KeyPair>>() {
}).to(CreateUniqueKeyPair.class);
bind(new TypeLiteral<Function<RegionAndName, Image>>() {
bind(new TypeLiteral<CacheLoader<RegionAndName, Image>>() {
}).to(RegionAndIdToImage.class);
bind(new TypeLiteral<ComputeServiceContext>() {
}).to(new TypeLiteral<ComputeServiceContextImpl<EC2Client, EC2AsyncClient>>() {
@ -120,25 +120,35 @@ public class EC2ComputeServiceDependenciesModule extends AbstractModule {
@Provides
@Singleton
protected final Map<RegionAndName, KeyPair> credentialsMap(Function<RegionAndName, KeyPair> in) {
// doesn't seem to clear when someone issues remove(key)
// return new MapMaker().makeComputingMap(in);
return newLinkedHashMap();
protected Cache<RunningInstance, Credentials> credentialsMap(CacheLoader<RunningInstance, Credentials> in) {
return CacheBuilder.newBuilder().build(in);
}
@Provides
@Singleton
protected Cache<RegionAndName, KeyPair> keypairMap(CacheLoader<RegionAndName, KeyPair> in) {
return CacheBuilder.newBuilder().build(in);
}
@Provides
@Singleton
// keys that we know about.
protected Map<RegionAndName, KeyPair> knownKeys(){
return Maps.newConcurrentMap();
}
@Provides
@Singleton
@Named("SECURITY")
protected final Map<RegionAndName, String> securityGroupMap(Function<RegionNameAndIngressRules, String> in) {
// doesn't seem to clear when someone issues remove(key)
// return new MapMaker().makeComputingMap(in);
return newLinkedHashMap();
protected Cache<RegionAndName, String> securityGroupMap(CacheLoader<RegionAndName, String> in) {
return CacheBuilder.newBuilder().build(in);
}
@Provides
@Singleton
protected Map<RegionAndName, Image> provideImageMap(Function<RegionAndName, Image> regionAndIdToImage) {
return new MapMaker().makeComputingMap(regionAndIdToImage);
// keys that we know about.
protected Map<RegionAndName, Image> knownImages(){
return Maps.newConcurrentMap();
}
}

View File

@ -25,14 +25,15 @@ import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.ec2.EC2Client;
import org.jclouds.ec2.compute.domain.RegionAndName;
import org.jclouds.ec2.compute.domain.RegionNameAndIngressRules;
import org.jclouds.ec2.domain.IpProtocol;
import org.jclouds.ec2.domain.UserIdGroupPair;
import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.logging.Logger;
import com.google.common.base.Function;
import com.google.common.cache.CacheLoader;
import com.google.common.collect.Iterables;
/**
@ -40,7 +41,7 @@ import com.google.common.collect.Iterables;
* @author Adrian Cole
*/
@Singleton
public class CreateSecurityGroupIfNeeded implements Function<RegionNameAndIngressRules, String> {
public class CreateSecurityGroupIfNeeded extends CacheLoader<RegionAndName, String> {
@Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL;
@ -52,8 +53,9 @@ public class CreateSecurityGroupIfNeeded implements Function<RegionNameAndIngres
}
@Override
public String apply(RegionNameAndIngressRules from) {
createSecurityGroupInRegion(from.getRegion(), from.getName(), from.getPorts());
public String load(RegionAndName from) {
RegionNameAndIngressRules realFrom = RegionNameAndIngressRules.class.cast(from);
createSecurityGroupInRegion(from.getRegion(), from.getName(), realFrom.getPorts());
return from.getName();
}

View File

@ -20,6 +20,8 @@ package org.jclouds.ec2.compute.functions;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Map;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Named;
@ -32,30 +34,33 @@ import org.jclouds.ec2.domain.KeyPair;
import org.jclouds.logging.Logger;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
import com.google.common.base.Supplier;
import com.google.common.cache.CacheLoader;
/**
*
* @author Adrian Cole
*/
@Singleton
public class CreateUniqueKeyPair implements Function<RegionAndName, KeyPair> {
public class CreateUniqueKeyPair extends CacheLoader<RegionAndName, KeyPair> {
@Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL;
protected final EC2Client ec2Client;
protected final Supplier<String> randomSuffix;
protected final Map<RegionAndName, KeyPair> knownKeys;
@Inject
public CreateUniqueKeyPair(EC2Client ec2Client, Supplier<String> randomSuffix) {
public CreateUniqueKeyPair(Map<RegionAndName, KeyPair> knownKeys, EC2Client ec2Client, Supplier<String> randomSuffix) {
this.knownKeys = knownKeys;
this.ec2Client = ec2Client;
this.randomSuffix = randomSuffix;
}
@Override
public KeyPair apply(RegionAndName from) {
return createNewKeyPairInRegion(from.getRegion(), from.getName());
public KeyPair load(RegionAndName from) {
return knownKeys.containsKey(from) ? knownKeys.get(from) : createNewKeyPairInRegion(from.getRegion(),
from.getName());
}
@VisibleForTesting

View File

@ -20,43 +20,44 @@ package org.jclouds.ec2.compute.functions;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.ec2.compute.domain.RegionAndName;
import org.jclouds.ec2.domain.KeyPair;
import org.jclouds.ec2.domain.RunningInstance;
import org.jclouds.compute.domain.Image;
import org.jclouds.compute.strategy.PopulateDefaultLoginCredentialsForImageStrategy;
import org.jclouds.domain.Credentials;
import org.jclouds.ec2.compute.domain.RegionAndName;
import org.jclouds.ec2.domain.KeyPair;
import org.jclouds.ec2.domain.RunningInstance;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
import com.google.common.base.Supplier;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheLoader;
/**
*
* @author Adrian Cole
*/
@Singleton
public class CredentialsForInstance implements Function<RunningInstance, Credentials> {
private final Map<RegionAndName, KeyPair> credentialsMap;
public class CredentialsForInstance extends CacheLoader<RunningInstance, Credentials> {
private final Cache<RegionAndName, KeyPair> credentialsMap;
private final PopulateDefaultLoginCredentialsForImageStrategy credentialProvider;
private final Map<RegionAndName, Image> imageForInstance;
private final Supplier<Cache<RegionAndName, ? extends Image>> imageMap;
@Inject
CredentialsForInstance(Map<RegionAndName, KeyPair> credentialsMap,
PopulateDefaultLoginCredentialsForImageStrategy credentialProvider, Map<RegionAndName, Image> imageForInstance) {
CredentialsForInstance(Cache<RegionAndName, KeyPair> credentialsMap,
PopulateDefaultLoginCredentialsForImageStrategy credentialProvider, Supplier<Cache<RegionAndName, ? extends Image>> imageMap) {
this.credentialsMap = checkNotNull(credentialsMap, "credentialsMap");
this.credentialProvider = checkNotNull(credentialProvider, "credentialProvider");
this.imageForInstance = imageForInstance;
this.imageMap = imageMap;
}
@Override
public Credentials apply(RunningInstance instance) {
public Credentials load(RunningInstance instance) throws ExecutionException {
Credentials credentials = null;// default if no keypair exists
if (instance.getKeyName() != null) {
credentials = new Credentials(getLoginAccountFor(instance), getPrivateKeyOrNull(instance));
}
@ -64,15 +65,15 @@ public class CredentialsForInstance implements Function<RunningInstance, Credent
}
@VisibleForTesting
String getPrivateKeyOrNull(RunningInstance instance) {
String getPrivateKeyOrNull(RunningInstance instance) throws ExecutionException {
KeyPair keyPair = credentialsMap.get(new RegionAndName(instance.getRegion(), instance.getKeyName()));
return keyPair != null ? keyPair.getKeyMaterial() : null;
}
@VisibleForTesting
String getLoginAccountFor(RunningInstance from) {
String getLoginAccountFor(RunningInstance from) throws ExecutionException {
return checkNotNull(
credentialProvider.execute(imageForInstance.get(new RegionAndName(from.getRegion(), from.getImageId()))),
credentialProvider.execute(imageMap.get().get(new RegionAndName(from.getRegion(), from.getImageId()))),
"login from image: " + from.getImageId()).identity;
}
}

View File

@ -20,19 +20,19 @@ package org.jclouds.ec2.compute.functions;
import static org.jclouds.ec2.options.DescribeImagesOptions.Builder.imageIds;
import java.util.NoSuchElementException;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.compute.domain.Image;
import org.jclouds.ec2.EC2Client;
import org.jclouds.ec2.compute.domain.RegionAndName;
import org.jclouds.compute.domain.Image;
import org.jclouds.logging.Logger;
import org.jclouds.rest.ResourceNotFoundException;
import com.google.common.base.Function;
import com.google.common.cache.CacheLoader;
import com.google.common.collect.Iterables;
/**
@ -40,33 +40,31 @@ import com.google.common.collect.Iterables;
* @author Adrian Cole
*/
@Singleton
public final class RegionAndIdToImage implements Function<RegionAndName, Image> {
public class RegionAndIdToImage extends CacheLoader<RegionAndName, Image> {
@Resource
protected Logger logger = Logger.NULL;
private final Map<RegionAndName, Image> knownImages;
private final EC2ImageParser parser;
private final EC2Client sync;
@Inject
public RegionAndIdToImage(EC2ImageParser parser, EC2Client sync) {
public RegionAndIdToImage(Map<RegionAndName, Image> knownImages, EC2ImageParser parser, EC2Client sync) {
this.knownImages = knownImages;
this.parser = parser;
this.sync = sync;
}
public Image apply(RegionAndName key) {
@Override
public Image load(RegionAndName key) throws ExecutionException{
if (knownImages.containsKey(key))
return knownImages.get(key);
try {
org.jclouds.ec2.domain.Image image = Iterables.getOnlyElement(sync.getAMIServices()
.describeImagesInRegion(key.getRegion(), imageIds(key.getName())));
return parser.apply(image);
} catch (NoSuchElementException e) {
logger.debug(message(key, e));
return null;
} catch (ResourceNotFoundException e) {
logger.debug(message(key, e));
return null;
} catch (Exception e) {
logger.warn(e, message(key, e));
return null;
throw new ExecutionException(message(key, e), e);
}
}

View File

@ -30,11 +30,6 @@ import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.ec2.compute.domain.RegionAndName;
import org.jclouds.ec2.domain.BlockDevice;
import org.jclouds.ec2.domain.InstanceState;
import org.jclouds.ec2.domain.RootDeviceType;
import org.jclouds.ec2.domain.RunningInstance;
import org.jclouds.collect.Memoized;
import org.jclouds.compute.domain.Hardware;
import org.jclouds.compute.domain.HardwareBuilder;
@ -46,6 +41,11 @@ import org.jclouds.compute.domain.Volume;
import org.jclouds.compute.domain.internal.VolumeImpl;
import org.jclouds.domain.Credentials;
import org.jclouds.domain.Location;
import org.jclouds.ec2.compute.domain.RegionAndName;
import org.jclouds.ec2.domain.BlockDevice;
import org.jclouds.ec2.domain.InstanceState;
import org.jclouds.ec2.domain.RootDeviceType;
import org.jclouds.ec2.domain.RunningInstance;
import org.jclouds.logging.Logger;
import org.jclouds.util.NullSafeCollections;
@ -53,8 +53,10 @@ import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.base.Supplier;
import com.google.common.cache.Cache;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.util.concurrent.UncheckedExecutionException;
/**
* @author Adrian Cole
@ -67,17 +69,17 @@ public class RunningInstanceToNodeMetadata implements Function<RunningInstance,
protected final Supplier<Set<? extends Location>> locations;
protected final Supplier<Set<? extends Hardware>> hardware;
protected final Map<RegionAndName, Image> instanceToImage;
protected final Supplier<Cache<RegionAndName, ? extends Image>> imageMap;
protected final Map<String, Credentials> credentialStore;
protected final Map<InstanceState, NodeState> instanceToNodeState;
@Inject
protected RunningInstanceToNodeMetadata(Map<InstanceState, NodeState> instanceToNodeState,
Map<String, Credentials> credentialStore, Map<RegionAndName, Image> instanceToImage,
Map<String, Credentials> credentialStore, Supplier<Cache<RegionAndName, ? extends Image>> imageMap,
@Memoized Supplier<Set<? extends Location>> locations, @Memoized Supplier<Set<? extends Hardware>> hardware) {
this.locations = checkNotNull(locations, "locations");
this.hardware = checkNotNull(hardware, "hardware");
this.instanceToImage = checkNotNull(instanceToImage, "instanceToImage");
this.imageMap = checkNotNull(imageMap, "imageMap");
this.instanceToNodeState = checkNotNull(instanceToNodeState, "instanceToNodeState");
this.credentialStore = checkNotNull(credentialStore, "credentialStore");
}
@ -106,17 +108,13 @@ public class RunningInstanceToNodeMetadata implements Function<RunningInstance,
// extract the operating system from the image
RegionAndName regionAndName = new RegionAndName(instance.getRegion(), instance.getImageId());
try {
Image image = instanceToImage.get(regionAndName);
Image image = imageMap.get().getUnchecked(regionAndName);
if (image != null)
builder.operatingSystem(image.getOperatingSystem());
} catch (NullPointerException e) {
// The instanceToImage Map may throw NullPointerException (actually subclass
// NullOutputException) if the
// computing Function returns a null value.
//
// See the following for more information:
// MapMaker.makeComputingMap()
// RegionAndIdToImage.apply()
logger.debug("image not found for %s: %s", regionAndName, e);
} catch (UncheckedExecutionException e) {
logger.debug("error getting image for %s: %s", regionAndName, e);
}
return builder.build();

View File

@ -20,9 +20,9 @@ package org.jclouds.ec2.compute.internal;
import static com.google.common.base.Preconditions.checkArgument;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import javax.inject.Inject;
import javax.inject.Named;
@ -38,7 +38,8 @@ import org.jclouds.domain.Location;
import org.jclouds.ec2.compute.domain.RegionAndName;
import com.google.common.base.Supplier;
import com.google.common.collect.ComputationException;
import com.google.common.cache.Cache;
import com.google.common.util.concurrent.UncheckedExecutionException;
/**
*
@ -46,13 +47,13 @@ import com.google.common.collect.ComputationException;
*/
public class EC2TemplateBuilderImpl extends TemplateBuilderImpl {
private final Map<RegionAndName, Image> imageMap;
private final Supplier<Cache<RegionAndName, ? extends Image>> imageMap;
@Inject
protected EC2TemplateBuilderImpl(@Memoized Supplier<Set<? extends Location>> locations,
@Memoized Supplier<Set<? extends Image>> images, @Memoized Supplier<Set<? extends Hardware>> sizes,
Supplier<Location> defaultLocation, @Named("DEFAULT") Provider<TemplateOptions> optionsProvider,
@Named("DEFAULT") Provider<TemplateBuilder> defaultTemplateProvider, Map<RegionAndName, Image> imageMap) {
@Named("DEFAULT") Provider<TemplateBuilder> defaultTemplateProvider, Supplier<Cache<RegionAndName, ? extends Image>> imageMap) {
super(locations, images, sizes, defaultLocation, optionsProvider, defaultTemplateProvider);
this.imageMap = imageMap;
}
@ -67,11 +68,13 @@ public class EC2TemplateBuilderImpl extends TemplateBuilderImpl {
"amazon image ids must include the region ( ex. us-east-1/ami-7ea24a17 ) you specified: " + imageId);
RegionAndName key = new RegionAndName(regionName[0], regionName[1]);
try {
return imageMap.get(key);
return imageMap.get().get(key);
} catch (ExecutionException e) {
throw new NoSuchElementException(String.format("could not get imageId(%s/%s)", key.getRegion(), key.getName()));
} catch (UncheckedExecutionException e) {
throw new NoSuchElementException(String.format("could not get imageId(%s/%s)", key.getRegion(), key.getName()));
} catch (NullPointerException nex) {
throw new NoSuchElementException(String.format("imageId(%s/%s) not found", key.getRegion(), key.getName()));
} catch (ComputationException nex) {
throw new NoSuchElementException(String.format("imageId(%s/%s) not found", key.getRegion(), key.getName()));
}
}
return null;

View File

@ -23,7 +23,6 @@ import static com.google.common.base.Preconditions.checkState;
import java.util.Map;
import java.util.Set;
import org.jclouds.javax.annotation.Nullable;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Provider;
@ -37,11 +36,13 @@ import org.jclouds.ec2.compute.options.EC2TemplateOptions;
import org.jclouds.ec2.domain.BlockDeviceMapping;
import org.jclouds.ec2.domain.KeyPair;
import org.jclouds.ec2.options.RunInstancesOptions;
import org.jclouds.javax.annotation.Nullable;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
import com.google.common.cache.Cache;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSet.Builder;
import com.google.common.util.concurrent.UncheckedExecutionException;
/**
*
@ -49,26 +50,21 @@ import com.google.common.collect.ImmutableSet.Builder;
*/
@Singleton
public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions {
@VisibleForTesting
public final Map<RegionAndName, KeyPair> credentialsMap;
public final Map<RegionAndName, KeyPair> knownKeys;
@VisibleForTesting
public final Map<RegionAndName, String> securityGroupMap;
public final Cache<RegionAndName, KeyPair> credentialsMap;
@VisibleForTesting
public final Function<RegionAndName, KeyPair> createUniqueKeyPair;
@VisibleForTesting
public final Function<RegionNameAndIngressRules, String> createSecurityGroupIfNeeded;
public final Cache<RegionAndName, String> securityGroupMap;
protected final Provider<RunInstancesOptions> optionsProvider;
@Inject
public CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions(Map<RegionAndName, KeyPair> credentialsMap,
@Named("SECURITY") Map<RegionAndName, String> securityGroupMap, Function<RegionAndName, KeyPair> createUniqueKeyPair,
Function<RegionNameAndIngressRules, String> createSecurityGroupIfNeeded,
public CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions(Map<RegionAndName, KeyPair> knownKeys, Cache<RegionAndName, KeyPair> credentialsMap,
@Named("SECURITY") Cache<RegionAndName, String> securityGroupMap,
Provider<RunInstancesOptions> optionsProvider) {
this.knownKeys=knownKeys;
this.credentialsMap = credentialsMap;
this.securityGroupMap = securityGroupMap;
this.createUniqueKeyPair = createUniqueKeyPair;
this.createSecurityGroupIfNeeded = createSecurityGroupIfNeeded;
this.optionsProvider = optionsProvider;
}
@ -123,40 +119,32 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions {
if (options.getOverridingCredentials() != null && options.getOverridingCredentials().credential != null) {
KeyPair keyPair = KeyPair.builder().region(region).keyName(keyPairName).keyFingerprint("//TODO")
.keyMaterial(options.getOverridingCredentials().credential).build();
putKeyPairIntoCredentialMap(keyPair);
RegionAndName key = new RegionAndName(region, group);
knownKeys.put(key, keyPair);
credentialsMap.invalidate(key);
}
}
if (options.getRunScript() != null) {
RegionAndName regionAndName = new RegionAndName(region, keyPairName);
checkState(credentialsMap.containsKey(regionAndName),
"no private key configured for: %s; please use options.overrideLoginCredentialWith(rsa_private_text)",
regionAndName);
String message = String.format("no private key configured for: %s; please use options.overrideLoginCredentialWith(rsa_private_text)",
regionAndName);
// test to see if this is in cache.
try {
credentialsMap.getUnchecked(regionAndName);
} catch (NullPointerException nex) {
throw new IllegalArgumentException(message, nex);
} catch (UncheckedExecutionException nex) {
throw new IllegalArgumentException(message, nex);
}
}
return keyPairName;
}
// base EC2 driver currently does not support key import
protected String createOrImportKeyPair(String region, String group, TemplateOptions options) {
return createUniqueKeyPairAndPutIntoMap(region, group);
}
protected String createUniqueKeyPairAndPutIntoMap(String region, String group) {
RegionAndName regionAndName = new RegionAndName(region, group);
KeyPair keyPair = createUniqueKeyPair.apply(regionAndName);
putKeyPairIntoCredentialMap(keyPair);
return keyPair.getKeyName();
}
protected void putKeyPairIntoCredentialMap(KeyPair keyPair) {
// get or create incidental resources
// TODO race condition. we were using MapMaker, but it doesn't seem to
// refresh properly
// when
// another thread
// deletes a key
credentialsMap.put(new RegionAndName(keyPair.getRegion(), keyPair.getKeyName()), keyPair);
return credentialsMap.getUnchecked(new RegionAndName(region, group)).getKeyName();
}
@VisibleForTesting
@ -177,11 +165,8 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions {
regionNameAndIngessRulesForMarkerGroup = new RegionNameAndIngressRules(region, markerGroup,
options.getInboundPorts(), true);
}
if (!securityGroupMap.containsKey(regionNameAndIngessRulesForMarkerGroup)) {
securityGroupMap.put(regionNameAndIngessRulesForMarkerGroup,
createSecurityGroupIfNeeded.apply(regionNameAndIngessRulesForMarkerGroup));
}
// this will create if not yet exists.
securityGroupMap.getUnchecked(regionNameAndIngessRulesForMarkerGroup);
}
return groups.build();
}

View File

@ -52,6 +52,7 @@ import org.jclouds.logging.Logger;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.cache.Cache;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Multimap;
@ -77,7 +78,7 @@ public class EC2CreateNodesInGroupThenAddToSet implements CreateNodesInGroupThen
@VisibleForTesting
final ComputeUtils utils;
final InstancePresent instancePresent;
final Function<RunningInstance, Credentials> instanceToCredentials;
final Cache<RunningInstance, Credentials> instanceToCredentials;
final Map<String, Credentials> credentialStore;
final Provider<TemplateBuilder> templateBuilderProvider;
@ -87,7 +88,7 @@ public class EC2CreateNodesInGroupThenAddToSet implements CreateNodesInGroupThen
Provider<TemplateBuilder> templateBuilderProvider,
CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions createKeyPairAndSecurityGroupsAsNeededAndReturncustomize,
InstancePresent instancePresent, Function<RunningInstance, NodeMetadata> runningInstanceToNodeMetadata,
Function<RunningInstance, Credentials> instanceToCredentials, Map<String, Credentials> credentialStore,
Cache<RunningInstance, Credentials> instanceToCredentials, Map<String, Credentials> credentialStore,
ComputeUtils utils) {
this.client = checkNotNull(client, "client");
this.templateBuilderProvider = checkNotNull(templateBuilderProvider, "templateBuilderProvider");

View File

@ -18,16 +18,16 @@
*/
package org.jclouds.ec2.compute.suppliers;
import java.util.Map;
import java.util.Set;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.ec2.compute.domain.RegionAndName;
import org.jclouds.compute.domain.Image;
import org.jclouds.ec2.compute.domain.RegionAndName;
import com.google.common.base.Supplier;
import com.google.common.cache.Cache;
import com.google.common.collect.Sets;
/**
@ -36,16 +36,16 @@ import com.google.common.collect.Sets;
*/
@Singleton
public class EC2ImageSupplier implements Supplier<Set<? extends Image>> {
private final Supplier<Map<RegionAndName, ? extends Image>> map;
private final Supplier<Cache<RegionAndName, ? extends Image>> map;
@Inject
EC2ImageSupplier(Supplier<Map<RegionAndName, ? extends Image>> map) {
EC2ImageSupplier(Supplier<Cache<RegionAndName, ? extends Image>> map) {
this.map = map;
}
@Override
public Set<? extends Image> get() {
return Sets.newLinkedHashSet(map.get().values());
return Sets.newLinkedHashSet(map.get().asMap().values());
}
}

View File

@ -25,8 +25,8 @@ import static org.jclouds.ec2.options.DescribeImagesOptions.Builder.ownedBy;
import static org.jclouds.ec2.reference.EC2Constants.PROPERTY_EC2_AMI_OWNERS;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
import java.util.Set;
import javax.annotation.Resource;
import javax.inject.Inject;
@ -45,16 +45,19 @@ import org.jclouds.logging.Logger;
import com.google.common.base.Function;
import com.google.common.base.Predicates;
import com.google.common.base.Supplier;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableMap.Builder;
import com.google.common.collect.ImmutableSet;
/**
*
* @author Adrian Cole
*/
@Singleton
public class RegionAndNameToImageSupplier implements Supplier<Map<RegionAndName, ? extends Image>> {
public class RegionAndNameToImageSupplier implements Supplier<Cache<RegionAndName, ? extends Image>> {
@Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL;
@ -63,20 +66,23 @@ public class RegionAndNameToImageSupplier implements Supplier<Map<RegionAndName,
private final DescribeImagesParallel describer;
private final String[] amiOwners;
private final EC2ImageParser parser;
private final Map<RegionAndName, Image> images;
private final Map<RegionAndName, Image> knownImages;
private final CacheLoader<RegionAndName, Image> regionAndIdToImage;
@Inject
protected RegionAndNameToImageSupplier(@Region Set<String> regions, DescribeImagesParallel describer,
@Named(PROPERTY_EC2_AMI_OWNERS) String[] amiOwners, EC2ImageParser parser, Map<RegionAndName, Image> images) {
@Named(PROPERTY_EC2_AMI_OWNERS) String[] amiOwners, EC2ImageParser parser,
Map<RegionAndName, Image> knownImages, CacheLoader<RegionAndName, Image> regionAndIdToImage) {
this.regions = regions;
this.describer = describer;
this.amiOwners = amiOwners;
this.parser = parser;
this.images = images;
this.knownImages = knownImages;
this.regionAndIdToImage = regionAndIdToImage;
}
@Override
public Map<RegionAndName, ? extends Image> get() {
public Cache<RegionAndName, ? extends Image> get() {
if (amiOwners.length == 0) {
logger.debug(">> no owners specified, skipping image parsing");
} else {
@ -87,8 +93,8 @@ public class RegionAndNameToImageSupplier implements Supplier<Map<RegionAndName,
Iterable<? extends Image> parsedImages = ImmutableSet.copyOf(filter(transform(describer.apply(queries), parser), Predicates
.notNull()));
images.putAll(uniqueIndex(parsedImages, new Function<Image, RegionAndName>() {
knownImages.clear();
knownImages.putAll(uniqueIndex(parsedImages, new Function<Image, RegionAndName>() {
@Override
public RegionAndName apply(Image from) {
@ -96,14 +102,18 @@ public class RegionAndNameToImageSupplier implements Supplier<Map<RegionAndName,
}
}));
logger.debug("<< images(%d)", images.size());
logger.debug("<< images(%d)", knownImages.size());
}
return images;
Cache<RegionAndName, Image> cache = CacheBuilder.newBuilder().build(regionAndIdToImage);
// seed the cache
for (RegionAndName image : knownImages.keySet()) {
cache.getUnchecked(image);
}
return cache;
}
public Iterable<Entry<String, DescribeImagesOptions>> getDescribeQueriesForOwnersInRegions(Set<String> regions,
String[] amiOwners) {
String[] amiOwners) {
DescribeImagesOptions options = getOptionsForOwners(amiOwners);
Builder<String, DescribeImagesOptions> builder = ImmutableMap.<String, DescribeImagesOptions> builder();
for (String region : regions)

View File

@ -25,8 +25,10 @@ import static org.easymock.classextension.EasyMock.verify;
import static org.testng.Assert.assertEquals;
import java.net.UnknownHostException;
import java.util.Map;
import org.jclouds.ec2.EC2Client;
import org.jclouds.ec2.compute.domain.RegionAndName;
import org.jclouds.ec2.domain.KeyPair;
import org.jclouds.ec2.services.KeyPairClient;
import org.testng.annotations.Test;
@ -38,58 +40,127 @@ import com.google.common.base.Supplier;
*/
@Test(groups = "unit")
public class CreateUniqueKeyPairTest {
@SuppressWarnings( { "unchecked" })
@SuppressWarnings({ "unchecked" })
@Test
public void testApply() throws UnknownHostException {
EC2Client client = createMock(EC2Client.class);
KeyPairClient keyClient = createMock(KeyPairClient.class);
Supplier<String> uniqueIdSupplier = createMock(Supplier.class);
Map<RegionAndName, KeyPair> knownKeys = createMock(Map.class);
KeyPair pair = createMock(KeyPair.class);
expect(client.getKeyPairServices()).andReturn(keyClient).atLeastOnce();
expect(uniqueIdSupplier.get()).andReturn("1");
expect(keyClient.createKeyPairInRegion("region", "jclouds#tag#region#1")).andReturn(pair);
expect(keyClient.createKeyPairInRegion("region", "jclouds#group#region#1")).andReturn(pair);
replay(client);
replay(knownKeys);
replay(keyClient);
replay(uniqueIdSupplier);
CreateUniqueKeyPair parser = new CreateUniqueKeyPair(client, uniqueIdSupplier);
CreateUniqueKeyPair parser = new CreateUniqueKeyPair(knownKeys, client, uniqueIdSupplier);
assertEquals(parser.createNewKeyPairInRegion("region", "tag"), pair);
assertEquals(parser.createNewKeyPairInRegion("region", "group"), pair);
verify(client);
verify(knownKeys);
verify(keyClient);
verify(uniqueIdSupplier);
}
@SuppressWarnings( { "unchecked" })
@SuppressWarnings({ "unchecked" })
@Test
public void testApplyWithIllegalStateException() throws UnknownHostException {
EC2Client client = createMock(EC2Client.class);
KeyPairClient keyClient = createMock(KeyPairClient.class);
Supplier<String> uniqueIdSupplier = createMock(Supplier.class);
Map<RegionAndName, KeyPair> knownKeys = createMock(Map.class);
KeyPair pair = createMock(KeyPair.class);
expect(client.getKeyPairServices()).andReturn(keyClient).atLeastOnce();
expect(uniqueIdSupplier.get()).andReturn("1");
expect(keyClient.createKeyPairInRegion("region", "jclouds#tag#region#1")).andThrow(new IllegalStateException());
expect(keyClient.createKeyPairInRegion("region", "jclouds#group#region#1")).andThrow(new IllegalStateException());
expect(uniqueIdSupplier.get()).andReturn("2");
expect(keyClient.createKeyPairInRegion("region", "jclouds#tag#region#2")).andReturn(pair);
expect(keyClient.createKeyPairInRegion("region", "jclouds#group#region#2")).andReturn(pair);
replay(client);
replay(knownKeys);
replay(keyClient);
replay(uniqueIdSupplier);
CreateUniqueKeyPair parser = new CreateUniqueKeyPair(client, uniqueIdSupplier);
CreateUniqueKeyPair parser = new CreateUniqueKeyPair(knownKeys, client, uniqueIdSupplier);
assertEquals(parser.createNewKeyPairInRegion("region", "tag"), pair);
assertEquals(parser.createNewKeyPairInRegion("region", "group"), pair);
verify(client);
verify(knownKeys);
verify(keyClient);
verify(uniqueIdSupplier);
}
@SuppressWarnings({ "unchecked" })
@Test
public void testApplyWhenKnownKeyExists() throws UnknownHostException {
EC2Client client = createMock(EC2Client.class);
KeyPairClient keyClient = createMock(KeyPairClient.class);
Supplier<String> uniqueIdSupplier = createMock(Supplier.class);
Map<RegionAndName, KeyPair> knownKeys = createMock(Map.class);
KeyPair pair = createMock(KeyPair.class);
expect(knownKeys.containsKey(new RegionAndName("region", "group"))).andReturn(true);
expect(knownKeys.get(new RegionAndName("region", "group"))).andReturn(pair);
replay(client);
replay(knownKeys);
replay(keyClient);
replay(uniqueIdSupplier);
CreateUniqueKeyPair parser = new CreateUniqueKeyPair(knownKeys, client, uniqueIdSupplier);
assertEquals(parser.load(new RegionAndName("region", "group")), pair);
verify(client);
verify(knownKeys);
verify(keyClient);
verify(uniqueIdSupplier);
}
@SuppressWarnings({ "unchecked" })
@Test
public void testApplyWhenKnownKeyDoesntExist() throws UnknownHostException {
EC2Client client = createMock(EC2Client.class);
KeyPairClient keyClient = createMock(KeyPairClient.class);
Supplier<String> uniqueIdSupplier = createMock(Supplier.class);
Map<RegionAndName, KeyPair> knownKeys = createMock(Map.class);
KeyPair pair = createMock(KeyPair.class);
expect(client.getKeyPairServices()).andReturn(keyClient).atLeastOnce();
expect(knownKeys.containsKey(new RegionAndName("region", "group"))).andReturn(false);
expect(uniqueIdSupplier.get()).andReturn("1");
expect(keyClient.createKeyPairInRegion("region", "jclouds#group#region#1")).andThrow(new IllegalStateException());
expect(uniqueIdSupplier.get()).andReturn("2");
expect(keyClient.createKeyPairInRegion("region", "jclouds#group#region#2")).andReturn(pair);
replay(client);
replay(knownKeys);
replay(keyClient);
replay(uniqueIdSupplier);
CreateUniqueKeyPair parser = new CreateUniqueKeyPair(knownKeys, client, uniqueIdSupplier);
assertEquals(parser.load(new RegionAndName("region", "group")), pair);
verify(client);
verify(knownKeys);
verify(keyClient);
verify(uniqueIdSupplier);

View File

@ -26,13 +26,15 @@ import static org.easymock.classextension.EasyMock.verify;
import static org.jclouds.ec2.options.DescribeImagesOptions.Builder.imageIds;
import static org.testng.Assert.assertEquals;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import org.jclouds.compute.domain.Image;
import org.jclouds.ec2.EC2Client;
import org.jclouds.ec2.compute.domain.RegionAndName;
import org.jclouds.ec2.services.AMIClient;
import org.jclouds.compute.domain.Image;
import org.jclouds.rest.ResourceNotFoundException;
import org.testng.annotations.Test;
@ -46,46 +48,85 @@ public class RegionAndIdToImageTest {
@SuppressWarnings("unchecked")
@Test
public void testApply() {
public void testApply() throws ExecutionException {
EC2ImageParser parser = createMock(EC2ImageParser.class);
EC2Client caller = createMock(EC2Client.class);
AMIClient client = createMock(AMIClient.class);
Map<RegionAndName, Image> knownImages = createMock(Map.class);
org.jclouds.ec2.domain.Image ec2Image = createMock(org.jclouds.ec2.domain.Image.class);
Image image = createNiceMock(Image.class);
Set<? extends org.jclouds.ec2.domain.Image> images = ImmutableSet.<org.jclouds.ec2.domain.Image> of(ec2Image);
expect(knownImages.containsKey(new RegionAndName("region", "ami"))).andReturn(false);
expect(caller.getAMIServices()).andReturn(client).atLeastOnce();
expect(client.describeImagesInRegion("region", imageIds("ami"))).andReturn(Set.class.cast(images));
expect(parser.apply(ec2Image)).andReturn(image);
replay(knownImages);
replay(caller);
replay(image);
replay(parser);
replay(client);
RegionAndIdToImage function = new RegionAndIdToImage(parser, caller);
RegionAndIdToImage function = new RegionAndIdToImage(knownImages, parser, caller);
assertEquals(function.apply(new RegionAndName("region", "ami")), image);
assertEquals(function.load(new RegionAndName("region", "ami")), image);
verify(caller);
verify(image);
verify(parser);
verify(image);
verify(knownImages);
verify(client);
}
@SuppressWarnings("unchecked")
@Test
public void testApplyNotFound() {
public void testApplyWhenFoundDoesntCallClient() throws ExecutionException {
EC2ImageParser parser = createMock(EC2ImageParser.class);
EC2Client caller = createMock(EC2Client.class);
AMIClient client = createMock(AMIClient.class);
Map<RegionAndName, Image> knownImages = createMock(Map.class);
Image image = createNiceMock(Image.class);
expect(knownImages.containsKey(new RegionAndName("region", "ami"))).andReturn(true);
expect(knownImages.get(new RegionAndName("region", "ami"))).andReturn(image);
replay(knownImages);
replay(caller);
replay(image);
replay(parser);
replay(client);
RegionAndIdToImage function = new RegionAndIdToImage(knownImages, parser, caller);
assertEquals(function.load(new RegionAndName("region", "ami")), image);
verify(caller);
verify(image);
verify(image);
verify(knownImages);
verify(client);
}
@SuppressWarnings("unchecked")
@Test(expectedExceptions = ExecutionException.class)
public void testApplyNotFoundMakesExecutionException() throws ExecutionException {
EC2ImageParser parser = createMock(EC2ImageParser.class);
EC2Client caller = createMock(EC2Client.class);
AMIClient client = createMock(AMIClient.class);
Map<RegionAndName, Image> knownImages = createMock(Map.class);
org.jclouds.ec2.domain.Image ec2Image = createMock(org.jclouds.ec2.domain.Image.class);
Image image = createNiceMock(Image.class);
Set<? extends org.jclouds.ec2.domain.Image> images = ImmutableSet.<org.jclouds.ec2.domain.Image> of(ec2Image);
expect(knownImages.containsKey(new RegionAndName("region", "ami"))).andReturn(false);
expect(caller.getAMIServices()).andReturn(client).atLeastOnce();
expect(client.describeImagesInRegion("region", imageIds("ami"))).andReturn(Set.class.cast(images));
expect(parser.apply(ec2Image)).andThrow(new ResourceNotFoundException());
@ -93,45 +134,52 @@ public class RegionAndIdToImageTest {
replay(caller);
replay(image);
replay(parser);
replay(knownImages);
replay(client);
RegionAndIdToImage function = new RegionAndIdToImage(parser, caller);
RegionAndIdToImage function = new RegionAndIdToImage(knownImages, parser, caller);
assertEquals(function.apply(new RegionAndName("region", "ami")), null);
assertEquals(function.load(new RegionAndName("region", "ami")), null);
verify(caller);
verify(image);
verify(parser);
verify(knownImages);
verify(client);
}
@SuppressWarnings("unchecked")
@Test
public void testApplyNoSuchElementException() {
@Test(expectedExceptions = ExecutionException.class)
public void testApplyNoSuchElementExceptionMakesExecutionException() throws ExecutionException {
EC2ImageParser parser = createMock(EC2ImageParser.class);
EC2Client caller = createMock(EC2Client.class);
AMIClient client = createMock(AMIClient.class);
Map<RegionAndName, Image> knownImages = createMock(Map.class);
org.jclouds.ec2.domain.Image ec2Image = createMock(org.jclouds.ec2.domain.Image.class);
Image image = createNiceMock(Image.class);
Set<? extends org.jclouds.ec2.domain.Image> images = ImmutableSet.<org.jclouds.ec2.domain.Image> of(ec2Image);
expect(knownImages.containsKey(new RegionAndName("region", "ami"))).andReturn(false);
expect(caller.getAMIServices()).andReturn(client).atLeastOnce();
expect(client.describeImagesInRegion("region", imageIds("ami"))).andReturn(Set.class.cast(images));
expect(parser.apply(ec2Image)).andThrow(new NoSuchElementException());
replay(caller);
replay(image);
replay(knownImages);
replay(parser);
replay(client);
RegionAndIdToImage function = new RegionAndIdToImage(parser, caller);
RegionAndIdToImage function = new RegionAndIdToImage(knownImages, parser, caller);
assertEquals(function.apply(new RegionAndName("region", "ami")), null);
assertEquals(function.load(new RegionAndName("region", "ami")), null);
verify(caller);
verify(image);
verify(knownImages);
verify(parser);
verify(client);

View File

@ -25,8 +25,6 @@ import java.net.UnknownHostException;
import java.util.Map;
import java.util.Set;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.compute.domain.Hardware;
import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.NodeMetadata;
@ -43,14 +41,18 @@ import org.jclouds.ec2.compute.domain.RegionAndName;
import org.jclouds.ec2.domain.InstanceState;
import org.jclouds.ec2.domain.RunningInstance;
import org.jclouds.ec2.xml.DescribeInstancesResponseHandlerTest;
import org.jclouds.javax.annotation.Nullable;
import org.testng.annotations.Test;
import com.google.common.base.Function;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.MapMaker;
import com.google.common.collect.Maps;
/**
@ -167,14 +169,14 @@ public class RunningInstanceToNodeMetadataTest {
// Handle the case when the installed AMI no longer can be found in AWS.
// Create a null-returning function to simulate that the AMI can't be found.
Function<RegionAndName, Image> nullReturningFunction = new Function<RegionAndName, Image>() {
CacheLoader<RegionAndName, Image> nullReturningFunction = new CacheLoader<RegionAndName, Image>() {
@Override
public Image apply(@Nullable RegionAndName from) {
public Image load(@Nullable RegionAndName from) {
return null;
}
};
Map<RegionAndName, Image> instanceToImage = new MapMaker().makeComputingMap(nullReturningFunction);
Cache<RegionAndName, Image> instanceToImage = CacheBuilder.newBuilder().build(nullReturningFunction);
RunningInstanceToNodeMetadata parser = createNodeParser(ImmutableSet.of(m1_small32().build()), ImmutableSet
.of(provider), ImmutableMap.<String, Credentials> of(),
@ -197,25 +199,31 @@ public class RunningInstanceToNodeMetadataTest {
}
protected RunningInstanceToNodeMetadata createNodeParser(final ImmutableSet<Hardware> hardware,
final ImmutableSet<Location> locations, Set<org.jclouds.compute.domain.Image> images,
final ImmutableSet<Location> locations, final Set<org.jclouds.compute.domain.Image> images,
Map<String, Credentials> credentialStore) {
Map<InstanceState, NodeState> instanceToNodeState = EC2ComputeServiceDependenciesModule.instanceToNodeState;
Map<RegionAndName, Image> instanceToImage = Maps.uniqueIndex(images, new Function<Image, RegionAndName>() {
CacheLoader<RegionAndName, Image> getRealImage = new CacheLoader<RegionAndName, Image>() {
@Override
public RegionAndName apply(Image from) {
return new RegionAndName(from.getLocation().getId(), from.getProviderId());
public Image load(@Nullable RegionAndName from) {
return Maps.uniqueIndex(images, new Function<Image, RegionAndName>() {
@Override
public RegionAndName apply(Image from) {
return new RegionAndName(from.getLocation().getId(), from.getProviderId());
}
}).get(from);
}
});
};
Cache<RegionAndName, Image> instanceToImage = CacheBuilder.newBuilder().build(getRealImage);
return createNodeParser(hardware, locations, credentialStore, instanceToNodeState, instanceToImage);
}
private RunningInstanceToNodeMetadata createNodeParser(final ImmutableSet<Hardware> hardware,
final ImmutableSet<Location> locations, Map<String, Credentials> credentialStore,
Map<InstanceState, NodeState> instanceToNodeState, Map<RegionAndName, Image> instanceToImage) {
Map<InstanceState, NodeState> instanceToNodeState, Cache<RegionAndName, Image> instanceToImage) {
Supplier<Set<? extends Location>> locationSupplier = new Supplier<Set<? extends Location>>() {
@Override
@ -233,7 +241,8 @@ public class RunningInstanceToNodeMetadataTest {
};
RunningInstanceToNodeMetadata parser = new RunningInstanceToNodeMetadata(instanceToNodeState, credentialStore,
instanceToImage, locationSupplier, hardwareSupplier);
Suppliers.<Cache<RegionAndName, ? extends Image>> ofInstance(instanceToImage), locationSupplier,
hardwareSupplier);
return parser;
}

View File

@ -27,7 +27,6 @@ import static org.testng.Assert.assertEquals;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;
import javax.inject.Provider;
@ -46,11 +45,12 @@ import org.jclouds.ec2.compute.domain.RegionAndName;
import org.jclouds.ec2.compute.options.EC2TemplateOptions;
import org.testng.annotations.Test;
import com.google.common.base.Function;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.MapMaker;
import com.google.common.collect.Sets;
/**
@ -67,22 +67,21 @@ public class EC2TemplateBuilderImplTest extends TemplateBuilderImplTest {
@Override
protected EC2TemplateBuilderImpl createTemplateBuilder(final Image knownImage,
@Memoized Supplier<Set<? extends Location>> locations, @Memoized Supplier<Set<? extends Image>> images,
@Memoized Supplier<Set<? extends Hardware>> sizes, Location defaultLocation,
Provider<TemplateOptions> optionsProvider, Provider<TemplateBuilder> templateBuilderProvider) {
@Memoized Supplier<Set<? extends Location>> locations, @Memoized Supplier<Set<? extends Image>> images,
@Memoized Supplier<Set<? extends Hardware>> sizes, Location defaultLocation,
Provider<TemplateOptions> optionsProvider, Provider<TemplateBuilder> templateBuilderProvider) {
final RegionAndName knownRegionAndName = new RegionAndName("region", "ami");
ConcurrentMap<RegionAndName, Image> imageMap = new MapMaker()
.makeComputingMap(new Function<RegionAndName, Image>() {
@Override
public Image apply(RegionAndName from) {
return from.equals(knownRegionAndName) ? knownImage : null;
}
Cache<RegionAndName, ? extends Image> imageMap = CacheBuilder.newBuilder().build(new CacheLoader<RegionAndName, Image>() {
@Override
public Image load(RegionAndName from) {
return from.equals(knownRegionAndName) ? knownImage : null;
}
});
});
return new EC2TemplateBuilderImpl(locations, images, sizes, Suppliers.ofInstance(defaultLocation),
optionsProvider, templateBuilderProvider, imageMap);
optionsProvider, templateBuilderProvider, Suppliers.<Cache<RegionAndName, ? extends Image>>ofInstance(imageMap));
}
@SuppressWarnings("unchecked")
@ -91,11 +90,11 @@ public class EC2TemplateBuilderImplTest extends TemplateBuilderImplTest {
Location location = new LocationBuilder().scope(LocationScope.REGION).id("region").description("region").build();
Supplier<Set<? extends Location>> locations = Suppliers.<Set<? extends Location>> ofInstance(ImmutableSet
.<Location> of(location));
.<Location> of(location));
Supplier<Set<? extends Image>> images = Suppliers.<Set<? extends Image>> ofInstance(Sets
.<Image> newLinkedHashSet());
.<Image> newLinkedHashSet());
Supplier<Set<? extends Hardware>> sizes = Suppliers.<Set<? extends Hardware>> ofInstance(ImmutableSet
.<Hardware> of(c1_medium().build()));
.<Hardware> of(c1_medium().build()));
Provider<TemplateOptions> optionsProvider = createMock(Provider.class);
Provider<TemplateBuilder> templateBuilderProvider = createMock(Provider.class);
@ -127,7 +126,7 @@ public class EC2TemplateBuilderImplTest extends TemplateBuilderImplTest {
replay(templateBuilderProvider);
TemplateBuilderImpl template = createTemplateBuilder(knownImage, locations, images, sizes, location,
optionsProvider, templateBuilderProvider);
optionsProvider, templateBuilderProvider);
assertEquals(template.imageId("region/ami").build().getImage(), knownImage);
@ -144,10 +143,10 @@ public class EC2TemplateBuilderImplTest extends TemplateBuilderImplTest {
Location location = new LocationBuilder().scope(LocationScope.REGION).id("region").description("region").build();
Supplier<Set<? extends Location>> locations = Suppliers.<Set<? extends Location>> ofInstance(ImmutableSet
.<Location> of(location));
.<Location> of(location));
Supplier<Set<? extends Image>> images = Suppliers.<Set<? extends Image>> ofInstance(ImmutableSet.<Image> of());
Supplier<Set<? extends Hardware>> sizes = Suppliers.<Set<? extends Hardware>> ofInstance(ImmutableSet
.<Hardware> of(c1_medium().build()));
.<Hardware> of(c1_medium().build()));
Provider<TemplateOptions> optionsProvider = createMock(Provider.class);
Provider<TemplateBuilder> templateBuilderProvider = createMock(Provider.class);
@ -162,7 +161,7 @@ public class EC2TemplateBuilderImplTest extends TemplateBuilderImplTest {
replay(templateBuilderProvider);
TemplateBuilderImpl template = createTemplateBuilder(knownImage, locations, images, sizes, location,
optionsProvider, templateBuilderProvider);
optionsProvider, templateBuilderProvider);
try {
template.imageId("ami").build();
assert false;
@ -181,10 +180,10 @@ public class EC2TemplateBuilderImplTest extends TemplateBuilderImplTest {
Location location = new LocationBuilder().scope(LocationScope.REGION).id("region").description("region").build();
Supplier<Set<? extends Location>> locations = Suppliers.<Set<? extends Location>> ofInstance(ImmutableSet
.<Location> of(location));
.<Location> of(location));
Supplier<Set<? extends Image>> images = Suppliers.<Set<? extends Image>> ofInstance(ImmutableSet.<Image> of());
Supplier<Set<? extends Hardware>> sizes = Suppliers.<Set<? extends Hardware>> ofInstance(ImmutableSet
.<Hardware> of(c1_medium().build()));
.<Hardware> of(c1_medium().build()));
Location defaultLocation = createMock(Location.class);
Provider<TemplateOptions> optionsProvider = createMock(Provider.class);
@ -202,7 +201,7 @@ public class EC2TemplateBuilderImplTest extends TemplateBuilderImplTest {
replay(templateBuilderProvider);
TemplateBuilderImpl template = createTemplateBuilder(knownImage, locations, images, sizes, defaultLocation,
optionsProvider, templateBuilderProvider);
optionsProvider, templateBuilderProvider);
assertEquals(template.imageId("region/bad").build().getImage(), knownImage);

View File

@ -27,6 +27,7 @@ import static org.testng.Assert.assertEquals;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import javax.inject.Provider;
@ -38,8 +39,6 @@ import org.jclouds.domain.Credentials;
import org.jclouds.ec2.compute.domain.EC2HardwareBuilder;
import org.jclouds.ec2.compute.domain.RegionAndName;
import org.jclouds.ec2.compute.domain.RegionNameAndIngressRules;
import org.jclouds.ec2.compute.functions.CreateSecurityGroupIfNeeded;
import org.jclouds.ec2.compute.functions.CreateUniqueKeyPair;
import org.jclouds.ec2.compute.options.EC2TemplateOptions;
import org.jclouds.ec2.domain.BlockDeviceMapping;
import org.jclouds.ec2.domain.KeyPair;
@ -48,14 +47,14 @@ import org.jclouds.encryption.internal.Base64;
import org.jclouds.scriptbuilder.domain.Statements;
import org.testng.annotations.Test;
import com.google.common.base.Function;
import com.google.common.cache.Cache;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSet;
/**
* @author Adrian Cole
*/
@Test(groups = "unit")
@Test(groups = "unit", singleThreaded = true, testName = "CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest")
public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
private static final Provider<RunInstancesOptions> OPTIONS_PROVIDER = new javax.inject.Provider<RunInstancesOptions>() {
@ -209,7 +208,7 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
verifyStrategy(strategy);
}
@Test(expectedExceptions = IllegalStateException.class)
@Test(expectedExceptions = IllegalArgumentException.class)
public void testCreateNewKeyPairUnlessUserSpecifiedOtherwise_reusesKeyWhenToldToWithRunScriptButNoCredentials() {
// setup constants
String region = Region.AP_SOUTHEAST_1;
@ -225,7 +224,8 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
expect(options.getKeyPair()).andReturn(userSuppliedKeyPair);
expect(options.getOverridingCredentials()).andReturn(null);
expect(options.getRunScript()).andReturn(Statements.exec("echo foo"));
expect(strategy.credentialsMap.containsKey(new RegionAndName(region, userSuppliedKeyPair))).andReturn(false);
expect(strategy.credentialsMap.getUnchecked(new RegionAndName(region, userSuppliedKeyPair))).andThrow(new NullPointerException());
// replay mocks
replay(options);
@ -256,7 +256,8 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
expect(options.getKeyPair()).andReturn(userSuppliedKeyPair);
expect(options.getOverridingCredentials()).andReturn(null);
expect(options.getRunScript()).andReturn(Statements.exec("echo foo"));
expect(strategy.credentialsMap.containsKey(new RegionAndName(region, userSuppliedKeyPair))).andReturn(true);
expect(strategy.credentialsMap.getUnchecked(new RegionAndName(region, userSuppliedKeyPair))).andReturn(keyPair);
// replay mocks
replay(options);
@ -287,11 +288,13 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
expect(options.getKeyPair()).andReturn(userSuppliedKeyPair);
expect(options.getOverridingCredentials()).andReturn(new Credentials(null, "MyRsa")).atLeastOnce();
expect(
strategy.credentialsMap.put(new RegionAndName(region, userSuppliedKeyPair), KeyPair.builder()
.region(region).keyName(userSuppliedKeyPair).keyFingerprint("//TODO").keyMaterial("MyRsa").build()))
.andReturn(null);
strategy.knownKeys.put(
new RegionAndName(region, tag),
KeyPair.builder().region(region).keyName(userSuppliedKeyPair).keyFingerprint("//TODO")
.keyMaterial("MyRsa").build())).andReturn(null);
strategy.credentialsMap.invalidate(new RegionAndName(region, tag));
expect(options.getRunScript()).andReturn(Statements.exec("echo foo"));
expect(strategy.credentialsMap.containsKey(new RegionAndName(region, userSuppliedKeyPair))).andReturn(true);
expect(strategy.credentialsMap.getUnchecked(new RegionAndName(region, userSuppliedKeyPair))).andReturn(keyPair);
// replay mocks
replay(options);
@ -307,7 +310,8 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
verifyStrategy(strategy);
}
public void testCreateNewKeyPairUnlessUserSpecifiedOtherwise_createsNewKeyPairAndReturnsItsNameByDefault() {
public void testCreateNewKeyPairUnlessUserSpecifiedOtherwise_createsNewKeyPairAndReturnsItsNameByDefault()
throws ExecutionException {
// setup constants
String region = Region.AP_SOUTHEAST_1;
String tag = "tag";
@ -323,11 +327,8 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
// setup expectations
expect(options.getKeyPair()).andReturn(userSuppliedKeyPair);
expect(options.shouldAutomaticallyCreateKeyPair()).andReturn(shouldAutomaticallyCreateKeyPair);
expect(strategy.createUniqueKeyPair.apply(new RegionAndName(region, tag))).andReturn(keyPair);
expect(keyPair.getRegion()).andReturn(region).atLeastOnce();
expect(keyPair.getKeyName()).andReturn(systemGeneratedKeyPairName).atLeastOnce();
expect(strategy.credentialsMap.put(new RegionAndName(region, systemGeneratedKeyPairName), keyPair)).andReturn(
null);
expect(strategy.credentialsMap.getUnchecked(new RegionAndName(region, tag))).andReturn(keyPair);
expect(options.getRunScript()).andReturn(null);
// replay mocks
@ -377,7 +378,8 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
verifyStrategy(strategy);
}
public void testGetSecurityGroupsForTagAndOptions_createsNewGroupByDefaultWhenNoPortsAreSpecifiedWhenDoesntExist() {
public void testGetSecurityGroupsForTagAndOptions_createsNewGroupByDefaultWhenNoPortsAreSpecifiedWhenDoesntExist()
throws ExecutionException {
// setup constants
String region = Region.AP_SOUTHEAST_1;
String tag = "tag";
@ -385,7 +387,6 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
Set<String> groupIds = ImmutableSet.<String> of();
int[] ports = new int[] {};
boolean shouldAuthorizeSelf = true;
boolean groupExisted = false;
Set<String> returnVal = ImmutableSet.<String> of(generatedMarkerGroup);
// create mocks
@ -397,9 +398,7 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
expect(options.getInboundPorts()).andReturn(ports).atLeastOnce();
RegionNameAndIngressRules regionNameAndIngressRules = new RegionNameAndIngressRules(region, generatedMarkerGroup,
ports, shouldAuthorizeSelf);
expect(strategy.securityGroupMap.containsKey(regionNameAndIngressRules)).andReturn(groupExisted);
expect(strategy.createSecurityGroupIfNeeded.apply(regionNameAndIngressRules)).andReturn(generatedMarkerGroup);
expect(strategy.securityGroupMap.put(regionNameAndIngressRules, generatedMarkerGroup)).andReturn(null);
expect(strategy.securityGroupMap.getUnchecked(regionNameAndIngressRules)).andReturn(tag);
// replay mocks
replay(options);
@ -413,7 +412,8 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
verifyStrategy(strategy);
}
public void testGetSecurityGroupsForTagAndOptions_createsNewGroupByDefaultWhenPortsAreSpecifiedWhenDoesntExist() {
public void testGetSecurityGroupsForTagAndOptions_createsNewGroupByDefaultWhenPortsAreSpecifiedWhenDoesntExist()
throws ExecutionException {
// setup constants
String region = Region.AP_SOUTHEAST_1;
String tag = "tag";
@ -421,7 +421,6 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
Set<String> groupIds = ImmutableSet.<String> of();
int[] ports = new int[] { 22, 80 };
boolean shouldAuthorizeSelf = true;
boolean groupExisted = false;
Set<String> returnVal = ImmutableSet.<String> of(generatedMarkerGroup);
// create mocks
@ -433,9 +432,7 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
expect(options.getInboundPorts()).andReturn(ports).atLeastOnce();
RegionNameAndIngressRules regionNameAndIngressRules = new RegionNameAndIngressRules(region, generatedMarkerGroup,
ports, shouldAuthorizeSelf);
expect(strategy.securityGroupMap.containsKey(regionNameAndIngressRules)).andReturn(groupExisted);
expect(strategy.createSecurityGroupIfNeeded.apply(regionNameAndIngressRules)).andReturn(generatedMarkerGroup);
expect(strategy.securityGroupMap.put(regionNameAndIngressRules, generatedMarkerGroup)).andReturn(null);
expect(strategy.securityGroupMap.getUnchecked(regionNameAndIngressRules)).andReturn(generatedMarkerGroup);
// replay mocks
replay(options);
@ -449,7 +446,8 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
verifyStrategy(strategy);
}
public void testGetSecurityGroupsForTagAndOptions_reusesGroupByDefaultWhenNoPortsAreSpecifiedWhenDoesExist() {
public void testGetSecurityGroupsForTagAndOptions_reusesGroupByDefaultWhenNoPortsAreSpecifiedWhenDoesExist()
throws ExecutionException {
// setup constants
String region = Region.AP_SOUTHEAST_1;
String tag = "tag";
@ -457,7 +455,6 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
Set<String> groupIds = ImmutableSet.<String> of();
int[] ports = new int[] {};
boolean shouldAuthorizeSelf = true;
boolean groupExisted = true;
Set<String> returnVal = ImmutableSet.<String> of(generatedMarkerGroup);
// create mocks
@ -469,7 +466,7 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
expect(options.getInboundPorts()).andReturn(ports).atLeastOnce();
RegionNameAndIngressRules regionNameAndIngressRules = new RegionNameAndIngressRules(region, generatedMarkerGroup,
ports, shouldAuthorizeSelf);
expect(strategy.securityGroupMap.containsKey(regionNameAndIngressRules)).andReturn(groupExisted);
expect(strategy.securityGroupMap.getUnchecked(regionNameAndIngressRules)).andReturn(generatedMarkerGroup);
// replay mocks
replay(options);
@ -501,13 +498,9 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
// setup expectations
expect(options.getGroups()).andReturn(groupIds).atLeastOnce();
RegionNameAndIngressRules regionNameAndIngressRules = new RegionNameAndIngressRules(region, generatedMarkerGroup,
ports, shouldAuthorizeSelf); // note
// this
// works
// since
// there's
// no equals on portsq
expect(strategy.securityGroupMap.containsKey(regionNameAndIngressRules)).andReturn(groupExisted);
ports, shouldAuthorizeSelf);
expect(strategy.securityGroupMap.getUnchecked(regionNameAndIngressRules)).andReturn(groupExisted ? "tag" : null);
// replay mocks
replay(options);
@ -522,28 +515,24 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
}
private void verifyStrategy(CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions strategy) {
verify(strategy.knownKeys);
verify(strategy.credentialsMap);
verify(strategy.securityGroupMap);
verify(strategy.createUniqueKeyPair);
verify(strategy.createSecurityGroupIfNeeded);
}
@SuppressWarnings("unchecked")
private CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions setupStrategy() {
Map<RegionAndName, KeyPair> credentialsMap = createMock(Map.class);
Map<RegionAndName, String> securityGroupMap = createMock(Map.class);
CreateUniqueKeyPair createUniqueKeyPair = createMock(CreateUniqueKeyPair.class);
Function<RegionNameAndIngressRules, String> createSecurityGroupIfNeeded = createMock(CreateSecurityGroupIfNeeded.class);
return new CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions(credentialsMap, securityGroupMap,
createUniqueKeyPair, createSecurityGroupIfNeeded, OPTIONS_PROVIDER);
Map<RegionAndName, KeyPair> knownKeys = createMock(Map.class);
Cache<RegionAndName, KeyPair> credentialsMap = createMock(Cache.class);
Cache<RegionAndName, String> securityGroupMap = createMock(Cache.class);
return new CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions(knownKeys, credentialsMap, securityGroupMap,
OPTIONS_PROVIDER);
}
private void replayStrategy(CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions strategy) {
replay(strategy.knownKeys);
replay(strategy.credentialsMap);
replay(strategy.securityGroupMap);
replay(strategy.createUniqueKeyPair);
replay(strategy.createSecurityGroupIfNeeded);
}
}

View File

@ -51,7 +51,7 @@ import org.jclouds.ec2.options.RunInstancesOptions;
import org.jclouds.ec2.services.InstanceClient;
import org.testng.annotations.Test;
import com.google.common.base.Function;
import com.google.common.cache.Cache;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Multimap;
@ -222,7 +222,7 @@ public class EC2CreateNodesInGroupThenAddToSetTest {
CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions createKeyPairAndSecurityGroupsAsNeededAndReturncustomize = createMock(CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions.class);
InstancePresent instancePresent = createMock(InstancePresent.class);
RunningInstanceToNodeMetadata runningInstanceToNodeMetadata = createMock(RunningInstanceToNodeMetadata.class);
Function<RunningInstance, Credentials> instanceToCredentials = createMock(Function.class);
Cache<RunningInstance, Credentials> instanceToCredentials = createMock(Cache.class);
Map<String, Credentials> credentialStore = createMock(Map.class);
ComputeUtils utils = createMock(ComputeUtils.class);
return new EC2CreateNodesInGroupThenAddToSet(client, Providers.<TemplateBuilder> of(template),

View File

@ -25,13 +25,17 @@ import java.net.URI;
import java.util.Map;
import java.util.Properties;
import javax.inject.Singleton;
import org.jclouds.aws.domain.Region;
import org.jclouds.aws.filters.FormSigner;
import org.jclouds.compute.domain.Image;
import org.jclouds.date.DateService;
import org.jclouds.ec2.EC2AsyncClient;
import org.jclouds.ec2.EC2Client;
import org.jclouds.ec2.EC2ContextBuilder;
import org.jclouds.ec2.EC2PropertiesBuilder;
import org.jclouds.ec2.compute.domain.RegionAndName;
import org.jclouds.ec2.config.EC2RestClientModule;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.RequiresHttp;
@ -42,8 +46,12 @@ import org.jclouds.rest.RestContextSpec;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.collect.ImmutableMap;
import com.google.inject.Module;
import com.google.inject.Provides;
/**
* @author Adrian Cole
@ -58,6 +66,19 @@ public abstract class BaseEC2AsyncClientTest<T> extends RestClientTest<T> {
super(EC2Client.class, EC2AsyncClient.class, DELEGATE_MAP);
}
@Provides
@Singleton
Cache<RegionAndName, Image> provide(){
return CacheBuilder.newBuilder().build(new CacheLoader<RegionAndName, Image>() {
@Override
public Image load(RegionAndName key) throws Exception {
return null;
}
});
}
@Override
protected String provideTimeStamp(DateService dateService, int expiration) {
return "2009-11-08T15:54:08.897Z";

View File

@ -46,7 +46,6 @@ import org.jclouds.compute.domain.internal.VolumeImpl;
import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.domain.Credentials;
import org.jclouds.domain.Location;
import org.jclouds.elasticstack.ElasticStackAsyncClient;
import org.jclouds.elasticstack.ElasticStackClient;
import org.jclouds.elasticstack.domain.Device;
import org.jclouds.elasticstack.domain.Drive;
@ -62,23 +61,25 @@ import org.jclouds.logging.Logger;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.cache.Cache;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSet.Builder;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.UncheckedExecutionException;
/**
* defines the connection between the {@link ElasticStackClient} implementation and the jclouds
* {@link ComputeService}
* defines the connection between the {@link ElasticStackClient} implementation
* and the jclouds {@link ComputeService}
*
*/
@Singleton
public class ElasticStackComputeServiceAdapter implements
ComputeServiceAdapter<ServerInfo, Hardware, DriveInfo, Location> {
ComputeServiceAdapter<ServerInfo, Hardware, DriveInfo, Location> {
private final ElasticStackClient client;
private final ElasticStackAsyncClient aclient;
private final Predicate<DriveInfo> driveNotClaimed;
private final Map<String, WellKnownImage> preinstalledImages;
private final Map<String, DriveInfo> cache;
private final Cache<String, DriveInfo> cache;
private final JustProvider locationSupplier;
private final String defaultVncPassword;
private final ExecutorService executor;
@ -88,13 +89,11 @@ public class ElasticStackComputeServiceAdapter implements
protected Logger logger = Logger.NULL;
@Inject
public ElasticStackComputeServiceAdapter(ElasticStackClient client, ElasticStackAsyncClient aclient,
Predicate<DriveInfo> driveNotClaimed, JustProvider locationSupplier,
Map<String, WellKnownImage> preinstalledImages, Map<String, DriveInfo> cache,
@Named(ElasticStackConstants.PROPERTY_VNC_PASSWORD) String defaultVncPassword,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) {
public ElasticStackComputeServiceAdapter(ElasticStackClient client, Predicate<DriveInfo> driveNotClaimed,
JustProvider locationSupplier, Map<String, WellKnownImage> preinstalledImages, Cache<String, DriveInfo> cache,
@Named(ElasticStackConstants.PROPERTY_VNC_PASSWORD) String defaultVncPassword,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) {
this.client = checkNotNull(client, "client");
this.aclient = checkNotNull(aclient, "aclient");
this.driveNotClaimed = checkNotNull(driveNotClaimed, "driveNotClaimed");
this.locationSupplier = checkNotNull(locationSupplier, "locationSupplier");
this.preinstalledImages = checkNotNull(preinstalledImages, "preinstalledImages");
@ -105,12 +104,12 @@ public class ElasticStackComputeServiceAdapter implements
@Override
public ServerInfo createNodeWithGroupEncodedIntoNameThenStoreCredentials(String tag, String name, Template template,
Map<String, Credentials> credentialStore) {
Map<String, Credentials> credentialStore) {
long bootSize = (long) (template.getHardware().getVolumes().get(0).getSize() * 1024 * 1024 * 1024l);
logger.debug(">> creating boot drive bytes(%d)", bootSize);
DriveInfo drive = client.createDrive(new Drive.Builder().name(template.getImage().getId()).size(bootSize)
.build());
DriveInfo drive = client
.createDrive(new Drive.Builder().name(template.getImage().getId()).size(bootSize).build());
logger.debug("<< drive(%s)", drive.getUuid());
logger.debug(">> imaging boot drive source(%s)", template.getImage().getId());
@ -121,17 +120,16 @@ public class ElasticStackComputeServiceAdapter implements
client.destroyDrive(drive.getUuid());
throw new IllegalStateException("could not image drive in time!");
}
cache.put(drive.getUuid(), drive);
Server toCreate = small(name, drive.getUuid(), defaultVncPassword).mem(template.getHardware().getRam()).cpu(
(int) (template.getHardware().getProcessors().get(0).getSpeed())).build();
Server toCreate = small(name, drive.getUuid(), defaultVncPassword).mem(template.getHardware().getRam())
.cpu((int) (template.getHardware().getProcessors().get(0).getSpeed())).build();
ServerInfo from = client.createServer(toCreate);
client.startServer(from.getUuid());
from = client.getServerInfo(from.getUuid());
// store the credentials so that later functions can use them
credentialStore.put("node#"+ from.getUuid(), new Credentials(template.getImage().getDefaultCredentials().identity,
from.getVnc().getPassword()));
credentialStore.put("node#" + from.getUuid(), new Credentials(
template.getImage().getDefaultCredentials().identity, from.getVnc().getPassword()));
return from;
}
@ -155,30 +153,40 @@ public class ElasticStackComputeServiceAdapter implements
return "sizeLessThanOrEqual(" + size + ")";
}
}).ids(id).ram(ram).processors(ImmutableList.of(new Processor(1, cpu))).volumes(
ImmutableList.<Volume> of(new VolumeImpl(size, true, true))).build());
}).ids(id).ram(ram).processors(ImmutableList.of(new Processor(1, cpu)))
.volumes(ImmutableList.<Volume> of(new VolumeImpl(size, true, true))).build());
}
return hardware.build();
}
/**
* look up the current standard images and do not error out, if they are not found.
* look up the current standard images and do not error out, if they are not
* found.
*/
@Override
public Iterable<DriveInfo> listImages() {
Iterable<DriveInfo> drives = transformParallel(preinstalledImages.keySet(),
new Function<String, Future<DriveInfo>>() {
new Function<String, Future<DriveInfo>>() {
@Override
public Future<DriveInfo> apply(String input) {
return aclient.getDriveInfo(input);
@Override
public Future<DriveInfo> apply(String input) {
try {
return Futures.immediateFuture(cache.getUnchecked(input));
} catch (NullPointerException e) {
logger.debug("drive %s not found", input);
} catch (UncheckedExecutionException e) {
logger.warn(e, "error finding drive %s: %s", input, e.getMessage());
}
return Futures.immediateFuture(null);
}
}, executor, null, logger, "drives");
Iterable<DriveInfo> returnVal = filter(drives, notNull());
for (DriveInfo drive : returnVal)
cache.put(drive.getUuid(), drive);
return returnVal;
@Override
public String toString() {
return "seedDriveCache()";
}
}, executor, null, logger, "drives");
return filter(drives, notNull());
}
@SuppressWarnings("unchecked")

View File

@ -38,10 +38,10 @@ import org.jclouds.elasticstack.ElasticStackAsyncClient;
import org.jclouds.elasticstack.ElasticStackClient;
import org.jclouds.elasticstack.compute.ElasticStackComputeServiceAdapter;
import org.jclouds.elasticstack.compute.functions.ServerInfoToNodeMetadata;
import org.jclouds.elasticstack.compute.functions.WellKnownImageToImage;
import org.jclouds.elasticstack.compute.functions.ServerInfoToNodeMetadata.DeviceToVolume;
import org.jclouds.elasticstack.compute.functions.ServerInfoToNodeMetadata.FindImageForId;
import org.jclouds.elasticstack.compute.functions.ServerInfoToNodeMetadata.GetImageIdFromServer;
import org.jclouds.elasticstack.compute.functions.WellKnownImageToImage;
import org.jclouds.elasticstack.domain.Device;
import org.jclouds.elasticstack.domain.DriveInfo;
import org.jclouds.elasticstack.domain.Server;
@ -59,7 +59,9 @@ import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.base.Supplier;
import com.google.common.collect.MapMaker;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.collect.Maps;
import com.google.inject.Provides;
import com.google.inject.TypeLiteral;
@ -104,12 +106,12 @@ public class ElasticStackComputeServiceContextModule
@Provides
@Singleton
protected Map<String, DriveInfo> cache(GetDrive getDrive) {
return new MapMaker().makeComputingMap(getDrive);
protected Cache<String, DriveInfo> cache(GetDrive getDrive) {
return CacheBuilder.newBuilder().build(getDrive);
}
@Singleton
public static class GetDrive implements Function<String, DriveInfo> {
public static class GetDrive extends CacheLoader<String, DriveInfo> {
private final ElasticStackClient client;
@Inject
@ -118,7 +120,7 @@ public class ElasticStackComputeServiceContextModule
}
@Override
public DriveInfo apply(String input) {
public DriveInfo load(String input) {
return client.getDriveInfo(input);
}
}

View File

@ -18,27 +18,44 @@
*/
package org.jclouds.elasticstack.compute.functions;
import com.google.common.base.Function;
import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import org.jclouds.collect.FindResourceInSet;
import org.jclouds.collect.Memoized;
import org.jclouds.compute.domain.*;
import org.jclouds.domain.Credentials;
import org.jclouds.domain.Location;
import org.jclouds.elasticstack.domain.*;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.compute.util.ComputeServiceUtils.parseGroupFromName;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.compute.util.ComputeServiceUtils.parseGroupFromName;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.collect.FindResourceInSet;
import org.jclouds.collect.Memoized;
import org.jclouds.compute.domain.HardwareBuilder;
import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.NodeMetadataBuilder;
import org.jclouds.compute.domain.NodeState;
import org.jclouds.compute.domain.Processor;
import org.jclouds.compute.domain.Volume;
import org.jclouds.compute.domain.VolumeBuilder;
import org.jclouds.domain.Credentials;
import org.jclouds.domain.Location;
import org.jclouds.elasticstack.domain.Device;
import org.jclouds.elasticstack.domain.DriveInfo;
import org.jclouds.elasticstack.domain.Server;
import org.jclouds.elasticstack.domain.ServerInfo;
import org.jclouds.elasticstack.domain.ServerStatus;
import org.jclouds.logging.Logger;
import com.google.common.base.Function;
import com.google.common.base.Supplier;
import com.google.common.cache.Cache;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.util.concurrent.UncheckedExecutionException;
/**
* @author Adrian Cole
@ -93,16 +110,19 @@ public class ServerInfoToNodeMetadata implements Function<ServerInfo, NodeMetada
builder.state(serverStatusToNodeState.get(from.getStatus()));
builder.publicAddresses(ImmutableSet.<String> of(from.getNics().get(0).getDhcp()));
builder.privateAddresses(ImmutableSet.<String> of());
builder.credentials(credentialStore.get("node#"+ from.getUuid()));
builder.credentials(credentialStore.get("node#" + from.getUuid()));
return builder.build();
}
@Singleton
public static final class DeviceToVolume implements Function<Device, Volume> {
private final Map<String, DriveInfo> cache;
@Resource
protected Logger logger = Logger.NULL;
private final Cache<String, DriveInfo> cache;
@Inject
public DeviceToVolume(Map<String, DriveInfo> cache) {
public DeviceToVolume(Cache<String, DriveInfo> cache) {
this.cache = checkNotNull(cache, "cache");
}
@ -110,27 +130,34 @@ public class ServerInfoToNodeMetadata implements Function<ServerInfo, NodeMetada
public Volume apply(Device input) {
VolumeBuilder builder = new VolumeBuilder();
builder.id(input.getId());
DriveInfo drive = cache.get(input.getDriveUuid());
if (drive != null) {
try {
DriveInfo drive = cache.getUnchecked(input.getDriveUuid());
builder.size(drive.getSize() / 1024 / 1024f);
} catch (NullPointerException e) {
logger.debug("drive %s not found", input.getDriveUuid());
} catch (UncheckedExecutionException e) {
logger.warn(e, "error finding drive %s: %s", input.getDriveUuid(), e.getMessage());
}
return new VolumeBuilder().durable(true).type(Volume.Type.NAS).build();
}
}
/**
* When we create the boot drive of the server, by convention we set the name to the image it
* came from.
* When we create the boot drive of the server, by convention we set the name
* to the image it came from.
*
* @author Adrian Cole
*
*/
@Singleton
public static class GetImageIdFromServer implements Function<Server, String> {
private final Map<String, DriveInfo> cache;
@Resource
protected Logger logger = Logger.NULL;
private final Cache<String, DriveInfo> cache;
@Inject
public GetImageIdFromServer(Map<String, DriveInfo> cache) {
public GetImageIdFromServer(Cache<String, DriveInfo> cache) {
this.cache = cache;
}
@ -141,9 +168,12 @@ public class ServerInfoToNodeMetadata implements Function<ServerInfo, NodeMetada
Device bootDevice = from.getDevices().get(bootDeviceId);
if (bootDevice != null) {
try {
imageId = cache.get(bootDevice.getDriveUuid()).getName();
DriveInfo drive = cache.getUnchecked(bootDevice.getDriveUuid());
imageId = drive.getName();
} catch (NullPointerException e) {
logger.debug("drive %s not found", bootDevice.getDriveUuid());
} catch (UncheckedExecutionException e) {
logger.warn(e, "error finding drive %s: %s", bootDevice.getDriveUuid(), e.getMessage());
}
}
return imageId;

View File

@ -22,6 +22,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.trmk.vcloud_0_8.reference.TerremarkConstants.PROPERTY_TERREMARK_EXTENSION_NS;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import javax.inject.Inject;
import javax.inject.Named;
@ -33,6 +34,7 @@ import org.jclouds.rest.binders.BindToStringPayload;
import org.jclouds.util.Patterns;
import org.jclouds.util.Strings2;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableMap;
/**
@ -61,9 +63,13 @@ public class BindAddInternetServiceToXmlPayload implements MapBinder {
String description = postParams.get("description");
String payload = Strings2.replaceTokens(xmlTemplate,
ImmutableMap.of("name", name, "protocol", protocol, "port", port, "enabled", enabled, "ns", ns));
payload = Strings2.replaceAll(payload, Patterns.TOKEN_TO_PATTERN.get("description"), description == null ? ""
: String.format("\n\t<Description>%s</Description>", description));
payload = Strings2.replaceAll(payload, Patterns.TOKEN_TO_PATTERN.get("monitor"), getMonitorString(postParams));
try {
payload = Strings2.replaceAll(payload, Patterns.TOKEN_TO_PATTERN.get("description"), description == null ? ""
: String.format("\n\t<Description>%s</Description>", description));
payload = Strings2.replaceAll(payload, Patterns.TOKEN_TO_PATTERN.get("monitor"), getMonitorString(postParams));
} catch (ExecutionException e) {
Throwables.propagate(e);
}
return stringBinder.bindToRequest(request, payload);
}

View File

@ -22,6 +22,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.trmk.vcloud_0_8.reference.TerremarkConstants.PROPERTY_TERREMARK_EXTENSION_NS;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import javax.inject.Inject;
import javax.inject.Named;
@ -33,6 +34,7 @@ import org.jclouds.rest.binders.BindToStringPayload;
import org.jclouds.util.Patterns;
import org.jclouds.util.Strings2;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableMap;
/**
@ -62,8 +64,12 @@ public class BindAddNodeServiceToXmlPayload implements MapBinder {
String payload = Strings2.replaceTokens(xmlTemplate,
ImmutableMap.of("name", name, "ipAddress", ipAddress, "port", port, "enabled", enabled, "ns", ns));
payload = Strings2.replaceAll(payload, Patterns.TOKEN_TO_PATTERN.get("description"), description == null ? ""
: String.format("\n <Description>%s</Description>", description));
try {
payload = Strings2.replaceAll(payload, Patterns.TOKEN_TO_PATTERN.get("description"), description == null ? ""
: String.format("\n <Description>%s</Description>", description));
} catch (ExecutionException e) {
Throwables.propagate(e);
}
return stringBinder.bindToRequest(request, payload);
}

View File

@ -57,7 +57,7 @@ public interface ComputeServiceConstants {
public static class ReferenceData {
@Inject(optional = true)
@Named(PROPERTY_OS_VERSION_MAP_JSON)
public String osVersionMapJson = "{\"suse\":{\"\":\"\",\"11\":\"11\",\"11 SP1\":\"11 SP1\"},\"debian\":{\"\":\"\",\"lenny\":\"5.0\",\"squeeze\":\"6.0\"},\"centos\":{\"\":\"\",\"5\":\"5.0\",\"5.2\":\"5.2\",\"5.3\":\"5.3\",\"5.4\":\"5.4\",\"5.5\":\"5.5\"},\"rhel\":{\"\":\"\",\"5\":\"5.0\",\"5.2\":\"5.2\",\"5.3\":\"5.3\",\"5.4\":\"5.4\",\"5.5\":\"5.5\"},\"solaris\":{\"\":\"\",\"10\":\"10\"},\"ubuntu\":{\"\":\"\",\"hardy\":\"8.04\",\"karmic\":\"9.10\",\"lucid\":\"10.04\",\"10.04.1\":\"10.04\",\"maverick\":\"10.10\",\"natty\":\"11.04\",\"oneiric\":\"11.10\"},\"windows\":{\"\":\"\",\"2003\":\"2003\",\"2003 Standard\":\"2003\",\"2003 R2\":\"2003 R2\",\"2008\":\"2008\",\"2008 Web\":\"2008\",\"2008 Server\":\"2008\",\"Server 2008\":\"2008\",\"2008 R1\":\"2008 R1\",\"2008 R2\":\"2008 R2\",\"Server 2008 R2\":\"2008 R2\",\"2008 Server R2\":\"2008 R2\",\"2008 SP2\":\"2008 SP2\",\"Server 2008 SP2\":\"2008 SP2\"}}";
public String osVersionMapJson = "{\"suse\":{\"\":\"\",\"11\":\"11\",\"11 SP1\":\"11 SP1\"},\"debian\":{\"\":\"\",\"lenny\":\"5.0\",\"squeeze\":\"6.0\"},\"centos\":{\"\":\"\",\"5\":\"5.0\",\"5.2\":\"5.2\",\"5.3\":\"5.3\",\"5.4\":\"5.4\",\"5.5\":\"5.5\",\"5.6\":\"5.6\",\"5.7\":\"5.7\",\"6.0\":\"6.0\"},\"rhel\":{\"\":\"\",\"5\":\"5.0\",\"5.2\":\"5.2\",\"5.3\":\"5.3\",\"5.4\":\"5.4\",\"5.5\":\"5.5\",\"5.6\":\"5.6\",\"5.7\":\"5.7\",\"6.0\":\"6.0\"},\"solaris\":{\"\":\"\",\"10\":\"10\"},\"ubuntu\":{\"\":\"\",\"hardy\":\"8.04\",\"karmic\":\"9.10\",\"lucid\":\"10.04\",\"10.04.1\":\"10.04\",\"maverick\":\"10.10\",\"natty\":\"11.04\",\"oneiric\":\"11.10\"},\"windows\":{\"\":\"\",\"2003\":\"2003\",\"2003 Standard\":\"2003\",\"2003 R2\":\"2003 R2\",\"2008\":\"2008\",\"2008 Web\":\"2008\",\"2008 Server\":\"2008\",\"Server 2008\":\"2008\",\"2008 R1\":\"2008 R1\",\"2008 R2\":\"2008 R2\",\"Server 2008 R2\":\"2008 R2\",\"2008 Server R2\":\"2008 R2\",\"2008 SP2\":\"2008 SP2\",\"Server 2008 SP2\":\"2008 SP2\"}}";
}
@Singleton

View File

@ -109,7 +109,7 @@
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>r09</version>
<version>10.0-rc2</version>
</dependency>
</dependencies>

View File

@ -69,7 +69,7 @@ public class Futures {
// ExecutionException / CancellationException / RuntimeException
// The task is done, run the listeners.
}
executionList.run();
executionList.execute();
}
@Override
@ -116,7 +116,7 @@ public class Futures {
if (delegate.isDone()) {
// If the delegate is already done, run the execution list
// immediately on the current thread.
executionList.run();
executionList.execute();
return;
}
adapterExecutor.execute(new CallGetAndRunExecutionList<T>(delegate, executionList));

View File

@ -26,7 +26,6 @@ import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
@ -38,6 +37,7 @@ import org.jclouds.internal.ClassMethodArgs;
import org.jclouds.rest.annotations.Delegate;
import org.jclouds.util.Throwables2;
import com.google.common.cache.Cache;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import com.google.common.util.concurrent.ListenableFuture;
@ -62,13 +62,13 @@ public class SyncProxy implements InvocationHandler {
private final Map<Method, Method> methodMap;
private final Map<Method, Method> syncMethodMap;
private final Map<Method, Long> timeoutMap;
private final ConcurrentMap<ClassMethodArgs, Object> delegateMap;
private final Cache<ClassMethodArgs, Object> delegateMap;
private final Map<Class<?>, Class<?>> sync2Async;
private static final Set<Method> objectMethods = ImmutableSet.of(Object.class.getMethods());
@Inject
public SyncProxy(Class<?> declaring, Object async,
@Named("sync") ConcurrentMap<ClassMethodArgs, Object> delegateMap, Map<Class<?>, Class<?>> sync2Async)
@Named("sync") Cache<ClassMethodArgs, Object> delegateMap, Map<Class<?>, Class<?>> sync2Async)
throws SecurityException, NoSuchMethodException {
this.delegateMap = delegateMap;
this.delegate = async;

View File

@ -20,10 +20,11 @@ package org.jclouds.json.internal;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import com.google.common.base.Function;
import com.google.common.collect.MapMaker;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
@ -46,29 +47,26 @@ public class EnumTypeAdapterThatReturnsFromValue<T extends Enum<T>> implements J
try {
return (T) Enum.valueOf((Class<T>) classOfT, json.getAsString());
} catch (IllegalArgumentException e) {
Method converter = classToConvert.get(classOfT);
if (converter != null)
try {
return (T) converter.invoke(null, json.getAsString());
} catch (Exception e1) {
throw e;
}
else
try {
Method converter = classToConvert.get((Class<?>) classOfT);
return (T) converter.invoke(null, json.getAsString());
} catch (Exception e1) {
throw e;
}
}
}
private final static Map<Class<?>, Method> classToConvert = new MapMaker()
.makeComputingMap(new Function<Class<?>, Method>() {
private final static Cache<Class<?>, Method> classToConvert = CacheBuilder.newBuilder()
.build(new CacheLoader<Class<?>, Method>() {
@Override
public Method apply(Class<?> from) {
public Method load(Class<?> from) throws ExecutionException {
try {
Method method = from.getMethod("fromValue", String.class);
method.setAccessible(true);
return method;
} catch (Exception e) {
return null;
throw new ExecutionException(e);
}
}

View File

@ -20,8 +20,8 @@ package org.jclouds.rest.binders;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.net.InternetDomainName.fromLenient;
import static com.google.common.net.InternetDomainName.isValidLenient;
import static com.google.common.net.InternetDomainName.from;
import static com.google.common.net.InternetDomainName.isValid;
import javax.inject.Inject;
import javax.inject.Provider;
@ -51,9 +51,9 @@ public class BindAsHostPrefix implements Binder {
@SuppressWarnings("unchecked")
public <R extends HttpRequest> R bindToRequest(R request, Object payload) {
checkNotNull(payload, "hostprefix");
checkArgument(isValidLenient(request.getEndpoint().getHost()), "this is only valid for hostnames: " + request);
checkArgument(isValid(request.getEndpoint().getHost()), "this is only valid for hostnames: " + request);
UriBuilder builder = uriBuilderProvider.get().uri(request.getEndpoint());
InternetDomainName name = fromLenient(request.getEndpoint().getHost()).child(payload.toString());
InternetDomainName name = from(request.getEndpoint().getHost()).child(payload.toString());
builder.host(name.name());
return (R) request.toBuilder().endpoint(builder.build()).build();
}

View File

@ -19,7 +19,6 @@
package org.jclouds.rest.config;
import java.util.Map;
import java.util.concurrent.ConcurrentMap;
import javax.inject.Inject;
import javax.inject.Singleton;
@ -28,6 +27,7 @@ import org.jclouds.concurrent.internal.SyncProxy;
import org.jclouds.internal.ClassMethodArgs;
import com.google.common.base.Throwables;
import com.google.common.cache.Cache;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.Provider;
@ -58,8 +58,8 @@ public class ClientProvider<S, A> implements Provider<S> {
@Singleton
public S get() {
A client = (A) injector.getInstance(Key.get(asyncClientType));
ConcurrentMap<ClassMethodArgs, Object> delegateMap = injector.getInstance(Key.get(
new TypeLiteral<ConcurrentMap<ClassMethodArgs, Object>>() {
Cache<ClassMethodArgs, Object> delegateMap = injector.getInstance(Key.get(
new TypeLiteral<Cache<ClassMethodArgs, Object>>() {
}, Names.named("sync")));
try {
return (S) SyncProxy.proxy(syncClientType, new SyncProxy(syncClientType, client,

View File

@ -21,35 +21,37 @@ package org.jclouds.rest.config;
import static com.google.common.base.Preconditions.checkState;
import java.util.Map;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutionException;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Provider;
import org.jclouds.concurrent.internal.SyncProxy;
import org.jclouds.internal.ClassMethodArgs;
import com.google.common.base.Function;
import com.google.common.base.Throwables;
import com.google.inject.Provider;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheLoader;
/**
*
* @author Adrian Cole
*/
public class CreateClientForCaller implements Function<ClassMethodArgs, Object> {
private final ConcurrentMap<ClassMethodArgs, Object> asyncMap;
private final Provider<ConcurrentMap<ClassMethodArgs, Object>> delegateMap;
public class CreateClientForCaller extends CacheLoader<ClassMethodArgs, Object> {
private final Cache<ClassMethodArgs, Object> asyncMap;
private final Provider<Cache<ClassMethodArgs, Object>> delegateMap;
Map<Class<?>, Class<?>> sync2Async;
@Inject
CreateClientForCaller(@Named("async") ConcurrentMap<ClassMethodArgs, Object> asyncMap,
@Named("sync") Provider<ConcurrentMap<ClassMethodArgs, Object>> delegateMap) {
CreateClientForCaller(@Named("async") Cache<ClassMethodArgs, Object> asyncMap,
@Named("sync") Provider<Cache<ClassMethodArgs, Object>> delegateMap) {
this.asyncMap = asyncMap;
this.delegateMap = delegateMap;
}
public Object apply(ClassMethodArgs from) {
@Override
public Object load(ClassMethodArgs from) throws ExecutionException {
Class<?> syncClass = from.getMethod().getReturnType();
Class<?> asyncClass = sync2Async.get(syncClass);
checkState(asyncClass != null, "configuration error, sync class " + syncClass

View File

@ -19,7 +19,6 @@
package org.jclouds.rest.config;
import java.util.Map;
import java.util.concurrent.ConcurrentMap;
import javax.inject.Named;
import javax.inject.Singleton;
@ -30,8 +29,9 @@ import org.jclouds.rest.ConfiguresRestClient;
import org.jclouds.rest.RestContext;
import org.jclouds.rest.internal.RestContextImpl;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.MapMaker;
import com.google.inject.AbstractModule;
import com.google.inject.Provides;
import com.google.inject.Scopes;
@ -125,10 +125,10 @@ public class RestClientModule<S, A> extends AbstractModule {
@Provides
@Singleton
@Named("sync")
ConcurrentMap<ClassMethodArgs, Object> provideSyncDelegateMap(
Cache<ClassMethodArgs, Object> provideSyncDelegateMap(
CreateClientForCaller createClientForCaller) {
createClientForCaller.sync2Async = delegates;
return new MapMaker().makeComputingMap(createClientForCaller);
return CacheBuilder.newBuilder().build(createClientForCaller);
}
}

View File

@ -18,8 +18,6 @@
*/
package org.jclouds.rest.config;
import java.util.concurrent.ConcurrentMap;
import javax.inject.Named;
import javax.inject.Singleton;
import javax.ws.rs.core.UriBuilder;
@ -42,8 +40,10 @@ import org.jclouds.rest.internal.RestAnnotationProcessor;
import org.jclouds.rest.internal.SeedAnnotationCache;
import com.google.common.base.Function;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.MapMaker;
import com.google.inject.AbstractModule;
import com.google.inject.Inject;
import com.google.inject.Injector;
@ -77,18 +77,18 @@ public class RestModule extends AbstractModule {
@Provides
@Singleton
protected ConcurrentMap<Class<?>, Boolean> seedAnnotationCache(SeedAnnotationCache seedAnnotationCache) {
return new MapMaker().makeComputingMap(seedAnnotationCache);
protected Cache<Class<?>, Boolean> seedAnnotationCache(SeedAnnotationCache seedAnnotationCache) {
return CacheBuilder.newBuilder().build(seedAnnotationCache);
}
@Provides
@Singleton
@Named("async")
ConcurrentMap<ClassMethodArgs, Object> provideAsyncDelegateMap(CreateAsyncClientForCaller createAsyncClientForCaller) {
return new MapMaker().makeComputingMap(createAsyncClientForCaller);
Cache<ClassMethodArgs, Object> provideAsyncDelegateMap(CreateAsyncClientForCaller createAsyncClientForCaller) {
return CacheBuilder.newBuilder().build(createAsyncClientForCaller);
}
static class CreateAsyncClientForCaller implements Function<ClassMethodArgs, Object> {
static class CreateAsyncClientForCaller extends CacheLoader<ClassMethodArgs, Object> {
private final Injector injector;
private final AsyncRestClientProxy.Factory factory;
@ -100,7 +100,7 @@ public class RestModule extends AbstractModule {
@SuppressWarnings( { "unchecked", "rawtypes" })
@Override
public Object apply(final ClassMethodArgs from) {
public Object load(final ClassMethodArgs from) {
Class clazz = from.getAsyncClass();
TypeLiteral typeLiteral = TypeLiteral.get(clazz);
RestAnnotationProcessor util = (RestAnnotationProcessor) injector.getInstance(Key.get(TypeLiteral.get(Types
@ -108,8 +108,8 @@ public class RestModule extends AbstractModule {
// cannot use child injectors due to the super coarse guice lock on
// Singleton
util.setCaller(from);
ConcurrentMap<ClassMethodArgs, Object> delegateMap = injector.getInstance(Key.get(
new TypeLiteral<ConcurrentMap<ClassMethodArgs, Object>>() {
Cache<ClassMethodArgs, Object> delegateMap = injector.getInstance(Key.get(
new TypeLiteral<Cache<ClassMethodArgs, Object>>() {
}, Names.named("async")));
AsyncRestClientProxy proxy = new AsyncRestClientProxy(injector, factory, util, typeLiteral, delegateMap);
injector.injectMembers(proxy);

View File

@ -27,7 +27,6 @@ import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.NoSuchElementException;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutionException;
import javax.annotation.Resource;
@ -49,6 +48,7 @@ import org.jclouds.util.Throwables2;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.cache.Cache;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.util.concurrent.Futures;
@ -76,12 +76,12 @@ public class AsyncRestClientProxy<T> implements InvocationHandler {
@Resource
protected Logger logger = Logger.NULL;
private final ConcurrentMap<ClassMethodArgs, Object> delegateMap;
private final Cache<ClassMethodArgs, Object> delegateMap;
@SuppressWarnings("unchecked")
@Inject
public AsyncRestClientProxy(Injector injector, Factory factory, RestAnnotationProcessor<T> util,
TypeLiteral<T> typeLiteral, @Named("async") ConcurrentMap<ClassMethodArgs, Object> delegateMap) {
TypeLiteral<T> typeLiteral, @Named("async") Cache<ClassMethodArgs, Object> delegateMap) {
this.injector = injector;
this.annotationProcessor = util;
this.declaring = (Class<T>) typeLiteral.getRawType();

View File

@ -49,9 +49,8 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.SortedSet;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutionException;
import org.jclouds.javax.annotation.Nullable;
import javax.annotation.Resource;
import javax.inject.Named;
import javax.inject.Provider;
@ -98,6 +97,7 @@ import org.jclouds.io.Payloads;
import org.jclouds.io.payloads.MultipartForm;
import org.jclouds.io.payloads.Part;
import org.jclouds.io.payloads.Part.PartOptions;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.json.internal.GsonWrapper;
import org.jclouds.logging.Logger;
import org.jclouds.rest.Binder;
@ -137,6 +137,10 @@ import com.google.common.base.Function;
import com.google.common.base.Functions;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.base.Throwables;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSet;
@ -145,7 +149,6 @@ import com.google.common.collect.Iterables;
import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.LinkedListMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.MapMaker;
import com.google.common.collect.Multimap;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.inject.Inject;
@ -167,25 +170,25 @@ public class RestAnnotationProcessor<T> {
private final Class<T> declaring;
// TODO replace with Table object
static final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToBinderParamAnnotation = createMethodToIndexOfParamToAnnotation(BinderParam.class);
static final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToWrapWithAnnotation = createMethodToIndexOfParamToAnnotation(WrapWith.class);
static final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToHeaderParamAnnotations = createMethodToIndexOfParamToAnnotation(HeaderParam.class);
static final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToEndpointAnnotations = createMethodToIndexOfParamToAnnotation(Endpoint.class);
static final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToEndpointParamAnnotations = createMethodToIndexOfParamToAnnotation(EndpointParam.class);
static final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToMatrixParamAnnotations = createMethodToIndexOfParamToAnnotation(MatrixParam.class);
static final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToFormParamAnnotations = createMethodToIndexOfParamToAnnotation(FormParam.class);
static final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToQueryParamAnnotations = createMethodToIndexOfParamToAnnotation(QueryParam.class);
static final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToPathParamAnnotations = createMethodToIndexOfParamToAnnotation(PathParam.class);
static final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToPostParamAnnotations = createMethodToIndexOfParamToAnnotation(PayloadParam.class);
static final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToPartParamAnnotations = createMethodToIndexOfParamToAnnotation(PartParam.class);
static final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToParamParserAnnotations = createMethodToIndexOfParamToAnnotation(ParamParser.class);
static final Cache<Method, Cache<Integer, Set<Annotation>>> methodToIndexOfParamToBinderParamAnnotation = createMethodToIndexOfParamToAnnotation(BinderParam.class);
static final Cache<Method, Cache<Integer, Set<Annotation>>> methodToIndexOfParamToWrapWithAnnotation = createMethodToIndexOfParamToAnnotation(WrapWith.class);
static final Cache<Method, Cache<Integer, Set<Annotation>>> methodToIndexOfParamToHeaderParamAnnotations = createMethodToIndexOfParamToAnnotation(HeaderParam.class);
static final Cache<Method, Cache<Integer, Set<Annotation>>> methodToIndexOfParamToEndpointAnnotations = createMethodToIndexOfParamToAnnotation(Endpoint.class);
static final Cache<Method, Cache<Integer, Set<Annotation>>> methodToIndexOfParamToEndpointParamAnnotations = createMethodToIndexOfParamToAnnotation(EndpointParam.class);
static final Cache<Method, Cache<Integer, Set<Annotation>>> methodToIndexOfParamToMatrixParamAnnotations = createMethodToIndexOfParamToAnnotation(MatrixParam.class);
static final Cache<Method, Cache<Integer, Set<Annotation>>> methodToIndexOfParamToFormParamAnnotations = createMethodToIndexOfParamToAnnotation(FormParam.class);
static final Cache<Method, Cache<Integer, Set<Annotation>>> methodToIndexOfParamToQueryParamAnnotations = createMethodToIndexOfParamToAnnotation(QueryParam.class);
static final Cache<Method, Cache<Integer, Set<Annotation>>> methodToIndexOfParamToPathParamAnnotations = createMethodToIndexOfParamToAnnotation(PathParam.class);
static final Cache<Method, Cache<Integer, Set<Annotation>>> methodToIndexOfParamToPostParamAnnotations = createMethodToIndexOfParamToAnnotation(PayloadParam.class);
static final Cache<Method, Cache<Integer, Set<Annotation>>> methodToIndexOfParamToPartParamAnnotations = createMethodToIndexOfParamToAnnotation(PartParam.class);
static final Cache<Method, Cache<Integer, Set<Annotation>>> methodToIndexOfParamToParamParserAnnotations = createMethodToIndexOfParamToAnnotation(ParamParser.class);
static final Map<MethodKey, Method> delegationMap = newHashMap();
static Map<Method, Map<Integer, Set<Annotation>>> createMethodToIndexOfParamToAnnotation(
static Cache<Method, Cache<Integer, Set<Annotation>>> createMethodToIndexOfParamToAnnotation(
final Class<? extends Annotation> annotation) {
return new MapMaker().makeComputingMap(new Function<Method, Map<Integer, Set<Annotation>>>() {
public Map<Integer, Set<Annotation>> apply(Method method) {
return new MapMaker().makeComputingMap(new GetAnnotationsForMethodParameterIndex(method, annotation));
return CacheBuilder.newBuilder().build(new CacheLoader<Method, Cache<Integer, Set<Annotation>>>() {
public Cache<Integer, Set<Annotation>> load(Method method) {
return CacheBuilder.newBuilder().build(CacheLoader.from(new GetAnnotationsForMethodParameterIndex(method, annotation)));
}
});
}
@ -201,17 +204,17 @@ public class RestAnnotationProcessor<T> {
public Set<Annotation> apply(final Integer index) {
return ImmutableSet.<Annotation> copyOf(filter(ImmutableList.copyOf(method.getParameterAnnotations()[index]),
new Predicate<Annotation>() {
public boolean apply(Annotation input) {
return input.annotationType().equals(clazz);
}
}));
new Predicate<Annotation>() {
public boolean apply(Annotation input) {
return input.annotationType().equals(clazz);
}
}));
}
}
private static final Class<? extends HttpRequestOptions[]> optionsVarArgsClass = new HttpRequestOptions[] {}
.getClass();
.getClass();
private static final Function<? super Entry<String, String>, ? extends Part> ENTRY_TO_PART = new Function<Entry<String, String>, Part>() {
@ -222,23 +225,24 @@ public class RestAnnotationProcessor<T> {
};
static final Map<Method, Set<Integer>> methodToIndexesOfOptions = new MapMaker()
.makeComputingMap(new Function<Method, Set<Integer>>() {
public Set<Integer> apply(Method method) {
Builder<Integer> toReturn = ImmutableSet.<Integer> builder();
for (int index = 0; index < method.getParameterTypes().length; index++) {
Class<?> type = method.getParameterTypes()[index];
if (HttpRequestOptions.class.isAssignableFrom(type) || optionsVarArgsClass.isAssignableFrom(type))
toReturn.add(index);
}
return toReturn.build();
static final Cache<Method, Set<Integer>> methodToIndexesOfOptions = CacheBuilder.newBuilder().build(
new CacheLoader<Method, Set<Integer>>() {
@Override
public Set<Integer> load(Method method) {
Builder<Integer> toReturn = ImmutableSet.<Integer> builder();
for (int index = 0; index < method.getParameterTypes().length; index++) {
Class<?> type = method.getParameterTypes()[index];
if (HttpRequestOptions.class.isAssignableFrom(type) || optionsVarArgsClass.isAssignableFrom(type))
toReturn.add(index);
}
});
return toReturn.build();
}
});
private final ParseSax.Factory parserFactory;
private final HttpUtils utils;
private final Provider<UriBuilder> uriBuilderProvider;
private final ConcurrentMap<Class<?>, Boolean> seedAnnotationCache;
private final Cache<Class<?>, Boolean> seedAnnotationCache;
private final String apiVersion;
private char[] skips;
@ -252,7 +256,7 @@ public class RestAnnotationProcessor<T> {
@VisibleForTesting
public static Function<HttpResponse, ?> createResponseParser(ParseSax.Factory parserFactory, Injector injector,
Method method, HttpRequest request) {
Method method, HttpRequest request) {
Function<HttpResponse, ?> transformer;
Class<? extends HandlerWithResult<?>> handler = getSaxResponseParserClassOrNull(method);
if (handler != null) {
@ -272,9 +276,9 @@ public class RestAnnotationProcessor<T> {
if (method.isAnnotationPresent(SelectJson.class)) {
Type returnVal = getReturnTypeForMethod(method);
if (method.isAnnotationPresent(OnlyElement.class))
returnVal = Types.newParameterizedType(Set.class,returnVal);
transformer = new ParseFirstJsonValueNamed(injector.getInstance(GsonWrapper.class), TypeLiteral.get(returnVal),
method.getAnnotation(SelectJson.class).value());
returnVal = Types.newParameterizedType(Set.class, returnVal);
transformer = new ParseFirstJsonValueNamed(injector.getInstance(GsonWrapper.class),
TypeLiteral.get(returnVal), method.getAnnotation(SelectJson.class).value());
if (method.isAnnotationPresent(OnlyElement.class))
transformer = Functions.compose(new OnlyElementOrNull(), transformer);
} else {
@ -290,7 +294,7 @@ public class RestAnnotationProcessor<T> {
@VisibleForTesting
public static Function<Exception, ?> createExceptionParserOrThrowResourceNotFoundOn404IfNoAnnotation(
Injector injector, Method method) {
Injector injector, Method method) {
ExceptionParser annotation = method.getAnnotation(ExceptionParser.class);
if (annotation != null) {
return injector.getInstance(annotation.value());
@ -300,9 +304,9 @@ public class RestAnnotationProcessor<T> {
@SuppressWarnings("unchecked")
@Inject
public RestAnnotationProcessor(Injector injector, ConcurrentMap<Class<?>, Boolean> seedAnnotationCache,
@Named(Constants.PROPERTY_API_VERSION) String apiVersion, ParseSax.Factory parserFactory, HttpUtils utils,
TypeLiteral<T> typeLiteral) {
public RestAnnotationProcessor(Injector injector, Cache<Class<?>, Boolean> seedAnnotationCache,
@Named(Constants.PROPERTY_API_VERSION) String apiVersion, ParseSax.Factory parserFactory, HttpUtils utils,
TypeLiteral<T> typeLiteral) throws ExecutionException {
this.declaring = (Class<T>) typeLiteral.getRawType();
this.injector = injector;
this.parserFactory = parserFactory;
@ -366,8 +370,8 @@ public class RestAnnotationProcessor<T> {
this.name = method.getName();
this.declaringPackage = method.getDeclaringClass().getPackage();
int parametersTypeHashCode = 0;
for (Class<?> param: method.getParameterTypes())
parametersTypeHashCode +=param.hashCode();
for (Class<?> param : method.getParameterTypes())
parametersTypeHashCode += param.hashCode();
this.parametersTypeHashCode = parametersTypeHashCode;
}
@ -379,154 +383,166 @@ public class RestAnnotationProcessor<T> {
private URI callerEndpoint;
public void setCaller(ClassMethodArgs caller) {
seedAnnotationCache.get(caller.getMethod().getDeclaringClass());
try {
seedAnnotationCache.get(caller.getMethod().getDeclaringClass());
} catch (ExecutionException e) {
Throwables.propagate(e);
}
this.caller = caller;
try {
callerEndpoint = getEndpointFor(caller.getMethod(), caller.getArgs(), injector);
} catch (IllegalStateException e) {
} catch (ExecutionException e) {
Throwables.propagate(e);
}
}
public GeneratedHttpRequest<T> createRequest(Method method, Object... args) {
inputParamValidator.validateMethodParametersOrThrow(method, args);
ClassMethodArgs cma = logger.isTraceEnabled() ? new ClassMethodArgs(method.getDeclaringClass(), method, args)
try {
inputParamValidator.validateMethodParametersOrThrow(method, args);
ClassMethodArgs cma = logger.isTraceEnabled() ? new ClassMethodArgs(method.getDeclaringClass(), method, args)
: null;
URI endpoint = callerEndpoint;
try {
if (endpoint == null) {
endpoint = getEndpointFor(method, args, injector);
logger.trace("using endpoint %s for %s", endpoint, cma);
URI endpoint = callerEndpoint;
try {
if (endpoint == null) {
endpoint = getEndpointFor(method, args, injector);
logger.trace("using endpoint %s for %s", endpoint, cma);
} else {
logger.trace("using endpoint %s from caller %s for %s", caller, endpoint, cma);
}
} catch (IllegalStateException e) {
logger.trace("looking up default endpoint for %s", cma);
endpoint = injector.getInstance(Key.get(URI.class, org.jclouds.location.Provider.class));
logger.trace("using default endpoint %s for %s", endpoint, cma);
}
GeneratedHttpRequest.Builder<T> requestBuilder;
HttpRequest r = RestAnnotationProcessor.findHttpRequestInArgs(args);
if (r != null) {
requestBuilder = GeneratedHttpRequest.Builder.<T> from(r);
endpoint = r.getEndpoint();
} else {
logger.trace("using endpoint %s from caller %s for %s", caller, endpoint, cma);
}
} catch (IllegalStateException e) {
logger.trace("looking up default endpoint for %s", cma);
endpoint = injector.getInstance(Key.get(URI.class, org.jclouds.location.Provider.class));
logger.trace("using default endpoint %s for %s", endpoint, cma);
}
GeneratedHttpRequest.Builder<T> requestBuilder;
HttpRequest r = RestAnnotationProcessor.findHttpRequestInArgs(args);
if (r != null) {
requestBuilder = GeneratedHttpRequest.Builder.<T> from(r);
endpoint = r.getEndpoint();
} else {
requestBuilder = GeneratedHttpRequest.<T> builder();
requestBuilder.method(getHttpMethodOrConstantOrThrowException(method));
}
requestBuilder.declaring(declaring).javaMethod(method).args(args).skips(skips);
requestBuilder.filters(getFiltersIfAnnotated(method));
UriBuilder builder = uriBuilderProvider.get().uri(endpoint);
Multimap<String, String> tokenValues = LinkedHashMultimap.create();
tokenValues.put(Constants.PROPERTY_API_VERSION, apiVersion);
tokenValues.putAll(addPathAndGetTokens(declaring, method, args, builder));
Multimap<String, String> formParams = addFormParams(tokenValues.entries(), method, args);
Multimap<String, String> queryParams = addQueryParams(tokenValues.entries(), method, args);
Multimap<String, String> matrixParams = addMatrixParams(tokenValues.entries(), method, args);
Multimap<String, String> headers = buildHeaders(tokenValues.entries(), method, args);
if (r != null)
headers.putAll(r.getHeaders());
if (shouldAddHostHeader(method)) {
StringBuilder hostHeader = new StringBuilder(endpoint.getHost());
if (endpoint.getPort() != -1)
hostHeader.append(":").append(endpoint.getPort());
headers.put(HOST, hostHeader.toString());
}
Payload payload = null;
HttpRequestOptions options = findOptionsIn(method, args);
if (options != null) {
injector.injectMembers(options);// TODO test case
for (Entry<String, String> header : options.buildRequestHeaders().entries()) {
headers.put(header.getKey(), Strings2.replaceTokens(header.getValue(), tokenValues.entries()));
}
for (Entry<String, String> matrix : options.buildMatrixParameters().entries()) {
matrixParams.put(matrix.getKey(), Strings2.replaceTokens(matrix.getValue(), tokenValues.entries()));
}
for (Entry<String, String> query : options.buildQueryParameters().entries()) {
queryParams.put(query.getKey(), Strings2.replaceTokens(query.getValue(), tokenValues.entries()));
}
for (Entry<String, String> form : options.buildFormParameters().entries()) {
formParams.put(form.getKey(), Strings2.replaceTokens(form.getValue(), tokenValues.entries()));
requestBuilder = GeneratedHttpRequest.<T> builder();
requestBuilder.method(getHttpMethodOrConstantOrThrowException(method));
}
String pathSuffix = options.buildPathSuffix();
if (pathSuffix != null) {
builder.path(pathSuffix);
requestBuilder.declaring(declaring).javaMethod(method).args(args).skips(skips);
requestBuilder.filters(getFiltersIfAnnotated(method));
UriBuilder builder = uriBuilderProvider.get().uri(endpoint);
Multimap<String, String> tokenValues = LinkedHashMultimap.create();
tokenValues.put(Constants.PROPERTY_API_VERSION, apiVersion);
tokenValues.putAll(addPathAndGetTokens(declaring, method, args, builder));
Multimap<String, String> formParams = addFormParams(tokenValues.entries(), method, args);
Multimap<String, String> queryParams = addQueryParams(tokenValues.entries(), method, args);
Multimap<String, String> matrixParams = addMatrixParams(tokenValues.entries(), method, args);
Multimap<String, String> headers = buildHeaders(tokenValues.entries(), method, args);
if (r != null)
headers.putAll(r.getHeaders());
if (shouldAddHostHeader(method)) {
StringBuilder hostHeader = new StringBuilder(endpoint.getHost());
if (endpoint.getPort() != -1)
hostHeader.append(":").append(endpoint.getPort());
headers.put(HOST, hostHeader.toString());
}
String stringPayload = options.buildStringPayload();
if (stringPayload != null)
payload = Payloads.newStringPayload(stringPayload);
}
if (matrixParams.size() > 0) {
for (String key : matrixParams.keySet())
builder.matrixParam(key, Lists.newArrayList(matrixParams.get(key)).toArray());
}
Payload payload = null;
HttpRequestOptions options = findOptionsIn(method, args);
if (options != null) {
injector.injectMembers(options);// TODO test case
for (Entry<String, String> header : options.buildRequestHeaders().entries()) {
headers.put(header.getKey(), Strings2.replaceTokens(header.getValue(), tokenValues.entries()));
}
for (Entry<String, String> matrix : options.buildMatrixParameters().entries()) {
matrixParams.put(matrix.getKey(), Strings2.replaceTokens(matrix.getValue(), tokenValues.entries()));
}
for (Entry<String, String> query : options.buildQueryParameters().entries()) {
queryParams.put(query.getKey(), Strings2.replaceTokens(query.getValue(), tokenValues.entries()));
}
for (Entry<String, String> form : options.buildFormParameters().entries()) {
formParams.put(form.getKey(), Strings2.replaceTokens(form.getValue(), tokenValues.entries()));
}
if (queryParams.size() > 0) {
builder.replaceQuery(ModifyRequest.makeQueryLine(queryParams, null, skips));
}
requestBuilder.headers(filterOutContentHeaders(headers));
try {
requestBuilder.endpoint(builder.buildFromEncodedMap(Maps2.convertUnsafe(tokenValues)));
} catch (IllegalArgumentException e) {
throw new IllegalStateException(e);
} catch (UriBuilderException e) {
throw new IllegalStateException(e);
}
if (payload == null)
payload = findPayloadInArgs(args);
List<? extends Part> parts = getParts(method, args, concat(tokenValues.entries(), formParams.entries()));
if (parts.size() > 0) {
if (formParams.size() > 0) {
parts = newLinkedList(concat(transform(formParams.entries(), ENTRY_TO_PART), parts));
String pathSuffix = options.buildPathSuffix();
if (pathSuffix != null) {
builder.path(pathSuffix);
}
String stringPayload = options.buildStringPayload();
if (stringPayload != null)
payload = Payloads.newStringPayload(stringPayload);
}
payload = new MultipartForm(BOUNDARY, parts);
} else if (formParams.size() > 0) {
payload = Payloads.newUrlEncodedFormPayload(formParams, skips);
} else if (headers.containsKey(CONTENT_TYPE)) {
if (matrixParams.size() > 0) {
for (String key : matrixParams.keySet())
builder.matrixParam(key, Lists.newArrayList(matrixParams.get(key)).toArray());
}
if (queryParams.size() > 0) {
builder.replaceQuery(ModifyRequest.makeQueryLine(queryParams, null, skips));
}
requestBuilder.headers(filterOutContentHeaders(headers));
try {
requestBuilder.endpoint(builder.buildFromEncodedMap(Maps2.convertUnsafe(tokenValues)));
} catch (IllegalArgumentException e) {
throw new IllegalStateException(e);
} catch (UriBuilderException e) {
throw new IllegalStateException(e);
}
if (payload == null)
payload = Payloads.newByteArrayPayload(new byte[] {});
payload.getContentMetadata().setContentType(Iterables.get(headers.get(CONTENT_TYPE), 0));
}
if (payload != null) {
requestBuilder.payload(payload);
}
GeneratedHttpRequest<T> request = requestBuilder.build();
org.jclouds.rest.MapBinder mapBinder = getMapPayloadBinderOrNull(method, args);
if (mapBinder != null) {
Map<String, String> mapParams = buildPostParams(method, args);
if (method.isAnnotationPresent(PayloadParams.class)) {
PayloadParams params = method.getAnnotation(PayloadParams.class);
addMapPayload(mapParams, params, headers.entries());
payload = findPayloadInArgs(args);
List<? extends Part> parts = getParts(method, args, concat(tokenValues.entries(), formParams.entries()));
if (parts.size() > 0) {
if (formParams.size() > 0) {
parts = newLinkedList(concat(transform(formParams.entries(), ENTRY_TO_PART), parts));
}
payload = new MultipartForm(BOUNDARY, parts);
} else if (formParams.size() > 0) {
payload = Payloads.newUrlEncodedFormPayload(formParams, skips);
} else if (headers.containsKey(CONTENT_TYPE)) {
if (payload == null)
payload = Payloads.newByteArrayPayload(new byte[] {});
payload.getContentMetadata().setContentType(Iterables.get(headers.get(CONTENT_TYPE), 0));
}
request = mapBinder.bindToRequest(request, mapParams);
} else {
request = decorateRequest(request);
}
if (payload != null) {
requestBuilder.payload(payload);
}
GeneratedHttpRequest<T> request = requestBuilder.build();
if (request.getPayload() != null)
request.getPayload().getContentMetadata().setPropertiesFromHttpHeaders(headers);
utils.checkRequestHasRequiredProperties(request);
return request;
org.jclouds.rest.MapBinder mapBinder = getMapPayloadBinderOrNull(method, args);
if (mapBinder != null) {
Map<String, String> mapParams = buildPostParams(method, args);
if (method.isAnnotationPresent(PayloadParams.class)) {
PayloadParams params = method.getAnnotation(PayloadParams.class);
addMapPayload(mapParams, params, headers.entries());
}
request = mapBinder.bindToRequest(request, mapParams);
} else {
request = decorateRequest(request);
}
if (request.getPayload() != null)
request.getPayload().getContentMetadata().setPropertiesFromHttpHeaders(headers);
utils.checkRequestHasRequiredProperties(request);
return request;
} catch (ExecutionException e) {
Throwables.propagate(e);
return null;
}
}
public static Multimap<String, String> filterOutContentHeaders(Multimap<String, String> headers) {
// TODO make a filter like {@link Maps.filterKeys} instead of this
ImmutableMultimap.Builder<String, String> headersBuilder = ImmutableMultimap.builder();
// http message usually comes in as a null key header, let's filter it out.
// http message usually comes in as a null key header, let's filter it
// out.
for (String header : Iterables.filter(headers.keySet(), Predicates.notNull())) {
if (!ContentMetadata.HTTP_HEADERS.contains(header)) {
headersBuilder.putAll(header, headers.get(header));
@ -537,7 +553,7 @@ public class RestAnnotationProcessor<T> {
public static final String BOUNDARY = "--JCLOUDS--";
private Multimap<String, String> addPathAndGetTokens(Class<?> clazz, Method method, Object[] args, UriBuilder builder) {
private Multimap<String, String> addPathAndGetTokens(Class<?> clazz, Method method, Object[] args, UriBuilder builder) throws ExecutionException {
if (clazz.isAnnotationPresent(Path.class))
builder.path(clazz);
if (method.isAnnotationPresent(Path.class))
@ -550,14 +566,14 @@ public class RestAnnotationProcessor<T> {
}
public static URI replaceQuery(Provider<UriBuilder> uriBuilderProvider, URI in, String newQuery,
@Nullable Comparator<Entry<String, String>> sorter, char... skips) {
@Nullable Comparator<Entry<String, String>> sorter, char... skips) {
UriBuilder builder = uriBuilderProvider.get().uri(in);
builder.replaceQuery(ModifyRequest.makeQueryLine(ModifyRequest.parseQueryToMap(newQuery), sorter, skips));
return builder.build();
}
private Multimap<String, String> addMatrixParams(Collection<Entry<String, String>> tokenValues, Method method,
Object... args) {
Object... args) throws ExecutionException {
Multimap<String, String> matrixMap = LinkedListMultimap.create();
if (declaring.isAnnotationPresent(MatrixParams.class)) {
MatrixParams matrix = declaring.getAnnotation(MatrixParams.class);
@ -576,7 +592,7 @@ public class RestAnnotationProcessor<T> {
}
private Multimap<String, String> addFormParams(Collection<Entry<String, String>> tokenValues, Method method,
Object... args) {
Object... args) throws ExecutionException {
Multimap<String, String> formMap = LinkedListMultimap.create();
if (declaring.isAnnotationPresent(FormParams.class)) {
FormParams form = declaring.getAnnotation(FormParams.class);
@ -595,7 +611,7 @@ public class RestAnnotationProcessor<T> {
}
private Multimap<String, String> addQueryParams(Collection<Entry<String, String>> tokenValues, Method method,
Object... args) {
Object... args) throws ExecutionException {
Multimap<String, String> queryMap = LinkedListMultimap.create();
if (declaring.isAnnotationPresent(QueryParams.class)) {
QueryParams query = declaring.getAnnotation(QueryParams.class);
@ -614,7 +630,7 @@ public class RestAnnotationProcessor<T> {
}
private void addForm(Multimap<String, String> formParams, FormParams form,
Collection<Entry<String, String>> tokenValues) {
Collection<Entry<String, String>> tokenValues) {
for (int i = 0; i < form.keys().length; i++) {
if (form.values()[i].equals(FormParams.NULL)) {
formParams.removeAll(form.keys()[i]);
@ -626,7 +642,7 @@ public class RestAnnotationProcessor<T> {
}
private void addQuery(Multimap<String, String> queryParams, QueryParams query,
Collection<Entry<String, String>> tokenValues) {
Collection<Entry<String, String>> tokenValues) {
for (int i = 0; i < query.keys().length; i++) {
if (query.values()[i].equals(QueryParams.NULL)) {
queryParams.removeAll(query.keys()[i]);
@ -638,7 +654,7 @@ public class RestAnnotationProcessor<T> {
}
private void addMatrix(Multimap<String, String> matrixParams, MatrixParams matrix,
Collection<Entry<String, String>> tokenValues) {
Collection<Entry<String, String>> tokenValues) {
for (int i = 0; i < matrix.keys().length; i++) {
if (matrix.values()[i].equals(MatrixParams.NULL)) {
matrixParams.removeAll(matrix.keys()[i]);
@ -650,7 +666,7 @@ public class RestAnnotationProcessor<T> {
}
private void addMapPayload(Map<String, String> postParams, PayloadParams mapDefaults,
Collection<Entry<String, String>> tokenValues) {
Collection<Entry<String, String>> tokenValues) {
for (int i = 0; i < mapDefaults.keys().length; i++) {
if (mapDefaults.values()[i].equals(PayloadParams.NULL)) {
postParams.put(mapDefaults.keys()[i], null);
@ -683,9 +699,10 @@ public class RestAnnotationProcessor<T> {
}
@VisibleForTesting
public static URI getEndpointInParametersOrNull(Method method, final Object[] args, Injector injector) {
public static URI getEndpointInParametersOrNull(Method method, final Object[] args, Injector injector)
throws ExecutionException {
Map<Integer, Set<Annotation>> map = indexWithAtLeastOneAnnotation(method,
methodToIndexOfParamToEndpointParamAnnotations);
methodToIndexOfParamToEndpointParamAnnotations);
if (map.size() >= 1 && args.length > 0) {
EndpointParam firstAnnotation = (EndpointParam) get(get(map.values(), 0), 0);
Function<Object, URI> parser = injector.getInstance(firstAnnotation.parser());
@ -694,8 +711,8 @@ public class RestAnnotationProcessor<T> {
int index = map.keySet().iterator().next();
try {
URI returnVal = parser.apply(args[index]);
checkArgument(returnVal != null, String.format("endpoint for [%s] not configured for %s", args[index],
method));
checkArgument(returnVal != null,
String.format("endpoint for [%s] not configured for %s", args[index], method));
return returnVal;
} catch (NullPointerException e) {
throw new IllegalArgumentException(String.format("argument at index %d on method %s", index, method), e);
@ -712,19 +729,19 @@ public class RestAnnotationProcessor<T> {
});
try {
URI returnVal = parser.apply(argsToParse);
checkArgument(returnVal != null, String.format("endpoint for [%s] not configured for %s", argsToParse,
method));
checkArgument(returnVal != null,
String.format("endpoint for [%s] not configured for %s", argsToParse, method));
return returnVal;
} catch (NullPointerException e) {
throw new IllegalArgumentException(String.format("illegal argument in [%s] for method %s", argsToParse,
method), e);
method), e);
}
}
}
return null;
}
public static URI getEndpointFor(Method method, Object[] args, Injector injector) {
public static URI getEndpointFor(Method method, Object[] args, Injector injector) throws ExecutionException {
URI endpoint = getEndpointInParametersOrNull(method, args, injector);
if (endpoint == null) {
Endpoint annotation;
@ -753,29 +770,29 @@ public class RestAnnotationProcessor<T> {
public static final TypeLiteral<ListenableFuture<HttpResponse>> futureHttpResponseLiteral = new TypeLiteral<ListenableFuture<HttpResponse>>() {
};
@SuppressWarnings( { "unchecked", "rawtypes" })
@SuppressWarnings({ "unchecked", "rawtypes" })
public static Key<? extends Function<HttpResponse, ?>> getParserOrThrowException(Method method) {
ResponseParser annotation = method.getAnnotation(ResponseParser.class);
if (annotation == null) {
if (method.getReturnType().equals(void.class)
|| TypeLiteral.get(method.getGenericReturnType()).equals(futureVoidLiteral)) {
|| TypeLiteral.get(method.getGenericReturnType()).equals(futureVoidLiteral)) {
return Key.get(ReleasePayloadAndReturn.class);
} else if (method.getReturnType().equals(boolean.class) || method.getReturnType().equals(Boolean.class)
|| TypeLiteral.get(method.getGenericReturnType()).equals(futureBooleanLiteral)) {
|| TypeLiteral.get(method.getGenericReturnType()).equals(futureBooleanLiteral)) {
return Key.get(ReturnTrueIf2xx.class);
} else if (method.getReturnType().equals(InputStream.class)
|| TypeLiteral.get(method.getGenericReturnType()).equals(futureInputStreamLiteral)) {
|| TypeLiteral.get(method.getGenericReturnType()).equals(futureInputStreamLiteral)) {
return Key.get(ReturnInputStream.class);
} else if (method.getReturnType().equals(HttpResponse.class)
|| TypeLiteral.get(method.getGenericReturnType()).equals(futureHttpResponseLiteral)) {
|| TypeLiteral.get(method.getGenericReturnType()).equals(futureHttpResponseLiteral)) {
return Key.get((Class) IdentityFunction.class);
} else if (getAcceptHeadersOrNull(method).contains(MediaType.APPLICATION_JSON)) {
return getJsonParserKeyForMethod(method);
} else if (method.getReturnType().equals(String.class)
|| TypeLiteral.get(method.getGenericReturnType()).equals(futureStringLiteral)) {
|| TypeLiteral.get(method.getGenericReturnType()).equals(futureStringLiteral)) {
return Key.get(ReturnStringIf2xx.class);
} else if (method.getReturnType().equals(URI.class)
|| TypeLiteral.get(method.getGenericReturnType()).equals(futureURILiteral)) {
|| TypeLiteral.get(method.getGenericReturnType()).equals(futureURILiteral)) {
return Key.get(ParseURIFromListOrLocationHeaderIf20x.class);
} else {
throw new IllegalStateException("You must specify a ResponseParser annotation on: " + method.toString());
@ -804,7 +821,7 @@ public class RestAnnotationProcessor<T> {
return returnVal;
}
@SuppressWarnings( { "unchecked", "rawtypes" })
@SuppressWarnings({ "unchecked", "rawtypes" })
public static Key<? extends Function<HttpResponse, ?>> getJsonParserKeyForMethodAnType(Method method, Type returnVal) {
ParameterizedType parserType;
if (method.isAnnotationPresent(Unwrap.class)) {
@ -820,7 +837,7 @@ public class RestAnnotationProcessor<T> {
parserType = Types.newParameterizedType(UnwrapOnlyNestedJsonValueInSet.class, returnVal);
else
throw new IllegalStateException(String.format("depth(%d) edgeCollection(%s) not yet supported for @Unwrap",
depth, edgeCollection));
depth, edgeCollection));
} else {
parserType = Types.newParameterizedType(ParseJson.class, returnVal);
}
@ -850,7 +867,7 @@ public class RestAnnotationProcessor<T> {
} else {
if (postBinders[0] instanceof org.jclouds.rest.MapBinder) {
throw new IllegalArgumentException("we currently do not support multiple varargs postBinders in: "
+ method.getName());
+ method.getName());
}
}
} else if (arg instanceof org.jclouds.rest.MapBinder) {
@ -883,8 +900,8 @@ public class RestAnnotationProcessor<T> {
Set<String> requests = getHttpMethods(method);
if (requests == null || requests.size() != 1) {
throw new IllegalStateException(
"You must use at least one, but no more than one http method or pathparam annotation on: "
+ method.toString());
"You must use at least one, but no more than one http method or pathparam annotation on: "
+ method.toString());
}
return requests.iterator().next();
}
@ -902,11 +919,13 @@ public class RestAnnotationProcessor<T> {
}
};
public GeneratedHttpRequest<T> decorateRequest(GeneratedHttpRequest<T> request) {
public GeneratedHttpRequest<T> decorateRequest(GeneratedHttpRequest<T> request) throws NegativeArraySizeException,
ExecutionException {
OUTER: for (Entry<Integer, Set<Annotation>> entry : concat(//
filterValues(methodToIndexOfParamToBinderParamAnnotation.get(request.getJavaMethod()), notEmpty)
.entrySet(), //
filterValues(methodToIndexOfParamToWrapWithAnnotation.get(request.getJavaMethod()), notEmpty).entrySet())) {
filterValues(methodToIndexOfParamToBinderParamAnnotation.get(request.getJavaMethod()).asMap(), notEmpty)
.entrySet(), //
filterValues(methodToIndexOfParamToWrapWithAnnotation.get(request.getJavaMethod()).asMap(), notEmpty)
.entrySet())) {
boolean shouldBreak = false;
Annotation annotation = Iterables.get(entry.getValue(), 0);
Binder binder;
@ -914,7 +933,7 @@ public class RestAnnotationProcessor<T> {
binder = injector.getInstance(BinderParam.class.cast(annotation).value());
else
binder = injector.getInstance(BindToJsonPayloadWrappedWith.Factory.class).create(
WrapWith.class.cast(annotation).value());
WrapWith.class.cast(annotation).value());
if (request.getArgs().size() >= entry.getKey() + 1 && request.getArgs().get(entry.getKey()) != null) {
Object input;
Class<?> parameterType = request.getJavaMethod().getParameterTypes()[entry.getKey()];
@ -947,28 +966,28 @@ public class RestAnnotationProcessor<T> {
}
public static Map<Integer, Set<Annotation>> indexWithOnlyOneAnnotation(Method method, String description,
Map<Method, Map<Integer, Set<Annotation>>> toRefine) {
Cache<Method, Cache<Integer, Set<Annotation>>> toRefine) throws ExecutionException {
Map<Integer, Set<Annotation>> indexToPayloadAnnotation = indexWithAtLeastOneAnnotation(method, toRefine);
if (indexToPayloadAnnotation.size() > 1) {
throw new IllegalStateException(String.format(
"You must not specify more than one %s annotation on: %s; found %s", description, method.toString(),
indexToPayloadAnnotation));
"You must not specify more than one %s annotation on: %s; found %s", description, method.toString(),
indexToPayloadAnnotation));
}
return indexToPayloadAnnotation;
}
private static Map<Integer, Set<Annotation>> indexWithAtLeastOneAnnotation(Method method,
Map<Method, Map<Integer, Set<Annotation>>> toRefine) {
Map<Integer, Set<Annotation>> indexToPayloadAnnotation = filterValues(toRefine.get(method),
new Predicate<Set<Annotation>>() {
public boolean apply(Set<Annotation> input) {
return input.size() == 1;
}
});
Cache<Method, Cache<Integer, Set<Annotation>>> toRefine) throws ExecutionException {
Map<Integer, Set<Annotation>> indexToPayloadAnnotation = filterValues(toRefine.get(method).asMap(),
new Predicate<Set<Annotation>>() {
public boolean apply(Set<Annotation> input) {
return input.size() == 1;
}
});
return indexToPayloadAnnotation;
}
private HttpRequestOptions findOptionsIn(Method method, Object... args) {
private HttpRequestOptions findOptionsIn(Method method, Object... args) throws ExecutionException {
for (int index : methodToIndexesOfOptions.get(method)) {
if (args.length >= index + 1) {// accomodate varargs
if (args[index] instanceof Object[]) {
@ -983,7 +1002,7 @@ public class RestAnnotationProcessor<T> {
} else {
if (options[0] instanceof HttpRequestOptions) {
throw new IllegalArgumentException("we currently do not support multiple varargs options in: "
+ method.getName());
+ method.getName());
}
}
} else {
@ -995,11 +1014,11 @@ public class RestAnnotationProcessor<T> {
}
public Multimap<String, String> buildHeaders(Collection<Entry<String, String>> tokenValues, Method method,
final Object... args) {
final Object... args) throws ExecutionException {
Multimap<String, String> headers = LinkedHashMultimap.create();
addHeaderIfAnnotationPresentOnMethod(headers, method, tokenValues);
Map<Integer, Set<Annotation>> indexToHeaderParam = methodToIndexOfParamToHeaderParamAnnotations.get(method);
for (Entry<Integer, Set<Annotation>> entry : indexToHeaderParam.entrySet()) {
Cache<Integer, Set<Annotation>> indexToHeaderParam = methodToIndexOfParamToHeaderParamAnnotations.get(method);
for (Entry<Integer, Set<Annotation>> entry : indexToHeaderParam.asMap().entrySet()) {
for (Annotation key : entry.getValue()) {
String value = args[entry.getKey()].toString();
value = Strings2.replaceTokens(value, tokenValues);
@ -1042,7 +1061,7 @@ public class RestAnnotationProcessor<T> {
}
public void addHeaderIfAnnotationPresentOnMethod(Multimap<String, String> headers, Method method,
Collection<Entry<String, String>> tokenValues) {
Collection<Entry<String, String>> tokenValues) {
if (declaring.isAnnotationPresent(Headers.class)) {
Headers header = declaring.getAnnotation(Headers.class);
addHeader(headers, header, tokenValues);
@ -1054,7 +1073,7 @@ public class RestAnnotationProcessor<T> {
}
private void addHeader(Multimap<String, String> headers, Headers header,
Collection<Entry<String, String>> tokenValues) {
Collection<Entry<String, String>> tokenValues) {
for (int i = 0; i < header.keys().length; i++) {
String value = header.values()[i];
value = Strings2.replaceTokens(value, tokenValues);
@ -1063,10 +1082,10 @@ public class RestAnnotationProcessor<T> {
}
List<? extends Part> getParts(Method method, Object[] args, Iterable<Entry<String, String>> iterable) {
List<? extends Part> getParts(Method method, Object[] args, Iterable<Entry<String, String>> iterable) throws ExecutionException {
List<Part> parts = newLinkedList();
Map<Integer, Set<Annotation>> indexToPartParam = methodToIndexOfParamToPartParamAnnotations.get(method);
for (Entry<Integer, Set<Annotation>> entry : indexToPartParam.entrySet()) {
Cache<Integer, Set<Annotation>> indexToPartParam = methodToIndexOfParamToPartParamAnnotations.get(method);
for (Entry<Integer, Set<Annotation>> entry : indexToPartParam.asMap().entrySet()) {
for (Annotation key : entry.getValue()) {
PartParam param = (PartParam) key;
PartOptions options = new PartOptions();
@ -1101,12 +1120,12 @@ public class RestAnnotationProcessor<T> {
return null;
}
private Multimap<String, String> getPathParamKeyValues(Method method, Object... args) {
private Multimap<String, String> getPathParamKeyValues(Method method, Object... args) throws ExecutionException {
Multimap<String, String> pathParamValues = LinkedHashMultimap.create();
Map<Integer, Set<Annotation>> indexToPathParam = methodToIndexOfParamToPathParamAnnotations.get(method);
Cache<Integer, Set<Annotation>> indexToPathParam = methodToIndexOfParamToPathParamAnnotations.get(method);
Map<Integer, Set<Annotation>> indexToParamExtractor = methodToIndexOfParamToParamParserAnnotations.get(method);
for (Entry<Integer, Set<Annotation>> entry : indexToPathParam.entrySet()) {
Cache<Integer, Set<Annotation>> indexToParamExtractor = methodToIndexOfParamToParamParserAnnotations.get(method);
for (Entry<Integer, Set<Annotation>> entry : indexToPathParam.asMap().entrySet()) {
for (Annotation key : entry.getValue()) {
Set<Annotation> extractors = indexToParamExtractor.get(entry.getKey());
String paramKey = ((PathParam) key).value();
@ -1138,12 +1157,12 @@ public class RestAnnotationProcessor<T> {
return encoded;
}
private Multimap<String, String> getMatrixParamKeyValues(Method method, Object... args) {
private Multimap<String, String> getMatrixParamKeyValues(Method method, Object... args) throws ExecutionException {
Multimap<String, String> matrixParamValues = LinkedHashMultimap.create();
Map<Integer, Set<Annotation>> indexToMatrixParam = methodToIndexOfParamToMatrixParamAnnotations.get(method);
Cache<Integer, Set<Annotation>> indexToMatrixParam = methodToIndexOfParamToMatrixParamAnnotations.get(method);
Map<Integer, Set<Annotation>> indexToParamExtractor = methodToIndexOfParamToParamParserAnnotations.get(method);
for (Entry<Integer, Set<Annotation>> entry : indexToMatrixParam.entrySet()) {
Cache<Integer, Set<Annotation>> indexToParamExtractor = methodToIndexOfParamToParamParserAnnotations.get(method);
for (Entry<Integer, Set<Annotation>> entry : indexToMatrixParam.asMap().entrySet()) {
for (Annotation key : entry.getValue()) {
Set<Annotation> extractors = indexToParamExtractor.get(entry.getKey());
String paramKey = ((MatrixParam) key).value();
@ -1167,12 +1186,12 @@ public class RestAnnotationProcessor<T> {
return matrixParamValues;
}
private Multimap<String, String> getFormParamKeyValues(Method method, Object... args) {
private Multimap<String, String> getFormParamKeyValues(Method method, Object... args) throws ExecutionException {
Multimap<String, String> formParamValues = LinkedHashMultimap.create();
Map<Integer, Set<Annotation>> indexToFormParam = methodToIndexOfParamToFormParamAnnotations.get(method);
Cache<Integer, Set<Annotation>> indexToFormParam = methodToIndexOfParamToFormParamAnnotations.get(method);
Map<Integer, Set<Annotation>> indexToParamExtractor = methodToIndexOfParamToParamParserAnnotations.get(method);
for (Entry<Integer, Set<Annotation>> entry : indexToFormParam.entrySet()) {
Cache<Integer, Set<Annotation>> indexToParamExtractor = methodToIndexOfParamToParamParserAnnotations.get(method);
for (Entry<Integer, Set<Annotation>> entry : indexToFormParam.asMap().entrySet()) {
for (Annotation key : entry.getValue()) {
Set<Annotation> extractors = indexToParamExtractor.get(entry.getKey());
String paramKey = ((FormParam) key).value();
@ -1196,12 +1215,12 @@ public class RestAnnotationProcessor<T> {
return formParamValues;
}
private Multimap<String, String> getQueryParamKeyValues(Method method, Object... args) {
private Multimap<String, String> getQueryParamKeyValues(Method method, Object... args) throws ExecutionException {
Multimap<String, String> queryParamValues = LinkedHashMultimap.create();
Map<Integer, Set<Annotation>> indexToQueryParam = methodToIndexOfParamToQueryParamAnnotations.get(method);
Cache<Integer, Set<Annotation>> indexToQueryParam = methodToIndexOfParamToQueryParamAnnotations.get(method);
Map<Integer, Set<Annotation>> indexToParamExtractor = methodToIndexOfParamToParamParserAnnotations.get(method);
for (Entry<Integer, Set<Annotation>> entry : indexToQueryParam.entrySet()) {
Cache<Integer, Set<Annotation>> indexToParamExtractor = methodToIndexOfParamToParamParserAnnotations.get(method);
for (Entry<Integer, Set<Annotation>> entry : indexToQueryParam.asMap().entrySet()) {
for (Annotation key : entry.getValue()) {
Set<Annotation> extractors = indexToParamExtractor.get(entry.getKey());
String paramKey = ((QueryParam) key).value();
@ -1225,11 +1244,11 @@ public class RestAnnotationProcessor<T> {
return queryParamValues;
}
private Map<String, String> buildPostParams(Method method, Object... args) {
private Map<String, String> buildPostParams(Method method, Object... args) throws ExecutionException {
Map<String, String> postParams = newHashMap();
Map<Integer, Set<Annotation>> indexToPathParam = methodToIndexOfParamToPostParamAnnotations.get(method);
Map<Integer, Set<Annotation>> indexToParamExtractor = methodToIndexOfParamToParamParserAnnotations.get(method);
for (Entry<Integer, Set<Annotation>> entry : indexToPathParam.entrySet()) {
Cache<Integer, Set<Annotation>> indexToPathParam = methodToIndexOfParamToPostParamAnnotations.get(method);
Cache<Integer, Set<Annotation>> indexToParamExtractor = methodToIndexOfParamToParamParserAnnotations.get(method);
for (Entry<Integer, Set<Annotation>> entry : indexToPathParam.asMap().entrySet()) {
for (Annotation key : entry.getValue()) {
Set<Annotation> extractors = indexToParamExtractor.get(entry.getKey());
String paramKey = ((PayloadParam) key).value();

View File

@ -36,6 +36,7 @@ import static org.jclouds.rest.internal.RestAnnotationProcessor.methodToIndexOfP
import static org.jclouds.rest.internal.RestAnnotationProcessor.methodToIndexesOfOptions;
import java.lang.reflect.Method;
import java.util.concurrent.ExecutionException;
import javax.annotation.Resource;
import javax.inject.Named;
@ -48,7 +49,7 @@ import org.jclouds.logging.Logger;
import org.jclouds.rest.annotations.Delegate;
import org.jclouds.rest.internal.RestAnnotationProcessor.MethodKey;
import com.google.common.base.Function;
import com.google.common.cache.CacheLoader;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Multimap;
import com.google.inject.Inject;
@ -63,7 +64,7 @@ import com.google.inject.Provides;
*/
@Singleton
public class SeedAnnotationCache implements Function<Class<?>, Boolean> {
public class SeedAnnotationCache extends CacheLoader<Class<?>, Boolean> {
@Resource
protected Logger logger = Logger.NULL;
@ -82,7 +83,8 @@ public class SeedAnnotationCache implements Function<Class<?>, Boolean> {
constants.put(key, value);
}
public Boolean apply(Class<?> declaring) {
@Override
public Boolean load(Class<?> declaring) throws ExecutionException {
for (Method method : difference(ImmutableSet.copyOf(declaring.getMethods()), ImmutableSet.copyOf(Object.class
.getMethods()))) {
if (isHttpMethod(method) || method.isAnnotationPresent(Delegate.class)) {

View File

@ -20,11 +20,12 @@ package org.jclouds.util;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.regex.Pattern;
import com.google.common.base.Function;
import com.google.common.collect.MapMaker;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
/**
*
@ -43,36 +44,38 @@ public class Patterns {
public static final Pattern _7E_PATTERN = Pattern.compile("%7E");
public static final Pattern NEWLINE_PATTERN = Pattern.compile("\r?\n");
public static final Pattern SLASH_PATTERN = Pattern.compile("[/]");
public static final Pattern IP_PATTERN = Pattern
.compile("b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).)"
+ "{3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)b");
public static final Pattern IP_PATTERN = Pattern.compile("b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).)"
+ "{3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)b");
public static final Pattern LEADING_SLASHES = Pattern.compile("^[/]+");
public static final Pattern TRAILING_SLASHES = Pattern.compile("[/]*$");
public static final Pattern REST_CONTEXT_BUILDER = Pattern.compile("(.*ContextBuilder)<([^,]+), ?([^>]+)>");
public final static Map<Character, Pattern> CHAR_TO_ENCODED_PATTERN = new MapMaker()
.makeComputingMap(new Function<Character, Pattern>() {
public Pattern apply(Character plain) {
try {
String encoded = URLEncoder.encode(plain + "", "UTF-8");
return Pattern.compile(encoded);
} catch (UnsupportedEncodingException e) {
throw new IllegalStateException("Bad encoding on input: " + plain, e);
}
public final static Cache<Character, Pattern> CHAR_TO_ENCODED_PATTERN = CacheBuilder.newBuilder()
.<Character, Pattern> build(new CacheLoader<Character, Pattern>() {
@Override
public Pattern load(Character plain) throws ExecutionException {
try {
String encoded = URLEncoder.encode(plain + "", "UTF-8");
return Pattern.compile(encoded);
} catch (UnsupportedEncodingException e) {
throw new ExecutionException("Bad encoding on input: " + plain, e);
}
});
}
});
public final static Map<Character, Pattern> CHAR_TO_PATTERN = new MapMaker()
.makeComputingMap(new Function<Character, Pattern>() {
public Pattern apply(Character plain) {
return Pattern.compile(plain + "");
}
});
public final static Cache<Character, Pattern> CHAR_TO_PATTERN = CacheBuilder.newBuilder()
.<Character, Pattern> build(new CacheLoader<Character, Pattern>() {
@Override
public Pattern load(Character plain) {
return Pattern.compile(plain + "");
}
});
public final static Map<String, Pattern> TOKEN_TO_PATTERN = new MapMaker()
.makeComputingMap(new Function<String, Pattern>() {
public Pattern apply(String tokenValue) {
return Pattern.compile("\\{" + tokenValue + "\\}");
}
});
public final static Cache<String, Pattern> TOKEN_TO_PATTERN = CacheBuilder.newBuilder()
.<String, Pattern> build(new CacheLoader<String, Pattern>() {
@Override
public Pattern load(String tokenValue) {
return Pattern.compile("\\{" + tokenValue + "\\}");
}
});
}

View File

@ -37,6 +37,7 @@ import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ExecutionException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -70,6 +71,8 @@ public class Strings2 {
return returnVal;
} catch (UnsupportedEncodingException e) {
throw new IllegalStateException("Bad encoding on input: " + in, e);
} catch (ExecutionException e) {
throw new IllegalStateException("error creating pattern: " + in, e);
}
}
@ -87,7 +90,11 @@ public class Strings2 {
public static String replaceTokens(String value, Iterable<Entry<String, String>> tokenValues) {
for (Entry<String, String> tokenValue : tokenValues) {
value = Strings2.replaceAll(value, TOKEN_TO_PATTERN.get(tokenValue.getKey()), tokenValue.getValue());
try {
value = Strings2.replaceAll(value, TOKEN_TO_PATTERN.get(tokenValue.getKey()), tokenValue.getValue());
} catch (ExecutionException e) {
throw new IllegalStateException("error creating pattern: " + tokenValue.getKey(), e);
}
}
return value;
}
@ -107,7 +114,11 @@ public class Strings2 {
public static String replaceAll(String input, char match, String replacement) {
if (input.indexOf(match) != -1) {
input = CHAR_TO_PATTERN.get(match).matcher(input).replaceAll(replacement);
try {
input = CHAR_TO_PATTERN.get(match).matcher(input).replaceAll(replacement);
} catch (ExecutionException e) {
throw new IllegalStateException("error creating pattern: " + match, e);
}
}
return input;
}

View File

@ -88,8 +88,8 @@ public class Throwables2 {
throw (Exception) throwable;
}
}
Throwables.throwCause(exception, true);
return exception;
Throwables.propagateIfPossible(exception.getCause(), Exception.class);
throw exception;
}
public static <T> T propagateAuthorizationOrOriginalException(Exception e) {

View File

@ -67,7 +67,7 @@ import com.google.common.collect.Sets;
*
* @author Adrian Cole
*/
@Test(groups = "performance", enabled = false, sequential = true, testName = "FuturesTransformPerformanceTest")
@Test(groups = "performance", enabled = false, singleThreaded = true, testName = "FuturesTransformPerformanceTest")
public class FuturesTransformPerformanceTest {
private static final int FUDGE = 5;
private static final int COUNT = 100;
@ -175,7 +175,7 @@ public class FuturesTransformPerformanceTest {
long start = System.currentTimeMillis();
Map<String, Future<Long>> responses = newHashMap();
for (int i = 0; i < COUNT; i++)
responses.put(i + "", Futures.transform(Futures.makeListenable(simultateIO(), chainExecutor),
responses.put(i + "", Futures.transform(JdkFutureAdapters.listenInPoolThread(simultateIO(), chainExecutor),
new Function<Long, Long>() {
@Override

View File

@ -25,7 +25,6 @@ import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
@ -36,6 +35,10 @@ import org.jclouds.internal.ClassMethodArgs;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
import com.google.common.base.Functions;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.util.concurrent.ListenableFuture;
@ -162,8 +165,8 @@ public class SyncProxyTest {
@BeforeTest
public void setUp() throws IllegalArgumentException, SecurityException, NoSuchMethodException {
sync = SyncProxy.proxy(Sync.class, new SyncProxy(Sync.class, new Async(),
new ConcurrentHashMap<ClassMethodArgs, Object>(), ImmutableMap.<Class<?>, Class<?>> of()));
Cache<ClassMethodArgs, Object> cache = CacheBuilder.newBuilder().build(CacheLoader.from(Functions.<Object>constant(null)));
sync = SyncProxy.proxy(Sync.class, new SyncProxy(Sync.class, new Async(),cache, ImmutableMap.<Class<?>, Class<?>> of()));
// just to warm up
sync.string();
}
@ -225,8 +228,9 @@ public class SyncProxyTest {
@Test(expectedExceptions = IllegalArgumentException.class)
public void testWrongTypedException() throws IllegalArgumentException, SecurityException, NoSuchMethodException,
IOException {
Cache<ClassMethodArgs, Object> cache = CacheBuilder.newBuilder().build(CacheLoader.from(Functions.<Object>constant(null)));
SyncProxy.proxy(SyncWrongException.class, new SyncProxy(SyncWrongException.class, new Async(),
new ConcurrentHashMap<ClassMethodArgs, Object>(), ImmutableMap.<Class<?>, Class<?>> of()));
cache, ImmutableMap.<Class<?>, Class<?>> of()));
}
private static interface SyncNoTimeOut {
@ -243,8 +247,9 @@ public class SyncProxyTest {
@Test(expectedExceptions = IllegalArgumentException.class)
public void testNoTimeOutException() throws IllegalArgumentException, SecurityException, NoSuchMethodException,
IOException {
Cache<ClassMethodArgs, Object> cache = CacheBuilder.newBuilder().build(CacheLoader.from(Functions.<Object>constant(null)));
SyncProxy.proxy(SyncNoTimeOut.class, new SyncProxy(SyncNoTimeOut.class, new Async(),
new ConcurrentHashMap<ClassMethodArgs, Object>(), ImmutableMap.<Class<?>, Class<?>> of()));
cache, ImmutableMap.<Class<?>, Class<?>> of()));
}
}

View File

@ -0,0 +1,81 @@
/**
* 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.functions;
import static org.testng.Assert.assertEquals;
import java.util.concurrent.ExecutionException;
import org.testng.annotations.Test;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.util.concurrent.UncheckedExecutionException;
/**
*
* @author Adrian Cole
*/
@Test(groups = "unit", singleThreaded = true, testName = "CacheLearningTest")
public class CacheLearningTest {
@Test
public void howTo() throws ExecutionException {
Cache<String, String> cache = CacheBuilder.newBuilder().build(new CacheLoader<String, String>() {
@Override
public String load(String key) throws Exception {
if (key.equals("runtimeexception"))
throw new RuntimeException("runtimeexception");
if (key.equals("exception"))
throw new Exception("exception");
return key.equals("foo") ? null : key;
}
@Override
public String toString() {
return "testLoader";
}
});
try {
cache.get("foo");
} catch (NullPointerException e) {
assertEquals(e.getMessage(), "testLoader returned null for key foo.");
}
try {
cache.get("exception");
} catch (ExecutionException e) {
assertEquals(e.getMessage(), "java.lang.Exception: exception");
}
try {
cache.get("runtimeexception");
} catch (UncheckedExecutionException e) {
assertEquals(e.getMessage(), "java.lang.RuntimeException: runtimeexception");
}
try {
cache.getUnchecked("exception");
} catch (UncheckedExecutionException e) {
assertEquals(e.getMessage(), "java.lang.Exception: exception");
}
assertEquals(cache.get("bar"), "bar");
assertEquals(cache.get("baz"), "baz");
assertEquals(cache.asMap().size(), 2);
}
}

View File

@ -2157,7 +2157,7 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
}
@Test
public void testOneHeader() throws SecurityException, NoSuchMethodException {
public void testOneHeader() throws SecurityException, NoSuchMethodException, ExecutionException {
Method method = TestHeaders.class.getMethod("oneHeader", String.class);
Multimap<String, String> headers = factory(TestHeaders.class).buildHeaders(
ImmutableMultimap.<String, String> of().entries(), method, "robot");
@ -2166,7 +2166,7 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
}
@Test
public void testOneIntHeader() throws SecurityException, NoSuchMethodException {
public void testOneIntHeader() throws SecurityException, NoSuchMethodException, ExecutionException {
Method method = TestHeaders.class.getMethod("oneIntHeader", int.class);
Multimap<String, String> headers = factory(TestHeaders.class).buildHeaders(
ImmutableMultimap.<String, String> of().entries(), method, 1);
@ -2175,7 +2175,7 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
}
@Test
public void testTwoDifferentHeaders() throws SecurityException, NoSuchMethodException {
public void testTwoDifferentHeaders() throws SecurityException, NoSuchMethodException, ExecutionException {
Method method = TestHeaders.class.getMethod("twoDifferentHeaders", String.class, String.class);
Multimap<String, String> headers = factory(TestHeaders.class).buildHeaders(
ImmutableMultimap.<String, String> of().entries(), method, "robot", "egg");
@ -2185,7 +2185,7 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
}
@Test
public void testTwoSameHeaders() throws SecurityException, NoSuchMethodException {
public void testTwoSameHeaders() throws SecurityException, NoSuchMethodException, ExecutionException {
Method method = TestHeaders.class.getMethod("twoSameHeaders", String.class, String.class);
Multimap<String, String> headers = factory(TestHeaders.class).buildHeaders(
ImmutableMultimap.<String, String> of().entries(), method, "robot", "egg");
@ -2228,7 +2228,7 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
@SuppressWarnings("static-access")
@Test
public void testOneEndpointParam() throws SecurityException, NoSuchMethodException {
public void testOneEndpointParam() throws SecurityException, NoSuchMethodException, ExecutionException {
Method method = TestEndpointParams.class.getMethod("oneEndpointParam", String.class);
URI uri = factory(TestEndpointParams.class).getEndpointInParametersOrNull(method, new Object[] { "robot" },
injector);
@ -2238,7 +2238,7 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
@SuppressWarnings("static-access")
@Test
public void testTwoDifferentEndpointParams() throws SecurityException, NoSuchMethodException {
public void testTwoDifferentEndpointParams() throws SecurityException, NoSuchMethodException, ExecutionException {
Method method = TestEndpointParams.class.getMethod("twoEndpointParams", String.class, String.class);
URI uri = factory(TestEndpointParams.class).getEndpointInParametersOrNull(method,
new Object[] { "robot", "egg" }, injector);

View File

@ -64,6 +64,7 @@ import org.jclouds.util.Preconditions2;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Predicate;
import com.google.common.base.Supplier;
import com.google.common.cache.Cache;
/**
* @author Adrian Cole
@ -71,7 +72,7 @@ import com.google.common.base.Supplier;
@Singleton
public class AWSEC2ComputeService extends EC2ComputeService {
private final Map<RegionAndName, String> placementGroupMap;
private final Cache<RegionAndName, String> placementGroupMap;
private final Predicate<PlacementGroup> placementGroupDeleted;
private final AWSEC2Client ec2Client;
@ -90,8 +91,8 @@ public class AWSEC2ComputeService extends EC2ComputeService {
RunScriptOnNode.Factory runScriptOnNodeFactory, InitAdminAccess initAdminAccess,
PersistNodeCredentials persistNodeCredentials, Timeouts timeouts,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor, AWSEC2Client ec2Client,
Map<RegionAndName, KeyPair> credentialsMap, @Named("SECURITY") Map<RegionAndName, String> securityGroupMap,
@Named("PLACEMENT") Map<RegionAndName, String> placementGroupMap,
Cache<RegionAndName, KeyPair> credentialsMap, @Named("SECURITY") Cache<RegionAndName, String> securityGroupMap,
@Named("PLACEMENT") Cache<RegionAndName, String> placementGroupMap,
@Named("DELETED") Predicate<PlacementGroup> placementGroupDeleted) {
super(context, credentialStore, images, sizes, locations, listNodesStrategy, getNodeMetadataStrategy,
runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, startNodeStrategy, stopNodeStrategy,
@ -117,7 +118,7 @@ public class AWSEC2ComputeService extends EC2ComputeService {
checkState(
placementGroupDeleted.apply(new PlacementGroup(region, placementGroup, "cluster", State.PENDING)),
String.format("placementGroup region(%s) name(%s) failed to delete", region, placementGroup));
placementGroupMap.remove(new RegionAndName(region, placementGroup));
placementGroupMap.invalidate(new RegionAndName(region, placementGroup));
logger.debug("<< deleted placementGroup(%s)", placementGroup);
} catch (IllegalStateException e) {
logger.debug("<< inUse placementGroup(%s)", placementGroup);

View File

@ -18,7 +18,6 @@
*/
package org.jclouds.aws.ec2.compute;
import java.util.Map;
import java.util.Set;
import javax.inject.Inject;
@ -35,6 +34,7 @@ import org.jclouds.ec2.compute.domain.RegionAndName;
import org.jclouds.ec2.compute.internal.EC2TemplateBuilderImpl;
import com.google.common.base.Supplier;
import com.google.common.cache.Cache;
/**
*
@ -46,7 +46,7 @@ public class AWSEC2TemplateBuilderImpl extends EC2TemplateBuilderImpl {
protected AWSEC2TemplateBuilderImpl(@Memoized Supplier<Set<? extends Location>> locations,
@Memoized Supplier<Set<? extends Image>> images, @Memoized Supplier<Set<? extends Hardware>> sizes,
Supplier<Location> defaultLocation, @Named("DEFAULT") Provider<TemplateOptions> optionsProvider,
@Named("DEFAULT") Provider<TemplateBuilder> defaultTemplateProvider, Map<RegionAndName, Image> imageMap) {
@Named("DEFAULT") Provider<TemplateBuilder> defaultTemplateProvider, Supplier<Cache<RegionAndName, ? extends Image>> imageMap) {
super(locations, images, sizes, defaultLocation, optionsProvider, defaultTemplateProvider, imageMap);
}

View File

@ -21,8 +21,6 @@ package org.jclouds.aws.ec2.compute.config;
import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL;
import static org.jclouds.compute.domain.OsFamily.AMZN_LINUX;
import java.util.Map;
import javax.inject.Named;
import javax.inject.Singleton;
@ -56,6 +54,7 @@ import org.jclouds.ec2.compute.suppliers.EC2HardwareSupplier;
import org.jclouds.rest.suppliers.MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier;
import com.google.common.base.Supplier;
import com.google.common.cache.Cache;
import com.google.inject.Injector;
import com.google.inject.Provides;
@ -89,12 +88,12 @@ public class AWSEC2ComputeServiceContextModule extends BaseComputeServiceContext
@Provides
@Singleton
protected Supplier<Map<RegionAndName, ? extends Image>> provideRegionAndNameToImageSupplierCache(
protected Supplier<Cache<RegionAndName, ? extends Image>> provideRegionAndNameToImageSupplierCache(
@Named(PROPERTY_SESSION_INTERVAL) long seconds, final AWSRegionAndNameToImageSupplier supplier) {
return new MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier<Map<RegionAndName, ? extends Image>>(
authException, seconds, new Supplier<Map<RegionAndName, ? extends Image>>() {
return new MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier<Cache<RegionAndName, ? extends Image>>(
authException, seconds, new Supplier<Cache<RegionAndName, ? extends Image>>() {
@Override
public Map<RegionAndName, ? extends Image> get() {
public Cache<RegionAndName, ? extends Image> get() {
return supplier.get();
}
});

View File

@ -18,9 +18,6 @@
*/
package org.jclouds.aws.ec2.compute.config;
import static com.google.common.collect.Maps.newLinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
@ -47,7 +44,6 @@ import org.jclouds.compute.options.TemplateOptions;
import org.jclouds.domain.Credentials;
import org.jclouds.ec2.compute.config.EC2ComputeServiceDependenciesModule;
import org.jclouds.ec2.compute.domain.RegionAndName;
import org.jclouds.ec2.compute.domain.RegionNameAndIngressRules;
import org.jclouds.ec2.compute.functions.CreateSecurityGroupIfNeeded;
import org.jclouds.ec2.compute.functions.CreateUniqueKeyPair;
import org.jclouds.ec2.compute.functions.CredentialsForInstance;
@ -62,6 +58,9 @@ import org.jclouds.rest.internal.RestContextImpl;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.collect.Sets;
import com.google.inject.Provides;
import com.google.inject.Scopes;
@ -80,15 +79,15 @@ public class AWSEC2ComputeServiceDependenciesModule extends EC2ComputeServiceDep
bind(ComputeService.class).to(AWSEC2ComputeService.class);
bind(new TypeLiteral<Function<RunningInstance, NodeMetadata>>() {
}).to(RunningInstanceToNodeMetadata.class);
bind(new TypeLiteral<Function<RunningInstance, Credentials>>() {
bind(new TypeLiteral<CacheLoader<RunningInstance, Credentials>>() {
}).to(CredentialsForInstance.class);
bind(new TypeLiteral<Function<RegionNameAndIngressRules, String>>() {
bind(new TypeLiteral<CacheLoader<RegionAndName, String>>() {
}).to(CreateSecurityGroupIfNeeded.class);
bind(new TypeLiteral<Function<RegionAndName, KeyPair>>() {
bind(new TypeLiteral<CacheLoader<RegionAndName, KeyPair>>() {
}).to(CreateUniqueKeyPair.class);
bind(new TypeLiteral<Function<RegionNameAndPublicKeyMaterial, KeyPair>>() {
}).to(ImportOrReturnExistingKeypair.class);
bind(new TypeLiteral<Function<RegionAndName, Image>>() {
bind(new TypeLiteral<CacheLoader<RegionAndName, Image>>() {
}).to(RegionAndIdToImage.class);
bind(new TypeLiteral<ComputeServiceContext>() {
}).to(new TypeLiteral<ComputeServiceContextImpl<AWSEC2Client, AWSEC2AsyncClient>>() {
@ -116,10 +115,8 @@ public class AWSEC2ComputeServiceDependenciesModule extends EC2ComputeServiceDep
@Provides
@Singleton
@Named("PLACEMENT")
protected Map<RegionAndName, String> placementGroupMap(CreateSecurityGroupIfNeeded in) {
// doesn't seem to clear when someone issues remove(key)
// return new MapMaker().makeComputingMap(in);
return newLinkedHashMap();
protected Cache<RegionAndName, String> placementGroupMap(CreateSecurityGroupIfNeeded in) {
return CacheBuilder.newBuilder().build(in);
}
@Provides

View File

@ -38,6 +38,7 @@ import org.jclouds.ec2.domain.InstanceState;
import org.jclouds.ec2.domain.RunningInstance;
import com.google.common.base.Supplier;
import com.google.common.cache.Cache;
/**
* @author Adrian Cole
@ -47,9 +48,9 @@ public class AWSRunningInstanceToNodeMetadata extends RunningInstanceToNodeMetad
@Inject
protected AWSRunningInstanceToNodeMetadata(Map<InstanceState, NodeState> instanceToNodeState,
Map<String, Credentials> credentialStore, Map<RegionAndName, Image> instanceToImage,
Map<String, Credentials> credentialStore, Supplier<Cache<RegionAndName, ? extends Image>> imageMap,
@Memoized Supplier<Set<? extends Location>> locations, @Memoized Supplier<Set<? extends Hardware>> hardware) {
super(instanceToNodeState, credentialStore, instanceToImage, locations, hardware);
super(instanceToNodeState, credentialStore, imageMap, locations, hardware);
}
@Override

View File

@ -49,6 +49,7 @@ import org.jclouds.logging.Logger;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
import com.google.common.cache.Cache;
import com.google.common.collect.Iterables;
/**
@ -73,7 +74,7 @@ public class AWSEC2CreateNodesInGroupThenAddToSet extends EC2CreateNodesInGroupT
CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions createKeyPairAndSecurityGroupsAsNeededAndReturncustomize,
AWSEC2InstancePresent instancePresent,
Function<RunningInstance, NodeMetadata> runningInstanceToNodeMetadata,
Function<RunningInstance, Credentials> instanceToCredentials, Map<String, Credentials> credentialStore,
Cache<RunningInstance, Credentials> instanceToCredentials, Map<String, Credentials> credentialStore,
ComputeUtils utils, SpotInstanceRequestToAWSRunningInstance spotConverter) {
super(client, templateBuilderProvider, createKeyPairAndSecurityGroupsAsNeededAndReturncustomize, instancePresent,
runningInstanceToNodeMetadata, instanceToCredentials, credentialStore, utils);

View File

@ -37,7 +37,6 @@ import org.jclouds.compute.domain.Template;
import org.jclouds.compute.options.TemplateOptions;
import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.ec2.compute.domain.RegionAndName;
import org.jclouds.ec2.compute.domain.RegionNameAndIngressRules;
import org.jclouds.ec2.compute.options.EC2TemplateOptions;
import org.jclouds.ec2.compute.strategy.CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions;
import org.jclouds.ec2.domain.KeyPair;
@ -47,6 +46,7 @@ import org.jclouds.logging.Logger;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.cache.Cache;
/**
*
@ -59,21 +59,21 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL;
@VisibleForTesting
final Map<RegionAndName, String> placementGroupMap;
final Cache<RegionAndName, String> placementGroupMap;
@VisibleForTesting
final CreatePlacementGroupIfNeeded createPlacementGroupIfNeeded;
@VisibleForTesting
final Function<RegionNameAndPublicKeyMaterial, KeyPair> importExistingKeyPair;
@Inject
public CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions(
Map<RegionAndName, KeyPair> credentialsMap, @Named("SECURITY") Map<RegionAndName, String> securityGroupMap,
@Named("PLACEMENT") Map<RegionAndName, String> placementGroupMap,
Function<RegionAndName, KeyPair> createUniqueKeyPair,
Function<RegionNameAndIngressRules, String> createSecurityGroupIfNeeded,
Provider<RunInstancesOptions> optionsProvider, CreatePlacementGroupIfNeeded createPlacementGroupIfNeeded,
public CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions(Map<RegionAndName, KeyPair> knownKeys,
Cache<RegionAndName, KeyPair> credentialsMap,
@Named("SECURITY") Cache<RegionAndName, String> securityGroupMap,
Provider<RunInstancesOptions> optionsProvider,
@Named("PLACEMENT") Cache<RegionAndName, String> placementGroupMap,
CreatePlacementGroupIfNeeded createPlacementGroupIfNeeded,
Function<RegionNameAndPublicKeyMaterial, KeyPair> importExistingKeyPair) {
super(credentialsMap, securityGroupMap, createUniqueKeyPair, createSecurityGroupIfNeeded, optionsProvider);
super(knownKeys, credentialsMap, securityGroupMap, optionsProvider);
this.placementGroupMap = placementGroupMap;
this.createPlacementGroupIfNeeded = createPlacementGroupIfNeeded;
this.importExistingKeyPair = importExistingKeyPair;
@ -110,9 +110,8 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions
// http://docs.amazonwebservices.com/AWSEC2/latest/UserGuide/index.html?using_cluster_computing.html
placementGroupName = String.format("jclouds#%s#%s", group, region);
RegionAndName regionAndName = new RegionAndName(region, placementGroupName);
if (!placementGroupMap.containsKey(regionAndName)) {
placementGroupMap.put(regionAndName, createPlacementGroupIfNeeded.apply(regionAndName));
}
// make this entry as needed
placementGroupMap.getUnchecked(regionAndName);
}
return placementGroupName;
}
@ -120,7 +119,7 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions
@Override
protected String createOrImportKeyPair(String region, String group, TemplateOptions options) {
RegionAndName key = new RegionAndName(region, "jclouds#" + group);
KeyPair pair = credentialsMap.get(key);
KeyPair pair = knownKeys.get(key);
if (pair != null)
return pair.getKeyName();
if (and(hasPublicKeyMaterial, or(doesntNeedSshAfterImportingPublicKey, hasLoginCredential)).apply(options)) {
@ -128,12 +127,12 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions
options.dontAuthorizePublicKey();
if (hasLoginCredential.apply(options))
pair = pair.toBuilder().keyMaterial(options.getOverridingCredentials().credential).build();
credentialsMap.put(key, pair);
knownKeys.put(key, pair);
} else {
if (hasPublicKeyMaterial.apply(options)) {
logger.warn("to avoid creating temporary keys in aws-ec2, use templateOption overrideLoginCredentialWith(id_rsa)");
}
return createUniqueKeyPairAndPutIntoMap(region, group);
return super.createOrImportKeyPair(region, group, options);
}
return pair.getKeyName();
}

View File

@ -47,6 +47,9 @@ import com.google.common.base.Function;
import com.google.common.base.Splitter;
import com.google.common.base.Supplier;
import com.google.common.base.Throwables;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
@ -58,12 +61,13 @@ import com.google.common.util.concurrent.Futures;
* @author Adrian Cole
*/
@Singleton
public class AWSRegionAndNameToImageSupplier implements Supplier<Map<RegionAndName, ? extends Image>> {
public class AWSRegionAndNameToImageSupplier implements Supplier<Cache<RegionAndName, ? extends Image>> {
@Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL;
private final Map<RegionAndName, Image> images;
private final Map<RegionAndName, Image> knownImages;
private final CacheLoader<RegionAndName, Image> regionAndIdToImage;
private final Set<String> clusterComputeIds;
private final CallForImages.Factory factory;
private final ExecutorService executor;
@ -73,10 +77,11 @@ public class AWSRegionAndNameToImageSupplier implements Supplier<Map<RegionAndNa
private final Iterable<String> clusterRegions;
private final String ccAmiQuery;
@Inject
protected AWSRegionAndNameToImageSupplier(@Region Set<String> regions,
@Named(PROPERTY_EC2_AMI_QUERY) String amiQuery, @Named(PROPERTY_EC2_CC_REGIONS) String clusterRegions,
@Named(PROPERTY_EC2_CC_AMI_QUERY) String ccAmiQuery, Map<RegionAndName, Image> images,
@Named(PROPERTY_EC2_CC_AMI_QUERY) String ccAmiQuery, Map<RegionAndName, Image> knownImages, CacheLoader<RegionAndName, Image> regionAndIdToImage,
CallForImages.Factory factory, @ClusterCompute Set<String> clusterComputeIds,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) {
this.factory = factory;
@ -84,13 +89,14 @@ public class AWSRegionAndNameToImageSupplier implements Supplier<Map<RegionAndNa
this.amiQuery = amiQuery;
this.clusterRegions = Splitter.on(',').split(clusterRegions);
this.ccAmiQuery = ccAmiQuery;
this.images = images;
this.knownImages = knownImages;
this.regionAndIdToImage=regionAndIdToImage;
this.clusterComputeIds = clusterComputeIds;
this.executor = executor;
}
@Override
public Map<RegionAndName, ? extends Image> get() {
public Cache<RegionAndName, ? extends Image> get() {
Future<Iterable<Image>> normalImages = images(regions, amiQuery, PROPERTY_EC2_AMI_QUERY);
ImmutableSet<Image> clusterImages;
try {
@ -115,8 +121,8 @@ public class AWSRegionAndNameToImageSupplier implements Supplier<Map<RegionAndNa
Throwables.propagate(e);
return null;
}
images.putAll(uniqueIndex(parsedImages, new Function<Image, RegionAndName>() {
knownImages.clear();
knownImages.putAll(uniqueIndex(parsedImages, new Function<Image, RegionAndName>() {
@Override
public RegionAndName apply(Image from) {
@ -124,7 +130,13 @@ public class AWSRegionAndNameToImageSupplier implements Supplier<Map<RegionAndNa
}
}));
return images;
logger.debug("<< images(%d)", knownImages.size());
Cache<RegionAndName, Image> cache = CacheBuilder.newBuilder().build(regionAndIdToImage);
// seed the cache
for (RegionAndName image : knownImages.keySet()){
cache.getUnchecked(image);
}
return cache;
}
private Future<Iterable<Image>> images(Iterable<String> regions, String query, String tag) {

View File

@ -88,7 +88,7 @@ public class AWSEC2TemplateBuilderLiveTest extends BaseTemplateBuilderLiveTest {
.build();
assert (template.getImage().getProviderId().startsWith("ami-")) : template;
assertEquals(template.getImage().getOperatingSystem().getVersion(), "11.10");
assertEquals(template.getImage().getOperatingSystem().getVersion(), "11.04");
assertEquals(template.getImage().getOperatingSystem().is64Bit(), false);
assertEquals(template.getImage().getOperatingSystem().getFamily(), OsFamily.UBUNTU);
assertEquals(template.getImage().getUserMetadata().get("rootDeviceType"), "instance-store");
@ -107,7 +107,7 @@ public class AWSEC2TemplateBuilderLiveTest extends BaseTemplateBuilderLiveTest {
.build();
assert (template.getImage().getProviderId().startsWith("ami-")) : template;
assertEquals(template.getImage().getOperatingSystem().getVersion(), "11.10");
assertEquals(template.getImage().getOperatingSystem().getVersion(), "11.04");
assertEquals(template.getImage().getOperatingSystem().is64Bit(), false);
assertEquals(template.getImage().getOperatingSystem().getFamily(), OsFamily.UBUNTU);
assertEquals(template.getImage().getUserMetadata().get("rootDeviceType"), "instance-store");
@ -183,7 +183,7 @@ public class AWSEC2TemplateBuilderLiveTest extends BaseTemplateBuilderLiveTest {
fastestTemplate = context.getComputeService().templateBuilder().fastest().build();
assert (fastestTemplate.getImage().getProviderId().startsWith("ami-")) : fastestTemplate;
assertEquals(fastestTemplate.getHardware().getProviderId(), InstanceType.CC1_4XLARGE);
assertEquals(fastestTemplate.getImage().getOperatingSystem().getVersion(), "11.10");
assertEquals(fastestTemplate.getImage().getOperatingSystem().getVersion(), "11.04");
assertEquals(fastestTemplate.getImage().getOperatingSystem().is64Bit(), true);
assertEquals(fastestTemplate.getImage().getOperatingSystem().getFamily(), OsFamily.UBUNTU);
assertEquals(fastestTemplate.getImage().getUserMetadata().get("rootDeviceType"), "ebs");

View File

@ -45,6 +45,10 @@ import org.testng.annotations.Test;
import com.google.common.base.Function;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
@ -118,7 +122,7 @@ public class AWSRunningInstanceToNodeMetadataTest {
Map<String, Credentials> credentialStore) {
Map<InstanceState, NodeState> instanceToNodeState = EC2ComputeServiceDependenciesModule.instanceToNodeState;
Map<RegionAndName, Image> instanceToImage = Maps.uniqueIndex(images, new Function<Image, RegionAndName>() {
final ImmutableMap<RegionAndName, Image> backing = Maps.uniqueIndex(images, new Function<Image, RegionAndName>() {
@Override
public RegionAndName apply(Image from) {
@ -127,12 +131,22 @@ public class AWSRunningInstanceToNodeMetadataTest {
});
Cache<RegionAndName, Image> instanceToImage = CacheBuilder.newBuilder().build(new CacheLoader<RegionAndName, Image> (){
@Override
public Image load(RegionAndName key) throws Exception {
return backing.get(key);
}
});
return createNodeParser(hardware, locations, credentialStore, instanceToNodeState, instanceToImage);
}
private AWSRunningInstanceToNodeMetadata createNodeParser(final ImmutableSet<Hardware> hardware,
final ImmutableSet<Location> locations, Map<String, Credentials> credentialStore,
Map<InstanceState, NodeState> instanceToNodeState, Map<RegionAndName, Image> instanceToImage) {
Map<InstanceState, NodeState> instanceToNodeState, Cache<RegionAndName, ? extends Image> instanceToImage) {
Supplier<Set<? extends Location>> locationSupplier = new Supplier<Set<? extends Location>>() {
@Override
@ -150,7 +164,8 @@ public class AWSRunningInstanceToNodeMetadataTest {
};
AWSRunningInstanceToNodeMetadata parser = new AWSRunningInstanceToNodeMetadata(instanceToNodeState,
credentialStore, instanceToImage, locationSupplier, hardwareSupplier);
credentialStore, Suppliers.<Cache<RegionAndName, ? extends Image>> ofInstance(instanceToImage),
locationSupplier, hardwareSupplier);
return parser;
}

View File

@ -54,13 +54,14 @@ import org.jclouds.scriptbuilder.domain.Statements;
import org.testng.annotations.Test;
import com.google.common.base.Function;
import com.google.common.cache.Cache;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSet;
/**
* @author Adrian Cole
*/
@Test(groups = "unit")
@Test(groups = "unit", singleThreaded = true, testName = "CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptionsTest")
public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
private static final Provider<RunInstancesOptions> OPTIONS_PROVIDER = new javax.inject.Provider<RunInstancesOptions>() {
@ -385,7 +386,7 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptionsT
}
@Test(expectedExceptions = IllegalStateException.class)
@Test(expectedExceptions = IllegalArgumentException.class)
public void testCreateNewKeyPairUnlessUserSpecifiedOtherwise_reusesKeyWhenToldToWithRunScriptButNoCredentials() {
// setup constants
String region = Region.AP_SOUTHEAST_1;
@ -401,7 +402,7 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptionsT
expect(options.getKeyPair()).andReturn(userSuppliedKeyPair);
expect(options.getOverridingCredentials()).andReturn(null);
expect(options.getRunScript()).andReturn(Statements.exec("echo foo"));
expect(strategy.credentialsMap.containsKey(new RegionAndName(region, userSuppliedKeyPair))).andReturn(false);
expect(strategy.credentialsMap.getUnchecked(new RegionAndName(region, userSuppliedKeyPair))).andThrow(new NullPointerException());
// replay mocks
replay(options);
@ -432,7 +433,7 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptionsT
expect(options.getKeyPair()).andReturn(userSuppliedKeyPair);
expect(options.getOverridingCredentials()).andReturn(null);
expect(options.getRunScript()).andReturn(Statements.exec("echo foo"));
expect(strategy.credentialsMap.containsKey(new RegionAndName(region, userSuppliedKeyPair))).andReturn(true);
expect(strategy.credentialsMap.getUnchecked(new RegionAndName(region, userSuppliedKeyPair))).andReturn(keyPair);
// replay mocks
replay(options);
@ -463,11 +464,13 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptionsT
expect(options.getKeyPair()).andReturn(userSuppliedKeyPair);
expect(options.getOverridingCredentials()).andReturn(new Credentials(null, "MyRsa")).atLeastOnce();
expect(
strategy.credentialsMap.put(new RegionAndName(region, userSuppliedKeyPair), KeyPair.builder()
.region(region).keyName(userSuppliedKeyPair).keyFingerprint("//TODO").keyMaterial("MyRsa").build()))
.andReturn(null);
strategy.knownKeys.put(
new RegionAndName(region, tag),
KeyPair.builder().region(region).keyName(userSuppliedKeyPair).keyFingerprint("//TODO")
.keyMaterial("MyRsa").build())).andReturn(null);
strategy.credentialsMap.invalidate(new RegionAndName(region, tag));
expect(options.getRunScript()).andReturn(Statements.exec("echo foo"));
expect(strategy.credentialsMap.containsKey(new RegionAndName(region, userSuppliedKeyPair))).andReturn(true);
expect(strategy.credentialsMap.getUnchecked(new RegionAndName(region, userSuppliedKeyPair))).andReturn(keyPair);
// replay mocks
replay(options);
@ -483,6 +486,7 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptionsT
verifyStrategy(strategy);
}
@Test(enabled = false)
public void testCreateNewKeyPairUnlessUserSpecifiedOtherwise_importsKeyPairAndUnsetsTemplateInstructionWhenPublicKeySuppliedAndAddsCredentialToMapWhenOverridingCredsAreSet() {
// setup constants
String region = Region.AP_SOUTHEAST_1;
@ -496,18 +500,19 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptionsT
KeyPair keyPair = new KeyPair(region, "jclouds#" + group, "fingerprint", null);
// setup expectations
expect(strategy.knownKeys.get(new RegionAndName(region, "jclouds#" + group))).andReturn(null);
expect(options.getKeyPair()).andReturn(userSuppliedKeyPair);
expect(options.shouldAutomaticallyCreateKeyPair()).andReturn(shouldAutomaticallyCreateKeyPair);
expect(strategy.credentialsMap.get(new RegionAndName(region, "jclouds#" + group))).andReturn(null);
expect(strategy.credentialsMap.getUnchecked(new RegionAndName(region, "jclouds#" + group))).andThrow(new NullPointerException());
expect(options.getPublicKey()).andReturn("ssh-rsa").times(2);
expect(strategy.importExistingKeyPair.apply(new RegionNameAndPublicKeyMaterial(region, group, "ssh-rsa")))
.andReturn(keyPair);
expect(options.dontAuthorizePublicKey()).andReturn(options);
expect(options.getOverridingCredentials()).andReturn(new Credentials("foo", "bar")).times(3);
expect(options.getRunScript()).andReturn(null).times(2);
expect(options.getPrivateKey()).andReturn(null);
expect(options.dontAuthorizePublicKey()).andReturn(options);
expect(
strategy.credentialsMap.put(new RegionAndName(region, "jclouds#" + group),
strategy.knownKeys.put(new RegionAndName(region, "jclouds#" + group),
keyPair.toBuilder().keyMaterial("bar").build())).andReturn(null);
// replay mocks
@ -522,6 +527,7 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptionsT
verifyStrategy(strategy);
}
@Test(enabled = false)
public void testCreateNewKeyPairUnlessUserSpecifiedOtherwise_importsKeyPairAndUnsetsTemplateInstructionWhenPublicKeySupplied() {
// setup constants
String region = Region.AP_SOUTHEAST_1;
@ -535,9 +541,10 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptionsT
KeyPair keyPair = new KeyPair(region, "jclouds#" + group, "fingerprint", null);
// setup expectations
expect(strategy.knownKeys.get(new RegionAndName(region, "jclouds#" + group))).andReturn(null);
expect(options.getKeyPair()).andReturn(userSuppliedKeyPair);
expect(options.shouldAutomaticallyCreateKeyPair()).andReturn(shouldAutomaticallyCreateKeyPair);
expect(strategy.credentialsMap.get(new RegionAndName(region, "jclouds#" + group))).andReturn(null);
expect(strategy.credentialsMap.getUnchecked(new RegionAndName(region, "jclouds#" + group))).andThrow(new NullPointerException());
expect(options.getPublicKey()).andReturn("ssh-rsa").times(2);
expect(strategy.importExistingKeyPair.apply(new RegionNameAndPublicKeyMaterial(region, group, "ssh-rsa")))
.andReturn(keyPair);
@ -545,7 +552,7 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptionsT
expect(options.getOverridingCredentials()).andReturn(null);
expect(options.getRunScript()).andReturn(null).times(2);
expect(options.getPrivateKey()).andReturn(null);
expect(strategy.credentialsMap.put(new RegionAndName(region, "jclouds#" + group), keyPair)).andReturn(null);
expect(strategy.knownKeys.put(new RegionAndName(region, "jclouds#" + group), keyPair)).andReturn(null);
// replay mocks
replay(options);
@ -573,16 +580,13 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptionsT
KeyPair keyPair = createMock(KeyPair.class);
// setup expectations
expect(strategy.knownKeys.get(new RegionAndName(region, "jclouds#" + group))).andReturn(null);
expect(options.getKeyPair()).andReturn(userSuppliedKeyPair);
expect(options.shouldAutomaticallyCreateKeyPair()).andReturn(shouldAutomaticallyCreateKeyPair);
expect(strategy.credentialsMap.get(new RegionAndName(region, "jclouds#" + group))).andReturn(null);
expect(strategy.credentialsMap.getUnchecked(new RegionAndName(region, group))).andReturn(keyPair);
expect(options.getPublicKey()).andReturn(null).times(2);
expect(strategy.createUniqueKeyPair.apply(new RegionAndName(region, group))).andReturn(keyPair);
expect(keyPair.getRegion()).andReturn(region).atLeastOnce();
expect(keyPair.getKeyName()).andReturn(systemGeneratedKeyPairName).atLeastOnce();
expect(options.getRunScript()).andReturn(null);
expect(strategy.credentialsMap.put(new RegionAndName(region, systemGeneratedKeyPairName), keyPair)).andReturn(
null);
// replay mocks
replay(options);
@ -613,10 +617,10 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptionsT
KeyPair keyPair = createMock(KeyPair.class);
// setup expectations
expect(strategy.knownKeys.get(new RegionAndName(region, "jclouds#" + group))).andReturn(keyPair);
expect(options.getKeyPair()).andReturn(userSuppliedKeyPair);
expect(options.getRunScript()).andReturn(null);
expect(options.shouldAutomaticallyCreateKeyPair()).andReturn(shouldAutomaticallyCreateKeyPair);
expect(strategy.credentialsMap.get(new RegionAndName(region, "jclouds#" + group))).andReturn(keyPair);
expect(keyPair.getKeyName()).andReturn(systemGeneratedKeyPairName).atLeastOnce();
// replay mocks
replay(options);
@ -673,7 +677,6 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptionsT
Set<String> groupNames = ImmutableSet.<String> of();
int[] ports = new int[] {};
boolean shouldAuthorizeSelf = true;
boolean groupExisted = false;
Set<String> returnVal = ImmutableSet.<String> of(generatedMarkerGroup);
// create mocks
@ -686,9 +689,7 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptionsT
expect(options.getInboundPorts()).andReturn(ports).atLeastOnce();
RegionNameAndIngressRules regionNameAndIngressRules = new RegionNameAndIngressRules(region, generatedMarkerGroup,
ports, shouldAuthorizeSelf);
expect(strategy.securityGroupMap.containsKey(regionNameAndIngressRules)).andReturn(groupExisted);
expect(strategy.createSecurityGroupIfNeeded.apply(regionNameAndIngressRules)).andReturn(generatedMarkerGroup);
expect(strategy.securityGroupMap.put(regionNameAndIngressRules, generatedMarkerGroup)).andReturn(null);
expect(strategy.securityGroupMap.getUnchecked(regionNameAndIngressRules)).andReturn(group);
// replay mocks
replay(options);
@ -710,7 +711,6 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptionsT
Set<String> groupNames = ImmutableSet.<String> of();
int[] ports = new int[] { 22, 80 };
boolean shouldAuthorizeSelf = true;
boolean groupExisted = false;
Set<String> returnVal = ImmutableSet.<String> of(generatedMarkerGroup);
// create mocks
@ -723,9 +723,7 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptionsT
expect(options.getInboundPorts()).andReturn(ports).atLeastOnce();
RegionNameAndIngressRules regionNameAndIngressRules = new RegionNameAndIngressRules(region, generatedMarkerGroup,
ports, shouldAuthorizeSelf);
expect(strategy.securityGroupMap.containsKey(regionNameAndIngressRules)).andReturn(groupExisted);
expect(strategy.createSecurityGroupIfNeeded.apply(regionNameAndIngressRules)).andReturn(generatedMarkerGroup);
expect(strategy.securityGroupMap.put(regionNameAndIngressRules, generatedMarkerGroup)).andReturn(null);
expect(strategy.securityGroupMap.getUnchecked(regionNameAndIngressRules)).andReturn(generatedMarkerGroup);
// replay mocks
replay(options);
@ -747,7 +745,6 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptionsT
Set<String> groupNames = ImmutableSet.<String> of();
int[] ports = new int[] {};
boolean shouldAuthorizeSelf = true;
boolean groupExisted = true;
Set<String> returnVal = ImmutableSet.<String> of(generatedMarkerGroup);
// create mocks
@ -760,7 +757,7 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptionsT
expect(options.getInboundPorts()).andReturn(ports).atLeastOnce();
RegionNameAndIngressRules regionNameAndIngressRules = new RegionNameAndIngressRules(region, generatedMarkerGroup,
ports, shouldAuthorizeSelf);
expect(strategy.securityGroupMap.containsKey(regionNameAndIngressRules)).andReturn(groupExisted);
expect(strategy.securityGroupMap.getUnchecked(regionNameAndIngressRules)).andReturn(generatedMarkerGroup);
// replay mocks
replay(options);
@ -793,13 +790,9 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptionsT
expect(options.getGroupIds()).andReturn(ImmutableSet.<String>of());
expect(options.getGroups()).andReturn(groupNames).atLeastOnce();
RegionNameAndIngressRules regionNameAndIngressRules = new RegionNameAndIngressRules(region, generatedMarkerGroup,
ports, shouldAuthorizeSelf); // note
// this
// works
// since
// there's
// no equals on portsq
expect(strategy.securityGroupMap.containsKey(regionNameAndIngressRules)).andReturn(groupExisted);
ports, shouldAuthorizeSelf);
expect(strategy.securityGroupMap.getUnchecked(regionNameAndIngressRules)).andReturn(groupExisted ? "tag" : null);
// replay mocks
replay(options);
@ -832,13 +825,9 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptionsT
expect(options.getGroupIds()).andReturn(ImmutableSet.<String>of("group1", "group2"));
expect(options.getGroups()).andReturn(groupNames).atLeastOnce();
RegionNameAndIngressRules regionNameAndIngressRules = new RegionNameAndIngressRules(region, generatedMarkerGroup,
ports, shouldAuthorizeSelf); // note
// this
// works
// since
// there's
// no equals on portsq
expect(strategy.securityGroupMap.containsKey(regionNameAndIngressRules)).andReturn(groupExisted);
ports, shouldAuthorizeSelf);
expect(strategy.securityGroupMap.getUnchecked(regionNameAndIngressRules)).andReturn(groupExisted ? "tag" : null);
// replay mocks
replay(options);
@ -895,11 +884,7 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptionsT
// setup expectations
expect(options.getPlacementGroup()).andReturn(userSuppliedPlacementGroup);
expect(options.shouldAutomaticallyCreatePlacementGroup()).andReturn(shouldAutomaticallyCreatePlacementGroup);
expect(strategy.placementGroupMap.containsKey(new RegionAndName(region, generatedMarkerGroup))).andReturn(false);
expect(strategy.createPlacementGroupIfNeeded.apply(new RegionAndName(region, generatedMarkerGroup))).andReturn(
generatedMarkerGroup);
expect(strategy.placementGroupMap.put(new RegionAndName(region, generatedMarkerGroup), generatedMarkerGroup))
.andReturn(null);
expect(strategy.placementGroupMap.getUnchecked(new RegionAndName(region, generatedMarkerGroup))).andReturn(generatedMarkerGroup);
// replay mocks
replay(options);
@ -946,37 +931,33 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptionsT
}
private void verifyStrategy(CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions strategy) {
verify(strategy.knownKeys);
verify(strategy.credentialsMap);
verify(strategy.securityGroupMap);
verify(strategy.placementGroupMap);
verify(strategy.createUniqueKeyPair);
verify(strategy.importExistingKeyPair);
verify(strategy.createSecurityGroupIfNeeded);
verify(strategy.createPlacementGroupIfNeeded);
}
@SuppressWarnings("unchecked")
private CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions setupStrategy() {
Map<RegionAndName, KeyPair> credentialsMap = createMock(Map.class);
Map<RegionAndName, String> securityGroupMap = createMock(Map.class);
Map<RegionAndName, String> placementGroupMap = createMock(Map.class);
Function<RegionAndName, KeyPair> createOrGetKeyPair = createMock(Function.class);
Function<RegionNameAndIngressRules, String> createSecurityGroupIfNeeded = createMock(Function.class);
Map<RegionAndName, KeyPair> knownKeys = createMock(Map.class);
Cache<RegionAndName, KeyPair> credentialsMap = createMock(Cache.class);
Cache<RegionAndName, String> securityGroupMap = createMock(Cache.class);
Cache<RegionAndName, String> placementGroupMap = createMock(Cache.class);
Function<RegionNameAndPublicKeyMaterial, KeyPair> importExistingKeyPair = createMock(Function.class);
CreatePlacementGroupIfNeeded createPlacementGroupIfNeeded = createMock(CreatePlacementGroupIfNeeded.class);
return new CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions(credentialsMap, securityGroupMap,
placementGroupMap, createOrGetKeyPair, createSecurityGroupIfNeeded, OPTIONS_PROVIDER,
createPlacementGroupIfNeeded, importExistingKeyPair);
return new CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions(knownKeys, credentialsMap, securityGroupMap,
OPTIONS_PROVIDER, placementGroupMap, createPlacementGroupIfNeeded, importExistingKeyPair);
}
private void replayStrategy(CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions strategy) {
replay(strategy.knownKeys);
replay(strategy.credentialsMap);
replay(strategy.securityGroupMap);
replay(strategy.placementGroupMap);
replay(strategy.createUniqueKeyPair);
replay(strategy.importExistingKeyPair);
replay(strategy.createSecurityGroupIfNeeded);
replay(strategy.createPlacementGroupIfNeeded);
}

View File

@ -25,10 +25,14 @@ import java.net.URI;
import java.util.Map;
import java.util.Properties;
import javax.inject.Singleton;
import org.jclouds.aws.domain.Region;
import org.jclouds.aws.ec2.config.AWSEC2RestClientModule;
import org.jclouds.aws.filters.FormSigner;
import org.jclouds.compute.domain.Image;
import org.jclouds.date.DateService;
import org.jclouds.ec2.compute.domain.RegionAndName;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.RequiresHttp;
import org.jclouds.rest.ConfiguresRestClient;
@ -38,8 +42,12 @@ import org.jclouds.rest.RestContextSpec;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.collect.ImmutableMap;
import com.google.inject.Module;
import com.google.inject.Provides;
/**
* @author Adrian Cole
@ -60,6 +68,18 @@ public abstract class BaseAWSEC2AsyncClientTest<T> extends RestClientTest<T> {
bindRegionsToProvider(Regions.class);
}
@Provides
@Singleton
Cache<RegionAndName, Image> provide(){
return CacheBuilder.newBuilder().build(new CacheLoader<RegionAndName, Image>() {
@Override
public Image load(RegionAndName key) throws Exception {
return null;
}
});
}
static class Regions implements javax.inject.Provider<Map<String, URI>> {
@Override
public Map<String, URI> get() {

View File

@ -32,7 +32,6 @@ import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.Constants;
import org.jclouds.cloudsigma.CloudSigmaAsyncClient;
import org.jclouds.cloudsigma.CloudSigmaClient;
import org.jclouds.cloudsigma.domain.Device;
import org.jclouds.cloudsigma.domain.DriveInfo;
@ -60,33 +59,35 @@ import org.jclouds.logging.Logger;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.cache.Cache;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSet.Builder;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.UncheckedExecutionException;
/**
* defines the connection between the {@link CloudSigmaClient} implementation and the jclouds
* {@link ComputeService}
* defines the connection between the {@link CloudSigmaClient} implementation
* and the jclouds {@link ComputeService}
*
*/
@Singleton
public class CloudSigmaComputeServiceAdapter implements
ComputeServiceAdapter<ServerInfo, Hardware, DriveInfo, Location> {
ComputeServiceAdapter<ServerInfo, Hardware, DriveInfo, Location> {
private static final Predicate<DriveInfo> PREINSTALLED_DISK = Predicates.and(Predicates.notNull(),
new Predicate<DriveInfo>() {
new Predicate<DriveInfo>() {
@Override
public boolean apply(DriveInfo drive) {
return drive.getType().equals(DriveType.DISK) && drive.getDriveType().contains("preinstalled");
}
@Override
public boolean apply(DriveInfo drive) {
return drive.getType().equals(DriveType.DISK) && drive.getDriveType().contains("preinstalled");
}
});
});
private final CloudSigmaClient client;
private final CloudSigmaAsyncClient aclient;
private final Predicate<DriveInfo> driveNotClaimed;
private final JustProvider locationSupplier;
private final String defaultVncPassword;
private final Map<String, DriveInfo> cache;
private final Cache<String, DriveInfo> cache;
private final ExecutorService executor;
@Resource
@ -94,12 +95,10 @@ public class CloudSigmaComputeServiceAdapter implements
protected Logger logger = Logger.NULL;
@Inject
public CloudSigmaComputeServiceAdapter(CloudSigmaClient client, CloudSigmaAsyncClient aclient,
Predicate<DriveInfo> driveNotClaimed, JustProvider locationSupplier,
@Named(CloudSigmaConstants.PROPERTY_VNC_PASSWORD) String defaultVncPassword, Map<String, DriveInfo> cache,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) {
public CloudSigmaComputeServiceAdapter(CloudSigmaClient client, Predicate<DriveInfo> driveNotClaimed,
JustProvider locationSupplier, @Named(CloudSigmaConstants.PROPERTY_VNC_PASSWORD) String defaultVncPassword,
Cache<String, DriveInfo> cache, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) {
this.client = checkNotNull(client, "client");
this.aclient = checkNotNull(aclient, "aclient");
this.driveNotClaimed = checkNotNull(driveNotClaimed, "driveNotClaimed");
this.locationSupplier = checkNotNull(locationSupplier, "locationSupplier");
this.defaultVncPassword = checkNotNull(defaultVncPassword, "defaultVncPassword");
@ -109,21 +108,20 @@ public class CloudSigmaComputeServiceAdapter implements
@Override
public ServerInfo createNodeWithGroupEncodedIntoNameThenStoreCredentials(String tag, String name, Template template,
Map<String, Credentials> credentialStore) {
Map<String, Credentials> credentialStore) {
long bootSize = (long) (template.getHardware().getVolumes().get(0).getSize() * 1024 * 1024 * 1024l);
logger.debug(">> imaging boot drive source(%s) bytes(%d)", template.getImage().getId(), bootSize);
DriveInfo drive = client.cloneDrive(template.getImage().getId(), template.getImage().getId(),
new CloneDriveOptions().size(bootSize));
new CloneDriveOptions().size(bootSize));
boolean success = driveNotClaimed.apply(drive);
logger.debug("<< image(%s) complete(%s)", drive.getUuid(), success);
if (!success) {
client.destroyDrive(drive.getUuid());
throw new IllegalStateException("could not image drive in time!");
}
cache.put(drive.getUuid(), drive);
Server toCreate = Servers.small(name, drive.getUuid(), defaultVncPassword).mem(template.getHardware().getRam())
.cpu((int) (template.getHardware().getProcessors().get(0).getSpeed())).build();
.cpu((int) (template.getHardware().getProcessors().get(0).getSpeed())).build();
logger.debug(">> creating server");
ServerInfo from = client.createServer(toCreate);
@ -131,7 +129,7 @@ public class CloudSigmaComputeServiceAdapter implements
logger.debug(">> starting server(%s)", from.getUuid());
client.startServer(from.getUuid());
// store the credentials so that later functions can use them
credentialStore.put("node#"+ from.getUuid(), new Credentials("cloudsigma", "cloudsigma"));
credentialStore.put("node#" + from.getUuid(), new Credentials("root", defaultVncPassword));
return from;
}
@ -155,30 +153,39 @@ public class CloudSigmaComputeServiceAdapter implements
return "sizeLessThanOrEqual(" + size + ")";
}
}).ids(id).ram(ram).processors(ImmutableList.of(new Processor(1, cpu))).volumes(
ImmutableList.<Volume> of(new VolumeImpl(size, true, true))).build());
}).ids(id).ram(ram).processors(ImmutableList.of(new Processor(1, cpu)))
.volumes(ImmutableList.<Volume> of(new VolumeImpl(size, true, true))).build());
}
return hardware.build();
}
/**
* look up the current standard images and do not error out, if they are not found.
* look up the current standard images and do not error out, if they are not
* found.
*/
@Override
public Iterable<DriveInfo> listImages() {
Iterable<DriveInfo> drives = transformParallel(client.listStandardDrives(),
new Function<String, Future<DriveInfo>>() {
new Function<String, Future<DriveInfo>>() {
@Override
public Future<DriveInfo> apply(String input) {
return aclient.getDriveInfo(input);
@Override
public Future<DriveInfo> apply(String input) {
try {
return Futures.immediateFuture(cache.getUnchecked(input));
} catch (NullPointerException e) {
logger.debug("drive %s not found", input);
} catch (UncheckedExecutionException e) {
logger.warn(e, "error finding drive %s: %s", input, e.getMessage());
}
return Futures.immediateFuture(null);
}
}, executor, null, logger, "drives");
Iterable<DriveInfo> returnVal = filter(drives, PREINSTALLED_DISK);
for (DriveInfo drive : returnVal)
cache.put(drive.getUuid(), drive);
return returnVal;
@Override
public String toString() {
return "seedDriveCache()";
}
}, executor, null, logger, "drives");
return filter(drives, PREINSTALLED_DISK);
}
@SuppressWarnings("unchecked")

View File

@ -25,6 +25,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Singleton;
@ -45,13 +46,16 @@ import org.jclouds.compute.domain.Volume;
import org.jclouds.compute.domain.VolumeBuilder;
import org.jclouds.domain.Credentials;
import org.jclouds.domain.Location;
import org.jclouds.logging.Logger;
import com.google.common.base.Function;
import com.google.common.base.Supplier;
import com.google.common.cache.Cache;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.util.concurrent.UncheckedExecutionException;
/**
* @author Adrian Cole
@ -113,10 +117,13 @@ public class ServerInfoToNodeMetadata implements Function<ServerInfo, NodeMetada
@Singleton
public static final class DeviceToVolume implements Function<Device, Volume> {
private final Map<String, DriveInfo> cache;
@Resource
protected Logger logger = Logger.NULL;
private final Cache<String, DriveInfo> cache;
@Inject
public DeviceToVolume(Map<String, DriveInfo> cache) {
public DeviceToVolume(Cache<String, DriveInfo> cache) {
this.cache = checkNotNull(cache, "cache");
}
@ -124,9 +131,13 @@ public class ServerInfoToNodeMetadata implements Function<ServerInfo, NodeMetada
public Volume apply(Device input) {
VolumeBuilder builder = new VolumeBuilder();
builder.id(input.getId());
DriveInfo drive = cache.get(input.getDriveUuid());
if (drive != null) {
try {
DriveInfo drive = cache.getUnchecked(input.getDriveUuid());
builder.size(drive.getSize() / 1024 / 1024f);
} catch (NullPointerException e) {
logger.debug("drive %s not found", input.getDriveUuid());
} catch (UncheckedExecutionException e) {
logger.warn(e, "error finding drive %s: %s", input.getDriveUuid(), e.getMessage());
}
return new VolumeBuilder().durable(true).type(Volume.Type.NAS).build();
}
@ -141,10 +152,13 @@ public class ServerInfoToNodeMetadata implements Function<ServerInfo, NodeMetada
*/
@Singleton
public static class GetImageIdFromServer implements Function<Server, String> {
private final Map<String, DriveInfo> cache;
@Resource
protected Logger logger = Logger.NULL;
private final Cache<String, DriveInfo> cache;
@Inject
public GetImageIdFromServer(Map<String, DriveInfo> cache) {
public GetImageIdFromServer(Cache<String, DriveInfo> cache) {
this.cache = cache;
}
@ -155,9 +169,12 @@ public class ServerInfoToNodeMetadata implements Function<ServerInfo, NodeMetada
Device bootDevice = from.getDevices().get(bootDeviceId);
if (bootDevice != null) {
try {
imageId = cache.get(bootDevice.getDriveUuid()).getName();
DriveInfo drive = cache.getUnchecked(bootDevice.getDriveUuid());
imageId = drive.getName();
} catch (NullPointerException e) {
logger.debug("drive %s not found", bootDevice.getDriveUuid());
} catch (UncheckedExecutionException e) {
logger.warn(e, "error finding drive %s: %s", bootDevice.getDriveUuid(), e.getMessage());
}
}
return imageId;