java.io.Console support in Eclipse IDE - java

I use the Eclipse IDE to develop, compile, and run my Java projects. Today, I'm trying to use the java.io.Console class to manage output and, more importantly, user input.
The problem is that System.console() returns null when an application is run "through" Eclipse. Eclipse run the program on a background process, rather than a top-level process with the console window we're familiar with.
Is there a way to force Eclipse to run the program as a top level process, or at least create a Console that the JVM will recognize? Otherwise, I'm forced to jar the project up and run on a command-line environment external to Eclipse.

I assume you want to be able to use step-through debugging from Eclipse. You can just run the classes externally by setting the built classes in the bin directories on the JRE classpath.
java -cp workspace\p1\bin;workspace\p2\bin foo.Main
You can debug using the remote debugger and taking advantage of the class files built in your project.
In this example, the Eclipse project structure looks like this:
workspace\project\
\.classpath
\.project
\debug.bat
\bin\Main.class
\src\Main.java
1. Start the JVM Console in Debug Mode
debug.bat is a Windows batch file that should be run externally from a cmd.exe console.
#ECHO OFF
SET A_PORT=8787
SET A_DBG=-Xdebug -Xnoagent -Xrunjdwp:transport=dt_socket,address=%A_PORT%,server=y,suspend=y
java.exe %A_DBG% -cp .\bin Main
In the arguments, the debug port has been set to 8787. The suspend=y argument tells the JVM to wait until the debugger attaches.
2. Create a Debug Launch Configuration
In Eclipse, open the Debug dialog (Run > Open Debug Dialog...) and create a new Remote Java Application configuration with the following settings:
Project: your project name
Connection Type: Standard (Socket Attach)
Host: localhost
Port: 8787
3. Debugging
So, all you have to do any time you want to debug the app is:
set a break point
launch the batch file in a console
launch the debug configuration
You can track this issue in bug 122429. You can work round this issue in your application by using an abstraction layer as described here.

The workaround that I use is to just use System.in/System.out instead of Console when using Eclipse. For example, instead of:
String line = System.console().readLine();
You can use:
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
String line = bufferedReader.readLine();

The reason this occurs is because eclipse runs your app as a background process and not as a top-level process with a system console.

You can implement a class yourself. Following is an example:
public class Console {
BufferedReader br;
PrintStream ps;
public Console(){
br = new BufferedReader(new InputStreamReader(System.in));
ps = System.out;
}
public String readLine(String out){
ps.format(out);
try{
return br.readLine();
}catch(IOException e)
{
return null;
}
}
public PrintStream format(String format, Object...objects){
return ps.format(format, objects);
}
}

Found something about this at http://www.stupidjavatricks.com/?p=43 .
And sadly, since console is final, you can't extend it to create a a wrapper around system.in and system.out that does it either. Even inside the eclipse console you still have access to those. Thats probably why eclipse hasn't plugged this into their console yet...
I understand why you wouldn't want to have any other way to get a console other than System.console, with no setter, but i don't understand why you wouldn't want someone to be able to override the class to make a mock/testing console...

Another option is to create a method to wrap up both options, and "fail over" to the System.in method when Console isn't available. The below example is a fairly basic one - you can follow the same process to wrap up the other methods in Console (readPassword, format) as required. That way you can run it happily in Eclipse & when its deployed you get the Console features (e.g. password hiding) kicking in.
private static String readLine(String prompt) {
String line = null;
Console c = System.console();
if (c != null) {
line = c.readLine(prompt);
} else {
System.out.print(prompt);
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
try {
line = bufferedReader.readLine();
} catch (IOException e) {
//Ignore
}
}
return line;
}

As far as I can tell, there is no way to get a Console object from Eclipse. I'd just make sure that console != null, then JAR it up and run it from the command line.

There seems to be no way to get a java.io.Console object when running an application through Eclipse. A command-line console window is not opened with the application, as it is run as a background process (background to Eclipse?). Currently, there is no Eclipse plugin to handle this issue, mainly due to the fact that java.io.Console is a final class.
All you can really do is test the returned Console object for null and proceed from there.

This link offers alternatives to using System.console(). One is to use a BufferedReader wrapped around System.in, the second is to use a Scanner wrapped around System.in.
Neither are as concise as console, but both work in eclipse without having to resort to debug silliness!

Let's say your Eclipse workspace is C:\MyWorkspace,
you created your java application inside a maven project MyProject,
and your Java main class is com.mydomain.mypackage.MyClass.
In this case, you can run your main class that uses System.console() on the command line:
java -cp C:\MyWorkspace\MyProject\target\classes com.mydomain.mypackage.MyClass
NB1: if it's not in a maven project, check the output folder in project properties | Java Build Path | Source. It might not be "target/classes"
NB2: if it is a maven project, but your class is in src/test/java, you'll likely have to use "target\test-classes" instead of "target\classes"

Related

Why doesn't cd command work using Java JSch?

