Java Code stucking when attempt read output messages of Process - java

I use ProcessBuilder for execute the cmd commands in my application for Start & Stop Derby Network Server. But somethings going wrong and i don't find where the problem. Let me explain it;
Starting Network Server;
//Defining path of db files located
File file= new File(FirstTimeMainFrame.class.getProtectionDomain()
.getCodeSource()
.getLocation()
.getPath().replace(new File(FirstTimeMainFrame.class.getProtectionDomain().getCodeSource().getLocation().getPath()).getName(), "").replace("%20", " "));
String path = file+"\\DB";
//Process Creating
ProcessBuilder builder = new ProcessBuilder();
Process process = null;
String[] command = new String[3];
command[0] = "cmd.exe";
command[1] = "/c"; //This things say to CMD close when commands complete.
command[2] = "cd "+path+" && java -jar derbyrun.jar server start";
builder = new ProcessBuilder(command[0], command[1], command[2]);
builder.redirectErrorStream(true);
process = builder.start();
//Reading CMD outputs
BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while (true) {
line = br.readLine();
if (line == null) { break; }
System.out.println(line);
}
When i debug the project i see output for two lines and debug stuck at line = br.readLine(); when While loop come and check for third time. Whole program stuck and can't continue.
Outputs;
Fri Dec 25 20:54:36 EET 2015 : Security manager installed using the Basic server security policy.
Fri Dec 25 20:54:36 EET 2015 : Apache Derby Network Server - 10.12.1.1 - (1704137) started and ready to accept connections on port 1527
Important P.S.: If i remove //Reading CMD outputs codes all things working perfectly. Server Starting, DB Created, Tables Created etc.
Also i tried same CMD Command under Windows directly. When i execute the command, two line writed and Command Prompt window stuck at the flashing cursor (not closed or complete i think) but Derby Server is started without problem in programaticly or directly in Windows.

There are actually two processes running in the scenario: CMD process started from java code and Derby server process spawned by CMD.
The output from Derby server process is directed to command line and then can be read in java code. Server process can run infinetly long until it will be terminated, that's why output stream never ends.
Hanging in java code happens because there are no available bytes in the stream at the moment - server process told you that it was successfully initialized and then moved to waiting state.

Related

J2ssh get empty input stream

I'm trying to read data from the server with SSH protocol. For this, I'm using the j2ssh library. My server connects with the other server in ssh without any problem. The problem is when I try to read any data from the shell command line. Whatever "command" I send to program "read = in.read(buffer)" never get any data, I tried with "ls" with "cat filename.txt" and other commands.
Only one command works fine and is "tail -f filename.txt". With this command, I can see the buffer is not empty, this contain the text of file, but the tail command does not close and while listening, sends the program in loop.
Can Anyone help me to know why I can't get any data from othere command?
This is my code:
private String exec(String cmd) throws SSHHandlerException {
String result = null;
session = ssh.openSessionChannel();
if(session.startShell())
{
session.getOutputStream().write((cmd+"\n").getBytes());
session.getOutputStream().close();
result = read(session,log);
}
session.close();
ssh.disconnect();
return result;
}
private static String read(SessionChannelClient session, ProcessLogger log) throws Exception{
byte buffer[] = new byte[255];
int read;
StringBuffer out=new StringBuffer();
InputStream in = session.getInputStream();
while((read = in.read(buffer)) > 0) {
out.append(new String(buffer, 0, read));
}
return out.toString();
}
If your goal is to transfer files, you should be using an SFTP client instead. SFTP is exactly what you're looking for: a file transfer protocol on top of SSH. It's much, much more efficient than using some command on the host and redirecting the stream.
J2SSH has an SftpClient implementation that can be constructed with an SshClient. Just use one of the get methods. Javadocs are here.
Edit after learning that you're not trying to transfer files:
You need to request a pseudo-terminal before you start the shell. From the docs:
The remote process may require a pseudo terminal. Call this method before executing a command or starting a shell.
Also, because it appears that you're using a Linux environment, I would recommend using terminal type "xterm" rather than their example of "vt100".
The reason that tail was working and not the other commands was because you were calling tail interactively. The interactive command creates its own pseudo-terminal of sorts. If, instead, you call tail -n 16 filename.txt then you will get the same results as with the other commands because it won't be interactive.

