How can I pipe input to a Java app with Perl? - java

I need to write a Perl script that pipes input into a Java program. This is related to this, but that didn't help me. My issue is that the Java app doesn't get the print statements until I close the handle. What I found online was that $| needs to be set to something greater than 0, in which case newline characters will flush the buffer. This still doesn't work.
This is the script:
#! /usr/bin/perl -w
use strict;
use File::Basename;
$|=1;
open(TP, "| java -jar test.jar") or die "fail";
sleep(2);
print TP "this is test 1\n";
print TP "this is test 2\n";
print "tests printed, waiting 5s\n";
sleep(5);
print "wait over. closing handle...\n";
close TP;
print "closed.\n";
print "sleeping for 5s...\n";
sleep(5);
print "script finished!\n";
exit
And here is a sample Java app:
import java.util.Scanner;
public class test{
public static void main( String[] args ){
Scanner sc = new Scanner( System.in );
int crashcount = 0;
while( true ){
try{
String input = sc.nextLine();
System.out.println( ":: INPUT: " + input );
if( "bananas".equals(input) ){
break;
}
} catch( Exception e ){
System.out.println( ":: EXCEPTION: " + e.toString() );
crashcount++;
if( crashcount == 5 ){
System.out.println( ":: Looks like stdin is broke" );
break;
}
}
}
System.out.println( ":: IT'S OVER!" );
return;
}
}
The Java app should respond to receiving the test prints immediately, but it doesn't until the close statement in the Perl script. What am I doing wrong?
Note: the fix can only be in the Perl script. The Java app can't be changed. Also, File::Basename is there because I'm using it in the real script.

I've grown rather fond of the IO::Handle derived modules. They make it easy to control flushing, reading data, binary mode, and many other aspects of a handle.
In this case we use IO::File.
use IO::File;
my $tp = IO::File->new( "| java -jar test.jar" )
or die "fail - $!";
# Manual print and flush
$tp->print( 'I am fond of cake' );
$tp->flush;
# print and flush in one method
$tp->printflush( 'I like pie' );
# Set autoflush ON
$tp->autoflush(1);
$tp->print( 'I still like pie' );
Also, since the file handle is lexically scoped, you don't have to close it manually. It will automatically close when it goes out of scope.
BTW, unless you are targeting a perl older than 5.6, you can use the warnings pragma instead of -w. See perllexwarn for more info.

$|=1 only works on the currently selected file handle (by default, STDOUT). To make your TP file handle hot you need to do this after opening it:
select(TP);
$| = 1;
select(STDOUT);

Related

Java: populating Scanner with default value on Scanner.nextLine();

