executing a curl request with a shell command in java? - java

I am wondering how to run this command line code for an API that I have found on the web. The code the API wants me to run goes as follows:
curl -i "https://api-fxtrade.oanda.com/v1/prices?instruments=EUR_USD"
This code will give data back in a JSON response. I am trying to accomplish this by running this threw a shell command. My code goes as follows:
import java.io.*;
public class FxTest {
public static void main(String[] args) {
FxTest obj = new FxTest();
String command = "curl -i \"https://api-fxtrade.oanda.com/v1/prices?instruments=EUR_USD\"";
String output = obj.executeCommand(command);
System.out.println(output);
}
private String executeCommand(String command) {
StringBuffer output = new StringBuffer();
Process p;
try {
p = Runtime.getRuntime().exec(command);
p.waitFor();
BufferedReader reader =
new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = "";
while ((line = reader.readLine())!= null) {
output.append(line + "\n");
}
} catch (Exception e) {
e.printStackTrace();
}
return output.toString();
}
}
When I run this code I get this error:
java.io.IOException: Cannot run program "curl": CreateProcess error=2, The system cannot find the file specified
Will a shell command execute this code that I am trying to execute or is their a better way to go about this? If this code is impossible to execute in a shell command what options do I have, how do these options work and Where should I look to learn more. If a shell command is a good way to go about this than what is wrong with my code and where should I look to learn more about how to use a shell command? Thank you for your help!!!

Why not just use the native java methods for this: HttpURLConnection? It is a little long winded as you can see in this tutorial: http://www.journaldev.com/7148/java-httpurlconnection-example-to-send-http-getpost-requests. Better still, try the apache httpclient. It has a nice fluid interface that lets you call a url as simple as:
// Execute a GET with timeout settings and return response content as String.
Request.Get("http://somehost/") .execute().returnContent().asString();
Then you can use one of the java Jason libraries to manipulate the results. json-simple is among the easiest to use (but there are lots to choose from): https://github.com/fangyidong/json-simple. You start by parsing the string returned by the http call above:
Object obj=JSONValue.parse(s);

Related

How to execute bash commands in Java (Raspberry pi)