Invoking Seagull Diameter Client using Java

i need to send some messages from my java web application to some servers using Diameter protocol, in particular CCR-CCA scenario. I had a look at jdiameter opensource project, but my usecase does not require such complexity, since that i just need to send a single request and log the response (actually i don't even need the CER-CEA part).
So i thought i could just have used Seagull running under my webapp. I downloaded Seagull (for Windows), and what i'm trying to do is basically to run the .bat file coming from Seagull for the diameter environment from my java environment.
That's what i've done till now..
1) A simple test to invoke the client.. Here wrapper simply sets working dir and starts the process
public static void main(String[] args) {
List<String> cmd=new ArrayList<>();
cmd.add("cmd.exe");
cmd.add("/c");
cmd.add("my_start_client.bat");
JavaProcessBuilderWrapper wrapper = new JavaProcessBuilderWrapper();
Process p = wrapper.createProcess(RedirectErrorsTo.STDERR,
new HashMap<>(), new File("my_working_dir"), cmd);
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
StringBuilder output = new StringBuilder();
String line;
try {
while ((line = reader.readLine()) != null) {
output.append(line);
}
System.out.println(line);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
2) I modified the client's and server's .bat files coming from Seagull to use CCR-CCA protocol.
Running Java main with this configuration caused a
Fatal: Keyboard saved configuration failure error
on my logs.
3) So, as mentioned here i further modified my client's .bat file to run in background mode, adding -bg at the end. Now my client's bat look like this
#ECHO OFF
rem
"Diameter Start Script Sample"
"Local env"
SET RUN_DIR=C:\Program Files\Seagull
set PATH=%PATH%;%RUN_DIR%
set LD_LIBRARY_PATH=%RUN_DIR%
set RUN_DIR=%RUN_DIR%\diameter-env\run
cd %RUN_DIR%
cls
mode 81,25
echo "Seagull Diameter Client Sample Start"
seagull -conf ..\config\conf.client.xml -dico ..\config\base_ro_3gpp.xml -scen ..\scenario\ccr-cca.ro.client.xml -log ..\logs\ccr-cca.client.log -llevel ETM -bg
pause
Since i was facing some troubles, to keep things simple, i just tried to make it work at least via cmd (not using my java method), but i think background mode is messing around, because now when i start my server and then my client in bg mode, sometimes i get a
Fatal: Forking error
but the most of the times, the client send a single message and then on my console i see that my software is causing connection abort (error code -1), and from the log i see that the channel just get closed, and my client does not even receive an answer. (NB for now i left the configuration files untouched)
Has any of you faced this behaviour? Is something else closing the connection (firewall perhaps)? Do i have to provide other configurations to make this work?
Once i can get this working, can i use my java web app (with a method similar to the one i already mentioned) to make diameter calls?
Thanks in advance, any help is really welcomed.

How to parse output of a background process with Java?

In my Java program I would like to start a PostgreSQL server. For this task I am using this code:
ProcessBuilder pb = new ProcessBuilder(pgHome + "/bin/pg_ctl", "start");
Map<String, String> env = pb.environment();
env.put("PGDATA", pgDataDir);
Process p = pb.start();
InputStream is = p.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String line;
boolean started = false;
while (!started && (line = reader.readLine()) != null) {
started = line.contains("database system is ready to accept connections");
}
if (!started) {
throw new IllegalStateException("Unable to start PostgreSQL server");
}
When I am starting the postgres server on the command line with the same options, I receive:
server starting
LOG: database system was shut down at 2013-02-08 09:07:50 CET
LOG: autovacuum launcher started
LOG: database system is ready to accept connections
The first line (server starting) is printed before the command returns. All following lines are printed by the background process.
My Java code only sees the first line but I want to parse the LOG messages. Is there any way to read an the input of such a background process?
I also encountered a strange and unreproducible behavior: When I debug the code, the output is parsed completely, including the LOG statements. At first I thought it is a timing issue but even waiting after starting the process did not change this.
Most likely pg_ctl is not the actual database program. It's just a script or wrapper program which outputs the first server starting line but then launches the database as a background daemon process and then returns. You cannot attach the output stream of that new process to your program.
The line you want is probably printed to stderr in which case you want to use Process.getErrorStream ().