I am writing a java program that runs a loop and keeps asking the user for input. The program then does a bunch of things with the string, and asks for another string and repeats.
The issue is that many strings are very similar, so i would like to populate the prompt with the input from the last time in the loop. For instance: If the user enters a value as follows:
Enter the SKU Number: APE-6603/A
... Then the next time it asks for an SKU, it will wait till the user presses enter as normal, but be ready with the last value before the user even types anything:
Enter the SKU Number: APE-6603/A
... And the user can make simple changes very fast like replace the /A with /B and press enter! If the string that holds the user input is called "lookFor", is there a way to populate the prompt with this value in Java? It would be VERY useful!
Thanks!
After discussing this idea with a few people, it seems that what i want is not possible. The way of input is too simple to allow something like this.
My only possible solutions involve not running this from my IDE. I can either elect to use my application, or change the application into a GUI based applet. Running from the console will open up the "Press up" option, as suggested by rchirino, and using a GUI would let the value entered sit there for editing later.
If anyone is looking to do what i posted above, the answer is "Java cant do it!". Sorry. :)
You might want to try something like this:
public String promptandgetWithShowDefault(String prompt, String supplied) {
String prmpt = prompt + " (press Enter for \"" + supplied + "\"):";
String tmpch = null;
System.out.print(prmpt);
tmpch = scanner.nextLine().trim();
if (tmpch == null || tmpch.equals("")) {
return supplied;
} else {
return tmpch;
}
}
If the goal is to get a simple binar answer from the user like:
Would you like to do that? ( y / n ) y
then the empty string returned by the user, in the answer from Dmv, will do the trick, except that when the user types "n" or attempts to delete the trailing "y", it won't disappear, so it would then be clearer to write the prompt like:
Would you like to do that? ( [ y ] / n )
But when the goal is to get a long string, like the original question or a file path for instance, that the user can edit to correct a typo or not to overwrite previous file .... then you definitely need something else which doesn't seem to be available in Java.
Well do it in C then!!! with the help of libreadline...
it's probably possible, easier and more portable to do the same trick in Python, but I have no idea how to code in Python.
Here is a simple Java MRE to illustrate it:
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
public class Main
{
public static void main(String[] args)
{
String path = System.getProperty("user.home") + File.separatorChar + "Documents";
File file = null;
do {
path = askForString("Enter the filepath to open:", path );
if ( ( path == null) || ( path.isBlank())) break;
file = new File( path );
} while ( ! file.exists() );
System.out.println("Openning " + path + "....");
// ......
}
public static String askForString( String message, String defaultString)
{
String response = null;
System.out.println( message);
// any extra String in cmd[] will be added in readline history
String[] cmd = { "/path/to/executable/ask4stringWdefault", defaultString};
try
{
ProcessBuilder pb = new ProcessBuilder(cmd);
// Make sure the subprocess can print on console and capture keyboard events
pb.redirectInput(ProcessBuilder.Redirect.INHERIT);
pb.redirectOutput(ProcessBuilder.Redirect.INHERIT);
Process p = pb.start();
BufferedReader stderrBuffer = new BufferedReader(new InputStreamReader(p.getErrorStream()));
int retcode= p.waitFor();
if ( retcode != 0)
{
System.err.println("The process terminated with error code: " + retcode + "\n" + stderrBuffer.readLine());
return null;
}
response = stderrBuffer.readLine();
} catch( Exception e) {
e.printStackTrace();
}
return response;
}
}
To build the executable "ask4stringWdefault" you need first to get the GNU Readline Library utility and compile it, ideally cross-compile for any platform Java supports, to get a static library that you will link while compiling ( or cross-compiling ) the following C script:
#include <stdio.h>
#include <stdlib.h>
#include <readline/readline.h>
#include <readline/history.h>
const char *defstr;
int prefill(const char *txt, int i);
int main(int argc, const char * argv[])
{
if ( argc < 2)
{
fprintf(stderr, "You must provide a default value\n");
return -1;
} else if ( argc > 2) {
// * optional extra values can be passed to populate history * //
if ( argc > 255) argc = 255;
for ( unsigned char i=0; i < argc; i++)
{
add_history(argv[i]);
}
}
defstr = argv[1];
char *cbuffer;
rl_startup_hook = prefill;
if ((cbuffer = readline(NULL)) == NULL) /* if the user sends EOF, readline will return NULL */
return 1;
fprintf( stderr, "%s\n", cbuffer);
free(cbuffer);
return 0;
}
int prefill(const char *t, int i)
{
rl_insert_text(defstr);
return 0;
}
The result is printed on stderr as it is the only stream that Java can keep track of, stdout and stdin being under the control of the executable subprocess itself.
It works fine on a Mac with arm64 architecture, using Eclipse you can't actually edit the default provided, any character typed at the prompt will be append to default string, but just hitting return will send unchanged default value back, which can be enough for basic testing.
I think I understand what you want to do, but it's rather simple. If your program is a console application (command-line), which I'll assume, then you just need to press the UP key to populate the prompt with the last typed characters.
If you're working with GUI elements then you can check the API documentation for the particular class of object you're using and check out it's fields.
Hope this helps!

