Problem description: Compile 2 jar files independently, without having to include each other on classpath; and at runtime, include both and invoke main() in one jar to print a string on stdout. Parts of the output string have to come from the 2nd jar.
Constraints: The solution cannot be IDE-dependent or use any other jar files.
Answering what have I done so far: My Solution is described below.
Reason to ask the question: I am trying to figure out if/how to use annotations to solve this problem (hopefully in a more elegant manner), but cannot find any suitable documentation or tutorial. I appreciate any pointer(s) for that also.
My Solution: A batch file (on Unix, please change the backslash to forward slash, semicolon to colon and the rem's to #) as follows:
rem Compile and package the testing class (Main) without any library
javac -d target core\*.java
cd target
jar cvf ..\main.jar .\core
cd ..
rem Compile and package the Greeting and Greeted classes as a library
javac -d lib impl\*.java
cd lib
jar cvf ..\mylib.jar .\impl
cd ..
rem Use the two parts above at runtime and execute main() in Main class
java -cp main.jar;mylib.jar core.Main
There are 2 files in the impl directory and 2 in the core, as follows:
/* File: impl/Greeting.java */
package impl;
public class Greeting {
public String getGreeting () {
return "Hello";
}}
/* File: impl/Greeted.java */
package impl;
public class Greeted {
public String getGreeted () {
return "world";
}
/* File: core/Main.java */
package core;
public class Main {
private String greeting = "Learn annotations", greeted = "keep using Java",
// Can read the following 4 values from a configuration file, too
// Trying to see if we can get these using Java annotations
greetingClassName = "impl.Greeting", greetingMethod = "getGreeting",
greetedClassName = "impl.Greeted", greetedMethod = "getGreeted";
public Main () {
try {
MyRunTime runTime = new MyRunTime();
Object gting = runTime.getInstance(greetingClassName),
gted = runTime.getInstance(greetedClassName),
g1Str = runTime.getResponseNoArg (gting, greetingMethod),
g2Str = runTime.getResponseNoArg (gted, greetedMethod);
if (g1Str instanceof String) greeting = (String) g1Str;
if (g2Str instanceof String) greeted = (String) g2Str;
} catch (Exception ex) {
System.err.println ("Error in Library loading: " + ex.getMessage());
}}
public void greet () {
System.out.println (greeting + ", " + greeted + "!");
}
public static void main (String[] args) {
new Main().greet();
}}
/* File: core/MyRunTime.java */
package core;
import java.lang.reflect.*;
public class MyRunTime {
public Object getResponseNoArg (Object anInstance, String methodName) throws
NoSuchMethodException,
IllegalAccessException,
InvocationTargetException {
Method method = anInstance.getClass().getMethod (methodName);
return method.invoke (anInstance);
}
public Object getInstance (String className) throws
ClassNotFoundException,
InstantiationException,
IllegalAccessException {
Class c = Class.forName (className);
return c.newInstance();
}
}
That's it. I would also like not to mess with the ClassLoader unless absolutely necessary. Once I get a handle on how to do this with annotations, I can look into passing arguments and go forward. Thank you for your help.
I wouldn't use Annotations for this - it's probably worth covering what Annotations are and where they are best used.
Instead I would do something like:
Place different files in each jar
A main class to each jar file, which does the same thing: list the files on the classpath
I think that would meet the project requirements.
To list the files on the classpath you could so something like:
public class Main {
public static void main(final String[] args) throws java.lang.Throwable {
final String list = System.getProperty( "java.class.path" );
for (String path : list.split( ";" )) {
java.io.File object = new java.io.File( path );
if ( object.isDirectory() )
for ( String entry : object.list() ) {
java.io.File thing = new java.io.File( entry );
if ( thing.isFile() )
System.out.println( thing );
else if( object.isFile() )
System.out.println( object );
}
}
}
}
Related
I'm pretty new to groovy, and scripting in java generally, and I really
hope there is a simple solution for my problem.
In our application, the users can execute groovy scripts which they write
themselves, and we need to control what those scripts can and can not do.
I read a lot of stuff about sandboxing groovy, but either I am looking at
wrong places or I am overlooking the obvious.
To make it simple, I have a small example which demonstrates the problem.
This is my class loader which should prevent java.lang.System from being
loaded and available to scripts:
public class MyClassLoader extends ClassLoader {
#Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
if (name.startsWith("java.lang.System")) {
throw new ClassNotFoundException("Class not found: " + name);
}
return super.loadClass(name);
}
}
And this is a simple program that tries to call System.currentTimeMillis():
public static void main(String[] args) {
String code = "java.lang.System.currentTimeMillis();";
ClassLoader classLoader = new MyClassLoader();
Thread.currentThread().setContextClassLoader(classLoader);
GroovyShell shell = new GroovyShell();
Script script = shell.parse(code);
Object result = script.run();
log.debug(result);
}
MyClassLoader throws exceptions for java.lang.SystemBeanInfo
and java.lang.SystemCustomizer, but the code executes.
Same thing happens if I use javax.script classes:
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByName("Groovy");
Object o = engine.eval(code);
log.debug(o);
And if I try it with JavaScript engine, it works as expected (just replace
"Groovy" with "JavaScript" in the above example).
Can anyone help me with this? BTW, I'm using groovy-all-1.8.8.jar, with
jdk1.7.0_55.
Thanks
I can recommend Groovy Sandbox for this purpose. In contrast to SecureASTCustomizer it will check if an execution is allowed dynamically at runtime. It intercepts every method call, object allocations, property/attribute access, array access, and so on - and you thus have a very fine grained control on what you allow (white-listing).
Naturally the configuration on what is allowed is very important. For example you may want to allow using Strings and use methods like substring, but probably not the execute method on String, which could be exploited with something like 'rm -R ~/*'.execute().
Creating a configuration that is really safe is a challenge, and it is more difficult the more you allow.
Downside of the Groovy Sandbox is that the code must run with the interceptor registered and you will have a performance penalty during execution.
This image [1] shows an example from a project where we used Groovy Sandbox for Groovy code entered by the user. The code is run to valide the script - so if the statement there would actually be executed as part of it, the application would have exited before I could do the screenshot ;)
Perhaps you'd be interested in using a SecureASTCustomizer in conjunction with a CompilerConfiguration. If you are concerned with security, an explicit white list might be better than a black list.
def s = new SecureASTCustomizer()
s.importsWhiteList = [ 'a.legal.Klass', 'other.legal.Klass' ]
def c = new CompilerConfiguration()
c.addCompilationCustomizers(s)
def sh = new GroovyShell(c)
Take a look at that class, it contains a lot of options that are ready to use.
import groovy.lang.GroovyClassLoader;
import groovy.lang.GroovyShell;
import groovy.lang.Script;
public class SandboxGroovyClassLoader extends ClassLoader {
public SandboxGroovyClassLoader(ClassLoader parent) {
super(parent);
}
#Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
if (name.startsWith("java.lang.System"))
return null;
return super.loadClass(name);
}
#Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
if (name.startsWith("java.lang.System"))
return null;
return super.loadClass(name, resolve);
}
static void runWithGroovyClassLoader() throws Exception {
System.out.println("Begin runWithGroovyClassLoader");
String code = "def hello_world() { java.lang.System.currentTimeMillis(); };";
GroovyClassLoader groovyClassLoader = new GroovyClassLoader();
Class<?> scriptClass = groovyClassLoader.parseClass(code);
Object scriptInstance = scriptClass.newInstance();
Object result = scriptClass.getDeclaredMethod("hello_world", new Class[] {}).invoke(scriptInstance, new Object[] {});
System.out.println(result);
groovyClassLoader.close();
System.out.println("End runWithGroovyClassLoader");
}
static void runWithSandboxGroovyClassLoader() throws Exception {
System.out.println("Begin runWithSandboxGroovyClassLoader");
ClassLoader parentClassLoader = SandboxGroovyClassLoader.class.getClassLoader();
SandboxGroovyClassLoader classLoader = new SandboxGroovyClassLoader(parentClassLoader);
String code = "def hello_world() { java.lang.System.currentTimeMillis(); };";
GroovyClassLoader groovyClassLoader = new GroovyClassLoader(classLoader);
Class<?> scriptClass = groovyClassLoader.parseClass(code);
Object scriptInstance = scriptClass.newInstance();
Object result = scriptClass.getDeclaredMethod("hello_world", new Class[] {}).invoke(scriptInstance, new Object[] {});
System.out.println(result);
groovyClassLoader.close();
System.out.println("End runWithSandboxGroovyClassLoader");
}
static void runWithSandboxGroovyShellClassLoader() throws Exception {
System.out.println("Begin runWithSandboxGroovyShellClassLoader");
String code = "java.lang.System.currentTimeMillis();";
ClassLoader parentClassLoader = SandboxGroovyClassLoader.class.getClassLoader();
SandboxGroovyClassLoader classLoader = new SandboxGroovyClassLoader(parentClassLoader);
Thread.currentThread().setContextClassLoader(classLoader);
GroovyShell shell = new GroovyShell();
Script script = shell.parse(code);
Object result = script.run();
System.out.println(result);
System.out.println("End runWithSandboxGroovyShellClassLoader");
}
public static void main(String[] args) throws Exception {
runWithGroovyClassLoader();
runWithSandboxGroovyClassLoader();
runWithSandboxGroovyShellClassLoader();
}
}
Is it what you want ?
Here is my code to invoke a java project from another java project
package pkgtry;
import java.io.*;
public class Try
{
private static void runProcess(String command) throws Exception
{
Process pro = Runtime.getRuntime().exec(command);
pro.waitFor();
InputStream inputStream = pro.getInputStream();
int b = -1;
while ( (b = inputStream.read()) != -1 )
{
System.out.write(b);
}
}
public static void main(String[] args)
{
int x=10;
try
{
runProcess("javac -d . C:\\Users\\owner\\Documents\\NetBeansProjects\\input\\src\\input\\Input.java");
runProcess("java input.Input");
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
This code is working perfectly. What i want is to pass an variable say 'x' from Try.java to Input.java
i would like to know the what all changes are to be made in Try.java to send the parameter and in Input.java to receive the parameter. Thanks in advance
You need to append it to command and in Input.java in main method you will have this value stored in args parameter.
Everything you want to pass to the called program is added to its commandline, like this
runProcess("java input.Input All Parameters You Want To Pass");
In Input.java you can retrieve these parameters by reading out String[] args, like this:
public class Input {
public static void main (String[] args) {
for (String s: args) {
System.out.println(s);
}
}
}
will produce
All
Parameters
You
Want
To
Pass
But you should know that this is a rather heavy-handed way to make one piece of Java code call some other piece of Java code, you can add the jar produced by the project containing Input to the Try project and instantiate the Input class directly. Calling via the command line is slow and cumbersome, and severely limits the communication between the two classes (command line parameters in one direction, an integer return value in the other direction.
I've got a java class, calling a native method and trying to load library:
import java.io.UnsupportedEncodingException;
public class Main {
public static native String getMyString(String s);
/**
* #param args
* #throws UnsupportedEncodingException
*/
public static void main(String[] args) throws UnsupportedEncodingException {
// TODO Auto-generated method stub
// System.out.println("here!");
String s2 = getMyString("string text");
for (Byte b : s2.getBytes("UTF-8")) {
System.out.print(b);
System.out.print(",");
}
}
static {
System.loadLibrary("mylib.so");
}
}
The "mylib.so" is in the directory, where Main.class is located.
When I run java Main I get following exception:
Exception in thread "main" java.lang.UnsatisfiedLinkError: no mylib.so in java.library.path
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1856)
at java.lang.Runtime.loadLibrary0(Runtime.java:845)
at java.lang.System.loadLibrary(System.java:1084)
at Main.<clinit>(Main.java:24)
What should I change for this to wark?
I've tried setting library full path without success
Do the following:
Use System.loadLibrary("mylib");
Copy mylib.so to libmylib.so
Run java -Djava.library.path=/root/ Main
"How to load native library"
public final class NativeLibsLoaderUtil {
private static final String JAVA_LIBRARY_PATH = "java.library.path";
private static final String SYS_PATHS = "sys_paths";
private NativeLibsLoaderUtil() {
}
private static void addLibsToJavaLibraryPath(final String tmpDirName) {
try {
System.setProperty(JAVA_LIBRARY_PATH, tmpDirName);
/* Optionally add these two lines */
System.setProperty("jna.library.path", tmpDirName);
System.setProperty("jni.library.path", tmpDirName);
final Field fieldSysPath = ClassLoader.class.getDeclaredField(SYS_PATHS);
fieldSysPath.setAccessible(true);
fieldSysPath.set(null, null);
} catch (IllegalAccessException | NoSuchFieldException e) {
LOGGER.error(e.getMessage(), e);
}
}
}
Where tmpDirName is a directory where you store your library.
Or you can modify above class and use temp directory from your system property, like this:
/**
* Temporary directory system property name
*/
private static final String JAVA_IO_TMPDIR = "java.io.tmpdir";
/**
*
* #return
*/
private static File getTempDir() {
final String tmpDirName = System.getProperty(JAVA_IO_TMPDIR);
final File tmpDir = new File(tmpDirName);
if (!tmpDir.exists()) {
tmpDir.mkdir();
}
return tmpDir;
}
!But first you have to copy there your native lib :)
Then to load native library call "addLibsToJavaLibraryPath" method in static block in "most root" class before any class constructor was executed.
static {
NativeLibsLoaderUtil.addLibsToJavaLibraryPath("/tmp");
}
You should add the so to library path:
-Djava.libarary.path= (this is in the java command).
if you run from eclipse:
How to add native library to "java.library.path" with Eclipse launch (instead of overriding it)
If you compiled opencv, on installation you should have seen something like:
make install:
-- Up-to-date: /usr/local/share/java/opencv4/libopencv_java460.so
-- Up-to-date: /usr/local/share/java/opencv4/opencv-460.jar
make a hard link to the /usr/lib/ folder:
$ sudo ln /usr/local/share/java/opencv4/libopencv_java460.so /usr/lib/libopencv_java460.so
And then just run:
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
that he will get the *.so
As Reimeus answered.
Or you can use
System.load("/Library/Path/libsample.so");
How do you call a function defined in a Groovy script file from Java?
Example groovy script:
def hello_world() {
println "Hello, world!"
}
I've looked at the GroovyShell, GroovyClassLoader, and GroovyScriptEngine.
Assuming you have a file called test.groovy, which contains (as in your example):
def hello_world() {
println "Hello, world!"
}
Then you can create a file Runner.java like this:
import groovy.lang.GroovyShell ;
import groovy.lang.GroovyClassLoader ;
import groovy.util.GroovyScriptEngine ;
import java.io.File ;
class Runner {
static void runWithGroovyShell() throws Exception {
new GroovyShell().parse( new File( "test.groovy" ) ).invokeMethod( "hello_world", null ) ;
}
static void runWithGroovyClassLoader() throws Exception {
// Declaring a class to conform to a java interface class would get rid of
// a lot of the reflection here
Class scriptClass = new GroovyClassLoader().parseClass( new File( "test.groovy" ) ) ;
Object scriptInstance = scriptClass.newInstance() ;
scriptClass.getDeclaredMethod( "hello_world", new Class[] {} ).invoke( scriptInstance, new Object[] {} ) ;
}
static void runWithGroovyScriptEngine() throws Exception {
// Declaring a class to conform to a java interface class would get rid of
// a lot of the reflection here
Class scriptClass = new GroovyScriptEngine( "." ).loadScriptByName( "test.groovy" ) ;
Object scriptInstance = scriptClass.newInstance() ;
scriptClass.getDeclaredMethod( "hello_world", new Class[] {} ).invoke( scriptInstance, new Object[] {} ) ;
}
public static void main( String[] args ) throws Exception {
runWithGroovyShell() ;
runWithGroovyClassLoader() ;
runWithGroovyScriptEngine() ;
}
}
compile it with:
$ javac -cp groovy-all-1.7.5.jar Runner.java
Note: Runner.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
(Note: The warnings are left as an exercise to the reader) ;-)
Then, you can run this Runner.class with:
$ java -cp .:groovy-all-1.7.5.jar Runner
Hello, world!
Hello, world!
Hello, world!
The simplest way is to compile the script into a java class file and just call it directly. Example:
// Script.groovy
def hello_world() {
println "Hello, World!"
}
// Main.java
public class Main {
public static void main(String[] args) {
Script script = new Script();
script.hello_world();
}
}
$ groovyc Script.groovy
$ javac -classpath .:$GROOVY_HOME/embeddable/groovy-all-1.7.5.jar Main.java
$ java -classpath .:$GROOVY_HOME/embeddable/groovy-all-1.7.5.jar Main
Hello, World!
Either
Compile as ataylor suggests
Use JSR-223 as explained here
If you are using Spring, have a groovy class that implements a Java interface, and inject into your code with:
<lang:groovy id="messenger" script-source="classpath:Messenger.groovy">
<lang:property name="message" value="I Can Do The Frug" />
</lang:groovy>
One advantage of the spring approach is the concept of 'refreshable beans'. That is, Spring can be configured to monitor your script file for modifications, and replace at runtime.
You too can use the Bean Scripting Framework to embed any scripting language into your Java code. BSF give you the opportunity of integrate other languages, but is not native integration.
If you are clearly focused to use Groovy the GroovyScriptEngine is the most complete solution.
=)
One simple example:
import groovy.lang.GroovyClassLoader;
import groovy.lang.Script;
public class GroovyEmbedder {
static public final String GROOVY_SCRIPT=
"println ('Hello World !')";
static public void main(String[] args) throws Exception {
((Script) new GroovyClassLoader().parseClass(GROOVY_SCRIPT).newInstance()).run();
}
}
Testing
> javac -cp groovy-all-2.4.10.jar GroovyEmbedder.java
> java -cp groovy-all-2.4.10.jar:. GroovyEmbedder
Hello World !
Just more elegant ways:
GroovyScriptEngine engine = new GroovyScriptEngine( "." )
Object instance = engine
.loadScriptByName(scriptName)
.newInstance()
Object result = InvokerHelper.invokeMethod(instance, methodName, args)
And if script class extends groovy.lang.Script:
Object result = engine
.createScript(scriptName, new Binding())
.invokeMethod(methodName, args)
No need to extend groovy.lang.Script if you just want call main method of your groovy class:
Object result = engine
.createScript(scriptName, new Binding())
.run()
I'm writing a network app, where each Client has a Singleton ClientManager.
For testing, I would like to create several clients (each in their own VM / process) without starting the program by hand n-times.
The following two questions on stackoverflow already describe how-to do that:
Is this really the best way to start a second JVM from Java code?
Java: Executing a Java application in a separate process
My Code is based on these, but it's not working:
The main program doesn't continue after spawn is called.
The spawned code doesn't get executed.
Here's the complete code using ProcessBuilder:
public class NewVM {
static class HelloWorld2 {
public static void main(String[] args) {
System.out.println("Hello World");
System.err.println("Hello World 2");
}
}
public static void main(String[] args) throws Exception {
startSecondJVM(HelloWorld2.class, true);
startSecondJVM(HelloWorld2.class, false);
System.out.println("Main");
}
public static void startSecondJVM(Class<? extends Object> clazz, boolean redirectStream) throws Exception {
System.out.println(clazz.getCanonicalName());
String separator = System.getProperty("file.separator");
String classpath = System.getProperty("java.class.path");
String path = System.getProperty("java.home")
+ separator + "bin" + separator + "java";
ProcessBuilder processBuilder =
new ProcessBuilder(path, "-cp",
classpath,
clazz.getCanonicalName());
processBuilder.redirectErrorStream(redirectStream);
Process process = processBuilder.start();
process.waitFor();
System.out.println("Fin");
}
}
What am I doing wrong???
Btw:
I'm using Eclipse.
The Singleton problem is a simplified example. Please do not suggest creating a factory.
Solution: HelloWorld2 mustn't be an inner class.
I suggest you make HelloWorld2 a top level class. It appears java expects a top level class.
This is the code I tried.
class Main
{
static class Main2
{
public static void main ( String [ ] args )
{
System . out . println ( "YES!!!!!!!!!!!" ) ;
}
}
public static void main ( String [ ] args )
{
System . out . println ( Main2 . class . getCanonicalName ( ) ) ;
System . out . println ( Main2 . class . getName ( ) ) ;
}
}
class Main3
{
public static void main ( String [ ] args )
{
System . out . println ( "YES!!!!!!!!!!!" ) ;
}
}
getCanonicalName and getName return different names. Which one is right? They are both wrong.
Main3 works.
I think I see a fix for part of the problem: process.waitFor() prevents control from returning to main() before the subprocess ends.
To figure out why your spawned process isn't starting, I'd recommend printing out all the arguments to the ProcessBuilder constructor and checking that a hand-called JVM called with those arguments succeeds. In particular, you need that class name to be the name of a class having a static void main(String[]).