changes to ease use of WALA from an executable jar. also some very

basic support for GXL, a graph format used by some software engineering
tools.
This commit is contained in:
Julian Dolby 2013-05-15 13:35:38 -04:00
parent 837528592a
commit 310d0fff25
10 changed files with 362 additions and 227 deletions

View File

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="source"/>
<classpathentry exported="true" kind="lib" path="lib/js.jar"/>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
<classpathentry kind="output" path="bin"/>

View File

@ -35,5 +35,5 @@ Export-Package: com.ibm.wala.cast.js.translator,
org.mozilla.javascript.xml,
org.mozilla.javascript.xml.impl.xmlbeans,
org.mozilla.javascript.xmlimpl
Bundle-ClassPath: lib/rhino-1.7R3.jar,
.
Bundle-ClassPath: .,
lib/js.jar

View File

@ -2,5 +2,5 @@ source.. = source/
output.. = bin/
bin.includes = META-INF/,\
.,\
lib/rhino-1.7R3.jar
lib/js.jar
jars.extra.classpath = lib/rhino-1.7R3.jar

View File

@ -9,33 +9,43 @@ import com.ibm.wala.ipa.callgraph.AnalysisScope;
import com.ibm.wala.ipa.callgraph.CallGraph;
import com.ibm.wala.ipa.callgraph.Entrypoint;
import com.ibm.wala.ipa.callgraph.cha.CHACallGraph;
import com.ibm.wala.ipa.callgraph.impl.AllApplicationEntrypoints;
import com.ibm.wala.ipa.callgraph.impl.Util;
import com.ibm.wala.ipa.cha.ClassHierarchy;
import com.ibm.wala.ipa.cha.ClassHierarchyException;
import com.ibm.wala.ipa.cha.IClassHierarchy;
import com.ibm.wala.util.CancelException;
import com.ibm.wala.util.functions.Function;
public class CHACallGraphTest {
@Test public void testJava_cup() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException {
testCHA(TestConstants.JAVA_CUP, TestConstants.JAVA_CUP_MAIN);
testCHA(TestConstants.JAVA_CUP, TestConstants.JAVA_CUP_MAIN, CallGraphTestUtil.REGRESSION_EXCLUSIONS);
}
public static CallGraph testCHA(String scopeFile, final String mainClass, final String exclusionsFile) throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException {
return testCHA(scopeFile, exclusionsFile, new Function<IClassHierarchy, Iterable<Entrypoint>>() {
@Override
public Iterable<Entrypoint> apply(IClassHierarchy cha) {
return Util.makeMainEntrypoints(cha.getScope(), cha, mainClass);
}
});
}
public static CallGraph testCHA(String scopeFile, String mainClass) throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException {
AnalysisScope scope = CallGraphTestUtil.makeJ2SEAnalysisScope(scopeFile, CallGraphTestUtil.REGRESSION_EXCLUSIONS);
ClassHierarchy cha = ClassHierarchy.make(scope);
Iterable<Entrypoint> entrypoints;
if (mainClass == null) {
entrypoints = new AllApplicationEntrypoints(scope, cha);
} else {
entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, mainClass);
}
public static CallGraph testCHA(String scopeFile,
String exclusionsFile,
Function<IClassHierarchy, Iterable<Entrypoint>> makeEntrypoints)
throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException
{
AnalysisScope scope = CallGraphTestUtil.makeJ2SEAnalysisScope(scopeFile, exclusionsFile);
IClassHierarchy cha = ClassHierarchy.make(scope);
CHACallGraph CG = new CHACallGraph(cha);
CG.init(entrypoints);
CG.init(makeEntrypoints.apply(cha));
return CG;
}
public static void main(String[] args) throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException {
testCHA(args[0], args.length>1? args[1]: null);
testCHA(args[0], args.length>1? args[1]: null, "Java60RegressionExclusions.txt");
}
}

View File

