I'd like to get UnitGraph from a Java Class.
I load it by ClassFile and get the method_info of main().
Then I create a CFG and try to convert it into a UnitGraph.
My method is to get JimpleBody of the CFG and then create a UnitGraph.
However, I can't get JimpleBody by invoking cfg.jimplify(...) since it throws the following error:
Exception in thread "main" java.lang.RuntimeException: no method associated w/ body
at soot.Body.getMethod(Body.java:137)
at soot.coffi.CFG.jimplify(CFG.java:814)
at com.LiveVariableAnalysis.main(LiveVariableAnalysis.java:151)
My code is as follows:
String mainClassName = "Calculate";
String mainClassPath = String.format("./target/test-classes/%s.class", mainClassName);
ClassFile mainClassFile = new ClassFile(mainClassName);
FileInputStream is = new FileInputStream(mainClassPath);
mainClassFile.loadClassFile(is);
logger.info(String.format("Loading Class: %s ...", mainClassFile));
method_info methodInfo = null;
for (method_info method: mainClassFile.methods) {
if (Objects.equals(method.toName(mainClassFile.constant_pool), "main")) {
methodInfo = method;
}
}
logger.info(String.format("Loading method_info: %s ...", methodInfo.toName(mainClassFile.constant_pool)));
mainClassFile.parseMethod(methodInfo);
CFG cfg = new CFG(methodInfo);
JimpleBody jimpleBody = new JimpleBody();
// Error occurs here
cfg.jimplify(mainClassFile.constant_pool, mainClassFile.this_class, mainClassFile.bootstrap_methods_attribute, jimpleBody);
UnitGraph unitGraph = new ClassicCompleteUnitGraph(jimpleBody);
logger.info(String.format("Creating unitGraph with %d units ...", unitGraph.size()));
I know there are other ways to create a UnitGraph, such as:
String mainClassName = "Calculate";
SootClass mainClass = Scene.v().loadClassAndSupport(className);
Scene.v().setMainClass(mainClass);
soot.Main.main(args);
SootClass mainClass = Scene.v().getMainClass();
String methodSignature = "void main(java.lang.String[])";
SootMethod mainMethod = mainClass.getMethod(methodSignature);
Body jimpleBody = mainMethod.retrieveActiveBody();
UnitGraph unitGraph = new ClassicCompleteUnitGraph(jimpleBody);
However, in this way, I need to set Scene.v().setSootClassPath(path) for jce.jar and rt.jar, which I don't want to occur in my code. So if there is another way I can get UnitGraph without setting such a path, please help me.
Although I still can't turn method_info into a SootMathod and then get a UnitGraph, I can use Options.v().set_prepend_classpath(true) to avoid set jce.jar and rt.jar dirctly. This also achieves my goal.
Related
Hi everyone tried different ways to run a groovy in java with no luck, had read some documentation but things aren't that clear at the moment.
Anyone may know how to run this groovy?
package com.test.dev.search;
public class SearchQueryBase implements SearchQuery {
public QueryString getMatterQuery( SearchFilter filter ) {
String[] terms = filter.getSearchTerm().toLowerCase().split( " " );
...
...
...
}
}
This is a .groovy file (the one from above), I've tried the follow to run it without luck.
Down here is the Java class in which I want to run the above Groovy and execute getMatterQuery() to see the output from java main.
public static void main(String args[]) throws CGException {
String TEMPLATE_PACKAGE_PREFIX = "<path_to_groovy_file.";
String templateFileName = TEMPLATE_PACKAGE_PREFIX + "SearchQueryBase";
SearchFilter test = null;
Binding binding = new Binding();
binding.setVariable("filter", test);
GroovyShell shell = new GroovyShell(binding);
shell.evaluate(templateFileName);
System.out.println("Finish");
}
EDIT #1
This is the error I'm getting when I run it;
Exception in thread "main" groovy.lang.MissingPropertyException: No such property: Common for class: Script1
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:50)
at org.codehaus.groovy.runtime.callsite.PogoGetPropertySite.getProperty(PogoGetPropertySite.java:49)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callGroovyObjectGetProperty(AbstractCallSite.java:231)
at Script1.run(Script1.groovy:1)
at groovy.lang.GroovyShell.evaluate(GroovyShell.java:580)
at groovy.lang.GroovyShell.evaluate(GroovyShell.java:618)
at groovy.lang.GroovyShell.evaluate(GroovyShell.java:589)
1.
the GroovyShell.evaluate(java.lang.String scriptText) accepts string as a groovy text (content), and you try to call it with filename instead. use shell.evaluate( new File(templateFileName) )
2.
you can continue using shell.evaluate( new File(...) ) but keep in your groovy file only content of the method getMatterQuery():
String[] terms = filter.getSearchTerm().toLowerCase().split( " " );
...
...
...
so you'll have groovy script, and your code should work
3.
if you want to keep groovy as a class and call the method getMatterQuery() from this class with parameter, then your java code should be like this:
import groovy.lang.*;
...
public static void main(String[]s)throws Exception{
GroovyClassLoader cl=new GroovyClassLoader();
//path to base folder where groovy classes located
cl.addClasspath(path_to_groovy_root);
//the groovy file with SearchQueryBase.groovy
//must be located in "com/test/dev/search" subfolder under path_to_groovy_root
Class c = cl.loadClass("com.test.dev.search.SearchQueryBase");
SearchQuery o = (SearchQuery) c.newInstance();
System.out.println( o.getMatterQuery(test) );
}
I'm using Nutch to crawl some websites (as a process that runs separate of everything else), while I want to use a Java (Scala) program to analyse the HTML data of websites using Jsoup.
I got Nutch to work by following the tutorial (without the script, only executing the individual instructions worked), and I think it's saving the websites' HTML in the crawl/segments/<time>/content/part-00000 directory.
The problem is that I cannot figure out how to actually read the website data (URLs and HTML) in a Java/Scala program. I read this document, but find it a bit overwhelming since I've never used Hadoop.
I tried to adapt the example code to my environment, and this is what I arrived at (mostly by guesswprk):
val reader = new MapFile.Reader(FileSystem.getLocal(new Configuration()), ".../apache-nutch-1.8/crawl/segments/20140711115438/content/part-00000", new Configuration())
var key = null
var value = null
reader.next(key, value) // test for a single value
println(key)
println(value)
However, I am getting this exception when I run it:
Exception in thread "main" java.lang.NullPointerException
at org.apache.hadoop.io.SequenceFile$Reader.next(SequenceFile.java:1873)
at org.apache.hadoop.io.MapFile$Reader.next(MapFile.java:517)
I am not sure how to work with a MapFile.Reader, specifically, what constructor parameters I am supposed to pass to it. What Configuration objects am I supposed to pass in? Is that the correct FileSystem? And is that the data file I'm interested in?
Scala:
val conf = NutchConfiguration.create()
val fs = FileSystem.get(conf)
val file = new Path(".../part-00000/data")
val reader = new SequenceFile.Reader(fs, file, conf)
val webdata = Stream.continually {
val key = new Text()
val content = new Content()
reader.next(key, content)
(key, content)
}
println(webdata.head)
Java:
public class ContentReader {
public static void main(String[] args) throws IOException {
Configuration conf = NutchConfiguration.create();
Options opts = new Options();
GenericOptionsParser parser = new GenericOptionsParser(conf, opts, args);
String[] remainingArgs = parser.getRemainingArgs();
FileSystem fs = FileSystem.get(conf);
String segment = remainingArgs[0];
Path file = new Path(segment, Content.DIR_NAME + "/part-00000/data");
SequenceFile.Reader reader = new SequenceFile.Reader(fs, file, conf);
Text key = new Text();
Content content = new Content();
// Loop through sequence files
while (reader.next(key, content)) {
try {
System.out.write(content.getContent(), 0,
content.getContent().length);
} catch (Exception e) {
}
}
}
}
Alternatively, you can use org.apache.nutch.segment.SegmentReader (example).
I am successfully able to compile Groovy in Java at runtime and store it in a database and pull it out. I can't compile a Groovy class if it has inner classes or an inner enum. Has anyone successfully compiled Groovy code like this and included inner classes/enums and able to pull the script out by classname?
For example, I want to load the "Test" script shown below that contains inner classes and run the script at run time.
Compiler code:
public byte[] compileGroovyScript(final String className, final String script) {
byte[] compiledScriptBytes = null;
CompilationUnit compileUnit = new CompilationUnit();
compileUnit.addSource(className, script);
compileUnit.compile(Phases.CLASS_GENERATION);
for (Object compileClass : compileUnit.getClasses()) {
GroovyClass groovyClass = (GroovyClass) compileClass;
compiledScriptBytes = groovyClass.getBytes();
}
return compiledScriptBytes;
}
Code to pull script out:
public Class getGroovyScript(final String className, final byte[] script) {
Class clazz = null;
try (GroovyClassLoader classLoader = new GroovyClassLoader(this.getClass().getClassLoader())) {
clazz = classLoader.defineClass(className, script);
} catch (IOException e) {
} catch (Exception e) {
}
return clazz;
}
Code to run the script:
Class groovyClass = app.getGroovyScript(className, compiledScript);
TestScript script = (TestScript) groovyClass.newInstance();
System.out.println(script.getMessage());
Groovy script:
import com.groovy.groovy.TestScript
class Test implements TestScript {
String getMessage() {
[1..10].each(){
println it
}
return "Jello"
}
}
It isn't clear from the description why you are doing the compiling yourself. If you can just let Groovy do it for you then the whole thing can just be simplified to something like this:
String script = // string containing the script you want to parse
GroovyClassLoader groovyClassLoader = new GroovyClassLoader();
Class theParsedClass = groovyClassLoader.parseClass(script);
Ok this may be a little late but hopefully it helps the next person. I think you need to save a List for each groovy class and then cl.defineClass and finally cl.loadClass. I think groovy sometimes compile to a list of classes basically as in below when I addSource(), I add one class and then loop over all the generated classes from that one file.
This is the code I am currently running(though I have not tried saving and reloading at a later time)
GroovyClassLoader cl = new GroovyClassLoader();
CompilationUnit compileUnit = new CompilationUnit();
compileUnit.addSource(scriptCode.getClassName(), scriptCode.getScriptSourceCode());
compileUnit.compile(Phases.CLASS_GENERATION);
compileUnit.setClassLoader(cl);
GroovyClass target = null;
for (Object compileClass : compileUnit.getClasses()) {
GroovyClass groovyClass = (GroovyClass) compileClass;
cl.defineClass(groovyClass.getName(), groovyClass.getBytes());
if(groovyClass.getName().equals(scriptCode.getClassName())) {
target = groovyClass;
}
}
if(target == null)
throw new IllegalStateException("Could not find proper class");
return cl.loadClass(target.getName());
take note of the cl.defineClass call which puts the class in the classloader so when it is looked up(the enum or innerclass), it will be there.
and so now I think you do not need to create your own class loader(though you avoid useless defineClass until it is needed with your own classloader which can be useful and more performant).
This forgoes any error handling for the sake of simplicity here, but this is probably what you want:
public byte[] compileGroovyScript(final String className, final String script) {
byte[] compiledScriptBytes = null;
CompilationUnit compileUnit = new CompilationUnit();
compileUnit.addSource(className, script);
compileUnit.compile(Phases.CLASS_GENERATION);
List classes = compileUnit.getClasses();
GroovyClass firstClass = (GroovyClass)classes.get(0);
compiledScriptBytes = firstClass.getBytes();
return compiledScriptBytes;
}
Depending on your requirements, you might want to provide access to the inner classes and you could do that with something like this which finds the class with the matching name instead of assuming the first class:
public byte[] compileGroovyScript(final String className, final String script) {
byte[] compiledScriptBytes = null;
CompilationUnit compileUnit = new CompilationUnit();
compileUnit.addSource(className, script);
compileUnit.compile(Phases.CLASS_GENERATION);
for (Object compileClass : compileUnit.getClasses()) {
GroovyClass groovyClass = (GroovyClass) compileClass;
if(className.equals(groovyClass.getName())) {
compiledScriptBytes = groovyClass.getBytes();
break;
}
}
return compiledScriptBytes;
}
I am running into this myself but having just done an on-demand java compiler at runtime, I believe you are running into the same issue I solved in this code
https://github.com/deanhiller/webpieces/tree/master/runtimecompile/src/main/java/org/webpieces/compiler/api
webpieces/runtimecompile is a re-usable on-demand java compiler using the eclipse compiler.
Now, for groovy, I think you are running into this case
1. you compile ONE script
2. this results in 'multiple' class file objects (I think) just like mine did
3. This is where you need to store EACH in the database SEPARATELY
4. Then you need a classloader that tries to lookup the 'inner classes' when jvm asks for it
5. finally you do a yourclassLoader.loadApplicationClass (much like the one in CompileOnDemandImpl.java in the project above
6. To be clear, step 5 causes step 4 to happen behind the scenes (and that is what is confusing).
If you step through the test case AnonymousByteCacheTest, it pretty much is doing something like that.
you don't need to install ANYTHING to run the build on that project, just clone it and "./gradlew test" and will pass and "./gradlew eclipse" or "./gradlew idea" and it generates IDE files so you can step through it.
It is very very similar. I am trying to get the groovy version working next myself.
Actually I need to download the XLS file from Test Resource using Resource ID in java
Can any one help me out Please
I tried with below pece of code but m missing something on it
IQCResourceFolderFactory rft = tdc.queryInterface(IQCResourceFolderFactory.class);
Com4jObject dfe = rft.item(3252);
IQCResourceFactory fds = dfe.queryInterface(IQCResourceFactory.class);
IList C = fds.newList("");
System.out.println(C.count());
above code throw me "Null pointer exception in Com4jObject dfe = rft.item(3252);
Please Help
Thanks in advance
Successfully downloaded the desired files from Test Resources by providing Resource Folder ID
Here is the working source code :
ITDConnection6 QCConnection = ClassFactory.createTDConnection();
QCConnection object should be declared with ITDConnection6 to access all QC attributes
IQCResourceFolderFactory resourceFolderFactory = QCConnection.qcResourceFolderFactory().queryInterface(IQCResourceFolderFactory.class);
IList folders = resourceFolderFactory.newList("");
for(Com4jObject rec : folders)
{
IQCResourceFolder resourceFolder = rec.queryInterface(IQCResourceFolder.class);
if(resourceFolder.id().toString().equals(properties.getProperty("ResourceFolderID")))
{
Com4jObject objResourceFactory = resourceFolder.qcResourceFactory();
IQCResourceFactory resourceFactory = objResourceFactory.queryInterface(IQCResourceFactory.class);
IList resources = resourceFactory.newList("");
for(Com4jObject objResource : resources)
{
IQCResource resource = objResource.queryInterface(IQCResource.class); ;
IResourceStorage resourceStorage = resource.queryInterface(IResourceStorage.class);
resourceStorage.downloadResource("D:\\", true);
}
}
}
Is there any way to run program compiled by JavaCompiler? [javax.tools.JavaCompiler]
My code:
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
CompilationTask task = compiler.getTask(null, null, diagnostics, null, null, prepareFile(nazwa, content));
task.call();
List<String> returnErrors = new ArrayList<String>();
String tmp = new String();
for (Diagnostic diagnostic : diagnostics.getDiagnostics()) {
tmp = String.valueOf(diagnostic.getLineNumber());
tmp += " msg: "+ diagnostic.getMessage(null);
returnErrors.add(tmp.replaceAll("\n", " "));
}
Now i want to run that program with lifetime 1 sec and get output to string variable. Is there any way i could do that?
You need to use reflection, something like that:
// Obtain a class loader for the compiled classes
ClassLoader cl = fileManager.getClassLoader(CLASS_OUTPUT);
// Load the compiled class
Class compiledClass = cl.loadClass(CLASS_NAME);
// Find the eval method
Method myMethod = compiledClass.getMethod("myMethod");
// Invoke it
return myMethod.invoke(null);
Adapt it of course to suit your needs
You have to add the compiled class to the current classpath.
There's a number of ways to do that, depending on how your project is set up. Here's one instance using java.net.URLClassLoader:
ClassLoader cl_old = Thread.currentThread().getContextClassLoader();
ClassLoader cl_new = new URLClassLoader(urls.toArray(new URL[0]), cl_old);
where "urls" is a list of urls pointing to the filesystem.