package kr.ac.snu.selab.soot;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import kr.ac.snu.selab.soot.core.AbstractProject;
import kr.ac.snu.selab.soot.core.AnalyzerRunner;
import kr.ac.snu.selab.soot.core.InvalidAnalyzerException;
import kr.ac.snu.selab.soot.core.ProjectFileParseException;
import kr.ac.snu.selab.soot.core.ProjectManager;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.PosixParser;
import org.apache.log4j.Logger;
public class Main {
private static Logger log = Logger.getLogger(Main.class);
public static void main(String[] args) {
Map<String, String> optionMap = parseArgs(args);
if (optionMap == null)
return;
String projectFilePath = optionMap.get("project_file");
File projectFile = null;
if (projectFilePath == null) {
projectFile = findDefaultProjectsFile();
if (projectFile == null || !projectFile.exists()
|| !projectFile.isFile()) {
log.error("Can't find project file");
System.err.println("Can't find project file: "
+ DEFAULT_PROJECTS_FILE_NAME);
return;
}
} else {
projectFile = new File(projectFilePath);
if (projectFile == null || !projectFile.exists()
|| !projectFile.isFile()) {
log.error("Can't find project file");
System.err.println("Can't find project file: "
+ projectFilePath);
return;
}
}
log.debug("Project file: " + projectFile);
ProjectManager projects = ProjectManager.getInstance();
FileInputStream fis = null;
try {
fis = new FileInputStream(projectFile);
projects.loadProjects(fis);
} catch (ProjectFileParseException e) {
log.error("An error occured while loading project file", e);
System.err.println("An error occured while loading project file");
return;
} catch (FileNotFoundException e) {
log.error("An error occured while loading project file", e);
System.err.println("An error occured while loading project file");
return;
} catch (Exception e) {
e.printStackTrace();
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
}
}
}
String projectName = optionMap.get("project");
AbstractProject project = projects.getProject(projectName);
if (project == null) {
log.error("Can not find project information: " + projectName);
System.err.println("Can not find project information: "
+ projectName);
return;
}
File outputDirectory = project.getOutputDirectory();
if (!outputDirectory.exists()) {
outputDirectory.mkdirs();
}
boolean useSimpleCallGraph = Boolean.parseBoolean(optionMap
.get("simple_call_graph"));
project.setUseSimpleCallGraph(useSimpleCallGraph);
String analyzer = optionMap.get("analyzer");
boolean noJimpleOutput = Boolean.parseBoolean(optionMap
.get("no_jimple"));
try {
AnalyzerRunner.run(project, analyzer, noJimpleOutput);
} catch (InvalidAnalyzerException e) {
log.error(e);
System.err.println("ERROR: " + e.getMessage());
}
}
@SuppressWarnings("static-access")
private static Map<String, String> parseArgs(String... args) {
String analyzerDescription = "Analyzer\n\tPredefined anlayzers:\n"
+ "\t\t\tr: Role analyzer" + "\t\t\tc: Code analyzer"
+ "\t\t\tct: Call graph text creater"
+ "\t\t\tcx: Call graph xml creater"
+ "\t\t\tpfc: Path from caller"
+ "\t\t\ts: State pattern recovery";
Option analyzer = OptionBuilder.withArgName("r|c|ct|cx|pfc|ts")
.hasArg().withDescription(analyzerDescription)
.withLongOpt("analyzer").create("a");
Option projectFilePath = OptionBuilder.hasArg()
.withArgName("project file").withDescription("Project file")
.withLongOpt("pfile").create("pf");
Option noJimpleOutput = OptionBuilder
.withDescription("Do not generate jimple files")
.withLongOpt("no-jimple").create("nj");
Option useSimpleCallGraph = OptionBuilder
.withDescription("Use simple call graph")
.withLongOpt("simple-call-graph").create("scg");
Options options = new Options();
options.addOption(analyzer);
options.addOption(projectFilePath);
options.addOption(noJimpleOutput);
options.addOption(useSimpleCallGraph);
CommandLine cmd = null;
try {
CommandLineParser parser = new PosixParser();
cmd = parser.parse(options, args);
} catch (ParseException e) {
System.err.println("Invalid option: " + e.getMessage());
showUsage(options);
return null;
}
String[] realArguments = cmd.getArgs();
if (realArguments.length < 1) {
System.err.println("Missing project!!!");
showUsage(options);
return null;
}
HashMap<String, String> map = new HashMap<String, String>();
String projectName = realArguments[0];
map.put("project", projectName);
if (cmd.hasOption("a")) {
map.put("analyzer", cmd.getOptionValue("a"));
} else {
map.put("analyzer", "r");
}
if (cmd.hasOption("pf")) {
map.put("project_file", cmd.getOptionValue("pf"));
} else {
map.put("project_file", null);
}
if (cmd.hasOption("nj")) {
map.put("no_jimple", "true");
} else {
map.put("no_jimple", "false");
}
if (cmd.hasOption("scg")) {
map.put("simple_call_graph", "true");
} else {
map.put("simple_call_graph", "false");
}
return map;
}
private static void showUsage(Options options) {
HelpFormatter formatter = new HelpFormatter();
formatter.printHelp("java " + Main.class + " [OPTIONS] project",
options);
}
private static final String DEFAULT_PROJECTS_FILE_NAME = "projects.xml";
private static File findDefaultProjectsFile() {
URL url = ClassLoader.getSystemResource(DEFAULT_PROJECTS_FILE_NAME);
if (url == null) {
return null;
}
File file = new File(url.getFile());
if (file == null || !file.exists() || !file.isFile()) {
return null;
}
return file;
}
}