@ -0,0 +1,228 @@
/*******************************************************************************
* Copyright (c) 2002 - 2006 IBM Corporation.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package com.ibm.wala.classLoader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.jar.JarInputStream;
import java.util.zip.ZipEntry;
import com.ibm.wala.util.collections.HashMapFactory;
import com.ibm.wala.util.debug.Assertions;
import com.ibm.wala.util.io.FileSuffixes;
import com.ibm.wala.util.warnings.Warning;
import com.ibm.wala.util.warnings.Warnings;
/**
* A Jar file nested in a parent jar file
*/
public abstract class AbstractNestedJarFileModule implements Module {
private static final boolean DEBUG = false;
/**
* For efficiency, we cache the byte[] holding each ZipEntry's contents; this will help avoid multiple unzipping TODO: use a soft
* reference?
*/
private HashMap<String, byte[]> cache = null;
protected abstract InputStream getNestedContents() throws IOException;
public InputStream getInputStream(String name) {
populateCache();
byte[] b = cache.get(name);
return new ByteArrayInputStream(b);
}
private void populateCache() {
if (cache != null) {
return;
}
cache = HashMapFactory.make();
try {
final JarInputStream stream = new JarInputStream(getNestedContents());
for (ZipEntry z = stream.getNextEntry(); z != null; z = stream.getNextEntry()) {
final String name = z.getName();
if (DEBUG) {
System.err.println(("got entry: " + name));
}
if (FileSuffixes.isClassFile(name) || FileSuffixes.isSourceFile(name)) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] temp = new byte[1024];
int n = stream.read(temp);
while (n != -1) {
out.write(temp, 0, n);
n = stream.read(temp);
}
byte[] bb = out.toByteArray();
cache.put(name, bb);
}
}
} catch (IOException e) {
// just go with what we have
Warnings.add(new Warning() {
@Override
public String getMsg() {
return "could not read contents of nested jar file " + toString();
}
});
}
}
protected long getEntrySize(String name) {
populateCache();
byte[] b = cache.get(name);
return b.length;
}
/*
* @see com.ibm.wala.classLoader.Module#getEntries()
*/
public Iterator<ModuleEntry> getEntries() {
populateCache();
final Iterator<String> it = cache.keySet().iterator();
return new Iterator<ModuleEntry>() {
String next = null;
{
advance();
}
private void advance() {
if (it.hasNext()) {
next = it.next();
} else {
next = null;
}
}
public boolean hasNext() {
return next != null;
}
public ModuleEntry next() {
ModuleEntry result = new Entry(next);
advance();
return result;
}
public void remove() {
Assertions.UNREACHABLE();
}
};
}
/**
* @author sfink an entry in a nested jar file.
*/
private class Entry implements ModuleEntry {
private final String name;
Entry(String name) {
this.name = name;
}
/*
* @see com.ibm.wala.classLoader.ModuleEntry#getName()
*/
public String getName() {
return name;
}
/*
* @see com.ibm.wala.classLoader.ModuleEntry#isClassFile()
*/
public boolean isClassFile() {
return FileSuffixes.isClassFile(getName());
}
/*
* @see com.ibm.wala.classLoader.ModuleEntry#getInputStream()
*/
public InputStream getInputStream() {
return AbstractNestedJarFileModule.this.getInputStream(name);
}
/*
* @see com.ibm.wala.classLoader.ModuleEntry#isModuleFile()
*/
public boolean isModuleFile() {
return false;
}
/*
* @see com.ibm.wala.classLoader.ModuleEntry#asModule()
*/
public Module asModule() {
Assertions.UNREACHABLE();
return null;
}
@Override
public String toString() {
return "nested entry: " + name;
}
/*
* @see com.ibm.wala.classLoader.ModuleEntry#getClassName()
*/
public String getClassName() {
return FileSuffixes.stripSuffix(getName());
}
/*
* @see com.ibm.wala.classLoader.ModuleEntry#isSourceFile()
*/
public boolean isSourceFile() {
return FileSuffixes.isSourceFile(getName());
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + getOuterType().hashCode();
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Entry other = (Entry) obj;
if (!getOuterType().equals(other.getOuterType()))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
private AbstractNestedJarFileModule getOuterType() {
return AbstractNestedJarFileModule.this;
}
}
}

