/* * Eoulsan development code * * This code may be freely distributed and modified under the * terms of the GNU Lesser General Public License version 2.1 or * later and CeCILL-C. This should be distributed with the code. * If you do not have a copy, see: * * http://www.gnu.org/licenses/lgpl-2.1.txt * http://www.cecill.info/licences/Licence_CeCILL-C_V1-en.txt * * Copyright for this code is held jointly by the Genomic platform * of the Institut de Biologie de l'École normale supérieure and * the individual authors. These should be listed in @author doc * comments. * * For more information on the Eoulsan project and its aims, * or to join the Eoulsan Google group, visit the home page * at: * * http://outils.genomique.biologie.ens.fr/eoulsan * */ package fr.ens.biologie.genomique.eoulsan.core.workflow; import static com.google.common.base.Preconditions.checkNotNull; import static fr.ens.biologie.genomique.eoulsan.EoulsanLogger.getLogger; import static fr.ens.biologie.genomique.eoulsan.EoulsanRuntime.getSettings; import static fr.ens.biologie.genomique.eoulsan.annotations.ExecutionMode.HADOOP_COMPATIBLE; import static fr.ens.biologie.genomique.eoulsan.annotations.ExecutionMode.HADOOP_ONLY; import static fr.ens.biologie.genomique.eoulsan.annotations.ExecutionMode.LOCAL_ONLY; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Map; import com.google.common.base.Strings; import fr.ens.biologie.genomique.eoulsan.EoulsanException; import fr.ens.biologie.genomique.eoulsan.Main; import fr.ens.biologie.genomique.eoulsan.annotations.ExecutionMode; import fr.ens.biologie.genomique.eoulsan.core.Module; import fr.ens.biologie.genomique.eoulsan.core.Version; import fr.ens.biologie.genomique.eoulsan.data.DataFile; import fr.ens.biologie.genomique.eoulsan.modules.GalaxyToolModule; import fr.ens.biologie.genomique.eoulsan.util.ClassPathResourceLoader; import fr.ens.biologie.genomique.eoulsan.util.FileResourceLoader; /** * This class define a registry for steps. * @author Laurent Jourdren * @since 2.0 */ public class ModuleRegistry { private static final String RESOURCE_PREFIX = "META-INF/services/registrytoolshed/"; private static final String GALAXY_TOOL_SUBDIR = "galaxytools"; private static ModuleRegistry instance; private final ModuleService service; private final GalaxyToolStepClassPathLoader galaxyClassPathLoader; private final GalaxyToolModuleFileResourceLoader galaxyFileLoader; // // Inner classes // /** * This class define a resource loader for resource defined in the file * system. */ private static final class GalaxyToolModuleFileResourceLoader extends FileResourceLoader<GalaxyToolModule> { @Override protected String getExtension() { return ".xml"; } @Override protected GalaxyToolModule load(final InputStream in, final String source) throws IOException, EoulsanException { checkNotNull(in, "in argument cannot be null"); try { return new GalaxyToolModule(in, source); } catch (EoulsanException e) { throw new EoulsanException( "Unable to load Galaxy tool module: " + source, e); } } /** * Get the default format directory. * @return the default format directory */ private static DataFile getDefaultFormatDirectory() { final Main main = Main.getInstance(); if (main == null) { return new DataFile(GALAXY_TOOL_SUBDIR); } return new DataFile( new File(main.getEoulsanDirectory(), GALAXY_TOOL_SUBDIR)); } @Override protected String getResourceName(final GalaxyToolModule resource) { checkNotNull(resource, "resource argument cannot be null"); return resource.getName(); } // // Constructors // /** * Constructor. * @param resourcePaths paths where searching for the resources. */ public GalaxyToolModuleFileResourceLoader(final String resourcePaths) { super(GalaxyToolModule.class, getDefaultFormatDirectory()); if (resourcePaths != null) { addResourcePaths(resourcePaths); } } } /** * This class define a resource loader for resource defined in the class path. */ private static final class GalaxyToolStepClassPathLoader extends ClassPathResourceLoader<GalaxyToolModule> { @Override protected GalaxyToolModule load(final InputStream in, final String source) throws IOException, EoulsanException { return new GalaxyToolModule(in, source); } @Override protected String getResourceName(final GalaxyToolModule resource) { checkNotNull(resource, "resource argument cannot be null"); return resource.getName(); } // // Constructor // public GalaxyToolStepClassPathLoader() { super(GalaxyToolModule.class, RESOURCE_PREFIX); } } // // Singleton method // /** * Retrieve the singleton static instance of StepRegistry. * @return A StepRegistry instance */ public static synchronized ModuleRegistry getInstance() { if (instance == null) { instance = new ModuleRegistry(); // Load the available modules instance.reload(); } return instance; } // // Instances methods // /** * Load a module. * @param moduleName name of the required module * @param version version of the required module * @return a step object or null if the requested module has been not found */ public Module loadModule(final String moduleName, final String version) { final List<Module> stepsFound = new ArrayList<>(); stepsFound.addAll(this.service.newServices(moduleName)); stepsFound.addAll(this.galaxyClassPathLoader.loadResources(moduleName)); stepsFound.addAll(this.galaxyFileLoader.loadResources(moduleName)); // Filter steps filterModules(stepsFound, Strings.nullToEmpty(version).trim()); // Sort steps sortModules(stepsFound); if (stepsFound.isEmpty()) { return null; } return stepsFound.get(stepsFound.size() - 1); } /** * Reload the list of available steps. */ public void reload() { this.service.reload(); this.galaxyClassPathLoader.reload(); this.galaxyFileLoader.reload(); // Log steps defined in jars for (Map.Entry<String, String> e : this.service.getServiceClasses() .entries()) { getLogger() .config("Found step: " + e.getKey() + " (" + e.getValue() + ")"); } // Log Galaxy tool steps final List<GalaxyToolModule> stepsFound = new ArrayList<>(); stepsFound.addAll(this.galaxyClassPathLoader.loadAllResources()); stepsFound.addAll(this.galaxyFileLoader.loadAllResources()); for (GalaxyToolModule s : stepsFound) { getLogger().config("Found step: " + s.getName() + " (Galaxy tool, source: " + s.getSource() + ")"); } } /** * Filter the modules on their version. * @param modules steps to filter * @param version required version */ private void filterModules(final List<Module> modules, final String version) { // Do no filter if no version has been specified if (modules == null || "".equals(version)) { return; } final List<Module> toRemove = new ArrayList<>(); // For each module for (Module module : modules) { // Get the version Version stepVersion = module.getVersion(); // Discard null version if (stepVersion == null) { continue; } // Keep only the step with the right version if (!stepVersion.toString().equals(version)) { toRemove.add(module); } } // Remove all the entries modules.removeAll(toRemove); } /** * Sort the modules. * @param modules list of module to sort */ private void sortModules(final List<Module> modules) { // Do nothing if the list of module is null if (modules == null) { return; } // Sort the steps Collections.sort(modules, new Comparator<Module>() { @Override public int compare(final Module m1, final Module m2) { if (m1 == null) { return 1; } if (m2 == null) { return -1; } int result = compareStepModes(m1, m2); if (result != 0) { return result; } return compareStepVersions(m1, m2); } private int compareStepModes(final Module m1, final Module m2) { final ExecutionMode mode1 = ExecutionMode.getExecutionMode(m1.getClass()); final ExecutionMode mode2 = ExecutionMode.getExecutionMode(m2.getClass()); int result = compareModes(mode1, mode2, HADOOP_ONLY); if (result != 0) { return result; } result = compareModes(mode1, mode2, HADOOP_COMPATIBLE); if (result != 0) { return result; } return compareModes(mode1, mode2, LOCAL_ONLY); } private int compareModes(ExecutionMode mode1, ExecutionMode mode2, ExecutionMode modeToCompare) { if (mode1 == modeToCompare && mode2 != modeToCompare) { return 1; } if (mode2 == modeToCompare && mode1 != modeToCompare) { return -1; } return 0; } private int compareStepVersions(final Module s1, final Module s2) { final Version v1 = s1.getVersion(); final Version v2 = s2.getVersion(); if (v1 == null) { return 1; } if (v2 == null) { return -1; } return v1.compareTo(v2); } }); } // // Constructor // /** * Private constructor. */ private ModuleRegistry() { this.service = new ModuleService(); this.galaxyClassPathLoader = new GalaxyToolStepClassPathLoader(); this.galaxyFileLoader = new GalaxyToolModuleFileResourceLoader( getSettings().getGalaxyToolPath()); } }