/*
* JBoss, by Red Hat.
* Copyright 2010, Red Hat, Inc., and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.seam.forge.shell.command;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.annotation.PostConstruct;
import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.BeanManager;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jboss.seam.forge.project.Facet;
import org.jboss.seam.forge.project.packaging.PackagingType;
import org.jboss.seam.forge.resources.Resource;
import org.jboss.seam.forge.shell.Shell;
import org.jboss.seam.forge.shell.plugins.Plugin;
import org.jboss.seam.forge.shell.plugins.RequiresResource;
/**
* Stores the current registry of all installed & loaded plugins.
*
* @author <a href="mailto:lincolnbaxter@gmail.com">Lincoln Baxter, III</a>
*/
@Singleton
public class PluginRegistry
{
private Map<String, List<PluginMetadata>> plugins;
private Map<String, Map<Class<?>, PluginMetadata>> accessCache;
private final CommandLibraryExtension library;
private final BeanManager manager;
@Inject
public PluginRegistry(final CommandLibraryExtension library, final BeanManager manager)
{
this.library = library;
this.manager = manager;
}
@PostConstruct
public void init()
{
plugins = library.getPlugins();
accessCache = new HashMap<String, Map<Class<?>, PluginMetadata>>();
sanityCheck();
}
public Map<String, List<PluginMetadata>> getPlugins()
{
return plugins;
}
public void addPlugin(final PluginMetadata plugin)
{
if (!plugins.containsKey(plugin.getName()))
{
plugins.put(plugin.getName(), new ArrayList<PluginMetadata>());
}
plugins.get(plugin.getName()).add(plugin);
}
@Override
public String toString()
{
return "PluginRegistry [plugins=" + plugins + "]";
}
public Plugin instanceOf(final PluginMetadata meta)
{
return getContextualInstance(manager, meta.getType());
}
@SuppressWarnings("unchecked")
public static <T> T getContextualInstance(final BeanManager manager, final Class<T> type)
{
T result = null;
Bean<T> bean = (Bean<T>) manager.resolve(manager.getBeans(type));
if (bean != null)
{
CreationalContext<T> context = manager.createCreationalContext(bean);
if (context != null)
{
result = (T) manager.getReference(bean, type, context);
}
}
return result;
}
/**
* Get {@link PluginMetadata} for the plugin with the given name.
*
* @return the metadata, or null if no plugin with given name exists.
*/
public List<PluginMetadata> getPluginMetadata(final String plugin)
{
return Collections.unmodifiableList(plugins.get(plugin));
}
/**
* Get {@link PluginMetadata} matching the given name, {@link RequiresResource},
* {@link org.jboss.seam.forge.project.Project}, {@link PackagingType}, and {@link Facet} constraints.
* Return null if no match for the given constraints can be found.
*/
public PluginMetadata getPluginMetadataForScopeAndConstraints(final String name, final Shell shell)
{
Class<? extends Resource<?>> scope = shell.getCurrentResourceScope();
if (accessCache.containsKey(name) && accessCache.get(name).containsKey(scope))
{
return accessCache.get(name).get(scope);
}
List<PluginMetadata> pluginMetadataList = plugins.get(name);
if (pluginMetadataList == null)
{
return null;
}
PluginMetadata pmd = null;
for (PluginMetadata p : pluginMetadataList)
{
if (p.constrantsSatisfied(shell))
{
pmd = p;
break;
}
}
return pmd;
}
private void sanityCheck()
{
for (Map.Entry<String, List<PluginMetadata>> entry : plugins.entrySet())
{
Set<Class<? extends Resource<?>>> scopes = null;
for (PluginMetadata metaData : entry.getValue())
{
if (scopes == null)
{
scopes = metaData.getResourceScopes();
}
else
{
for (Class<? extends Resource<?>> r : metaData.getResourceScopes())
{
if (scopes.contains(r))
{
throw new RuntimeException("failed sanity check. overlapping scopes for overloaded plugin name: "
+ entry.getKey() + " [" + entry.getValue() + "]");
}
}
}
}
}
}
}