I'm just learning Java and Jsch, and I can get it to run other commands but not cd. The error code returned by the SSHManager sendCommand function is not null, but some unreadable string that is different every time (maybe that means it is null not that familiar with inner workings of Java).
Any idea why not? Similar question here JSch - Why doesn't CD work? but unanswered.
I won't copy and paste the whole SSHManager class here - useful answer with complete code here that I'm trying to follow. Run a command over SSH with JSch
Sample code below:
import SSH.SSHManager;
public class src
{
int ERROR = 0;
public static void main(String[] args)
{
String username = "debian";
String password = "temppwd";
String ipadd = "192.168.7.2";
SSHManager ssh = new SSHManager(username, password, ipadd, "");
ssh.connect();
String out = "";
//this doesn't work, printing output as bytes to show how weird it is
out = ssh.sendCommand("cd Desktop");
System.out.println(out.getBytes());
//some other test commands
out = ssh.sendCommand("mkdir test");
System.out.println(out);
out = ssh.sendCommand("ls");
System.out.println(out);
ssh.sendCommand("logout");
}
}
Output from the Eclipse Console (bin and Desktop are already there in root directory):
[B#b065c63
bin
Desktop
test
Each command executed over SSH "exec" channel (what is behind SSHManager.sendCommand) is executed in its own shell. So the commands have no effect on each other.
To execute multiple commands in the same shell, just use an appropriate syntax of your server shell. Most *nix shells use semicolon or double-ampersand (with a different semantics).
In your case, the double-ampersand would be more appropriate.
cd Desktop && mkdir test && ls
See also Multiple commands using JSch.
Though, if your want to read commands output, you will have problem distinguishing, where output of one commands ends and output of the following commands starts. Let alone if you wanted to check command exit code.
Then it's better to execute each command in its own "exec" channel in a way that does not require a context. In your case that means using full paths:
mkdir Desktop/test
ls Desktop
See also How to perform multiple operations with JSch.
Also as you were going to use file manipulation only, you actually should not execute shell commands at all. Use the standard SSH API for file manipulation, the SFTP.
The question has kind of an answer, in the comments. Every command in sendCommand uses it's own 'pipe', so it disconnects and starts over in each one.
A quick solution would be to send multiple commands in one one sendCommand, such as:
out = ssh.sendCommand("cd Desktop; mkdir test; ls; logout");
But the correct way is to use a session, such as https://stackoverflow.com/a/9269234/290036
I answered a similar question Using java jcabi SSH client (or other) to execute several commands in shell
My open-source API Maverick Synergy has a high-level API to execute multiple commands within a shell. Its currently designed for and works well with bash-type shells.

Gradle console() is null with daemon disabled

I'm using Gradle 2.13 with Java 1.8.0_121.
One of our Gradle tasks relies on user input.
def user = System.console().readLine('Please enter new user username: ')
However I get the following error: > Cannot invoke method readLine() on null object
So console() must be null... okay. I found this related issue suggesting to disable the daemon.
I did that and ran it with ./gradlew configureTask --no-daemon but got the same result... same error. I'm pretty sure it's not using the daemon as I get the following message: To honour the JVM settings for this build a new JVM will be forked. Please consider using the daemon: https://docs.gradle.org/2.13/userguide/gradle_daemon.html.
So if the Gradle daemon is not causing this issue, what else could be? Does anyone more experienced with Gradle know?
Gradle says it needs to run the build in a subprocess because of something in your build settings:
To honour the JVM settings for this build a new JVM will be forked.
And I guess Gradle creates that subprocess in a way that allows it to grab the output (which is the default with the APIs Java offers to spawn subprocesses). As a result, the subprocess does not have access to I/O of your terminal, and System.console() is null within that process: it is not attached to the system console.
It got me curious so I came up with a script that demonstrates the issue (using Groovy for its conciseness, it's the same thing as Java here):
import java.io.Console
println "Console for main JVM: " + System.console()
Process p1 = new ProcessBuilder("groovy", "-e", "print System.console()")
.redirectErrorStream(true)
.start()
p1.waitFor()
println "Console for child JVM: " + p1.text
Process p2 = new ProcessBuilder("groovy", "-e", "println 'Console for child JVM with inherited IO: ' + System.console()")
.redirectErrorStream(true)
.inheritIO() // <- this changes everything, as now p2 is attached to system console
.start()
p2.waitFor()
// No need to (actually cannot) get output of p2, as I/O is inherited by p2 it gets printed to terminal directly
Result:
Console for main JVM: java.io.Console#64cd705f
Console for child JVM: null
Console for child JVM with inherited IO: java.io.Console#3c130745
So Gradle is probably building the subprocess like p1 in my example. And I guess it needs to, because it needs to inspect the output (and not let it go directly to system output).
I think your only solutions are:
find a way to get Gradle do the build in the main JVM, without forking. Not a Gradle expert so I don't know how but the message seems to imply it's possible.
find another way to get user input. Maybe a Swing dialog? (not very elegant but hey, a build that takes user input is not very elegant in the first place, so the way it is collected does not matter much at this point)

Starting a Java application at startup

I have a Java application.
The application has a setting that decides whether or not the application starts at startup.
Currently, I have it this by placing/removing a shortcut in the StartUp items folder.
However, I am wondering if there is a better way to handle this behaviour.
EDIT
Yes, it's Windows. Sorry for not clearing that before.
The application has an UI where the user may trigger actions, also the application runs a few tasks in the background periodically while running.
#Peter, how could I change the registry with code from within the application? Is that approach compatible with all versions of Windows?
Below is a small example snippet of how it can be done from inside your application
static final String REG_ADD_CMD = "cmd /c reg add \"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run\" /v \"{0}\" /d \"{1}\" /t REG_EXPAND_SZ";
private void exec(String[] args) throws Exception
{
if (args.length != 2)
throw new IllegalArgumentException("\n\nUsage: java SetEnv {key} {value}\n\n");
String key = args[0];
String value = args[1];
String cmdLine = MessageFormat.format(REG_ADD_CMD, new Object[] { key, value });
Runtime.getRuntime().exec(cmdLine);
}
I'm pretty sure this will work with all versions of Windows since they all use the same Startup\Run registry entry.
Hope that helps! :)
Credit
On Windows I have used open source Java Service Wrapper to make our application as window service which you can setup automatic at startup.
What you need to do is to download latest wrapper.exe and create wrapper.config file put all the configuration like Main class any VM arument other parameters in defined standards and create a window service by this exe
Use the Registry to start your program at the startup and then it will be shown in the list provided by msconfig commnd through Run.
Use this registry path
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run

exec not working with java 1.7.21, but in netbeans works fine

I made a little program and it worked fine, but now. First, it mux the xml chapter file in the mkv file, so we get a muxed mkv file. Some day ago I updated java to 1.7.21 and I think this is the problem why it is not working now. It's a little strange, but when I run in netbeans everything is fine, but when I build and I run the .jar file, it is not working. It create the xml file, but not mux in the mkv file (and because not muxed not delete the xml file). Here is the code: (filename=xml file path; mkv=mkv file path)
public void muxing() {
try {
Runtime rt = Runtime.getRuntime();
Process p = rt.exec("c:\\Program Files\\MKVtoolnix\\mkvpropedit.exe --chapters \""+filename+"\" \""+mkv+"\"");
if (p.waitFor()==0) {
File xmlfile=new File(filename);
xmlfile.delete();
}
}
catch(Exception e) {
System.out.println(e.getMessage());
}
}
The program worked with java 1.6 and I think with 1.7.17 too. Win7 32bit. Sorry for my bad English.
Oracle has made breaking changes to Runtime.exec() in Java 7 update 21 (and 6 update 45).
If the program name contains spaces, you need to specify command and arguments in an array:
Process p = Runtime.getRuntime().exec(new String[] {
"C:\\Program Files\\MKVtoolnix\\mkvpropedit.exe",
"--chapters", "\""+filename+"\"", "\""+mkv+"\""});
Another option is to use java.lang.ProcessBuilder:
Process p = new ProcessBuilder("C:\\Program Files\\MKVtoolnix\\mkvpropedit.exe",
"--chapters", "\""+filename+"\"", "\""+mkv+"\"").start();
As stated by Oracle:
Applications that need to launch programs with spaces in the program name should consider using the variants of Runtime.exec that allow the command and arguments to be specified in an array.
Alternatively, the preferred way to create operating systems processes since JDK 5.0 is using java.lang.ProcessBuilder. The ProcessBuilder class has a much more complete API for setting the environment, working directory and redirecting streams for the process.

Run JAR file in PHP and write a file

I have the following problem in php when excecuting a jar file. I use the following command:
exec("java -jar JavaProject4.jar";
The JavaProject4.jar creates a txt file in a path given in the java code.
When i run the project in NetBeans the txt file is created. However, when i excecute the jar in php i don't get any errors but i can't get the file.
Here the java code I use to write the file:
public static void main(String[] args) throws InterruptedException, FileNotFoundException, IOException {
Main a = new Main();
List<Double> l1 = new ArrayList<Double>();
l1 = a.compute_features();
//System.out.println(l1);
FileWriter fstream1 = new FileWriter("C:/wamp/www/test/out.txt");
BufferedWriter out1 = new BufferedWriter(fstream1);
out1.write(l1.toString());
out1.newLine();
out1.close();
}
Im using a wamp server with php 5.2.4 and the latest java version.
Thanks a lot!
EDIT:
Problem solved, I moved the main java file in NetBeans to the default package and also fixed a wrong path and now everything is working as expected.
Thanks everyone
When you run it with PHP, how are you doing so? Are you using the PHP CLI (Command Line Interface), or are you running it through an Apache Module (CGI or otherwise)? The reason I ask, is because the problem you are having could have something to do with the user who the script is executing as. If you are using the CLI, you are running as your Windows User, however, if you are running it through Apache, then it is running as whatever user Apache is running as. Therefore, you might need to give the relevant permissions to the Apache user for that directory you are writing to.
Regards,
Ralfe
I think that you need to specify the full path for :
- the java executable
- your jar
Example :
exec("/usr/bin/java -jar /my/java/project/path/JavaProject4.jar");

Categories

Resources