I dont know why, but I can only execute a very small pallet of commands on my Raspberry 3B from code (I cane even execute echo). For some reason, 99% of the commands that you would normally be able to do in the terminal itself, you cant do from code.
Example: I execute this java code:
Runtime.getRuntime().exec("echo hi");
And I get this:
`java.io.IOException: Cannot run program "echo hi": error=2, No such file or directory
Is there a PATH configuration that I dont have access to in java code? why cant I execute any commands to the raspberry pi from code?
I've written some example that uses the exec() call. There are other methods to start processes from within Java (ProcessBuilder is the keyword here), but this example is relatively easy to understand:
import java.util.*;
import java.io.*;
import java.text.*;
public class X {
public static void main(String argv[])
{
String args[] = { "/bin/bash", "-c", "uptime" };
try {
Process p = Runtime.getRuntime().exec(args);
BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = in.readLine();
while (line != null) {
System.out.println("Found: " + line);
line = in.readLine();
}
} catch (Exception e) {
System.err.println("Some error occured : " + e.toString());
}
}
}
Basically the program executes the command line /bin/bash -c uptime; just an uptime would have done the same, but I wanted to show how to work with command line arguments for the program to start.

Not receiving output from ProcessBuilder in YARN job

I have a Hadoop YARN cluster set up on some machines at my university (all machines running Linux Fedora 25). When running a mapreduce job in YARN, I am unable to receive the output from a call I make to a separate program. Interestingly, if I run my job locally (configured in mapred-site.xml), my method for calling the program and receiving its output works just fine. Below is my executeShellCommand class, which is instantiated and used in my first map task.
public class ExecuteShellCommand {
public String executeCommand(String command) {
StringBuffer output = new StringBuffer();
Process p;
try {
String [] args = command.split(" ");
String cmd = args[0];
ProcessBuilder pb = new ProcessBuilder().command(cmd, args[1], args[2], args[3], args[4], args[5], args[6], args[7]).directory(new File("path to executable"));
p = pb.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
p.waitFor();
String line = "";
while ((line = reader.readLine())!= null) {
output.append(line + "\n");
}
} catch (Exception e) {
e.printStackTrace();
return e.toString();
}
return output.toString();
}
}
Things I have made sure to check:
1) Permissions are appropriately set for all files/directories needed
2) Map tasks are run as current user (me), so no issues with illegal access
3) I am not receiving a file not found exception, so the path to the program I'm calling is correct
4) Checked the input/output stream for Process p (input stream set as java.lang.UNIXProcess$ProcessPipeInputStream#1000e80, output stream is null)
5) Instead of calling the program I need to use, I have tried a simple "echo" command, and could not receive that output either.
6) I have also tried using
p = Runtime.getRuntime().exec("myCommand")
but the results are the same (no output received)
As I already mentioned, when I run a job locally, my executeCommand method functions perfectly, and returns the output from the program I call. Only in YARN do the issues occur. I have a feeling that the problem caused by either not reading from the correct buffer, or the command issued to ProcessBuilder is never actually executed. I am quite stumped as to how to debug what is going on here, and any tips would be greatly appreciated!
After hours of trying all sorts of solutions, I figured out how to get the error stream from the process spawned with ProcessBuilder. Turns out when I set the working directory for the process, I forgot to update the path to one of the arguments I was passing it. D'oh!!!

How to make Runtime.getRuntime().exec execute command one by one and get output rather than executing all commands

I am trying to run a *.bat file (which is capable of running several commands and retrieve the output one by one) from my java application. My intention is to send one command, read output use this output for second command and again retrieve the output.
To achieve this, through Runtime.getRuntime().exec I am passing more than one command as an input to PrintWriter. Issue is that after completing all the steps only I can read the output from *.bat through buffer ,but my intention is to run one command get the output and manipulate this output to send second command.
Unfortunately is not working. Any resolution for this?..
I got the idea to send more than one command to Runtime.getRuntime().exec from this link (How to execute cmd commands via Java)
The following is the same code which I got from above link
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();
PrintWriter stdin = new PrintWriter(p.getOutputStream());
stdin.println("dir c:\\ /A /Q");
// write any other commands you want here
stdin.close();
int returnCode = p.waitFor();
System.out.println("Return code = " + returnCode);
class SyncPipe implements Runnable
{
public SyncPipe(InputStream istrm, OutputStream ostrm) {
istrm_ = istrm;
ostrm_ = ostrm;
}
public void run() {
try
{
final byte[] buffer = new byte[1024];
for (int length = 0; (length = istrm_.read(buffer)) != -1; )
{
ostrm_.write(buffer, 0, length);
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
private final OutputStream ostrm_;
private final InputStream istrm_;
}
In your case I would not use Threads, you want a sequential execution path.
Actually, instead of trying to reinvent the wheel, I strongly suggest you to use an expect-like java library to do that kind of thing.
Just because there are several things that you'll have to deal with, such as timeout between requests, waiting for the output to return, etc.
Take a look at these libraries
http://expectj.sourceforge.net/
https://code.google.com/p/expect4j/
https://github.com/ronniedong/Expect-for-Java
http://code.google.com/p/enchanter/
In particular, I use expectj in my project and it works pretty well (although I think expect4j is more popular)
With expectj, your code will look like this (from http://expectj.sourceforge.net/)
// Create a new ExpectJ object with a timeout of 5s
ExpectJ expectinator = new ExpectJ(5);
// Fork the process
Spawn shell = expectinator.spawn("/bin/sh");
// Talk to it
shell.send("echo Chunder\n");
shell.expect("Chunder");
shell.send("exit\n");
shell.expectClose();
You can do the redirection of output of one command to other in the bat file itself using pipe.
I am sorry, i hadn't noticed that you want to manipulate the output first.
So instead of using bat file, you can run the commands that are in bat file from java using exec , get the out put, and use the out put to execute the next command.

How to execute a interactive shell script using java Runtime?

I am wondering is there any way to execute following shell script, which waits for user input using java's Runtime class?
#!/bin/bash
echo "Please enter your name:"
read name
echo "Welcome $name"
I am using following java code to do this task but it just shows blank console.
public class TestShellScript {
public static void main(String[] args) {
File wd = new File("/mnt/client/");
System.out.println("Working Directory: " +wd);
Process proc = null;
try {
proc = Runtime.getRuntime().exec("sudo ./test.sh", null, wd);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Thing is when I execute above program, I believed it will execute a shell script and that shell script will wait for user input, but it just prints current directory and then exits. Is there any way to do this or it is not possible at all in java?
Thanks in advance
The reason it prints the current dir and exits is because your java app exits. You need to add a (threaded) listener to the input and error streams of your created process, and you'll probably want to add a printStream to the process's output stream
example:
proc = Runtime.getRuntime().exec(cmds);
PrintStream pw = new PrintStream(proc.getOutputStream());
FetcherListener fl = new FetcherListener() {
#Override
public void fetchedMore(byte[] buf, int start, int end) {
textOut.println(new String(buf, start, end - start));
}
#Override
public void fetchedAll(byte[] buf) {
}
};
IOUtils.loadDataASync(proc.getInputStream(), fl);
IOUtils.loadDataASync(proc.getErrorStream(), fl);
String home = System.getProperty("user.home");
//System.out.println("home: " + home);
String profile = IOUtils.loadTextFile(new File(home + "/.profile"));
pw.println(profile);
pw.flush();
To run this, you will need to download my sourceforge project: http://tus.sourceforge.net/ but hopefully the code snippet is instructive enough that you can just adapt to J2SE and whatever else you are using.
If you use a Java ProcessBuilder you should be able to get the Input, Error and Output streams of the Process you create.
These streams can be used to get information coming out of the process (like prompts for input) but they can also be written to to put information into the process directly too. For instance:
InputStream stdout = process.getInputStream ();
BufferedReader reader = new BufferedReader (new InputStreamReader(stdout));
String line;
while(true){
line = reader.readLine();
//...
That'll get you the output from the process directly. I've not done it myself, but I'm pretty sure that process.getOutputStream() gives you something that can be written to directly to send input to the process.
The problem with running interactive programs, such as sudo, from Runtime.exec is that it attaches their stdin and stdout to pipes rather than the console device they need. You can make it work by redirecting the input and output to /dev/tty.
You can achieve the same behaviour using the new ProcessBuilder class, setting up the redirection using ProcessBuilder.Redirect.INHERIT.
Note sure at all you can send input to your script from Java. However I very strongly recommend to have a look at Commons Exec if you are to execute external scripts from Java:
Commons Exec homepage
Commons Exec API

Run bash scripts from JAVA and return the results

I am attempting to get output of a shell / bash script, that is run from a JAVA program, although I am not having much luck, the code is as follows:
GetStats(winhostname);
public static String winhostname "cmd /c hostname";
public static void GetStats(String operation)
{
try
{
Process p=Runtime.getRuntime().exec(operation);
p.waitFor();
BufferedReader reader=new BufferedReader(new InputStreamReader(p.getInputStream()));
String line=reader.readLine();
while(line!=null)
{
System.out.println(line);
if (operation.equals("winhostname"))
{
winhostnamevalue = line;
}
line=reader.readLine();
}
}
catch(IOException e1) {}
catch(InterruptedException e2) {}
}
This works on Windows fine, so I changed the value of winhostname to "sh namecheck.sh" (which simply echos the hostname) and the shell script is located in the same directory as the java / class file. Although when run I get a blank result, not null, just blank.
Try /bin/sh. I do not sure that when you are running program from java it has all environment that you have when you are working with shell.
If it does not work try to run some command (e.g. pwd). But provide full path. Then, when it works try your command again and be sure that it can find your script. For the beginning use absolute path. Then move to relative path.
Good luck.

Categories

Resources