/* * AnalysisManager.java - This file is part of the Jakstab project. * Copyright 2007-2015 Johannes Kinder <jk@jakstab.org> * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code 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 General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, see <http://www.gnu.org/licenses/>. */ package org.jakstab; import java.io.File; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import org.jakstab.analysis.ConfigurableProgramAnalysis; import org.jakstab.util.Logger; public class AnalysisManager { private static final Logger logger = Logger.getLogger(AnalysisManager.class); private static class SingletonHolder { public static final AnalysisManager INSTANCE = new AnalysisManager(); } public static AnalysisManager getInstance() { return SingletonHolder.INSTANCE; } private Map<Character, Class<? extends ConfigurableProgramAnalysis>> shortHandMap; private Map<Class<? extends ConfigurableProgramAnalysis>, AnalysisProperties> analysisProperties; private Map<Class<? extends ConfigurableProgramAnalysis>, ConfigurableProgramAnalysis> analysisInstances; private AnalysisManager() { shortHandMap = new HashMap<Character, Class<? extends ConfigurableProgramAnalysis>>(); analysisProperties = new HashMap<Class<? extends ConfigurableProgramAnalysis>, AnalysisProperties>(); analysisInstances = new HashMap<Class<? extends ConfigurableProgramAnalysis>, ConfigurableProgramAnalysis>(); // Enumerate all analyses and register them String pkg = "org.jakstab.analysis"; File dir = new File(Options.jakstabHome + "/bin/" + pkg.replace(".", "/")); List<Class<? extends ConfigurableProgramAnalysis>> classes = findCPAClasses(dir, pkg); for(Class<? extends ConfigurableProgramAnalysis> cpaClass : classes) { AnalysisProperties aProps = new AnalysisProperties(); try { //logger.debug("Trying to register " + cpaClass.getSimpleName()); cpaClass.getMethod("register", AnalysisProperties.class).invoke(cpaClass, aProps); if (aProps.getShortHand() != ' ') { if (shortHandMap.containsKey(aProps.getShortHand())) { logger.fatal("Duplicate short hand '" + aProps.getShortHand() + "' registered by " + shortHandMap.get(aProps.getShortHand()).getSimpleName() + " and " + cpaClass.getSimpleName() + "."); } shortHandMap.put(aProps.getShortHand(), cpaClass); } analysisProperties.put(cpaClass, aProps); // apply properties } catch (Exception e) { logger.warn("Failed to register " + cpaClass.getSimpleName()); if (e instanceof RuntimeException) e.printStackTrace(); } } } public ConfigurableProgramAnalysis createAnalysis(char shortHand) { Class<? extends ConfigurableProgramAnalysis> cpaClass = shortHandMap.get(shortHand); if (cpaClass == null) return null; try { ConfigurableProgramAnalysis cpaInstance = cpaClass.newInstance(); analysisInstances.put(cpaClass, cpaInstance); return cpaInstance; } catch (InstantiationException e) { e.printStackTrace(); throw new RuntimeException(e); } catch (IllegalAccessException e) { e.printStackTrace(); throw new RuntimeException(e); } } public char getShorthand(Class<? extends ConfigurableProgramAnalysis> clazz) { AnalysisProperties prop = analysisProperties.get(clazz); assert prop != null : "Analysis not registered"; return prop.getShortHand(); } /** * Get a previously instantiated analysis instance. * * @param clazz the class of the analysis to get * @return the instance of clazz most recently instantiated by this analysis manager */ public ConfigurableProgramAnalysis getAnalysis(Class<? extends ConfigurableProgramAnalysis> clazz) { return analysisInstances.get(clazz); } public String getName(char shortHand) { Class<? extends ConfigurableProgramAnalysis> cpaClass = shortHandMap.get(shortHand); if (cpaClass == null) return null; return analysisProperties.get(cpaClass).getName(); } public String getDescription(char shortHand) { Class<? extends ConfigurableProgramAnalysis> cpaClass = shortHandMap.get(shortHand); if (cpaClass == null) return null; return analysisProperties.get(cpaClass).getDescription(); } public AnalysisProperties getProperties(ConfigurableProgramAnalysis cpa) { return analysisProperties.get(cpa.getClass()); } public String getShorthandsString() { char[] shds = new char[shortHandMap.size()]; int i = 0; for (Character c : shortHandMap.keySet()) { shds[i++] = c; } Arrays.sort(shds); return new String(shds); } private static List<Class<? extends ConfigurableProgramAnalysis>> findCPAClasses(File directory, String packageName) { List<Class<? extends ConfigurableProgramAnalysis>> classes = new ArrayList<Class<? extends ConfigurableProgramAnalysis>>(); for (File file : directory.listFiles()) { String fileName = file.getName(); if (file.isDirectory()) { assert !fileName.contains("."); classes.addAll(findCPAClasses(file, packageName + "." + fileName)); } else if (fileName.endsWith(".class")) { Class<?> clazz; try { try { clazz = Class.forName(packageName + '.' + fileName.substring(0, fileName.length() - 6)); } catch (ExceptionInInitializerError e) { clazz = Class.forName(packageName + '.' + fileName.substring(0, fileName.length() - 6), false, Thread.currentThread().getContextClassLoader()); } if (ConfigurableProgramAnalysis.class.isAssignableFrom(clazz)) { int mod = clazz.getModifiers(); if (!Modifier.isAbstract(mod) && !Modifier.isInterface(mod)) classes.add(clazz.asSubclass(ConfigurableProgramAnalysis.class)); } } catch (ClassNotFoundException e) { logger.warn("Could not load class " + packageName + "." + fileName); } } } return classes; } }