JT400 ProgramCall's run() method is not returning any result

I am new to JT400. I am trying to invoke a test program in AS400 through JT400. Here is my code
public class TestRpg {
public static void main(String[] args){
try{
AS400 sys=new AS400("mydomain","username","password");
String number="asdf <= Return value from Java Input";
String lnsts="";
String amount="";
String lnofcd="";
AS400Text txt80 = new AS400Text(80);
AS400Text txt50 = new AS400Text(50);
ProgramParameter[] parmList = new ProgramParameter[4];
parmList[0] = new ProgramParameter( txt80.toBytes(number),80);
parmList[1] = new ProgramParameter( txt50.toBytes(lnsts),50);
parmList[2] = new ProgramParameter( txt80.toBytes(amount),80);
parmList[3] = new ProgramParameter( txt50.toBytes(lnofcd),50);
ProgramCall pgm = new ProgramCall(sys,"/QSYS.LIB/mylib.LIB/testrpg.PGM",parmList);
if (pgm.run()!=true) {
System.out.println("executed");
}else{
System.out.println("Output Data 0: " + (String)txt80.toObject( parmList[0].getOutputData() ) );
System.out.println("Output Data 1: " + (String)txt50.toObject( parmList[1].getOutputData() ) );
System.out.println("Output Data 2: " + (String)txt80.toObject( parmList[2].getOutputData() ) );
System.out.println("Output Data 3: " + (String)txt50.toObject( parmList[3].getOutputData() ) );
sys.disconnectService(AS400.COMMAND);
}
AS400Message[] messageList = pgm.getMessageList();
System.out.println(messageList.length);
for (int i=0; i < messageList.length; i++)
{
System.out.print ( messageList[i].getID() );
System.out.print ( ": " );
System.out.println( messageList[i].getText() );
}
sys.disconnectService(AS400.COMMAND);
}catch(Exception e) {
System.out.println(e.toString());
}
}
}
I had debug the code it's not giving any response after executing
pgm.run(). It is not even showing any exception. Programme is just holding at pgm.run() and not returning any thing.
As per the comments I got, I want to include the scenario I am trying to work on. In AS400 when we execute the testrpg.pgm program, it displays a screen with four input fields and some function keys to perform operations. My intention is to invoke f2 function key of that program from JT400. Is the approach I am following is the right way? Please suggest me
All program calls happen in batch so your program is most likely in MSGW on the server. Find it with wrkactjob and investigate the message it is waiting for, and give the appropriate action.
This is typically due to incorrectly formed parameters.
This is a common misunderstanding, so just for clarification for other readers:
Calling a Cobol/RPG program from Java is batch, just the same as calling the Cobol/RPG program from a Cobol/RPG/CL.
How to begin: Create a program which you can call from CL:
... declare and fill MYFIELD1, MYFIELD2 ...
CALL PGM(MYPGM) PARM(&MYFIELD1 &MYFIELD2)
...
If this works, it will also work from Java using jt400, if you:
call the right AS400 using correct credentials
call the right program in the right library
use the right number and lentgh of parameters
In case of crash as described (waiting forever), DSPMSG QSYSOPR will show an open message, like "MCH0801 = wrong number of parameters". D=Dump will create a spoolfile where you see which incoming parameters are filled with which content, or you see "undefined".

Perl Pipe not redirecting Java process output

