package kr.ac.snu.selab.soot.core;
import java.io.File;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.apache.log4j.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
public class ProjectManager {
private static Logger log = Logger.getLogger(ProjectManager.class);
private static final String DEFAULT_ROOT_DIRECTORY = "subjectsOfAnalysis";
private static ProjectManager instance = null;
public static ProjectManager getInstance() {
if (instance == null)
instance = new ProjectManager();
return instance;
}
private String targetRootPath = null;
private HashMap<String, AbstractProject> map;
private HashMap<String, String> abvMap;
private Map<String, String> jreLibraryMap;
private ProjectManager() {
map = new HashMap<String, AbstractProject>();
abvMap = new HashMap<String, String>();
}
public AbstractProject getProject(String projectName) {
String key = null;
if (abvMap.containsKey(projectName)) {
key = abvMap.get(projectName);
} else {
key = projectName;
}
return map.get(key);
}
public void loadProjects(InputStream is) throws ProjectFileParseException {
map.clear();
abvMap.clear();
if (is == null) {
throw new ProjectFileParseException(
"Unable to read project file: unknown error!!");
}
try {
DocumentBuilderFactory dbFactory = DocumentBuilderFactory
.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
dBuilder.setErrorHandler(new ErrorHandler() {
@Override
public void error(SAXParseException e) throws SAXException {
log.error(e.getMessage(), e);
}
@Override
public void fatalError(SAXParseException e) throws SAXException {
log.fatal(e.getMessage(), e);
}
@Override
public void warning(SAXParseException e) throws SAXException {
log.warn(e.getMessage(), e);
}
});
Document doc = dBuilder.parse(is);
doc.getDocumentElement().normalize();
String rootAttribute = doc.getDocumentElement()
.getAttribute("root");
if (rootAttribute == null || rootAttribute.equals("")) {
findDefaultTargetRoot();
} else {
rootAttribute = replaceText(rootAttribute, "\\/",
File.separator);
rootAttribute = replaceText(rootAttribute, "\\\\",
File.separator);
File rootDirectory = new File(rootAttribute);
targetRootPath = rootDirectory.getAbsolutePath();
}
loadJreLibraries();
NodeList nList = doc.getElementsByTagName("project");
for (int temp = 0; temp < nList.getLength(); temp++) {
Node nNode = nList.item(temp);
if (nNode.getNodeType() == Node.ELEMENT_NODE) {
Project project = parseProject((Element) nNode);
map.put(project.getProjectName(), project);
abvMap.put(project.projectNameAbv, project.getProjectName());
}
}
} catch (Exception e) {
throw new ProjectFileParseException(e);
}
}
private void findDefaultTargetRoot() throws ProjectFileParseException {
File rootDirectory = new File(System.getProperty("user.dir"));
File targetRoot = new File(rootDirectory, DEFAULT_ROOT_DIRECTORY);
if (targetRoot == null || !targetRoot.exists()
|| !targetRoot.isDirectory()) {
targetRootPath = null;
throw new ProjectFileParseException("Can not find target directory");
}
targetRootPath = targetRoot.getAbsolutePath();
}
private void loadJreLibraries() {
jreLibraryMap = new HashMap<String, String>();
String jreLibraryPath = System.getProperty("sun.boot.class.path");
String[] tokens = jreLibraryPath.split(File.pathSeparator);
for (String path : tokens) {
int lastIndexOfSeparator = path.lastIndexOf(File.separatorChar);
if (lastIndexOfSeparator < 0)
continue;
String fileName = path.substring(lastIndexOfSeparator + 1);
jreLibraryMap.put(fileName, path);
}
}
private Project parseProject(Element projectElement) {
String projectName = projectElement.getAttribute("name");
String projectNameAbv = projectElement.getAttribute("abv");
Project project = new Project(projectName, projectNameAbv);
NodeList nodeList = null;
Node node = null;
Element element = null;
String text = null;
nodeList = projectElement.getElementsByTagName("project_root");
assert (nodeList != null);
assert (nodeList.getLength() > 0);
node = nodeList.item(0);
assert (node.getNodeType() == Node.ELEMENT_NODE);
element = (Element) node;
text = element.getAttribute("path");
assert (text != null);
text = text.trim();
project.projectRoot = replaceKeywords(text, project, targetRootPath);
nodeList = projectElement.getElementsByTagName("source");
assert (nodeList != null);
assert (nodeList.getLength() > 0);
node = nodeList.item(0);
assert (node.getNodeType() == Node.ELEMENT_NODE);
element = (Element) node;
text = element.getAttribute("path");
assert (text != null);
text = text.trim();
project.sourcePath = replaceKeywords(text, project, targetRootPath);
nodeList = projectElement.getElementsByTagName("classpaths");
assert (nodeList != null);
assert (nodeList.getLength() > 0);
node = nodeList.item(0);
assert (node.getNodeType() == Node.ELEMENT_NODE);
parseClassPath((Element) node, project);
nodeList = projectElement.getElementsByTagName("output");
assert (nodeList != null);
assert (nodeList.getLength() > 0);
node = nodeList.item(0);
assert (node.getNodeType() == Node.ELEMENT_NODE);
element = (Element) node;
text = element.getAttribute("path");
assert (text != null);
text = text.trim();
project.setOutputPath(replaceKeywords(text, project, targetRootPath));
nodeList = projectElement.getElementsByTagName("jimple");
assert (nodeList != null);
assert (nodeList.getLength() > 0);
node = nodeList.item(0);
assert (node.getNodeType() == Node.ELEMENT_NODE);
element = (Element) node;
text = element.getAttribute("path");
assert (text != null);
text = text.trim();
project.setOutputJimplePath(replaceKeywords(text, project,
targetRootPath));
nodeList = projectElement.getElementsByTagName("include_package");
if (nodeList != null && nodeList.getLength() > 0) {
node = nodeList.item(0);
assert (node.getNodeType() == Node.ELEMENT_NODE);
element = (Element) node;
text = element.getAttribute("name");
assert (text != null);
text = text.trim();
project.setIncludePackage(text);
}
return project;
}
private void parseClassPath(Element parent, Project project) {
NodeList nodeList = null;
Node node = null;
Element element = null;
String text = null;
StringBuffer buffer = new StringBuffer();
if (jreLibraryMap.containsKey("classes.jar")) {
String path = jreLibraryMap.get("classes.jar");
buffer.append(path);
buffer.append(File.pathSeparator);
}
if (jreLibraryMap.containsKey("rt.jar")) {
String path = jreLibraryMap.get("rt.jar");
buffer.append(path);
buffer.append(File.pathSeparator);
}
nodeList = parent.getElementsByTagName("jre_path");
int length = nodeList.getLength();
for (int i = 0; i < length; i++) {
node = nodeList.item(i);
assert (node.getNodeType() == Node.ELEMENT_NODE);
element = (Element) node;
text = element.getTextContent();
assert (text != null);
text = text.trim();
if (!jreLibraryMap.containsKey(text)) {
continue;
}
String path = jreLibraryMap.get(text);
buffer.append(replaceKeywords(path, project, targetRootPath));
buffer.append(File.pathSeparator);
}
nodeList = parent.getElementsByTagName("path");
assert (nodeList != null);
length = nodeList.getLength();
assert (length > 0);
for (int i = 0; i < length; i++) {
node = nodeList.item(i);
assert (node.getNodeType() == Node.ELEMENT_NODE);
element = (Element) node;
text = element.getTextContent();
assert (text != null);
text = text.trim();
buffer.append(replaceKeywords(text, project, targetRootPath));
if (i < length - 1)
buffer.append(File.pathSeparator);
}
project.setClassPath(buffer.toString());
}
private static String replaceKeywords(String text, Project project,
String targetRootPath) {
text = replaceText(text, "\\$\\{ROOT\\}", targetRootPath);
text = replaceText(text, "\\$\\{PROJECT_NAME\\}",
project.getProjectName());
text = replaceText(text, "\\$\\{PROJECT_ROOT\\}", project.projectRoot);
text = replaceText(text, "\\$\\{SRC_PATH\\}", project.sourcePath);
text = replaceText(text, "\\$\\{OUTPUT_PATH\\}", project.outputPath);
text = replaceText(text, "\\/", File.separator);
text = replaceText(text, "\\\\", File.separator);
return text;
}
private static String replaceText(String text, String pattern, String to) {
if (to != null) {
to = to.replaceAll("\\\\", "\\\\\\\\");
text = text.replaceAll(pattern, to);
}
return text;
}
private static class Project extends AbstractProject {
private String sourcePath;
private File outputFile;
private String outputPath;
private String classPath;
private String outputJimplePath;
private String projectRoot;
private String projectNameAbv;
private String includePackage;
public Project(String aProjectName, String aProjectNameAbv) {
super(aProjectName);
this.projectNameAbv = aProjectNameAbv;
this.includePackage = null;
}
public void setOutputPath(String path) {
this.outputPath = path;
this.outputFile = new File(outputPath);
}
public String getClassPath() {
return classPath;
}
public String getJimpleDirectory() {
return outputJimplePath;
}
public String getSourceDirectory() {
return sourcePath;
}
@Override
public File getOutputDirectory() {
return outputFile;
}
public void setClassPath(String classPath) {
this.classPath = classPath;
}
public void setOutputJimplePath(String outputJimplePath) {
this.outputJimplePath = outputJimplePath;
}
@Override
public String getIncludePackage() {
return includePackage;
}
public void setIncludePackage(String pkg) {
this.includePackage = pkg;
}
}
}