/**
* Copyright (C) 2008 - Abiquo Holdings S.L. All rights reserved.
*
* Please see /opt/abiquo/tomcat/webapps/legal/ on Abiquo server
* or contact contact@abiquo.com for licensing information.
*/
package com.abiquo.hypervisor.plugin;
import static com.abiquo.hypervisor.plugin.predicate.PluginManagerPredicates.mandatoryFields;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.base.Strings.isNullOrEmpty;
import static com.google.common.collect.ImmutableMap.copyOf;
import static com.google.common.collect.Iterables.all;
import static com.google.common.collect.Iterables.filter;
import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Maps.filterKeys;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.ServiceLoader;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.abiquo.hypervisor.model.ConnectionData;
import com.abiquo.hypervisor.model.enumerator.ConstraintKey;
import com.abiquo.hypervisor.model.enumerator.DiskFormatType;
import com.abiquo.hypervisor.model.provider.Region;
import com.abiquo.hypervisor.plugin.annotation.AgentConnectionMetadata;
import com.abiquo.hypervisor.plugin.annotation.CloudProviderConnectionMetadata;
import com.abiquo.hypervisor.plugin.annotation.HostConnectionMetadata;
import com.abiquo.hypervisor.plugin.annotation.HypervisorMetadata;
import com.abiquo.hypervisor.plugin.annotation.ManagerConnectionMetadata;
import com.abiquo.hypervisor.plugin.enumerator.FieldConstraint;
import com.abiquo.hypervisor.plugin.exception.ComputeException;
import com.abiquo.hypervisor.plugin.exception.HypervisorPluginError;
import com.abiquo.hypervisor.plugin.exception.HypervisorPluginException;
import com.abiquo.hypervisor.plugin.internal.IsSupported;
import com.abiquo.hypervisor.plugin.internal.Plugin;
import com.abiquo.hypervisor.plugin.internal.PluginInvocationHandler;
import com.abiquo.hypervisor.plugin.internal.TryInvocationHandler;
import com.fasterxml.classmate.ResolvedType;
import com.fasterxml.classmate.TypeResolver;
import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Collections2;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMap.Builder;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.common.reflect.Reflection;
/**
* Hold {@link ICompute} instances loaded using a {@link ServiceLoader}
*/
public class PluginManager
{
private final static Logger LOG = LoggerFactory.getLogger(PluginManager.class);
private final static TypeResolver typeResolver = new TypeResolver();
private static PluginManager instance;
private final PluginAccessControl plugins;
private class LoadedPlugin
{
private final Class<IConnection> connectionClass;
private final Plugin proxy;
private final HypervisorMetadata metadata;
private final Map<ConstraintKey, String> constraints;
private final Pluggable computableObject;
private final IsSupported triable;
public LoadedPlugin(final String type, final Class<IConnection> connectionClass,
final Pluggable computableObject)
{
this.computableObject = computableObject;
this.connectionClass = connectionClass;
this.proxy =
Reflection.newProxy(Plugin.class, new PluginInvocationHandler(computableObject));
this.metadata = computableObject.getClass().getAnnotation(HypervisorMetadata.class);
this.triable =
Reflection.newProxy(IsSupported.class, new TryInvocationHandler(computableObject,
type));
this.constraints = copyOf(loadConstraints(computableObject, triable));
}
}
/**
* Stores the plugins and the white list.
* <p>
* The plugin white list is mutable and controlled by the Abiquo licenses. Any access to get a
* plugin instance must be "approved" by the whitelist; otherwise the plugin is not returned.
*/
private class PluginAccessControl
{
private final Map<String, LoadedPlugin> instances;
private final Set<String> whiteList;
public PluginAccessControl(final Map<String, LoadedPlugin> instances)
{
this.instances = Collections.unmodifiableMap(instances);
this.whiteList = Collections.synchronizedSet(new HashSet<String>(instances.keySet()));
}
public Set<String> loadedTypes()
{
synchronized (whiteList)
{
return Sets.intersection(whiteList, instances.keySet());
}
}
public Collection<LoadedPlugin> loadedPlugins()
{
synchronized (whiteList)
{
return filterKeys(instances, Predicates.in(whiteList)).values();
}
}
public boolean has(final String type)
{
return whiteList.contains(type) && instances.containsKey(type);
}
public Optional<LoadedPlugin> tryGet(final String type)
{
return has(type) ? Optional.of(instances.get(type)) : Optional.<LoadedPlugin> absent();
}
public void setEnabledPlugins(final Collection<String> types)
{
synchronized (whiteList)
{
whiteList.clear();
whiteList.addAll(types);
}
}
public void enableAllPlugins()
{
setEnabledPlugins(instances.keySet());
}
}
private PluginManager()
{
Map<String, LoadedPlugin> loadedPlugins = Maps.newHashMap();
for (ICompute< ? > pluggable : ServiceLoader.load(ICompute.class))
{
Optional<ImmutableMap<String, LoadedPlugin>> plugin = loadPlugin(pluggable);
if (plugin.isPresent())
{
add(loadedPlugins, plugin);
}
}
plugins = new PluginAccessControl(loadedPlugins);
}
private void add(final Map<String, LoadedPlugin> plugins,
final Optional<ImmutableMap<String, LoadedPlugin>> plugin)
{
for (Entry<String, LoadedPlugin> e : plugin.get().entrySet())
{
checkDuplicatedPlugins(plugins, e.getKey());
plugins.put(e.getKey(), e.getValue());
}
}
/** Only one instance per computable plugin. */
private void checkDuplicatedPlugins(final Map<String, LoadedPlugin> plugins, final String type)
{
if (plugins.containsKey(type))
{
String message =
String.format("A plugin for hypervisor/cloud provider %s has been already loaded",
type);
LOG.error(message);
throw new IllegalStateException(message);
}
}
/**
* Returns the {@link PluginManager} singleton instance
*
* @return the singleton instance
*/
public static PluginManager getInstance()
{
if (instance == null)
{
throw new IllegalStateException("PluginManager not initialized. That indicates some problem during the PluginLoaderContextListener startup");
}
return instance;
}
/**
* Returns the loaded plugins names.
*
* @return the loaded plugins names.
*/
public Set<String> getSupportedTypes()
{
return plugins.loadedTypes();
}
/**
* Returns the loaded plugins.
*
* @return the loaded plugins.
*/
private Collection<LoadedPlugin> getSupportedPlugins()
{
return plugins.loadedPlugins();
}
/**
* Returns the loaded {@link IHypervisor} plugins names.
*
* @return the loaded {@link IHypervisor} plugins names.
*/
public Set<String> getSupportedHypervisorTypes()
{
// Computed at runtime to use an up to date plugin white list
return ImmutableSet.<String> copyOf(FluentIterable.from(getSupportedHypervisors())
.transformAndConcat(getTypes()));
}
/**
* Returns the loaded {@link IHypervisor} plugins.
*
* @return the loaded {@link IHypervisor} plugins.
*/
private Collection<LoadedPlugin> getSupportedHypervisors()
{
return Collections2.filter(getSupportedPlugins(), assignableFrom(IHypervisor.class));
}
/**
* Returns the loaded {@link IManagerHypervisor} plugins names.
*
* @return the loaded {@link IManagerHypervisor} plugins names.
*/
public Set<String> getSupportedManagerHypervisorTypes()
{
// Computed at runtime to use an up to date plugin white list
return ImmutableSet.<String> copyOf(FluentIterable.from(getSupportedManagerHypervisors())
.transformAndConcat(getTypes()));
}
/**
* Returns the loaded {@link IManagerHypervisor} plugins.
*
* @return the loaded {@link IManagerHypervisor} plugins.
*/
private Collection<LoadedPlugin> getSupportedManagerHypervisors()
{
return Collections2.filter(getSupportedPlugins(), assignableFrom(IManagerHypervisor.class));
}
/**
* Returns the loaded {@link ICloudProvider} plugins names.
*
* @return the loaded {@link ICloudProvider} plugins names.
*/
public Set<String> getSupportedCloudProviderTypes()
{
// Computed at runtime to use an up to date plugin white list
return ImmutableSet.<String> copyOf(FluentIterable.from(getSupportedCloudProviders())
.transformAndConcat(getTypes()));
}
/**
* Modifies the whitelisted plugins.
* <p>
* This method should be ONLY invoked with the plugins provided by the Abiquo licenses.
*
* @param types The new plugin whitelist.
*/
public void setWhiteList(final Collection<String> types)
{
plugins.setEnabledPlugins(types);
}
/**
* Resets the whitelist to enable all plugins.
* <p>
* This method should be ONLY invoked with the plugins provided by the Abiquo licenses.
*/
public void resetWhiteList()
{
plugins.enableAllPlugins();
}
/**
* Returns the loaded {@link ICloudProvider} plugins.
*
* @return the loaded {@link ICloudProvider} plugins.
*/
private Collection<LoadedPlugin> getSupportedCloudProviders()
{
return Collections2.filter(getSupportedPlugins(), assignableFrom(ICloudProvider.class));
}
/**
* Predicate to filter the plugins by type
*
* @param type interface to filter
* @return Predicate to filter the plugins by type
*/
private static Predicate<LoadedPlugin> assignableFrom(final Class< ? extends Pluggable> type)
{
return new Predicate<LoadedPlugin>()
{
@Override
public boolean apply(final LoadedPlugin input)
{
return type.isAssignableFrom(input.computableObject.getClass());
}
};
}
/**
* Function to return the type of the plugins
*
* @return Function to return the type of the {@link LoadedPlugin}
*/
private static Function<LoadedPlugin, List<String>> getTypes()
{
return new Function<LoadedPlugin, List<String>>()
{
@Override
public List<String> apply(final LoadedPlugin input)
{
return newArrayList(filter(Arrays.asList(input.metadata.type()),
new Predicate<String>()
{
@Override
public boolean apply(final String input)
{
return getInstance().plugins.has(input);
}
}));
}
};
}
public Plugin get(final String type)
{
Optional<LoadedPlugin> plugin = plugins.tryGet(type);
if (!plugin.isPresent())
{
LOG.error("Trying to get the plugin instance for the non supported hypervisor type {}",
type);
throw new IllegalStateException("Plugin " + type + " is not loaded!");
}
return plugin.get().proxy;
}
public Optional<Plugin> tryFind(final String type)
{
Optional<LoadedPlugin> plugin = plugins.tryGet(type);
if (!plugin.isPresent())
{
LOG.error("Trying to get the plugin instance for the non supported hypervisor type {}",
type);
return Optional.absent();
}
return Optional.of(plugin.get().proxy);
}
public IsSupported isSupported(final String type)
{
Optional<LoadedPlugin> plugin = plugins.tryGet(type);
if (!plugin.isPresent())
{
LOG.error("Trying to get the plugin instance for the non supported hypervisor type {}",
type);
// Always unsupported
return Reflection.newProxy(IsSupported.class, new TryInvocationHandler(null, type));
}
return plugin.get().triable;
}
private boolean isCloudProvider(final Pluggable plugin)
{
return ICloudProvider.class.isAssignableFrom(plugin.getClass());
}
/**
* Returns the metadata of a plugin based on the given computable type
*
* @param type the computable type
* @return the metadata of a plugin based on the given computable type
* @throws HypervisorPluginException if there is not a loaded plugin for the given computable
* type
*/
public Optional<HypervisorMetadata> getHypervisorMetadata(final String type)
{
Optional<LoadedPlugin> plugin = plugins.tryGet(type);
if (!plugin.isPresent())
{
LOG.warn("Trying to get the plugin metadata for the non supported hypervisor type {}",
type);
return Optional.absent();
}
return Optional.fromNullable(plugin.get().metadata);
}
/**
* Returns the friendly name for plugin or absent if not loaded.
*
* @param type plugin
* @return friendly name or absent.
*/
public Optional<String> getFriendlyName(final String type)
{
Optional<HypervisorMetadata> metadata = getHypervisorMetadata(type);
if (!metadata.isPresent())
{
LOG.warn("getFriendlyName: Trying to aquire name for an unloaded plugin");
return Optional.absent();
}
int friendlyName = Arrays.asList(metadata.get().type()).indexOf(type);
return Optional.of(metadata.get().friendlyName()[friendlyName]);
}
public String getConstraintValue(final String hypervisorType, final ConstraintKey constraintKey)
{
Optional<LoadedPlugin> plugin = plugins.tryGet(hypervisorType);
return plugin.isPresent() ? plugin.get().constraints.get(constraintKey) : null;
}
public Map<ConstraintKey, String> getConstraints(final String hypervisorType)
{
Optional<LoadedPlugin> plugin = plugins.tryGet(hypervisorType);
return plugin.isPresent() ? plugin.get().constraints : ImmutableMap
.<ConstraintKey, String> of();
}
/**
* Check if there is a plugin loaded for the given hypervisor type.
*
* @param hypervisorType the hypervisor type to check
* @return True if there is a plugin loaded for the given hypervisor type and false otherwise
*/
public boolean isLoaded(final String hypervisorType)
{
return plugins.has(hypervisorType);
}
/**
* Creates a new instance of {@link IConnection} based on the given computable type
*
* @param type the computable type
* @return The {@link IConnection} instance
* @throws HypervisorPluginException if there is not a loaded plugin for the given computable
* type
*/
public IConnection newConnectionData(final String type) throws ComputeException
{
Optional<LoadedPlugin> plugin = plugins.tryGet(type);
if (!plugin.isPresent())
{
LOG.error("Trying to get the connection instance for the non supported plugin type {}",
type);
throw new HypervisorPluginException(HypervisorPluginError.THURMAN0, "Plugin type "
+ type);
}
try
{
return plugin.get().connectionClass.newInstance();
}
catch (Exception e)
{
LOG.error("Unable to create new plugin instance plugin type {}", type);
throw new HypervisorPluginException(HypervisorPluginError.PLUGIN_NEW_INSTANCE_ERROR,
"Plugin type " + type);
}
}
@SuppressWarnings("unchecked")
protected Optional<ImmutableMap<String, LoadedPlugin>> loadPlugin(final Pluggable plugin)
throws IllegalStateException
{
Optional<HypervisorMetadata> optionalMetadata = extractHypervisorMetadata(plugin);
if (!optionalMetadata.isPresent())
{
LOG.error(
"The plugin {} has invalid format. {} annotation is missing. Ignoring this plugin",
new Object[] {plugin.getClass().getName(), HypervisorMetadata.class.getName()});
return Optional.absent();
}
HypervisorMetadata metadata = optionalMetadata.get();
final List<DiskFormatType> diskFormatTypes = Arrays.asList(DiskFormatType.values());
List<DiskFormatType> compatibleTypes = Arrays.asList(metadata.compatibleDiskFormatTypes());
// Computable type must be informed
if (metadata.type().length == 0)
{
LOG.error("The type of the plugin {} is null or empty. Ignoring this plugin",
new Object[] {plugin.getClass().getName()});
return Optional.absent();
}
// Computable friendly name must be informed
if (metadata.friendlyName().length == 0)
{
LOG.error("The friendly name of the plugin {} is null or empty. Ignoring this plugin",
new Object[] {metadata.type()});
return Optional.absent();
}
// All compatible types must be in DiskFormatType otherwise we don't load this plugin
boolean allContained = Iterables.any(compatibleTypes, new Predicate<DiskFormatType>()
{
@Override
public boolean apply(final DiskFormatType input)
{
return diskFormatTypes.contains(input);
}
});
if (!allContained)
{
LOG.error(
"The plugin {} has invalid configuration compatibles disk format type is not a known disk format types (is not in DiskFormatTypes). Ignoring this plugin",
metadata.type());
return Optional.absent();
}
// Base format must be in compatible formats otherwise we don't load this plugin
if (!compatibleTypes.contains(metadata.baseDiskFormatType()))
{
LOG.error(
"The plugin {} has invalid configuration base disk format type is not in compatible disk format types. {} is not in compatibleDiskFormatTypes. Ignoring this plugin",
new Object[] {metadata.type(), metadata.baseDiskFormatType()});
return Optional.absent();
}
if (!areCompatibleInterfaces(plugin))
{
LOG.error(
"loadPlugin: plugin {} implements both {} and {} which is an imcompatible combination",
new Object[] {plugin.getClass(), IHypervisor.class.getName(),
ICloudProvider.class.getName()});
return Optional.absent();
}
// Validate specific plugin configuration
try
{
plugin.validateConfiguration();
}
catch (IllegalStateException e)
{
LOG.error("The plugin {} has invalid configuration: {}", new Object[] {metadata.type(),
e.getMessage()});
return Optional.absent();
}
// Validate at least one region is retrieved
if (isCloudProvider(plugin))
{
for (String type : metadata.type())
{
List<Region> regionNames =
((ICloudProvider< ? extends IConnection>) plugin).getRegions(type);
if (regionNames == null || regionNames.isEmpty())
{
LOG.error(
"The plugin {} extends from ICloudProvider but does not return any region",
metadata.type());
return Optional.absent();
}
}
}
try
{
Class<IConnection> connectionClass = resolveIConnectionData(plugin.getClass());
Builder<String, LoadedPlugin> builder = ImmutableMap.<String, LoadedPlugin> builder();
for (String pluginType : metadata.type())
{
LoadedPlugin loadedPlugin = new LoadedPlugin(pluginType, connectionClass, plugin);
builder.put(pluginType, loadedPlugin);
LOG.debug("Loaded plugin for type {}", pluginType);
}
return Optional.of(builder.build());
}
catch (Exception e)
{
LOG.error("Unable to load plugin for type {}", metadata.type(), e);
}
return Optional.absent();
}
private boolean areCompatibleInterfaces(final Pluggable plugin)
{
return !((plugin instanceof IHypervisor || plugin instanceof IManagerHypervisor) && plugin instanceof ICloudProvider);
}
private Optional<HypervisorMetadata> extractHypervisorMetadata(final Pluggable plugin)
{
Class< ? extends Pluggable> hypClass = plugin.getClass();
return Optional.fromNullable(hypClass.getAnnotation(HypervisorMetadata.class));
}
private Map<ConstraintKey, String> loadConstraints(final Pluggable plugin,
final IsSupported triable)
{
Map<ConstraintKey, String> constraints = Maps.newHashMap();
if (!ICompute.class.isAssignableFrom(plugin.getClass()))
{
return constraints;
}
@SuppressWarnings("unchecked")
ICompute< ? extends IConnection> compute = (ICompute< ? extends IConnection>) plugin;
for (ConstraintKey key : ConstraintKey.values())
{
String value = compute.getConstraint(key.name());
if (value != null)
{
constraints.put(key, value);
}
}
constraints.putAll(loadConnectionConstraints(compute.getClass().getAnnotation(
HostConnectionMetadata.class)));
constraints.putAll(loadConnectionConstraints(compute.getClass().getAnnotation(
AgentConnectionMetadata.class)));
constraints.putAll(loadConnectionConstraints(compute.getClass().getAnnotation(
ManagerConnectionMetadata.class)));
constraints.putAll(loadConnectionConstraints(compute.getClass().getAnnotation(
CloudProviderConnectionMetadata.class)));
if (triable.getManagedHostDefinitions()
&& !constraints.containsKey(ConstraintKey.DISCOVER_THROUGH_MANAGER))
{
constraints.put(ConstraintKey.DISCOVER_THROUGH_MANAGER, Boolean.TRUE.toString());
}
if (triable.getRegions())
{
// FIXME change to interfaces
constraints.put(ConstraintKey.REPOSITORY_NOT_SUPPORTED, Boolean.TRUE.toString());
constraints.put(ConstraintKey.EXTERNAL_STORAGE_NOT_SUPPORTED, Boolean.TRUE.toString());
}
return constraints;
}
private Map<ConstraintKey, String> loadConnectionConstraints(
final HostConnectionMetadata metadata)
{
FieldConstraint ip = FieldConstraint.NO_APPLICABLE;
FieldConstraint port = FieldConstraint.NO_APPLICABLE;
FieldConstraint credentials = FieldConstraint.NO_APPLICABLE;
if (metadata != null)
{
ip = metadata.ip();
port = metadata.port();
credentials = metadata.credentials();
}
return ImmutableMap.<ConstraintKey, String> builder().put(ConstraintKey.HOST_IP, ip.name())
.put(ConstraintKey.HOST_PORT, port.name())
.put(ConstraintKey.HOST_CREDENTIALS, credentials.name()).build();
}
private Map<ConstraintKey, String> loadConnectionConstraints(
final ManagerConnectionMetadata metadata)
{
FieldConstraint ip = FieldConstraint.NO_APPLICABLE;
FieldConstraint port = FieldConstraint.NO_APPLICABLE;
FieldConstraint credentials = FieldConstraint.NO_APPLICABLE;
if (metadata != null)
{
ip = metadata.ip();
port = metadata.port();
credentials = metadata.credentials();
}
return ImmutableMap.<ConstraintKey, String> builder()
.put(ConstraintKey.MANAGER_IP, ip.name()).put(ConstraintKey.MANAGER_PORT, port.name())
.put(ConstraintKey.MANAGER_CREDENTIALS, credentials.name()).build();
}
private Map<ConstraintKey, String> loadConnectionConstraints(
final AgentConnectionMetadata metadata)
{
FieldConstraint ip = FieldConstraint.NO_APPLICABLE;
FieldConstraint port = FieldConstraint.NO_APPLICABLE;
FieldConstraint credentials = FieldConstraint.NO_APPLICABLE;
if (metadata != null)
{
ip = metadata.ip();
port = metadata.port();
credentials = metadata.credentials();
}
return ImmutableMap.<ConstraintKey, String> builder()
.put(ConstraintKey.AGENT_IP, ip.name()).put(ConstraintKey.AGENT_PORT, port.name())
.put(ConstraintKey.AGENT_CREDENTIALS, credentials.name()).build();
}
private Map<ConstraintKey, String> loadConnectionConstraints(
final CloudProviderConnectionMetadata metadata)
{
FieldConstraint endpoint = FieldConstraint.NO_APPLICABLE;
FieldConstraint credentials = FieldConstraint.NO_APPLICABLE;
if (metadata != null)
{
endpoint = metadata.endpoint();
credentials = metadata.credentials();
}
return ImmutableMap.<ConstraintKey, String> builder()
.put(ConstraintKey.ENDPOINT, endpoint.name())
.put(ConstraintKey.PROVIDER_CREDENTIALS, credentials.name()).build();
}
/**
* Introspect an {@link ICompute} object to know the class of its {@link IConnection}
*
* @param hclass the class of an {@link ICompute} implementation
* @return the class of the associated generic type for {@link IConnection}
*/
@SuppressWarnings("unchecked")
// verified by ''typeParametersFor(ICompute.class)''
private static Class<IConnection> resolveIConnectionData(final Type hclass)
throws HypervisorPluginException
{
List<ResolvedType> rt = typeResolver.resolve(hclass).typeParametersFor(ICompute.class);
if (rt == null || rt.size() != 1)
{
throw new HypervisorPluginException(HypervisorPluginError.THURMAN0, hclass.toString());
}
return (Class<IConnection>) rt.get(0).getErasedType();
}
/**
* This method is meant to be executed <b>only</b> at start up time! To retrieve the instance
* use the {@link #getInstance()} instead.
*
* @see PluginManager#getInstance()
* @throws IllegalStateException if the instance is already created.
*/
public static synchronized void createInstance()
{
if (instance != null)
{
throw new IllegalStateException("An instance of the PluginManager already exists! Use getInstance() method instead");
}
instance = new PluginManager();
}
/**
* Validates the given {@link ConnectionData} for the {@link IHypervisor} implementation of the
* indicated hypervisor plugin type.
*
* @param connection the connection to validate
* @param type the hypervisor type
* @return True if is a valid connection and false otherwise.
*/
private boolean validateHostConnection(final ConnectionData connection)
{
Optional<LoadedPlugin> plugin = plugins.tryGet(connection.getType());
checkState(plugin.isPresent(), "Plugin %s is not loaded!", connection.getType());
return all(filter(plugin.get().constraints.entrySet(), mandatoryFields),
new Predicate<Entry<ConstraintKey, String>>()
{
@Override
public boolean apply(final Entry<ConstraintKey, String> entry)
{
switch (entry.getKey())
{
case HOST_IP:
return !isNullOrEmpty(connection.getIp());
case HOST_PORT:
return isNotNull(connection.getPort());
case HOST_CREDENTIALS:
return !isNullOrEmpty(connection.getUser())
&& !isNullOrEmpty(connection.getPassword());
case MANAGER_IP:
return !isNullOrEmpty(connection.getManagerIp());
case MANAGER_PORT:
return isNotNull(connection.getManagerPort());
case MANAGER_CREDENTIALS:
return !isNullOrEmpty(connection.getManagerUser())
&& !isNullOrEmpty(connection.getManagerPassword());
case AGENT_IP:
return !isNullOrEmpty(connection.getAgentIp());
case AGENT_PORT:
return isNotNull(connection.getAgentPort());
case AGENT_CREDENTIALS:
return !isNullOrEmpty(connection.getAgentUser())
&& !isNullOrEmpty(connection.getAgentPassword());
default:
return true;
}
}
});
}
/**
* Validates the given {@link ConnectionData} for the {@link IManagerHypervisor} implementation
* of the indicated hypervisor plugin type.
*
* @param connection the connection to validate
* @param type the hypervisor type
* @return True if is a valid connection and false otherwise.
*/
private boolean validateManagerConnection(final ConnectionData connection)
{
Optional<LoadedPlugin> plugin = plugins.tryGet(connection.getType());
checkState(plugin.isPresent(), "Plugin %s is not loaded!", connection.getType());
return all(filter(plugin.get().constraints.entrySet(), mandatoryFields),
new Predicate<Entry<ConstraintKey, String>>()
{
@Override
public boolean apply(final Entry<ConstraintKey, String> entry)
{
switch (entry.getKey())
{
case MANAGER_IP:
return !isNullOrEmpty(connection.getManagerIp());
case MANAGER_PORT:
return isNotNull(connection.getManagerPort());
case MANAGER_CREDENTIALS:
return !isNullOrEmpty(connection.getManagerUser())
&& !isNullOrEmpty(connection.getManagerPassword());
default:
return true;
}
}
});
}
public boolean validateConnection(final ConnectionData connection)
{
Optional<Plugin> plugin = tryFind(connection.getType());
if (!plugin.isPresent())
{
return false;
}
if (isSupported(connection.getType()).getManagedHostDefinitions())
{
return validateManagerConnection(connection);
}
if (isSupported(connection.getType()).getHostDefinition())
{
return validateHostConnection(connection);
}
if (isSupported(connection.getType()).getRegion())
{
return validateCloudProviderConnection(connection);
}
return false;
}
private boolean validateCloudProviderConnection(final ConnectionData connection)
{
Optional<LoadedPlugin> plugin = plugins.tryGet(connection.getType());
checkState(plugin.isPresent(), "Plugin %s is not loaded!", connection.getType());
return all(filter(plugin.get().constraints.entrySet(), mandatoryFields),
new Predicate<Entry<ConstraintKey, String>>()
{
@Override
public boolean apply(final Entry<ConstraintKey, String> entry)
{
switch (entry.getKey())
{
case ENDPOINT:
return !isNullOrEmpty(connection.getEndpoint());
case PROVIDER_CREDENTIALS:
return !isNullOrEmpty(connection.getUser())
&& !isNullOrEmpty(connection.getPassword());
default:
return true;
}
}
});
}
private boolean isNotNull(final Object value)
{
return value != null;
}
}