View File

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2002 - 2006 IBM Corporation.
* Copyright (c) 2007 IBM Corporation.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@ -11,37 +11,15 @@
package com.ibm.wala.classLoader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.jar.JarInputStream;
import java.util.zip.ZipEntry;
import com.ibm.wala.util.collections.HashMapFactory;
import com.ibm.wala.util.debug.Assertions;
import com.ibm.wala.util.io.FileSuffixes;
import com.ibm.wala.util.warnings.Warning;
import com.ibm.wala.util.warnings.Warnings;
/**
* A Jar file nested in a parent jar file
*/
public class NestedJarFileModule implements Module {
private static final boolean DEBUG = false;
public class NestedJarFileModule extends AbstractNestedJarFileModule {
private final JarFileModule parent;
private final ZipEntry entry;
/**
* For efficiency, we cache the byte[] holding each ZipEntry's contents; this will help avoid multiple unzipping TODO: use a soft
* reference?
*/
private HashMap<String, byte[]> cache = null;
public NestedJarFileModule(JarFileModule parent, ZipEntry entry) {
this.parent = parent;
this.entry = entry;
@ -53,190 +31,9 @@ public class NestedJarFileModule implements Module {
}
}
public InputStream getInputStream(String name) {
populateCache();
byte[] b = cache.get(name);
return new ByteArrayInputStream(b);
}
private void populateCache() {
if (cache != null) {
return;
}
cache = HashMapFactory.make();
final byte[] b = parent.getContents(entry);
try {
final JarInputStream stream = new JarInputStream(new ByteArrayInputStream(b));
for (ZipEntry z = stream.getNextEntry(); z != null; z = stream.getNextEntry()) {
final String name = z.getName();
if (DEBUG) {
System.err.println(("got entry: " + name));
}
if (FileSuffixes.isClassFile(name) || FileSuffixes.isSourceFile(name)) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] temp = new byte[1024];
int n = stream.read(temp);
while (n != -1) {
out.write(temp, 0, n);
n = stream.read(temp);
}
byte[] bb = out.toByteArray();
cache.put(name, bb);
}
}
} catch (IOException e) {
// just go with what we have
Warnings.add(new Warning() {
@Override
public String getMsg() {
return "could not read contents of nested jar file " + entry.getName() + ", parent " + parent.getAbsolutePath();
}
});
}
}
protected long getEntrySize(String name) {
populateCache();
byte[] b = cache.get(name);
return b.length;
}
/*
* @see com.ibm.wala.classLoader.Module#getEntries()
*/
public Iterator<ModuleEntry> getEntries() {
populateCache();
final Iterator<String> it = cache.keySet().iterator();
return new Iterator<ModuleEntry>() {
String next = null;
{
advance();
}
private void advance() {
if (it.hasNext()) {
next = it.next();
} else {
next = null;
}
}
public boolean hasNext() {
return next != null;
}
public ModuleEntry next() {
ModuleEntry result = new Entry(next);
advance();
return result;
}
public void remove() {
Assertions.UNREACHABLE();
}
};
}
/**
* @author sfink an entry in a nested jar file.
*/
private class Entry implements ModuleEntry {
private final String name;
Entry(String name) {
this.name = name;
}
/*
* @see com.ibm.wala.classLoader.ModuleEntry#getName()
*/
public String getName() {
return name;
}
/*
* @see com.ibm.wala.classLoader.ModuleEntry#isClassFile()
*/
public boolean isClassFile() {
return FileSuffixes.isClassFile(getName());
}
/*
* @see com.ibm.wala.classLoader.ModuleEntry#getInputStream()
*/
public InputStream getInputStream() {
return NestedJarFileModule.this.getInputStream(name);
}
/*
* @see com.ibm.wala.classLoader.ModuleEntry#isModuleFile()
*/
public boolean isModuleFile() {
return false;
}
/*
* @see com.ibm.wala.classLoader.ModuleEntry#asModule()
*/
public Module asModule() {
Assertions.UNREACHABLE();
return null;
}
@Override
public String toString() {
return "nested entry: " + name;
}
/*
* @see com.ibm.wala.classLoader.ModuleEntry#getClassName()
*/
public String getClassName() {
return FileSuffixes.stripSuffix(getName());
}
/*
* @see com.ibm.wala.classLoader.ModuleEntry#isSourceFile()
*/
public boolean isSourceFile() {
return FileSuffixes.isSourceFile(getName());
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + getOuterType().hashCode();
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Entry other = (Entry) obj;
if (!getOuterType().equals(other.getOuterType()))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
private NestedJarFileModule getOuterType() {
return NestedJarFileModule.this;
}
@Override
protected InputStream getNestedContents() {
return new ByteArrayInputStream(parent.getContents(entry));
}
@Override
@ -269,4 +66,4 @@ public class NestedJarFileModule implements Module {
return true;
}
}
}

View File

