Package com.abiquo.hypervisor.plugin

Source Code of com.abiquo.hypervisor.plugin.PluginManager

/**
* 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;
    }
}
TOP

Related Classes of com.abiquo.hypervisor.plugin.PluginManager

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.