I'm using Eclipse's external tools functionality to launch my test server (I can't use the normal servers view for it since it's not supported).
That works fine, but it's a bit sad that I can't click the stacktraces to automatically jump to that line in the code (as you could normally do). I always thought eclipse's console automatically recognized lines of code.
Is there any way to make it do that for external tools?
Thanks
You can copy the stack trace to a Java Stack Trace console. In the Console, switch to a new Java Stack Trace console, paste the stack trace and it will be immediately clickable.
Also, check out the LogViewer plugin, as far as I can recall, it can do that with less effort
As a workaround, I created a simple Java wrapper program which executes the command given as arguments. This allows an Eclipse Java run configuration to be used instead of an external tool.
public class Exec {
private final Process process;
private boolean error;
public Exec(Process process) {
this.process = process;
}
public static void main(String[] command) throws Exception {
new Exec(Runtime.getRuntime().exec(command)).run();
}
public void run() throws Exception {
Thread thread = new Thread(() -> copy(process.getInputStream(), System.out));
thread.start();
copy(process.getErrorStream(), System.err);
int status = process.waitFor();
thread.join();
System.err.flush();
System.out.flush();
System.exit(status != 0 ? status : error ? 1 : 0);
}
private void copy(InputStream in, OutputStream out) {
try {
byte[] buffer = new byte[4096];
for (int count; (count = in.read(buffer)) > 0;) {
out.write(buffer, 0, count);
}
} catch (IOException e) {
error = true;
e.printStackTrace();
}
}
}
Related
I am new in java, a self learner. I came accross the following issue and was stuck. In fact I am trying to sanitize this code against command injection but failed to understand how. I know how to sanitize user input but this specific has to do with command executed in the OS and I am not sure how anyone help please. here is the code:
public class CommandProcessor {
public CommandProcessor() {
// TODO Auto-generated constructor stub
}
public int invokeCommand(String command) throws IOException{
int exitCode =0;
if(command !=null && !command.isEmpty()) {
Process process = null;
try {
process = Runtime.getRuntime().exec(command);
process.waitFor();
exitCode = process.exitValue();
}catch(InterruptedException e) {
}
}
return exitCode;
}
}
The correct answer is to read the documentation as your current code is not safe.
https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/Runtime.html#exec(java.lang.String%5B%5D)
The "command to execute" should be a constant.
This is the code I'm running:
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
public class Main {
public static void main(String[] args) throws Exception {
String filePath = "D:/temp/file";
RandomAccessFile file = new RandomAccessFile(filePath, "rw");
try {
MappedByteBuffer buffer = file.getChannel().map(FileChannel.MapMode.READ_WRITE, 0, 128);
// Do something
buffer.putInt(4);
} finally {
file.close();
System.out.println("File closed");
}
System.out.println("Press any key...");
System.in.read();
System.out.println("Finished");
}
}
Before pressing a key, I'm trying to delete the file manually in FAR Manager. But FAR says that the file is locked:
The process cannot access the file because it is being used by another process.
Cannot delete the file
D:\temp\file
Object is being opened in:
Java(TM) Platform SE binary (PID: 5768, C:\Program Files\Java\jdk1.8.0_05\bin\javaw.exe)
Only after pressing a key, the application terminates and I can delete the file.
What is wrong with my code?
Try this one.
public class Test
{
public static void main(String[] args) throws Exception {
String filePath = "D:/temp/file";
RandomAccessFile file = new RandomAccessFile(filePath, "rw");
FileChannel chan = file.getChannel();
try {
MappedByteBuffer buffer = chan.map(FileChannel.MapMode.READ_WRITE, 0, 128);
// Do something
buffer.putInt(4);
buffer.force();
Cleaner cleaner = ((sun.nio.ch.DirectBuffer) buffer).cleaner();
if (cleaner != null) {
cleaner.clean();
}
} finally {
chan.close();
file.close();
System.out.println("File closed");
}
System.out.println("Press any key...");
System.in.read();
System.out.println("Finished");
}
}
#SANN3's answer doesn't work on Java 9 anymore. In Java 9 there is a new method sun.misc.Unsafe.invokeCleaner that can be used. Here is a working code:
MappedByteBuffer buffer = ...
// Java 9+ only:
Class<?> unsafeClass = Class.forName("sun.misc.Unsafe");
Field unsafeField = unsafeClass.getDeclaredField("theUnsafe");
unsafeField.setAccessible(true);
Object unsafe = unsafeField.get(null);
Method invokeCleaner = unsafeClass.getMethod("invokeCleaner", ByteBuffer.class);
invokeCleaner.invoke(unsafe, buffer);
If you are using java1.8 and cannot directly use sun.nio.ch.DirectBuffer and Cleaner, you can try:
public void clean(final ByteBuffer buffer) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
try {
Field field = buffer.getClass().getDeclaredField("cleaner");
field.setAccessible(true);
Object cleaner = field.get(buffer);
Method cleanMethod = cleaner.getClass().getMethod("clean");
cleanMethod.invoke(cleaner);
} catch (Exception e) {
e.printStackTrace();
}
return null;
});
}
This is actually a limitation of JDK. Since the JDK-4724038 which tracks this problem (even though it is marked an enhancement) in JDK says that invoking the cleanup method directly is strongly advised against (also, that the Unsafe class might go away in some future version of JDK), the only workaround seems to be to call the GC. If using the try-with-resources for the file, that would look like this:
try (RandomAccessFile file = new RandomAccessFile(filePath, "rw")) {
MappedByteBuffer buffer = file.getChannel().map(FileChannel.MapMode.READ_WRITE, 0, 128);
// Do something
buffer.putInt(4);
}
System.gc(); // has to be called outside the try-with-resources block
I created https://github.com/vladak/RandomAccessFileTrap to demonstrate this - take a look at the detail of a build in the Github actions tab for this repository to see the actual results.
In my Cucumber-jvm scenarios I need to run an external jar program before each scenario, interact with it using the FEST library in the steps, and finally shut the program down to clean the slate for the next scenario. The particular external program I need uses System.exit() to quit when closed. In turn I cannot just quit the program in my tests as that would terminate the entire VM. Instead I use the custom SecurityManager built into FEST to override System.exit() call. However, I cannot get it to work correctly.
The code in example 1 below tries to start the external program in a Cucumber #Before hook and shut it down in an #After hook. It works perfectly fine with only one scenario when I run mvn verify. However, with two or more scenarios maven just hangs on the lines:
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running test.acceptance.CucumberRunner
Nothing happens afterwards. I can see that the external program is launched and closed once, but the second time its launched it doesn't close. When I close it manually maven outputs the following:
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-failsafe-
plugin:2.16:integration-test (default) on project acceptance-tests: Execution default of
goal org.apache.maven.plugins:maven-failsafe-plugin:2.16:integration-test failed: The
forked VM terminated without saying properly goodbye. VM crash or System.exit called ?
Does anyone have any idea of what's going on here? It seems like the problem is that the external program is not terminated at all - maybe the fault of the NoExitSecurityManagerInstaller I am using. However, I don't know how else to prevent the call to System.exit terminating the entire VM. Somehow I just want to exit the program I started without affecting the VM in which it is running. Is that not possible?
Update - Solution found!
After having played around with the code for several hours, I accidentally discovered that the Robot class used by the WindowFinder has a cleanUp method that: "Cleans up any used resources (keyboard, mouse, open windows and {#link ScreenLock}) used by this robot.". I tried using this instead of frame.close() and it turns out it works! It doesn't even need the custom SecurityManager.
The problem seems to be that the BasicRobot.robotWithCurrentAwtHierarchy() call aquires a lock on the screen which is NOT release by frame.close(). So when the next call to BasicRobot.robotWithCurrentAwtHierarchy() is made in the second scenario/test the call will block waiting for the lock to be released, and effectively creating a deadlock. The solution is to manually release the lock using robot.cleanUp (which also closes and disposes any open windows). However, why frame.close doesn't do this when it closes the last frame is beyond me.
Example 1
public class CucumberHooks {
private FrameFixture frame;
#Before
public void setup() throws InterruptedException, IOException {
Thread t = new Thread(new Runnable() {
public void run() {
File file = new File(System.getProperty("external-jar"));
URLClassLoader cl = null;
try {
cl = new URLClassLoader( new URL[]{file.toURI().toURL()} );
}
catch (MalformedURLException e) {}
Class<?> clazz = null;
try {
clazz = cl.loadClass("MainClass");
}
catch (ClassNotFoundException e) {}
Method main = null;
try {
main = clazz.getMethod("main", String[].class);
}
catch (NoSuchMethodException e) {}
try {
main.invoke(null, new Object[]{new String[]{}});
}
catch (Exception e) {}
}
});
t.start();
GenericTypeMatcher<JFrame> matcher = new GenericTypeMatcher<JFrame>(JFrame.class) {
protected boolean isMatching(JFrame frame) {
return "External Jar Title".equals(frame.getTitle()) && frame.isShowing();
}
};
frame = WindowFinder.findFrame(matcher).using(BasicRobot.robotWithCurrentAwtHierarchy());
}
#After
public void shutDown() throws InterruptedException {
NoExitSecurityManagerInstaller i = NoExitSecurityManagerInstaller.installNoExitSecurityManager();
frame.close();
i.uninstall();
}
}
Example 2
public class CucumberHooks {
private FrameFixture frame;
private Robot robot;
#Before
public void setup() throws InterruptedException, IOException {
Thread t = new Thread(new Runnable() {
public void run() {
File file = new File(System.getProperty("external-jar"));
URLClassLoader cl = null;
try {
cl = new URLClassLoader( new URL[]{file.toURI().toURL()} );
}
catch (MalformedURLException e) {}
Class<?> clazz = null;
try {
clazz = cl.loadClass("MainClass");
}
catch (ClassNotFoundException e) {}
Method main = null;
try {
main = clazz.getMethod("main", String[].class);
}
catch (NoSuchMethodException e) {}
try {
main.invoke(null, new Object[]{new String[]{}});
}
catch (Exception e) {}
}
});
t.start();
GenericTypeMatcher<JFrame> matcher = new GenericTypeMatcher<JFrame>(JFrame.class) {
protected boolean isMatching(JFrame frame) {
return "External Jar Title".equals(frame.getTitle()) && frame.isShowing();
}
};
robot = BasicRobot.robotWithCurrentAwtHierarchy();
frame = WindowFinder.findFrame(matcher).using(robot);
}
#After
public void shutDown() {
robot.cleanUp();
}
}
It's just a guess: you have to install the NoExitSecurityManagerInstaller before you start your thread. See http://docs.codehaus.org/display/FEST/Handling+System.exit
am developing a java application in which I am using swings to develop GUI screens. i am supposed to run some application files. which I did by connecting to command prompt by using Runtime.exec() method. if my application failes to execute properly then a GUI frame will come up asking weather to run that file again or to skip.
here my problem is when I say run that file again the control should return to the point where the frame is called using ui.setvisible(true);
if not the swing frame what can i use to make my code work
public static boolean runFormat(String format,String buildNumber) throws Exception
{
try{
ProcessExecutor process = new ProcessExecutor();
process.executeCommand(format+"\\Scripts"+File.separator+"Step1.bat"+""+"02_00"+" "+format);
process.waitForCompletion();
File file = new File(format+File.separator+"Results1.log");
BufferedReader read = new BufferedReader (new FileReader(file));
String line;
while((line=read.readLine())!=null)
{
if(line.contains("Successful exit."))
{
return true;
}
}
return false;
}
catch(Exception e)
{
System.out.println("EXCEPTION OCCURED..................");
System.out.println("JTag has failed for "+format);
e.printStackTrace();
}
return true;
}
void run(Set<String> formats)
{
try
{
for(String ar : formats)
{
boolean b =runFormat(ar,"001");
if(b==false)
{
ExampleUi ui = new ExampleUi();
ui.setVisible(true);
}
}
}
catch(Exception e)
{
}
}
Thanks in advance
The short answer is no.
The long answer would involve using a SwingWorker and making the decisions about what to do within it's done method
Take a look at Worker Threads and SwingWorker for more details...
public class ProcessWorker extends SwingWorker<Boolean, Void> {
public Boolean doInBackground() throws Exception {
ProcessBuilder pb = new ProcessBuilder(...);
Process p = pb.start();
// Read the input stream in separate thread...
return p.waitFor() == 0;
}
public void done() {
try {
boolean okay = get();
if (!okay) {
// Re-run....?
}
} catch (Exception exp) {
// Show error message, maybe in a JOptionPane
}
}
}
How do I know if a software is done writing a file if I am executing that software from java?For example, I am executing geniatagger.exe with an input file RawText that will produce an output file TAGGEDTEXT.txt. When geniatagger.exe is finished writing the TAGGEDTEXT.txt file, I can do some other staffs with this file. The problem is- how can I know that geniatagger is finished writing the text file?
try{
Runtime rt = Runtime.getRuntime();
Process p = rt.exec("geniatagger.exe -i "+ RawText+ " -o TAGGEDTEXT.txt");
}
You can't, or at least not reliably.
In this particular case your best bet is to watch the Process complete.
You get the process' return code as a bonus, this could tell you if an error occurred.
If you are actually talking about this GENIA tagger, below is a practical example which demonstrates various topics (see explanation about numbered comments beneath the code). The code was tested with v1.0 for Linux and demonstrates how to safely run a process which expects both input and output stream piping to work correctly.
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.concurrent.Callable;
import org.apache.commons.io.IOUtils;
public class GeniaTagger {
/**
* #param args
*/
public static void main(String[] args) {
tagFile(new File("inputText.txt"), new File("outputText.txt"));
}
public static void tagFile(File input, File output) {
FileInputStream ifs = null;
FileOutputStream ofs = null;
try {
ifs = new FileInputStream(input);
ofs = new FileOutputStream(output);
final FileInputStream ifsRef = ifs;
final FileOutputStream ofsRef = ofs;
// {1}
ProcessBuilder pb = new ProcessBuilder("geniatagger.exe");
final Process pr = pb.start();
// {2}
runInThread(new Callable<Void>() {
public Void call() throws Exception {
IOUtils.copy(ifsRef, pr.getOutputStream());
IOUtils.closeQuietly(pr.getOutputStream()); // {3}
return null;
}
});
runInThread(new Callable<Void>() {
public Void call() throws Exception {
IOUtils.copy(pr.getInputStream(), ofsRef); // {4}
return null;
}
});
runInThread(new Callable<Void>() {
public Void call() throws Exception {
IOUtils.copy(pr.getErrorStream(), System.err);
return null;
}
});
// {5}
pr.waitFor();
// output file is written at this point.
} catch (Exception e) {
e.printStackTrace();
} finally {
// {6}
IOUtils.closeQuietly(ifs);
IOUtils.closeQuietly(ofs);
}
}
public static void runInThread(final Callable<?> c) {
new Thread() {
public void run() {
try {
c.call();
} catch (Exception e) {
e.printStackTrace();
} finally {
}
}
}.start();
}
}
Use a ProcessBuilder to start your process, it has a better interface than plain-old Runtime.getRuntime().exec(...).
Set up stream piping in different threads, otherwhise the waitFor() call in ({5}) might never complete.
Note that I piped a FileInputStream to the process. According to the afore-mentioned GENIA page, this command expects actual input instead of a -i parameter. The OutputStream which connects to the process must be closed, otherwhise the program will keep running!
Copy the result of the process to a FileOutputStream, the result file your are waiting for.
Let the main thread wait until the process completes.
Clean up all streams.
If the program exits after generating the output file then you can call Process.waitFor() to let it run to completion then you can process the file. Note that you will likely have to drain both the standard output and error streams (at least on Windows) for the process to finish.
[Edit]
Here is an example, untested and likely fraught with problems:
// ...
Process p = rt.exec("geniatagger.exe -i "+ RawText+ " -o TAGGEDTEXT.txt");
drain(p.getInputStream());
drain(p.getErrorStream());
int exitCode = p.waitFor();
// Now you should be able to process the output file.
}
private static void drain(InputStream in) throws IOException {
while (in.read() != -1);
}