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.
Related
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);
}
}
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 wrote some unit tests to check whether logging is working as intended. For example, here is one of the methods being tested:
// from my SampleObject class
public void configure(Context context) {
Log.d(TAG, "Configuration done.");
}
I want to flush LogCat before each test so that the logs from the previous test do not get picked up. To do that, I wrote a clearLogs() method that is called from setUp():
private void clearLogs() throws Exception {
Runtime.getRuntime().exec("logcat -c");
}
public void setUp() throws Exception {
super.setUp();
clearLogs();
SampleObject mSampleObject = new SampleObject();
}
And here is my unit test:
public void testConfigure() throws Exception {
String LOG_CONFIGURATION_DONE = "Configuration done.";
boolean stringFound = false;
mSampleObject.configure(new MockContext());
Process process = Runtime.getRuntime().exec("logcat -d SampleObject:D *:S");
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line = "";
while ((line = bufferedReader.readLine()) != null) {
if (line.contains(LOG_CONFIGURATION_DONE)) {
stringFound = true;
break;
}
}
assertTrue("Log message for configure() not found", stringFound);
}
The issue is that the log entry is cleared even though clearLogs() is only called in setUp(). The test works if I comment out clearLogs(). Anyone have an idea what I'm doing wrong?
After several weeks, I've finally discovered the cause: logcat -c does not clear the logs immediately but takes several seconds to do so. However, the process appears from the test application's point of view. As a result, the test case is executed immediately afterwards and runs while the logs are still being cleared. Adding a short delay of two seconds resolved the problem.
I am working on java Application where I am dealing with read and
write file. But I want to do this process simultaneously. As my file
is log file from which I am reading contents by some time interval for
this I used java.util.Timer. And during this time interval I am trying
to writing some contents in the file, but this is not updating in my
log file.
My Timer class is
public class Timer extends java.util.Timer {
public void startTimer() {
Timer t = new Timer();
Task task = new Task();
t.schedule(task, 0, 10000);
}
}
My class form which file read write class is called
public class Task extends TimerTask {
#Override
public void run() {
System.out.println("In task ....");
try {
SMSQuestions smsQuestions = new SMSQuestions();
smsQuestions.sendSMSAnswer();
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
My file read write class is
public void sendSMSAnswer()
{
long sender;
String question;
try {
BufferedReader br = new BufferedReader(new FileReader("C:/temp/NowSMS/TEST.log"));
String line = br.readLine();
while (line != null) {
sender = 0;
question = "";
System.out.println(line);
line = br.readLine();
}
//To delete all contents in file
BufferedWriter bw = new BufferedWriter(new FileWriter("C:/temp/NowSMS/TEST.log"));
bw.write("");
getDetails();
}catch(Exception exp)
{
exp.printStackTrace();
}
}
My problem is when i updated my log file by writing new contents it
can't be updated so my question is: is it possible in java to simultaneously read write file or not?
I would suggest you have a look at random access files (see http://docs.oracle.com/javase/tutorial/essential/io/rafs.html). This API is a little more complicated to work with since you'll be reading bytes, not lines, but it should give you what you need.
If you don't want to deal with NIO you can use http://docs.oracle.com/javase/7/docs/api/java/io/RandomAccessFile.html instead.
Try this topic. But the only answer you will get is, its only working with a few OSs.
I have two things to say about your code.
First:
I think that you are missing the finally block where you are supposed to close br and bw.
Try:
finally {
br.close();
bw.close();
}
after the catch block.
Second: It is not a good idea to write content to a file while it is opened. I mean, if you open a file with br maybe it is better to gives another file path to bw