package mil.nga.giat.geowave.core.cli.spi; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.ServiceLoader; import mil.nga.giat.geowave.core.cli.api.Operation; /** * This implementation uses the SPI to load all Operations across the program, * including those exported by plugsin. It parses the entries and places them * into a cache. */ public class OperationRegistry { private Map<Class<?>, OperationEntry> operationMapByClass = null; /** * Singleton pattern allows us to create a version that can be used by the * whole application. */ private static class OperationRegistryHolder { public static final OperationRegistry instance = new OperationRegistry(); } /** * But also allow the user to create their own if they want it to be * sanitized. */ public OperationRegistry() { init(); } public static OperationRegistry getInstance() { return OperationRegistryHolder.instance; } public OperationRegistry( List<OperationEntry> entries ) { operationMapByClass = new HashMap<Class<?>, OperationEntry>(); for (OperationEntry entry : entries) { operationMapByClass.put( entry.getOperationClass(), entry); } } private synchronized void init() { if (operationMapByClass == null) { operationMapByClass = new HashMap<Class<?>, OperationEntry>(); // Load SPI elements final Iterator<CLIOperationProviderSpi> operationProviders = ServiceLoader.load( CLIOperationProviderSpi.class).iterator(); while (operationProviders.hasNext()) { final CLIOperationProviderSpi operationProvider = operationProviders.next(); for (Class<?> clz : operationProvider.getOperations()) { if (Operation.class.isAssignableFrom(clz)) { OperationEntry entry = new OperationEntry( clz); operationMapByClass.put( clz, entry); } else { throw new RuntimeException( "CLI operations must be assignable from Operation.class: " + clz.getCanonicalName()); } } } // Build a hierarchy. for (OperationEntry entry : operationMapByClass.values()) { if (!entry.isTopLevel()) { OperationEntry parentEntry = operationMapByClass.get(entry.getParentOperationClass()); if (parentEntry == null) { throw new RuntimeException( "Cannot find parent entry for " + entry.getOperationClass().getName()); } if (parentEntry.isCommand()) { throw new RuntimeException( "Cannot have a command be a parent: " + entry.getClass().getCanonicalName()); } parentEntry.addChild(entry); } } } } /** * Allow the iteration and exploration of all operations by a caller. * Because we like callers. * * @return */ public Collection<OperationEntry> getAllOperations() { return Collections.unmodifiableCollection(operationMapByClass.values()); } /** * Get the exported service entry by class name * * @param operationClass * @return */ public OperationEntry getOperation( Class<?> operationClass ) { return operationMapByClass.get(operationClass); } }