The question on this page asks how to run a java program from a php page:
Run Java class file from PHP script on a website
I want to do the exact same thing from a JSP page. I don't want to import the classes and call functions or anything complicated like that. All I want to do is run a command like:
java Test
from a JSP page and then get whatever is printed out to System.out by Test saved in a variable in the JSP page.
How do I do this?
Thanks a lot!!
You can do this via Runtime.exec():
Process p = Runtime.getRuntime().exec("java Test");
BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = input.readLine();
while (line != null) {
// process output of the command
// ...
}
input.close();
// wait for the command complete
p.waitFor();
int ret = p.exitValue();
Since you already have a JVM running you should be able to do it by instantiating a classloader with the jars and reflectively find the main method and invoke it.
This is some boilerplate that may be helpful:
// add the classes dir and each file in lib to a List of URLs.
List urls = new ArrayList();
urls.add(new File(CLASSES).toURL());
for (File f : new File(LIB).listFiles()) {
urls.add(f.toURL());
}
// feed your URLs to a URLClassLoader
ClassLoader classloader =
new URLClassLoader(
urls.toArray(new URL[0]),
ClassLoader.getSystemClassLoader().getParent());
// relative to that classloader, find the main class and main method
Class mainClass = classloader.loadClass("Test");
Method main = mainClass.getMethod("main",
new Class[]{args.getClass()});
// well-behaved Java packages work relative to the
// context classloader. Others don't (like commons-logging)
Thread.currentThread().setContextClassLoader(classloader);
// Invoke with arguments
String[] nextArgs = new String[]{ "hello", "world" }
main.invoke(null, new Object[] { nextArgs });
Related
HI all i am trying to use this apache common exec, using this i am trying to create and write to a file.
the command line argument to write to a file is follows
Example: PDFAnnotator.exe "C:\My Documents\Test.pdf"
I have tried the following
public PrintResultHandler print(final File file, final long printJobTimeout, final boolean printInBackground)
throws IOException {
int exitValue;
ExecuteWatchdog watchdog = null;
PrintResultHandler resultHandler;
// build up the command line to using a 'java.io.File'
CommandLine commandLine = new CommandLine("C:\\Program Files (x86)\\Adobe\\Reader 11.0\\Reader\\AcroRd32.exe");
//CommandLine cmdLine = new CommandLine("C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe");
Map map = new HashMap();
map.put("file", new File("C:\\test\\invoice.pdf"));
commandLine.addArgument("/p");
commandLine.addArgument("/h");
commandLine.addArgument("${file}");
// create the executor and consider the exitValue '1' as success
final Executor executor = new DefaultExecutor();
executor.setExitValue(1);
// create a watchdog if requested
if (printJobTimeout > 0) {
watchdog = new ExecuteWatchdog(printJobTimeout);
executor.setWatchdog(watchdog);
}
// pass a "ExecuteResultHandler" when doing background printing
if (printInBackground) {
System.out.println("[print] Executing non-blocking print job ...");
resultHandler = new PrintResultHandler(watchdog);
executor.execute(commandLine, (Map<String, String>) resultHandler);
}
else {
System.out.println("[print] Executing blocking print job ...");
exitValue = executor.execute(commandLine);
resultHandler = new PrintResultHandler(exitValue);
}
return resultHandler;
}
it does not create any pdf file as an output can you please suggest.
It seems this code has been modified from the Apache Commons Exec tutorial code. There are a couple of modifications to the code it seems you have made which have caused problems.
Firstly, you have deleted the line
commandLine.setSubstitutionMap(map);
Without this line, you are creating the variable map, putting a single value into this map and then doing nothing further with it. Clearly, having a map that you never read any values out of achieves nothing. Reinstate this line, it's important.
The other problem is the line
executor.execute(commandLine, (Map<String, String>) resultHandler);
The difference between this code and the tutorial code is that you have added the cast to Map<String, String>. resultHandler is a PrintResultHandler, but this class does not implement Map<String, String> so this cast will fail.
I don't see why you have the cast at all. Get rid of it to leave you with:
executor.execute(commandLine, resultHandler);
If your code continues not to work, then I can't say what the reasons would be. Maybe the Adode Reader executable isn't where you think it is, maybe the file doesn't exist or doesn't have read permissions. In any case, suitable details should be written to standard output or standard error to help you further diagnose the problem.
There are many answers to this question in the stackoverflow?
But the most cast the ClassLoader.getSystemClassLoader() to URLClassLoader and this works anymore.
The classes must be found by the systemclassloader.
Is there an another solution?
- without restarting the jar
- without creating a own classloader (In this case I must replace the systemclassloader with my own)
The missing classes/jars must be added at the moment only on startup and I didn't want to add these in the manifest with "Classpath".
I found the Java Agent with the premain-Method. This can also work great, but in this case I want to start the premain method without calling "java -javaagent:... -jar ..."
Currently I restart my programm at the beginning with the missing classpaths:
public class LibLoader {
protected static List<File> files = new LinkedList<>();
public static void add(File file) {
files.add(file);
}
public static boolean containsLibraries() {
RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean();
String[] classpaths = runtimeMxBean.getClassPath().split(System.getProperty("path.separator"));
List<File> classpathfiles = new LinkedList<>();
for(String string : classpaths) classpathfiles.add(new File(string));
for(File file : files) {
if(!classpathfiles.contains(file)) return false;
}
return true;
}
public static String getNewClassPaths() {
StringBuilder builder = new StringBuilder();
RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean();
builder.append(runtimeMxBean.getClassPath());
for(File file : files) {
if(builder.length() > 0) builder.append(System.getProperty("path.separator"));
builder.append(file.getAbsolutePath());
}
return builder.toString();
}
public static boolean restartWithLibrary(Class<?> main, String[] args) throws IOException {
if(containsLibraries()) return false;
List<String> runc = new LinkedList<>();
runc.add(System.getProperty("java.home") + "\\bin\\javaw.exe");
RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean();
List<String> arguments = runtimeMxBean.getInputArguments();
runc.addAll(arguments);
File me = new File(LibLoader.class.getProtectionDomain().getCodeSource().getLocation().getPath());
String classpaths = getNewClassPaths();
if(!classpaths.isEmpty()) {
runc.add("-cp");
runc.add(classpaths);
}
if(me.isFile()) {
runc.add("-jar");
runc.add(me.getAbsolutePath().replace("%20", " "));
} else {
runc.add(main.getName());
}
for(String arg : args) runc.add(arg);
ProcessBuilder processBuilder = new ProcessBuilder(runc);
processBuilder.directory(new File("."));
processBuilder.redirectOutput(Redirect.INHERIT);
processBuilder.redirectError(Redirect.INHERIT);
processBuilder.redirectInput(Redirect.INHERIT);
Process process = processBuilder.start();
try {
process.waitFor();
} catch (InterruptedException e) {
e.printStackTrace();
}
return true;
}
}
Hope someone has a better solution.
Problem is, the classes must be found my the system ClassLoader not by a new ClassLoader.
It sound like your current solution of relaunching the JVM is the only clean way to do it.
The system ClassLoader cannot be changed, and you cannot add extra JARs to it at runtime.
(If you tried to use reflection to mess with the system classloader's data structures, at best it will be non-portable and version dependent. At worst it will be either error prone ... or blocked by the JVM's runtime security mechanisms.)
The solution suggested by Johannes Kuhn in a comment won't work. The java.system.class.loader property is consulted during JVM bootstrap. By the time your application is running, making changes to it will have no effect. I am not convinced that the approach in his Answer would work either.
Here is one possible alternative way to handle this ... if you can work out what the missing JARs are early enough.
Write yourself a Launcher class that does the following:
Save the command line arguments
Find the application JAR file
Extract the Main-Class and Class-Path attributes from the MANIFEST.MF.
Work out what the real classpath should be based on the above ... and other application specific logic.
Create a new URLClassLoader with the correct classpath, and the system classloader as its parent.
Use it to load the main class.
Use reflection to find the main classes main method.
Call it passing the save command line arguments.
This is essentially the approach that Spring Bootstrap and OneJar (and other things) take to handle the "jars in a jar" problem and so on. It avoids launching 2 VMs.
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 passing multiple tab delim files into R via Java.The R programm merges those tab delim files as single file and sends back to java and it is captured in the variable "name".Now I want to rename and save that file stored in "name" as tab delim using save dialog box in windows.Any help highly appreciated.Here is the java code:
import org.rosuda.REngine.*;
public class rjava {
// Before this run Rserve() command in R
public String ana(String filenames)
{
String name = "";
try{
System.out.println("INFO: Trying to connect to R ");
RConnection c = new RConnection();
System.out.println("INFO: Connected to R");
System.out.println("INFO: The Server version is "+ c.getServerVersion());
// c.voidEval("source('D:/combine/combining_files.r')");
c.voidEval("source('D:/combine/merge.r')");
c.assign("file",filenames);
// name = (c.eval("fn(file)").asString());
name = (c.eval("combine (file)").asString());
c.close();
}
catch(Exception e)
{
System.out.println("ERROR: In Connection to R");
System.out.println("The Exception is "+ e.getMessage());
e.printStackTrace();
}
return name;
}
}
I find passing complex objects between R and Java to be a pain the ass. I would not pass the full data, but rather would pass only file names as a string. Either have Java tell R to write out the new file (my pref) or have Java read in the file and then write out with a new name.
Can you modify the R program, so that it outputs files in the same path with a given file name, such as [path]/filename.out?
Otherwise, you can modify the execte string so that the R program outputs in a given location.
See http://cran.r-project.org/doc/manuals/R-intro.html#Invoking-R-from-the-command-line
When working at a command line on UNIX or Windows, the command ‘R’ can be used both for starting the main R program in the form R [options] [<infile] [>outfile]
-- EDIT
I just saw that you are using an RConnection. According to the R docs, you can define where to pipe stdout
The function sink, sink("record.lis") will divert all subsequent output from the console to an external file, record.lis.
Yes, the Internet says - "unzip them all, decompile and compare the code with some tool (total comander, WinCompare, meld(linux), whatever...) The reason why I need a tool to generate difference report automatically from Fodler1 and Folder2 is simple - there are too much JARs in these Folders and I need to compare these folders (with next version of Jars) say 1 time in a month. So, I really do not want to do it manually at all!
Let's see what I've got so far:
1) I can find all JARs in each Folder:)
2) I can get the list of classes from each JAR:
private static void AddAllClassesFromJAR(JarInputStream jarFile,
ArrayList<String> classes) throws IOException {
JarEntry jarEntry = null;
while (true) {
jarEntry = jarFile.getNextJarEntry();
if (jarEntry == null) {
break;
}
if (jarEntry.getName().endsWith(".class")) {
classes.add(jarEntry.getName());
}
}
}
public static List<String> getClasseNamesInPackage(String jarName) {
ArrayList<String> classes = new ArrayList<String>();
try {
JarInputStream jarFile = new JarInputStream(new FileInputStream(jarName));
AddAllClassesFromJAR(jarFile, classes);
} catch (Exception e) {
e.printStackTrace();
}
return classes;
}
3) There is Reflection in Java (Core Java 2 Volume I - Fundamentals, Example 5-5), so I can get the list of methods from one class once I know its name.
In order to do that I need to make an instance of each class, the problem is how can I make the instance of each Class which I got from each JAR file?
Now I'm loading each JAR:
loader_left = new JarClassLoader("left/1.jar");
public class JarClassLoader extends URLClassLoader {
public JarClassLoader( URL url ) {
super( new URL[]{url} );
}
public JarClassLoader( String urlString ) throws MalformedURLException {
this( new URL( "jar:file://" + urlString + "!/" ) );
}
No exceptions, but I can not find any resource in it, trying to load the class like:
class_left = loader_left.loadClass("level1.level2.class1");
And getting "java.lang.ClassNotFoundException".
Any glue where is the problem? (class name is verified. it is hardcoded just for testing, ideally it should get it from the list of the classes)
Second question: since most of the classes in Folder1 and Folder2 will be same, what will happen if I load the same class second time (from Fodler2)?
Try the jarcomp utility.
This is not directly answering your question, however you may get a look to the ASM framework . This allows you to analyze bytecode without having to load the classes with the class loader. It is probably easier to do it this way.