/* * Copyright 2015-2016 OpenCB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.opencb.opencga.analysis.execution.plugins; import org.reflections.Reflections; import org.reflections.scanners.SubTypesScanner; import org.reflections.util.ClasspathHelper; import org.reflections.util.ConfigurationBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.*; import java.util.concurrent.atomic.AtomicBoolean; /** * This class scans all the classpath using the library {@link Reflections} and find all the * implementations of the plugin interface {@link OpenCGAAnalysis}. * * Implements singleton pattern. Use {@link #get()} to obtain instance * * Created on 27/11/15 * * @author Jacobo Coll <jacobo167@gmail.com> */ public class PluginFactory { private Logger logger = LoggerFactory.getLogger(PluginFactory.class); private static PluginFactory pluginFactory; private Reflections reflections; private final Map<String, Class<? extends OpenCGAAnalysis>> pluginsIdMap = new HashMap<>(); private final AtomicBoolean init = new AtomicBoolean(false); private PluginFactory() { } private void lazyInit() { if (!init.get()) { synchronized (init) { if (!init.get()) { init(); } } init.set(true); } } /** * Initialize the pluginsIdMap. Find all the subtypes of {@link OpenCGAAnalysis} */ private void init() { // Reflections.log = null; // Uncomment to skip logs reflections = new Reflections(new ConfigurationBuilder() .setScanners(new SubTypesScanner()).addUrls(ClasspathHelper.forJavaClassPath()) .filterInputsBy(input -> input.endsWith(".class")) ); Set<Class<? extends OpenCGAAnalysis>> plugins = reflections.getSubTypesOf(OpenCGAAnalysis.class); List<String> duplicatedPlugins = new LinkedList<>(); for (Class<? extends OpenCGAAnalysis> pluginClazz : plugins) { try { OpenCGAAnalysis plugin = pluginClazz.newInstance(); String pluginId = plugin.getIdentifier(); if (pluginsIdMap.containsKey(pluginId)) { logger.error("Duplicated ID for class {} and {}", pluginClazz, pluginsIdMap.get(pluginId)); duplicatedPlugins.add(pluginId); continue; } pluginsIdMap.put(pluginId, pluginClazz); } catch (InstantiationException | IllegalAccessException | RuntimeException e) { logger.error("Unable to load class {} ", pluginClazz); } } duplicatedPlugins.forEach(pluginsIdMap::remove); } /** * Singleton accessor method * * @return Get the singleton instance of {@link PluginFactory} */ public static PluginFactory get() { if (pluginFactory == null) { pluginFactory = new PluginFactory(); } return pluginFactory; } /** * Get all the found plugin classes * * @return Map between plugin id and plugin class */ public Map<String, Class<? extends OpenCGAAnalysis>> getAllPlugins() { lazyInit(); return Collections.unmodifiableMap(pluginsIdMap); } /** * Get the class of a plugin given its id * * @param id Plugin id * @return Plugin class */ public Class<? extends OpenCGAAnalysis> getPluginClass(String id) { lazyInit(); return pluginsIdMap.get(id); } /** * Get a new instance of a plugin given its id. * * @param id Plugin id * @return New instance of the plugin */ public OpenCGAAnalysis getPlugin(String id) { Class<? extends OpenCGAAnalysis> pluginClass = getPluginClass(id); return getPlugin(pluginClass); } /** * Get a new instance of a plugin given its id. * * @param pluginClass Plugin class * @return New instance of the plugin */ public OpenCGAAnalysis getPlugin(Class<? extends OpenCGAAnalysis> pluginClass) { try { if (pluginClass == null) { return null; } else { return pluginClass.newInstance(); } } catch (InstantiationException | IllegalAccessException e) { //This should never happen. All the plugins in the Map can be instantiated throw new IllegalStateException("Error creating new instance"); } } }