I am running a Java application through my JSP page.
is it possible to redirect everything that the Java app prints into System.out into my page?
Edit:
I have a package pkg which contains a main function. this function has lots of System.out.println calls. e.g.
package pkg;
public class pkg {
public static void main(String[] args) {
System.out.println("Hello");
}
}
In my index.jsp I call:
<%
pkg.pkg.main(new String[] {});
%>
I need to see everything the pkg.pkg.main prints on the page. e.g.
Hello
A naive approach would be to call System.setOut() with a suitably wrapped response output stream. However, this would not work once multiple concurrent requests kick in, as there would be no differentiation between the outputs from the different threads.
You could create your own output stream subclass that delegates to another thread-local output stream which you set to your response's output stream before invoking your pkgmain() method on each request. If your pkgmain() spawns additional threads then this approach might not work (though you could try using InheritableThreadLocal in this case).
Refactor the code of the called class so that it takes a Writer as argument, and print to this Writer rather than System.out:
package pkg;
public class pkg {
public static void main(String[] args) {
main(new OutputStreamWriter(System.out), args);
}
public static void main(Writer writer, String[] args) {
PrintWriter out = new PrintWriter(writer);
out.println("Hello");
}
}
and call this second main method from your JSP (which should be a servlet):
<%
pkg.main(out, new String[] {});
%>
Another approach, if you can't edit the source code of the to be executed class, is to use Runtime#exec() to execute the class programmatically using the java command the usual way like as you would execute it in command prompt and then capture its stdout (and stderr!) by Process.
Process process = Runtime.getRuntime().exec("java -cp /path/to/your/pkg pkg.pkg");
InputStream stdout = process.getInputStream();
InputStream stderr = process.getErrorStream();
// Read and write it to response.getOutputStream() the usual way.
If you have never really used Runtime#exec() before, I strongly recommend to read this well known JavaWorld article (all the 4 pages) to learn and understand its caveats.
Last but not least, keep in mind that Java/JSP code runs physically in the machine where the webserver runs (the server side), not where the webbrowser runs (the client side) and also that the webserver's Java run time security manager should allow executing Runtime#exec() from inside a webapp. If you intend to deploy this app to a 3rd party host on which you don't have control over the security manager, chances are big that Runtime#exec() call will be blocked and throw SecurityException.
Needless to say, this is all pretty smelly. If those classes concerns user-controlled code, you're putting possibly huge security exploit holes open.
Related
I want to call node js function from java:
here is my hello.js javascript code:
function myFun(param)
{
console.log("hello"+param);
}
here is my java code:
public static void main(String[] args) throws IOException {
Process process = new ProcessBuilder("C:\\Program Files\\nodejs\\node.exe","hello.js").start();
InputStream is = process.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
}
With this java code i am able to execute hello.js file but i want to call myFun function and set the parameters in this function from java code .. is it possible to do this.
You can use GraalVM to call node.js function from java.
GraalVM offers you a polyglot runtime and the distribution includes both a JDK and a node.
You can execute JavaScript from Java, embedding the JavaScript context in your Java program, like this:
import org.graalvm.polyglot.*;
import org.graalvm.polyglot.proxy.*;
public class HelloPolyglot {
static String JS_CODE = "(function myFun(param){console.log('hello '+param);})";
public static void main(String[] args) {
System.out.println("Hello Java!");
try (Context context = Context.create()) {
Value value = context.eval("js", JS_CODE);
value.execute(args[0]);
}
}
}
Note the () wrapping the function definition, I just want it to return the function immediately there. You can use other ways too, not just code in String too, Files, modules, etc.
And run it with GraalVM on the PATH:
❯ javac HelloPolyglot.java
❯ java HelloPolyglot StackOverflow
Hello Java!
hello StackOverflow
While it's not strictly necessary for this question, here's the Javadoc for the Value class so you can use the polyglot values.
This way you can use JavaScript. It won't have the platform capabilities node.js offers like the node event loop, fs access, etc, node is a separate platform and it's tricky to embed that into a JVM process.
What you can do -- is start the node process, which will start the JVM.
Imagine you have an app like app.js
var HelloPolyglot = Java.type("HelloPolyglot");
HelloPolyglot.main(["from node.js"]);
console.log("done");
You can then run (with GraalVM node):
❯ node --jvm --vm.cp=. app.js
Hello Java!
hello from node.js
done
Note that we pass --jvm to start it with the JVM (otherwise there'll be no capabiltiy to do Java), and pass the classpath of the Java program to the node so it knows how to start the JVM properly.
Both node and JVM then run in the same process, and the interop works using the same Value classes as above.
It's not that easy. You have a few possible methods to do that:
Use JNI-Bindings to V8 (Node.js is just V8 with a big library and some glue).
Use ProcessBuilder and pass the arguments.
(It's not exactly what you asked for) Use a Javascript-Engine written in Java (GraalVM)
Pros/Cons
Has the advantage, that it may give you a lot of control (==>More flexible), but writing JNI is hard, error-prone and time-consuming.
is the most simple solution, but not that flexible.
is maybe another solution, that can be superior to 1. (No need to ship native libraries) and 2. (Very fragile, as you need a specific location for node.exe).
I would suggest looking into https://github.com/caoccao/Javet, it allows you to embed a node.js runtime into a java application.
I have an integration test (ClientIT) which uses the logging output from a test helper Class (ClientBasic) to determine whether the test passes or fails. I have re-directed the System.out/System.err inside the ClientBasic class to provide a link back to ClientIT using an OutputStream as follows,
System.setOut(new PrintStream(ClientBasic.out));
System.setErr(new PrintStream(ClientBasic.err));
where,
static OutputStream out;
static OutputStream err;
In ClientIT I call Client basic as follows,
ClientBasic.process(clientArgs.getArguments(), out, err);
This works fine, exactly how I wanted except when I run it using the Maven Failsafe plugins as part of the Package/Verify goal I get the message,
[WARNING] Corrupted STDOUT by directly writing to native stream in
forked JVM 1. See FAQ web page and the dump file
/path-to-project/target/failsafe-reports/2019-07-17T13-33-44_769-jvmRun1.dumpstream
which has the effect of really corrupting the display output of any logging info when the ClientBasic runs as part of my integration test - run locally from the command line or in Jenkins (using mvn ...) - strangely it still works fine when I run it from inside the IDE - maybe its not calling the failsafe plug-in directly ?
Anyway the above effect is documented on the Maven site as Corrupted STDOUT
So to try and get around this problem what I would like to do is to simply hook onto the System.out/err stream and create a copy - i.e. a bit like a splitter, rather than re-directing the System.out stream.
Does anyone now if this is possible and if so how to do this ?
As the error does not immediately blame setOut/setErr, it should be possible to make ones own splitter extending PrintStream.
public class Splitter extends PrintStream {
public Splitter(PrintStream sysPS, PrintWriter myOut) { ... }
... override methods by code generation in IDE.
}
PrintStream myOut = ...;
Splitter outSplitter = new Splitter(System.out, myOut);
Splitter errSplitter = new Splitter(System.err, myOut);
System.setOut(outSplitter);
System.setErr(errSplitter);
...
// At end:
System.setOut(outSplitter.getSysPS());
System.setErr(errSplitter.getSysPS());
IDE code generation and a couple of smart regex replaces will give you a correct class.
Alternatively there probably exists such a splitter as a Logger.
I am trying to use py4j to open up a gateway that I can use to pass objects from java into python. When I try to open a gateway with the py4j function launch_gateway it does not seem to properly connect to my Java class. However, when I launch my java class in the command line and then connect to it in python using JavaGateway everything works as expected. I would like to be able to use the built in method as I am sure that I am not accounting for things that have already been considered in the design of py4j, but I'm just not sure what I'm doing wrong.
Let's say I wanted to create a gateway to the class sandbox.demo.solver.UtilityReporterEntryPoint.class. In the command line I can do this by executing the following:
java -cp /Users/grr/anaconda/share/py4j/py4j0.10.4.jar: sandbox.demo.solver.UtilityReporterEntryPoint py4j.GatewayServer
This launches as expected and I can use the methods in my class from within python after connecting to the gateway. So far so good.
My understanding of the py4j documentation would lead me to believe I should do the following to launch the gateway in python:
port = launch_gateway(classpath='sandbox.demo.solver.UtilityReporterEntryPoint')
params = GatewayParameters(port=port)
gateway= JavaGateway(gateway_parameters=params)
I get no errors when executing these three lines, but when I try to access my java class methods with gateway.entry_point.someMethod() it fails with the following error:
Py4JError: An error occurred while calling t.getReport. Trace:
py4j.Py4JException: Target Object ID does not exist for this gateway :t
at py4j.Gateway.invoke(Gateway.java:277)
at py4j.commands.AbstractCommand.invokeMethod(AbstractCommand.java:132)
at py4j.commands.CallCommand.execute(CallCommand.java:79)
at py4j.GatewayConnection.run(GatewayConnection.java:214)
at java.lang.Thread.run(Thread.java:745)
Obviously something is not getting called correctly within launch_gateway or I am feeding it the wrong information.
In the py4j source code for launch_gateway you can see that given the inputs you provide and those constructed by the function, a command is constructed that eventually gets called by subprocess.Popen. So given the input passed to launch_gateway above the command passed into Popen would be:
command = ['java', '-classpath', '/Users/grr/anaconda/share/py4j/py4j0.10.4.jar:sandbox.demo.solver.UtilityReporterEntryPoint', 'py4j.GatewayServer', '0']
Passing this command to Popen returns the listening port as expected. However, connecting to this listening port still does not allow access to my class methods.
Finally, passing the command as a single string to Popen without the final argument ('0'), properly launches a gateway which again operates as expected. Having taken a glance at the Java source code for py4j.GatewayServer.class this makes no sense as the main method seems to indicate that the class should exit with status 1 if the length of arguments is 0.
At this point I'm kind of at a loss. I can hack my way into a workable solution, but as I said I'm sure that ignores important aspects of the gateway behavior and I don't like hacky solutions. I'd love to tag #Barthelemy in this one, but hopefully he reads this. Thanks in advance for any help.
EDIT
For now I have been able to work around this issue with the following steps.
Package entire project including all external dependencies into a single jar file magABM-all.jar, with 'Main-Class' set to UtilityReporterEntryPoint.
Include if...else block regarding presence of --die-on-exit exactly like it is in GatewayServer.java
Use subprocess.Popen to call the command to run the project jar.
UtilityReporterEntryPoint.java
public static void main(String[] args) throws IOException {
GatewayServer server = new GatewayServer(new UtilityReporterEntryPoint());
System.out.println("Gateway Server Started");
server.start();
if (args[0].equals("--die-on-exit")) {
try {
BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in, Charset.forName("UTF-8")));
stdin.readLine();
System.exit(0);
} catch (java.io.IOException e) {
System.exit(1);
}
}
}
app.py
def setup_gateway()
"""Launch a py4j gateway using UtilityReporterEntryPoint."""
process = subprocess.Popen('java -jar magABM-all.jar --die-on-exit', shell=True)
time.sleep(0.5)
gateway = JavaGateway()
return gateway
In this way I can still use gateway.shutdown if necessary and if the python process that starts the py4j gateway dies or is closed the gateway will be closed.
N.B I would by no means consider this a final solution as py4j was written by much smarter individuals with a clear purpose in mind and I am sure that there is a way to manage this exact workflow within the confines of py4j. This is just a stopgap solution.
There are a few issues:
The classpath parameter in launch_gateway should be a directory or a jar file, not a class name. For example, if you want to include additional Java libraries, you would add them to the classpath parameter.
The error you receive when you call gateway.entry_point.someMethod() means that you have no entry point. When you call launch_gateway, the JVM is started with GatewayServer.main, which launches a GatewayServer with no entry point: GatewayServer server = new GatewayServer(null, port). It is not possible currently to use launch_gateway and specify an entry point.
When you start the JVM with java -cp /Users/grr/anaconda/share/py4j/py4j0.10.4.jar: sandbox.demo.solver.UtilityReporterEntryPoint py4j.GatewayServer I believe the JVM uses UtilityReporterEntryPoint as the main class. Although you did not provide the code, I assume that this class has a main method and that it launches a GatewayServer with an instance of UtilityReporterEntryPoint as the entry point. Note that there is a whitespace between the colon and the class name so UtilityReporterEntryPoint is seen as the main class and not as being part of the classpath.
Note: this question isn't necessary just for Android developers. It should be the same for Java developers that performed root operations on Linux too.
Background
My app allows the user the perform various root operations (an operation that can only be performed on rooted devices).
Until now, each time the app wishes to perform a root operation, I had opened a new process using the Runtime.getRuntime().exec("su") command.
I wish to improve the way the app works, by calling this command only once, and then writing to the outputStream and reading from the inputStream while doing so.
A similar app that does this is "Terminal emulator". Once you type there "su" (and grant it root permission), it will allow you go perform any root operation and read any path of the device.
The problem
It seems that only the "echo" command works, but any other command doesn't. Also, I couldn't think of a good way to separate between the root operations output.
What I've tried
First, in order to initialize the root batching operations, I did this:
process=Runtime.getRuntime().exec("su");
_inputStreamReader=new BufferedReader(new InputStreamReader(process.getInputStream()));
_out=process.getOutputStream();
final String testLine=Long.toString(System.currentTimeMillis());
_out.write(("echo "+testLine+"\n").getBytes());
_out.flush();
final String resultLine=_inputStreamReader.readLine();
if(resultLine==null)
{
_out.write("exit \n".getBytes());
_out.flush();
_out.close();
_out=null;
_inputStreamReader.close();
_inputStreamReader=null;
process.waitFor();
return false;
}
while(!resultLine.equals(testLine))
resultLine=_inputStreamReader.readLine();
return true;
the code above (is supposed to) ensures I have root and that I can continue working on the "_out" and "inputStreamReader" . the call to "echo" has 2 purposes : to have some fake operation being done, and to also become a starting point and a separator between commands.
Here the second purpose is fake, but for each operation that I make further, this is how I thought of handling the separation of various root operations.
Now, if I want to make another root operation (assuming the above works fine), this is an example of an operation I wish to perform :
_out.write(("find "+someFolderPath+"/* -type f\n").getBytes());
_out.flush();
final String line=_inputStreamReader.readLine();
Thing is, it gets stuck on the "readLine" part, even though it should return a list of all of the file/folders within the specified path.
This command works perfectly using the previous way I performed root operations, and it should work here too.
using "echo" before those lines and then using "readLine()" shows that it's still available, as I will still get the result line. However, trying to call "readLine()" again (after the above command) will still make it stuck.
I've also tried adding "su" (or "su -" or "su -c") before the "find" command, but it didn't help.
This is the old code, which works fine:
final Process p=Runtime.getRuntime().exec("su");
final InputStream inputStream=p.getInputStream();
final DataOutputStream os=new DataOutputStream(p.getOutputStream());
os.writeBytes("find "+someFolderPath+"/* -type f\n");
os.writeBytes("exit\n");
os.flush();
//read from the inputstream (using BufferedReader) as much as I wish, till it ends.
The question
How should I avoid re-creating new processes for root operations? Is this a good way to do it?
How can I fix the above code? What is wrong with it?
Also, Is there a good way to run multiple root operations using a single "su" command, yet without any kind of separator like the one I've used (so that I could differentiate when a new command output starts and the previous one ends).
I am sure, that your find command is just too slow. You should run it in the different process.
There is great library to do this. And a manual.
OK, even though it's not quite what I wanted, and even though I wanted to learn how to do it myself, I've found that "libsuperuser" library (by "ChainFire") does it much easier.
What I've asked for is called "interactive mode" in this library.
Here's a sample class I've made that helps you do it using this library:
public class Root
{
private static final Root _instance =new Root();
private Boolean _hasRoot =null;
private Shell.Interactive _rootSession;
public interface IGotRootListener
{
public void onGotRootResult(boolean hasRoot);
}
public static Root getInstance()
{
return _instance;
}
public boolean hasRoot()
{
return _hasRoot!=null&&_hasRoot;
}
//should be called on the UI thread
public void getRoot(final IGotRootListener listener)
{
if(_hasRoot!=null&&_hasRoot)
{
listener.onGotRootResult(true);
return;
}
final AtomicReference<Interactive> rootSessionRef=new AtomicReference<>();
rootSessionRef.set(new Shell.Builder().useSU().setWantSTDERR(true).setWatchdogTimeout(5).setMinimalLogging(true).open(new Shell.OnCommandResultListener()
{
#Override
public void onCommandResult(final int commandCode,final int exitCode,final List<String> output)
{
final boolean success=exitCode==Shell.OnCommandResultListener.SHELL_RUNNING;
if(success)
_rootSession=rootSessionRef.get();
_hasRoot=success;
listener.onGotRootResult(success);
}
}));
}
... // TODO add functions to call commands via _rootSession.addCommand , only if got root
Still, if anyone has a solution to my original question, I would love to know about it.
Edit 2 After recieving a response from Mathworks support I've answered the question myself. In brief, there is an options class MWComponentOptions that is passed to the exported class when instantiated. This can, among other things, specify unique print streams for error output and regular output (i.e. from disp()-liked functions). Thanks for all the responses none the less :)
====================================================================
Just a quick question - is there any way to prevent MATLAB code from outputting to the Java console with disp (and similar) functions once compiled? What is useful debugging information in MATLAB quickly becomes annoying extra text in the Java logs.
The compilation tool I'm using is MATLAB Compiler (which I think is not the same as MATLAB Builder JA, but I might be wrong). I can't find any good documentation on the mcc command so am not sure if there are any options for this.
Of course if this is impossible and a direct consequence of the compiler converting all MATLAB code to its Java equivalent then that's completely understandable.
Thanks in advance
Edit This will also be useful to handle error reporting on the Java side alone - currently all MATLAB errors are sent to the console regardless of whether they are caught or not.
The isdeployed function returns true if run in a deployed application (with e.g. MATLAB Compiler or Builder JA) and false when running in live MATLAB.
You can surround your disp statements with an if isdeployed block.
I heard back from a request to Mathworks support, and they provided the following solution:
When creating whatever class has been exported, you can specify an MWComponentOptions object. This is poorly documented in R2012b, but for what I wanted the following example would work:
MWComponentOptions options = new MWComponentOptions();
PrintStream o = new PrintStream(new File("MATLAB log.log"));
options.setPrintStream(o); // send all standard dips() output to a log file
// the following ignores all error output (this will be caught by Java exception handling anyway)
options.setErrorStream((java.io.PrintStream)null);
// instantiate and use the exported class
myClass obj = new myClass(options);
obj.myMatlabFunction();
// etc...
Update
In case anyone does want to suppress all output, casing null to java.io.PrintStream ended up causing a NullPointerException in deployment. A better way to suppress all output is use to create a dummy print stream, something like:
PrintStream dummy = new PrintStream(new OutputStream() {
public void close() {}
public void flush() {}
public void write(byte[] b) {}
public void write(byte[] b, int off, int len) {}
public void write(int b) {}
} );
Then use
options.setErrorStream(dummy);
Hope this helps :)
Another possible hack if you have a stand-alone application and don't want to bother with classes at all:
Use evalc and deploy your func name during compile:
function my_wrap()
evalc('my_orig_func(''input_var'')');
end
And compile like
mcc -m my_wrap my_orig_func <...>
Well, it is obviously yet another hack.