I have a spring boot project and out of which i have created a jar, and i am calling this jar from another project by passing arguments.
Not able to get the output and it is getting stuck.
The below is the project from which i am getting a jar.
public class Demo1Application {
public static void main(String[] args) {
System.out.println("jar called");
for(String arg : args) {
System.out.println("next argument is"+ arg );
}
SpringApplication.run(Demo1Application.class, args);
}
}
Its a simple spring boot main class.
The below is the class of another project from which i want to invoke this jar by passing arguments.
public class AAAAAAAAAAAAAAAAA {
public static void main(String[] args) throws IOException, InterruptedException {
File jarFile = new File("D:\\NewConfigWorkSpace\\Demo1\\target\\Demo1-0.0.1-SNAPSHOT.jar");
Process p = Runtime.getRuntime().exec("java -jar D:\\NewConfigWorkSpace\\Demo1\\target\\Demo1-0.0.1-SNAPSHOT.jar bisnu mohan");
p.waitFor();
System.out.println("finished");
}
}
How to see the console when i am calling the jar, how to track how much execution has been happened.
What you need is the input stream of created process. This is what is normally returned to a console when you run your application.
Process p = Runtime.getRuntime().exec("java -jar D:\\NewConfigWorkSpace\\Demo1\\target\\Demo1-0.0.1-SNAPSHOT.jar bisnu mohan");
InputStream inputStream = p.getInputStream();
You can then read contents of it and print to a console of a running process like this:
StringBuilder outputLines = new StringBuilder();
String output;
try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, UTF_8))) {
String line;
while ((line = reader.readLine()) != null) {
logger.info("Command execution output: " + line);
outputLines.append(line).append("\n");
}
} finally {
output = outputLines.toString().trim();
}
It would also be a good idea to handle error stream the same way, because you can then see if your subprocess returns some errors.
InputStream errorStream = p.getErrorStream();
Use this streams handling in a separate threads so they don't block each other.
From my point of view, you don't need to execute JAR via command line.
If you include JAR into your project you can just import SpringApplication from JAR and run it directly like this:
public class AAAAAAAAAAAAAAAAA {
public static void main(String[] args) throws IOException, InterruptedException {
SpringApplication.run(Demo1Application.class, args);
}
}
Related
I want to run pmd inside a java process(created using ProcessBuilder) from within spring as a service.
public class PMDService {
private ProcessBuilder processBuilder;
private void createProcess() {
processBuilder = new ProcessBuilder();
final Map<String, String> envMap = processBuilder.environment();
String path = envMap.get("Path");
path += "../../../../../../../static-code-analyzers/pmd/bin;";
envMap.put("Path", path);
}
public String getCommand(PMDParameters params) {
final StringJoiner command = new StringJoiner(" ");
command.add("cmd")
.add("/c")
.add("pmd")
.add("-d")
.add(params.getSourceCodePath())
.add("-f")
.add(params.getOutputFormat())
.add("-R")
.add(params.getResultSet())
.add(">")
.add(params.getResultsPath());
return command.toString();
}
public void runAnalyzer(PMDParameters params) throws IOException, InterruptedException {
createProcess();
processBuilder.command(getCommand(params));
final Process process = processBuilder.start();
process.waitFor();
}
When I test the rest endpoint using postman i get following error :
""message": "Cannot run program \"cmd /c pmd -d
C:/bootcamp/Spring/springbootcode/springbootdemo -f xml -R
rulesets/java/quickstart.xml > .\": CreateProcess error=2, The system
cannot find the file specified","
Input json in postman
{
"sourceCodePath": "C:/bootcamp/Spring/springbootcode/springbootdemo",
"resultsPath": ".",
"outputFormat": "xml",
"resultSet": "rulesets/java/quickstart.xml"
}
Analysis
In the provided piece of code the program and its arguments are being passed as the single string value as the ProcessBuilder ProcessBuilder.command(String... command) method parameter.
But that should not be the case: instead, the program and its arguments should be passed separately.
Solution
Let's use the ProcessBuilder ProcessBuilder.command(List<String> command) method.
We will prepare the string list appropriately: it will contain the program and its arguments.
The draft solution:
public List<String> getProgramAndArguments(PMDParameters params) {
final List<String> programAndArguments = new ArrayList<String>();
programAndArguments.add("cmd");
programAndArguments.add("/c");
programAndArguments.add("pmd");
programAndArguments.add("-d");
programAndArguments.add(params.getSourceCodePath());
programAndArguments.add("-f");
programAndArguments.add(params.getOutputFormat());
programAndArguments.add("-R");
programAndArguments.add(params.getResultSet());
programAndArguments.add(">");
programAndArguments.add(params.getResultsPath());
return programAndArguments;
}
public void runAnalyzer(PMDParameters params) throws IOException, InterruptedException {
createProcess();
processBuilder.command(getProgramAndArguments(params));
final Process process = processBuilder.start();
process.waitFor();
}
Additionally, please, make sure that params.getResultsPath() has the correct value by providing the correct input: now it is ..
I'm on Windows, and i try to work on a Java application that was written to be use on a Linux OS, because the program will launch some shell script at some point.
I have WSL (Windows Subsystem for Linux, also know as Ubuntu bash), so executing shell script should not be a problem, but i have an error : 0x80070057
The code that launch the external process :
public Process startProcess(List<String> commands ) throws IOException {
ProcessBuilder etProcessBuilder= new ProcessBuilder(commands);
Process etProcess = etProcessBuilder.start();
ProcessOutputReader stdReader= new ProcessOutputReader(etProcess.getInputStream(), LOGGER::info);
ProcessOutputReader errReader= new ProcessOutputReader(etProcess.getErrorStream(), LOGGER::error);
new Thread(stdReader).start();
new Thread(errReader).start();
return etProcess;
}
The commands param are set with with something like this :
"/mnt/d/some/path/scripts/initEAF.sh"
"-argForTheScript"
"some value"
"-anotherArg"
"other value"
I also tried to add "bash.exe" as first command, but it doesn't seems to work.
The ProcessOutputReaderis a class to log the stream from the process
class ProcessOutputReader implements Runnable {
private final InputStream inputStream;
private Consumer<String> loggingFunction;
ProcessOutputReader(InputStream inputStream, Consumer<String> loggingFunction) {
this.inputStream = inputStream;
this.loggingFunction = loggingFunction;
}
private BufferedReader getBufferedReader(InputStream is) {
return new BufferedReader(new InputStreamReader(is));
}
#Override
public void run() {
BufferedReader br = getBufferedReader(inputStream);
String ligne;
try {
while ((ligne = br.readLine()) != null) {
loggingFunction.accept(ligne);
}
} catch (IOException e) {
LOGGER.error("Error occur while reading the output of process ", e);
}
}
}
Any idea is welcome.
*.sh is not an executable file.
You need run it by a shell, such as bash xxx.sh -args or sh xxx.sh -args if your java app run inside wsl.
If your java app run on Windows, it should be bash.exe -c xxx.sh
I am new to Java programming. Using eclipse for coding. I want to execute JarFile.jar. Following code works fine when placing JarFile.jar inside the same directory where the project is created.
public class CmdTest2
{
public static void main(String[] args)
{
final String dosCommand = "java -jar \"D:\\Java_codes\\CmdTest2\JarFile.jar\"
try
{
final Process process = Runtime.getRuntime().exec(dosCommand);
final InputStream in = process.getInputStream();
int ch;
while((ch = in.read()) != -1)
{
System.out.print((char)ch);
}
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
But I want to execute the jar file from any other directory (say E:\Test\JarFile.jar). How can I do that? (i.e. changing directory through as well as triggering jar file).
In continuation to above pl. let me know how to run MS-DOS commands through Java.
I have a java code that generates pig script. I am wondering if there is option to execute that script directly within the java code. I found there is a option to embed pig script execution inside java code using PigServer class.
The problem is that I'm using AvroStorage to store the results and the class contains method Store() that apparently uses file storage.
Is there any way how to execute my pig script using AvroStorage inside JAVA using PigServer class?
Its generic code from their DOC, they use pigServer.store("D", "myoutput"); but instead of the file i need to call AvroStorage.
public class WordCount {
public static void main(String[] args) {
PigServer pigServer = new PigServer();
try {
pigServer.registerJar("/mylocation/tokenize.jar");
runMyQuery(pigServer, "myinput.txt";
}
catch (IOException e) {
e.printStackTrace();
}
}
public static void runMyQuery(PigServer pigServer, String inputFile) throws IOException {
pigServer.registerQuery("A = load '" + inputFile + "' using TextLoader();");
pigServer.registerQuery("B = foreach A generate flatten(tokenize($0));");
pigServer.registerQuery("C = group B by $1;");
pigServer.registerQuery("D = foreach C generate flatten(group), COUNT(B.$0);");
pigServer.store("D", "myoutput");
}
}
Is it possible to launch a Java program from another Java program, just as if I were launching it using another Java command? When calling the main() method of a program from another program directly, the Java context is common to these both executions. I'm trying to have one Java context per thread.
Illustration:
src/com/project/ProjectLauncher.java
public class ProjectLauncher {
static {
PropertyConfigurator.configure("log4j.properties");
}
public static void main(String[] args) {
Logger.getLogger(ProjectLauncher.class).info("started!");
// Logs well as expected.
}
}
test/com/project/TestProject.java
public class TestProject extends TestCase {
public void testProject() {
ProjectLauncher.main(null);
Logger.getLogger(TestProject.class).info("tested!");
// The above line logs well, while log4j has been initialized in ProjectLauncher.
// I would like it to need its own initialization in this class.
}
}
I tried to launch the main method in another thread/runnable, but the logger is still initialized by ProjectLauncher.
Well when you start a Java process, its a new Instance of JVM. If you wish to start another JVM instance, then you need to start a separate process of it.
i.e.
List<String> command = new ArrayList<String>();
command.add("java");
command.add("ProjectLauncher");
ProcessBuilder builder = new ProcessBuilder(command);
builder.redirectErrorStream(true);
final Process process = builder.start();
try {
process.waitFor();
} catch (InterruptedException ex) {
ex.printStackTrace();
}
//if you wish to read the output of it then below code else you can omit it.
InputStream is = process.getErrorStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line;
while ((line = br.readLine()) != null) {
Logger.getLogger(MyClass.class.getName()).severe(line);
}
Above we are ultimately starting a new process which in reality is java ProjectLauncher. In case if the class is not already compiled, then you will have to compile it similar to above but using javac instead of java and ProjectLauncher.java instead of ProjectLauncher etc.