Access running java program from shell command

I am looking for a way to access running java program from command line. The best woud be something that does the following:
Starting java app:
bash$java -jar MyBundle.jar App
Accessing app:
bash$test.sh param1 param2
So, test.sh calls App from MyBundle.jar somehow and passes values param1 & param2.
Important: I am looking for very fast approach. App hold database connection and it is very expensive to start App every time I need access do DB.
I need solution that will work in Ubuntu and Debian. If it will work on Mac - great.
Any help is appreciated!
I think you need to take a client-server approach. You app is the server, it runs as a background process and listens for connections on some port. And your client makes requests to the server and gets back the response.
A fast and simple way of implementing this in java would be to wrap your app in the Jetty servlet container. You could set it up to return JSON responses for example, which are easy to process.
It would be quite straightforward to open a TCP/IP socket and use netcat from the shell.
Java code
final ServerSocket serverSocket = new ServerSocket(9050);
while (true) {
final Socket socket = serverSocket.accept();
java.util.logging.Logger.getAnonymousLogger().info("Accepted");
final BufferedReader br = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
final String input = br.readLine();
final BufferedWriter bw = new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream()));
bw.write("You said [" + input + "]");
bw.flush();
socket.close();
}
Shell code
echo 'bla' | nc localhost 9050
You'd need to muck around with threads to keep the sockets open to serve multiple requests.

Start Java DB server without NetBeans

I am creating a Java APP that manages a database. I've been starting the JAVA DB server manually by right clicking - start server. with NetBeans but since I am not going to be the one that runs the application that can't be done anymore. I need a way to start it without NetBeans. Embedded or server mode, I don't really mind.
I've searched a lot but nothing seems to work.
I tried this: Java DB - Starting Server within application
NetworkServerControl server = new NetworkServerControl(InetAddress.getLocalHost(),1527);
server.start(null)
I got java.net.ConnectException: Error al conectarse al servidor localhost en el puerto 1527 con el mensaje Connection refused: connect.
I tried also starting it with the command line
String[] command =
{
"cmd",
};
Process p = Runtime.getRuntime().exec(command);
new Thread(new SyncPipe(p.getErrorStream(), System.err)).start();
new Thread(new SyncPipe(p.getInputStream(), System.out)).start();
try (PrintWriter stdin = new PrintWriter(p.getOutputStream())) {
stdin.println("cd C:\\Program Files\\Java\\jdk1.8.0_31\\db\\lib");
stdin.println("java -jar derbyrun.jar server start");
}
int returnCode = p.waitFor();
Also got connection refused, (database Citas not found) so the only way it could work is this:
String host = "jdbc:derby://localhost:1527/Citas";
con = DriverManager.getConnection(host, username, password);
But it works only if I start the server by clicking in Java DB -> start.
Any help would be higly appreciated
Can you try starting it using Runtime?
Runtime runtime = Runtime.getRuntime();
runtime.exec(new String[]{ "java", "-jar", "/path/to/derbyrun.jar", "server", "start");
If you were to do this in its own thread, you could also append .waitFor() to the .exec command which will hang until the process finishes. This would be good to determine if the db closed unexpectedly.
Also using runtime, you can get read the stdout / stderr of the process, and kill it if need be. Possibilities are endless.

Categories