I'm trying to control a game server and display it's output in real time. This is what I have so far:
#!/usr/bin/perl -w
use IO::Socket;
use Net::hostent; # for OO version of gethostbyaddr
$PORT = 9000; # pick something not in use
$server = IO::Socket::INET->new( Proto => 'tcp',
LocalPort => $PORT,
Listen => SOMAXCONN,
Reuse => 1);
die "can't setup server" unless $server;
print "[Server $0 accepting clients]\n";
while ($client = $server->accept()) {
$client->autoflush(1);
print $client "Welcome to $0; type help for command list.\n";
$hostinfo = gethostbyaddr($client->peeraddr);
printf "[Connect from %s]\n", $hostinfo->name || $client->peerhost;
print $client "Command? ";
while ( <$client>) {
next unless /\S/; # blank line
if (/quit|exit/i) {
last; }
elsif (/fail|omg/i) {
printf $client "%s\n", scalar localtime; }
elsif (/start/i ) {
if (my $ping_pid = open(JAVA, "screen java -jar craftbukkit-0.0.1-SNAPSHOT.jar |")) {
while (my $ping_output = <JAVA>) {
# Do something with the output, let's say print
print $client $ping_output;
# Kill the C program based on some arbitrary condition (in this case
# the output of the program itself).
}
}
printf $client "I think it started...\n Say status for output\n"; }
elsif (/stop/i ) {
print RSPS "stop";
close(RSPS);
print $client "Should be closed.\n"; }
elsif (/status/i ) {
$output = RSPS;
print $client $output; }
else {
print $client "FAIL\n";
}
} continue {
print $client "Command? ";
}
close $client;
}
It starts the process just fine, the only flaw is that it's not outputting the output of the Java process to the socket (It is displaying the output in the terminal window that Perl was initiated with) I've tried this with ping and it worked just fine, any ideas?
Thanks in advance!
It sounds like the Java code (or maybe it's screen) is printing some output to the standard error stream. Assuming that you don't want to capture it separately, some easy fixes are:
Suppress it:
open(JAVA, "screen java -jar craftbukkit-0.0.1-SNAPSHOT.jar 2>/dev/null |")
Capture it in the standard output stream:
open(JAVA, "screen java -jar craftbukkit-0.0.1-SNAPSHOT.jar 2>&1 |")
screen redirects the output to the "screen". Get rid of the screen in the command.

Parse a task list

A file contains the following:
HPWAMain.exe 3876 Console 1 8,112 K
hpqwmiex.exe 3900 Services 0 6,256 K
WmiPrvSE.exe 3924 Services 0 8,576 K
jusched.exe 3960 Console 1 5,128 K
DivXUpdate.exe 3044 Console 1 16,160 K
WiFiMsg.exe 3984 Console 1 6,404 K
HpqToaster.exe 2236 Console 1 7,188 K
wmpnscfg.exe 3784 Console 1 6,536 K
wmpnetwk.exe 3732 Services 0 11,196 K
skypePM.exe 2040 Console 1 25,960 K
I want to get the process ID of the skypePM.exe. How is this possible in Java?
Any help is appreciated.
Algorithm
Open the file.
In a loop, read a line of text.
If the line of text starts with skypePM.exe then extract the number.
Repeat looping until all lines have been read from the file.
Close the file.
Implementation
import java.io.*;
public class T {
public static void main( String args[] ) throws Exception {
BufferedReader br = new BufferedReader(
new InputStreamReader(
new FileInputStream( "tasklist.txt" ) ) );
String line;
while( (line = br.readLine()) != null ) {
if( line.startsWith( "skypePM.exe" ) ) {
line = line.substring( "skypePM.exe".length() );
int taskId = Integer.parseInt( (line.trim().split( " " ))[0] );
System.out.println( "Task Id: " + taskId );
}
}
br.close();
}
}
Alternate Implementation
If you have Cygwin and related tools installed, you could use:
cat tasklist.txt | grep skypePM.exe | awk '{ print $2; }'
To find the Process Id of the application SlypePM..
Open the file
now read lines one by one
find the line which contains SkypePM.exe in the beginning
In the line containing SkypePM.exe parse the line to read the numbers after the process name leaving the spaces.
You get process id of the process
It is all string operations.
Remember the format of the file should not change after you write the code.
If you really want to parse the output, you may need a different strategy. If your output file really is the result of a tasklist execution, then it should have some column headers at the top of it like:
Image Name PID Session Name Session# Mem Usage
========================= ======== ================ =========== ============
I would use these, in particular the set of equal signs with spaces, to break any subsequent strings using a fixed-width column strategy. This way, you could have more flexibility in parsing the output if needed (i.e. maybe someone is looking for java.exe or wjava.exe). Do keep in mind the last column may not be padded with spaces all the way to the end.
I will say, in the strictest sense, the existing answers should work for just getting the PID.
Implementation in Java is not a good way. Shell or other script languages may help you a lot. Anyway, JAWK is a implementation of awk in Java, I think it may help you.

Execute jar file many times and analyse output

I'd like to test which of two implementation in java of a problem is the fastest.
I've 2 jar files with the two implementation I can execute from the terminal. I want to execute both about 100 times and analyse which one is the fastest to do that or that task.
In the output one of the line is "executing time : xx", I need to catch this xx to put in an array or something like that to analyse it later
While I'm executing the jar, I've also to give some input commands (like a name to search or a number).
I don't with which language is it the easiest to do it.
I know the basis in Bash and Python
thank you
Excuse me, but Why you dont make a jar that call n-times any jar?
For Example:
public static void main(String[] args) {
for(int i=0;i<1000;i++) {
params1 = randomNumber();
params2 = randomName();
...
paramsN = randomTime();
MYJAR1 test1 = new MYJAR1(params1,params2,...,paramsN);
timerStart();
test1.start();
timerEnd();
printTimer();
}
}
and make the same for the second jar.
I hope that my idea can help you.
Bye
If you use (say) Perl, you can spawn the process off, capture the output via a redirection and filter the times. e.g.
if (open(PROCESS, "myproc |")) {
while(<PROCESS>) {
if (/executing time : (\d+)/) {
# $1 has the time now
}
}
}
(not compiled or tested!)
Perhaps the simplest way of analysing the data is to redirect the above output to a file, and then load it into Excel. You can then use Excel to calculate averages/max/mins and std. devs (if you wish) trivially.
Ok I've found with 3 different scripts ^^
in the java code, for each function :
long time1 = System.currentTimeMillis();
// some code for function 1
long time2 = System.currentTimeMillis();
try {
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(new File("log.txt"),true));
osw.write("function1,"+(time2 - time1)+"\n");
osw.close();
} catch (FileNotFoundException ex) {
ex.printStackTrace();
} catch (IOException ex) {
ex.printStackTrace();
}
a bash code to run the 500 times the two algorithms
#!/bin/bash
i=0
while [ $i -lt 500 ]
do
./algo1.ex
./algo2.ex
i=$(( $i+1 ))
done
an (or two actually, one for each algorithm) expect code to do the command during the execution
#!/usr/bin/expect -f
spawn java -jar algo1.jar
expect "enter your choice" {send "1\n"}
expect "enter a name :" {send "Peju, M.\n"}
expect "enter your choice" {send "2\n"}
expect "enter a name :" {send "Creasy, R. J.\n"}
expect "enter your choice" {send "0\n"}
exit
As I didn't know how to do it in bash, to count I used a python code
#!/usr/bin/python
# -*- coding: utf8 -*-
import sys
if __name__ == "__main__":
if sys.argv[1:]:
arg = sys.argv[1]
filin = open(arg, 'r')
line = filin.readline()
res= 0, 0, 0
int n = 1
while line !='':
t = line.partition(',')
if t[0] == "function1":
res = (res[0] + int(t[2]), res[1], res[2])
if t[0] == "function2":
res = (res[0], res[1] + int(t[2]), res[2])
if t[0] == "function3":
res = (res[0], res[1], res[2] + int(t[2]))
ligne = filin.readline()
n = n+1
print res
print (res[0]/(n/3.0), res[1]/(n/3.0), res[2]/(n/3.0))
filin.close()
and it works
but thanks for your propositions

Categories