I have a JAX-WS webservice that receives a string as parameter, calls a Perl script, and returns the string converted to upper case. It is running on Tomcat 8 (localhost on Eclipse).
When I type from the console:
curl -X POST --data "mystring=HelloWorld" http://localhost:8080/MyServices/api/generatePath
Everything works except for the Perl call. On the debugger I see that line is executed, but apparently nothing happens (not even errors). If I run perl /home/me/workspace/match.pl from the console it works perfectly. The path of the match.pl file is correct.
In addition, process.exitValue() return 2.
#Path("/")
public class MyServices {
#POST
#Path("/generatePath")
#Produces(MediaType.APPLICATION_JSON)
public Response generatePathService(
#FormParam("mystring") String myString) {
Process process = null;
try {
process = Runtime.getRuntime().exec("perl /home/me/workspace/match.pl --lang en");
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return Response.status(200).entity(myString.toUpperCase()).build();
}
}
I got similar stuff some time ago. The solution for me was to 'accept' the output of the program. Something like this:
Process p = Runtime.getRuntime().exec(cmd);
final InputStream is = p.getInputStream();
new Thread(new Runnable() {
#Override
public void run() {
try {
while (is.available() != 0) {
is.read();
}
} catch (IOException ex) {
}
}
}).start();
You should also try to get the error stream with p.getErrorStream(). An alternative could be to change your perl program in that way that there is nothing printed to standard out or error out.
Or you call a shell script and redirect the output to dev/null (someting like ´blabla>/dev/null`.
Related
I have a java project, which complied into an executable jar file v-agent-exe.jar. This jar is a log server, log rows is sent to it for processing.
I can execute it by using this command:
`java -jar v-agent-exe.jar -a watch -f config.ini`.
After executed, this jar file will create a ServerSocket at port 1235 and listen for incoming data from clients. After data received, the program will process the data and send the result back to the client. When I execute the jar from CMD windows, the processing is working perfect.
Now I am trying to wrap the Jar file as a Windows service (I am using Windows 10). I created a "Windows service project"
in Visual studio like below:
- Caller class have call() method to execute the jar file using process.
- AgentService is the service, which execute Caller->call() in another thread.
- Program is the main entry to load AgentService.
Caller.cs
public class Caller
{
static Process proc;
public Process GetProcess(){
return proc;
}
public void call() {
try
{
String dir = AppDomain.CurrentDomain.BaseDirectory;
proc = new Process
{
StartInfo = new ProcessStartInfo
{
WorkingDirectory = dir,
FileName = "java.exe",
Arguments = #"-jar v-agent-exe.jar -a watch -f config.ini",
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
RedirectStandardInput = true,
CreateNoWindow = true
}
};
proc.Start();
while (!proc.StandardError.EndOfStream)
{
string line = proc.StandardError.ReadLine();
}
}
catch (Exception ex) {
VAgentService.writeLog("Error when call process: " + ex.Message);
}
}
}
AgentService
public partial class AgentService : ServiceBase
{
private string jarPath;
private string iniPath;
static Process proc;
Caller caller;
public AgentService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
writeLog("On start");
try
{
caller = new Caller();
writeLog("Prepare to launch thread");
Thread t = new Thread(new ThreadStart(caller.call));
t.Start();
}
catch (Exception ex)
{
EventLog.WriteEntry("Demo error: " + ex.Message);
}
}
protected override void OnStop()
{
proc = caller.GetProcess();
if (proc != null && !proc.HasExited)
{
proc.Kill();
}
else
{
...
}
}
}
Program.cs
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
static void Main(String[] args)
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new AgentService()
};
ServiceBase.Run(ServicesToRun);
}
}
After build the the service project, I have AgentService.exe.
I install it to my system using:
sc create VAgentLogging binpath= %CD%\AgentService.exe depend= lmhosts start= auto
After start the service in service.msc, I can telnet to port "1235" which the java process is listening (I am sure about
only the jar running in this port). According to the
log of java program, it still can received some part of data but seem like it cannot send back to client or something,
which cause the followed process cannot be done.
I think my problem is: the jar file can executed as standalone but somehow it sucks when wrapped under my service project.
I haven't posted the jar's code yet because I think the error is related to the Windows service project. If you need the java code, please tell me and I will update it here.
Any help would be appreciated.
I'm writing a Spring web application and I'm mapping the "/do" URL path to the following Controller's method
#Controller
public class MyController
{
#RequestMapping(value="/do", method=RequestMethod.GET)
public String do()
{
File f = new File("otherMethodEnded.tmp");
while (!f.exists())
{
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
}
}
// ok, let's continue
}
}
The otherMethodEnded.tmp file is written by one another Controller's method, so when the client calls the second URL I expect the first method to exit the while loop.
Everything works, except when the client calls the "/do" URL and then closes the connection before the response was received. The problem is that the server remains in the while (!f.exists()) loop even though the client is down and cannot call the second URL to unlock the while loop.
I would try to retrieve the connection status of the "/do" URL and exit the loop when the connection is closed by the client, but I cannot find any way to do so.
I tried with the HttpServletRequest.getSession(false) method but the returned HttpSession object is always not null, so the HttpServletRequest object is not updated in case of connection close of the client.
How can I check whether the client is still waiting for the risponse or not?
The simplest way to verify something is not right is to define a timeout value and then during your loop test if your time spent waiting has exceeded the timeout.
something like:
#Controller
public class MyController
{
private static final long MAX_LOOP_TIME = 1000 * 60 * 5; // 5 minutes? choose a value
#RequestMapping(value="/do", method=RequestMethod.GET)
public String do()
{
File f = new File("otherMethodEnded.tmp");
long startedAt = System.currentTimeMillis()
boolean forcedExit = false;
while (!forcedExit && !f.exists())
{
try {
Thread.sleep(5000);
if (System.currentTimeMillis() - startedAt > MAX_LOOP_TIME) {
forcedExit = true;
}
} catch (InterruptedException e) {
forcedExit = true;
}
}
// ok, let's continue
// if forcedExit , handle error scenario?
}
}
Additionally: InterruptedException is not something to blindly catch and ignore. see this discussion
In your case I would really exit the while loop if you're interrupted.
You only know if the client is no longer waiting on your connection when you notice the output stream you write to (response.outputstream) is closed. But there isn't a way to detect it.
(see this question for details)
Seeing as you've indicated your client does occasional callbacks, you could on the clientside poll if the other call has been completed. If this other call has completed, do the operation, otherwise return directly and have the client do the call again. (assuming you are sending json, but adapt as you require)
something like
public class MyController
{
#RequestMapping(value="/do", method=RequestMethod.GET)
public String do()
{
File f = new File("otherMethodEnded.tmp");
if (f.exists()) {
// do what you set out to do
// ok, let's continue
// and return with a response that indicates the call did what it did
// view that returns json { "result" : "success" }
return "viewThatSIgnalsToClientThatOperationSucceeded";
} else {
// view that returns json: { "result" : "retry" }
return "viewThatSignalsToClientToRetryIn5Seconds";
}
}
}
Then the clientside would run something like: (pseudojavascript as it's been a while)
val callinterval = setInterval(function() { checkServer() }, 5000);
function checkServer() {
$.ajax({
// ...
success: successFunction
});
}
function successFunction(response) {
// connection succeeded
var json = $.parseJSON(response);
if (json.result === "retry") {
// interval will call this again
} else {
clearInterval(callinterval);
if (json.result === "success") {
// do the good stuff
} else if (json.result === "failure") {
// report that the server reported an error
}
}
}
Ofcourse this is just semi-serious code but it's roughly how i'd try it if I were to have the dependency. If this is regarding afile upload, keep in mind that this file may not contain all of the bytes yet. file exists != file = completely uploaded, unless you use move it. cp / scp / etc. is not atomic.
I have a Javascript program that call a Java program via Applet with the following command inside the Applet:
script.code = "InJava.class";
It was necessary to make a change in the Java program, and now it creates two classes: InJava.class and InJava$1.class
Now, when I run the program in Javascript, the program does not answer anything.
If I change the statement to:
script.code = "InJava$1.class"
It returns the following error:
runtimeexceptionjava.lang.reflect.invocationtargetexception
How must I stated in the Javascript program?
Must I change something in my Java program?
The Java program is below:
Java Program
public void sayHello() throws IOException {
java.io.FileInputStream fis = AccessController.doPrivileged(new PrivilegedAction<FileInputStream>() {
public FileInputStream run() {
try {
return new FileInputStream(parametro);
} catch (IOException e) {
String retorno_exc = e.toString();
}
return null;
}
});
This example is based on an example from the book Restlet in Action.
If I try
public class StreamResource extends ServerResource
{
#Get
public Representation getStream() throws ResourceException, IOException
{
Representation representation = new WriterRepresentation(MediaType.TEXT_PLAIN)
{
#Override
public void write(Writer writer) throws IOException
{
String json = "{\"foo\" : \"bar\"}";
while (true)
{
writer.write(json);
}
}
};
return representation;
}
}
it works and it continuously sends the json string to the client.
If I introduce a delay in the while loop like this
String json = "{\"foo\" : \"bar\"}\r\n";
while (true)
{
writer.write(json);
try
{
Thread.sleep(250);
}
catch (InterruptedException e)
{}
}
I was hoping that the client would get data 4 times in a second BUT nothing seems to get to the client.
Can anyone explain why the introduction of Thread.sleep() does that? What is a good way to introduce delay in streaming data to the client?
You should try with the Jetty connector instead of the internal Restlet connector. This connector isn't ready for production even though we are working on fixing it.
You can also try the Simple extension which has less dependent JARs than the Jetty extension.
You can try to flush the buffer, like this:
String json = "{\"foo\" : \"bar\"}\r\n";
while (true)
{
writer.write(json);
writer.flush(); // flush the buffer.
try
{
Thread.sleep(250);
}
catch (InterruptedException e)
{}
}
Without writer.flush(), the writer waits to fill the internal buffer before writing the socket. Thread.sleep(250) reduces the output produced at each second, so that far more time is required to fill the buffer.
Part of a Java program I'm creating needs to talk to a service on a remote machine. That remote machine is running a service (written in Delphi I believe) on a Windows platform.
I need to connect to that machine, send command strings and receive (String) responses.
If I connect using Linux CLI telnet session I get responses as expected:
[dafoot#bigfoot ~]$ telnet [host IP] [host port]
Trying [host IP]...
Connected to [host IP].
Escape character is '^]'.
Welcome to MidWare server
ping
200 OK
ProcessDownload 4
200 OK
In the above the lines 'ping' and 'ProcessDownload 4' are me typing in the terminal, other lines are responses from remote system.
I created a Main in my Java class that will do the work to call the appropriate methods to try and test this (I've left out irrelevant stuff):
public class DownloadService {
Socket _socket = null; // socket representing connecton to remote machine
PrintWriter _send = null; // write to this to send data to remote server
BufferedReader _receive = null; // response from remote server will end up here
public DownloadServiceImpl() {
this.init();
}
public void init() {
int remoteSocketNumber = 1234;
try {
_socket = new Socket("1.2.3.4", remoteSocketNumber);
} catch (IOException e) {
e.printStackTrace();
}
if(_socket !=null) {
try {
_send = new PrintWriter(_socket.getOutputStream(), true);
_receive = new BufferedReader(new InputStreamReader(_socket.getInputStream()));
} catch (IOException e) {
e.printStackTrace();
}
}
}
public boolean reprocessDownload(int downloadId) {
String response = null;
this.sendCommandToProcessingEngine("Logon", null);
this.sendCommandToProcessingEngine("ping", null);
this.sendCommandToProcessingEngine("ProcessDownload", Integer.toString(downloadId));
try {
_socket.close();
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
private String sendCommandToProcessingEngine(String command, String param) {
String response = null;
if(!_socket.isConnected()) {
this.init();
}
System.out.println("send '"+command+"("+param+")'");
_send.write(command+" "+param);
try {
response = _receive.readLine();
System.out.println(command+"("+param+"):"+response);
return response;
} catch (IOException e2) {
e2.printStackTrace();
}
return response;
}
public static void main(String[] args) {
DownloadServiceImpl service = new DownloadServiceImpl();
service.reprocessDownload(0);
}
}
As you will see in the code, there are a couple of sys.outs to indicate when the program is attempting to send/receive data.
The output generated:
send 'Logon(null)'
Logon(null):Welcome to MidWare server
send 'ping(null)'
So Java is connecting to the server ok to get the "Welcome to Midware" message back, but when I try to send a command ('ping') I don't get a response.
So the questions:
- does the Java look about right?
- could problem be related to character encoding (Java -> windows)?
You need to flush the output stream:
_send.write(command+" "+param+"\n"); // Don't forget new line here!
_send.flush();
or, since you create a auto-flushing PrintWriter:
_send.println(command+" "+param);
The latter has the disadvantage that the line end can be \n or \r\n, depending on the system on which your Java VM runs. So I prefer the first solution.