@ -0,0 +1,31 @@
/*******************************************************************************
* Copyright (c) 2007 IBM Corporation.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package com.ibm.wala.classLoader;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
public class ResourceJarFileModule extends AbstractNestedJarFileModule {
private final URL resourceURL;
public ResourceJarFileModule(URL resourceURL) {
this.resourceURL = resourceURL;
}
@Override
protected InputStream getNestedContents() throws IOException {
return resourceURL.openConnection().getInputStream();
}
}

View File

@ -23,6 +23,7 @@ import java.util.regex.Pattern;
import com.ibm.wala.classLoader.IClass;
import com.ibm.wala.ipa.callgraph.impl.SetOfClasses;
import com.ibm.wala.types.TypeReference;
import com.ibm.wala.util.io.FileProvider;
/**
* An object which represents a set of classes read from a text file.
@ -43,7 +44,7 @@ public class FileOfClasses extends SetOfClasses implements Serializable {
private boolean needsCompile = false;
private FileOfClasses(File textFile) throws IOException {
this(new FileInputStream(textFile));
this(textFile.exists()? new FileInputStream(textFile): FileProvider.class.getClassLoader().getResourceAsStream(textFile.getName()));
}
public static FileOfClasses createFileOfClasses(File textFile) throws IOException {

View File

@ -27,6 +27,7 @@ import java.util.zip.ZipException;
import com.ibm.wala.classLoader.JarFileModule;
import com.ibm.wala.classLoader.Module;
import com.ibm.wala.classLoader.NestedJarFileModule;
import com.ibm.wala.classLoader.ResourceJarFileModule;
import com.ibm.wala.util.debug.Assertions;
/**
@ -35,7 +36,7 @@ import com.ibm.wala.util.debug.Assertions;
public class FileProvider {
private final static int DEBUG_LEVEL = 0;
private final static int DEBUG_LEVEL = Integer.parseInt(System.getProperty("wala.debug.file", "0"));
/**
* @param fileName
@ -164,6 +165,8 @@ public class FileProvider {
JarEntry entry = jc.getJarEntry();
JarFileModule parent = new JarFileModule(f);
return new NestedJarFileModule(parent, entry);
} else if (url.getProtocol().equals("rsrc")) {
return new ResourceJarFileModule(url);
} else {
String filePath = filePathFromURL(url);
return new JarFileModule(new JarFile(filePath, false));

View File

@ -0,0 +1,64 @@
package com.ibm.wala.util.graph;
import java.util.Iterator;
import java.util.Map;
import com.ibm.wala.util.functions.Function;
public class GXL {
public interface EntityTypes<T> {
String type(T entity);
String type(Graph<T> entity);
String type(T from, T to);
}
public static <T> String toGXL(Graph<T> G,
EntityTypes<T> types,
String graphId,
Function<T,String> nodeIds,
Function<T,Map<String,String>> nodeProperties)
{
StringBuffer sb = new StringBuffer();
sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
sb.append("<!DOCTYPE gxl SYSTEM \"http://www.gupro.de/GXL/gxl-1.0.dtd\">\n");
sb.append("<gxl xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n");
sb.append(" <graph id=\"" + graphId + "\" edgemode=\"directed\" hypergraph=\"false\">\n");
sb.append(" <type xlink:href=\"" + types.type(G) + "\"/>\n");
for(T n : G) {
sb.append(" <node id=\"" + nodeIds.apply(n) + "\">\n");
sb.append(" <type xlink:href=\"" + types.type(n) + "\"/>\n");
Map<String,String> props = nodeProperties.apply(n);
if (props != null) {
for(Map.Entry<String,String> e : props.entrySet()) {
sb.append(" <attr name=\"" + e.getKey() + "\">\n");
if (e.getValue() != null) {
sb.append(" <string>" + e.getValue() + "</string>\n");
} else {
sb.append(" <string/>\n");
}
sb.append(" </attr>\n");
}
}
sb.append(" </node>\n");
}
for(T n : G) {
Iterator<T> ss = G.getSuccNodes(n);
while (ss.hasNext()) {
T s = ss.next();
sb.append(" <edge from=\"" + nodeIds.apply(n) + "\" to=\"" + nodeIds.apply(s) + "\">\n");
sb.append(" <type xlink:href=\"" + types.type(n, s) + "\"/>\n");
sb.append(" </edge>\n");
}
}
sb.append(" </graph>\n");
sb.append("</gxl>\n");
return sb.toString();
}
}