I have a simple Java application, basically a server implemented using com.sun.net.HttpServer API, that reads a file and simply sends back the texts after some processing. The server part simply looks like this:
server = HttpServer.create(new InetSocketAddress(serverPort), 0);
logger.info("EventRetriever REST server listening to port: " + serverPort);
server.createContext("/getEvents", new MedatadaHandler());
server.setExecutor(null);
server.start();
// ...
#Override
public void handle(HttpExchange he) throws IOException {
//...
String response = requestEvents();
he.sendResponseHeaders(200, response.length());
OutputStream os = he.getResponseBody();
os.write(response.toString().getBytes());
os.close();
}
//...
public String requestEvents(){
//...
// this printing on the console looks fine though:
logger.info(jsonString);
return jsonString;
}
I run my jar file with java -jar myApp.jar on a command line or simply on my IDE. I'm witnessing some weird behaviors, sometimes just hanging, when it requires sending texts containing special characters, such as the music symbol ♪. When I call the IP:PORT/getEvent via a browser, the behavior is so weird:
If I run it on a Windows Powershell or Command Prompt, the symbol appears as ? on the console, and what I get from the browser is also shown as ?. But when I run the program on a linux server or my Eclipse IDE, it is shown correctly on the console (as ♪), but on the browser, I get the following error, although the status is 200 OK. I see on the console the java application keep looping printing the line every few seconds (as if it is trying to send the data, but can't maybe something is blocking it!). But I don't get any exception or errors on the app (I log all possible errors).
I'm very confused for this behavior. What's going on?!
First, why what I get is dependent on the environment I run my Java app?! If Windows Command Prompt/Powershell shows the character as ?, I expect it just showing it locally like that. Why should I see it also as ? on my browser?! Java app must be independent of the environment.
And second, what is going on with that error on the Linux/Eclipse envrionment when requesting a line that has this character?
The issue as could be predicted, was related to getBytes() and UTF-8 String representations. Did the following and it was all good then:
he.sendResponseHeaders(200, response.getBytes("UTF-8").length);
OutputStream os = he.getResponseBody();
os.write(response.getBytes("UTF-8"));
Related
Background
I am trying to create a java application to send ZPL command to a ZPL printer and get a label printed.
I set up a ZPL emulator(https://chrome.google.com/webstore/detail/zpl-printer/phoidlklenidapnijkabnfdgmadlcmjo) by following this post : Emulate ZPL printer
Issue
After setting the emulator up and add it as zpl printer via mac Printer&Scanner ,
I try to use lp command to print it. it is stable the reliable:
lp -o "raw" -q1 -d zpl <<< "^XA\n^FO50,60^A0,40^FDWorld Best Griddle^FS\n^FO60,120^BY3^BCN,60,,,,A^FD1234ABC^FS\n^FO25,25^GB380,200,2^FS\n^XZ"
However, my use case is send the command to a printer remotely on the network, Therefore I need to create a java application to send the Zpl command to the printer. It succeeds initially, then it randomly get splitted:
java code:
import java.io.*;
import java.net.*;
class TCPClient
{
public static void main (String argv[]) throws Exception
{
Socket clientSocket=new Socket("127.0.0.1",9100);
DataOutputStream outToServer = new DataOutputStream(clientSocket.getOutputStream() );
try {
outToServer.writeBytes("^XA\n^FO50,60^A0,40^FDWorld Best Griddle^FS\n^FO60,120^BY3^BCN,60,,,,A^FD1234ABC^FS\n^FO25,25^GB380,200,2^FS\n^XZ");
} catch (Throwable e) {
System.out.println(e);
}
outToServer.flush();
outToServer.close();
clientSocket.close();
// outToServer.flush();
}
}
Result:
So quite often, it succeeds once and then following 2 or 3 printing get fragmented or failed. I suspect it might be the socket TCP fragmentation issue. or there any socket option I can configure? But not sure how to solve it. Can anyone help here?
Update:
I try to use wireshark. The issue resides in the TCP package size:
For lp command, everything is sent as one single pack:
As for java app, it is broken down into smaller packs for some reason.
But I still don't know how to configure the pack size. Also it confuses me a lot why Java app will break the data packet to like 1 byte or two byte sized?
I think you are using a wrong method to send printing job. I'm not sure lp command uses Socket connection. Try calling lp from Java using Runtime.getRuntime().exec:
String cmd = "lp -o \"raw\" -q1 -d zpl <<< \"^XA\n^FO50,60^A0,40^FDWorld Best Griddle^FS\n^FO60,120^BY3^BCN,60,,,,A^FD1234ABC^FS\n^FO25,25^GB380,200,2^FS\n^XZ\"";
Runtime.getRuntime().exec(String.format(cmd));
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.
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.
I'm writing GUI using JAVA for a console program. It starts and works well, but when i send "\n" or "\r\n" to it's stdin it doesn't react as it reacts if i simply start this program in Terminal and press "Enter".
This code is used to start process:
String cmd="example.exe";
process = new ProcessBuilder(cmd).start();
And this code is used to send "\n"
OutputStream outputStream = process.getOutputStream();
outputStream.write("\n".getBytes());
outputStream.flush();
In other thread i'm trying to read from this process
while ((line = is.readLine()) != null && !Thread.currentThread().isInterrupted()) {
...
}
How can i properly send "\n" to receive information from the process?
Update:
I need to send a new line symbol. Or "Press Enter".
I read out and error, both are empty.
Application always reports it's status as reaction to pressing enter. So no reaction is a bug.
Presumably you are expecting the newline written to outputStream to trigger something that you can read using is.
Here are a couple of possible causes:
You could be reading from the wrong stream. The external program might be writing to "standard error" and you are reading "standard output" or vice-versa.
The external application might be failing to flush. For example, it (or the I/O library it uses) might only flush output after each newline if the output is directed to an interactive output stream (e.g. a "console"). The pipe connecting program output to your JVM might not show up as interactive.
These are only guesses ...
If I was trying to debug this, I would try to determine whether the problem is that the newline doesn't get to example.exe, that the response doesn't get written / flushed by example.exe, or that the Java side is failing to read it ... for some reason.
I have set up a local proxy server for request logging but my java code ignores it and connects directly (Windows XP, JDK 1.7). Web browsers work with it. So I wrote test code for discussion that seems to connect directly even if a (bogus) proxy is specified. With the bogus proxy, I would expect connection failure but the code succeeds, connecting directly:
System.setProperty("http.proxyHost", "localhost");
System.setProperty("http.proxyPort", "12345");
System.setProperty("http.nonProxyHosts", "noNonProxyHost.com");
URL url = new URL("http://docs.oracle.com/javase/7/docs/technotes/guides/net/proxies.html");
InputStream in = url.openStream();
System.out.println("Connection via bogus proxy succeeded");
The code is run as standalone Java, no Maven, no applet, no container. I have a direct internet connection.
In your case using java.net.URL(), if the proxy server cannot be reached at http.proxyHost and http.proxyPort then it simply falls back and tries to do a direct connect. If that succeeds, you'll see no exception thrown which is why your code works without error. You should see a pause while it tries to find the proxy though.
This sample code below happily fetches the URL and displays it, without error, even when run with bogus proxy settings. -Dhttp.proxyHost=bogus -Dhttp.proxyPort=2345 but will talk to my local proxy localhost port 8888 if set correctly
import java.io.*;
import java.net.URL;
import java.util.*;
public class URLClient {
private static String sUrl = "http://www.apache.org/";
public static void main(String[] args) {
try {
URL url = new URL(sUrl);
InputStream is = url.openStream();
java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\\A");
String output = s.hasNext() ? s.next() : "";
System.out.println(output);
} catch(Throwable e) {
System.err.println("exception");
}
}
}
The problem I was originally having with http.proxyHost and http.proxyPort being ignored (Google led me to your question) was that those settings are completely ignored by apache.commons.httpClient because it uses its own sockets, as described here.
http://cephas.net/blog/2007/11/14/java-commons-http-client-and-http-proxies/
I have faced a similar problem recently. First of all, one part of the above answer from Daemon42 explains pretty well, why the bogus proxy server didn't lead to a failure of the program:
if the proxy server cannot be reached at http.proxyHost and http.proxyPort then it simply falls back and tries to do a direct connect. If that succeeds, you'll see no exception thrown which is why your code works without error. You should see a pause while it tries to find the proxy though.
Still, your actual question was, why the proxy server configured via the operating system is not used by the Java application. As stated in the Oracle documentation (https://docs.oracle.com/javase/8/docs/technotes/guides/net/proxies.html), the system proxy settings are not evaluated by Java by default. To do so, you have to set the value of the system property "java.net.useSystemProxies" to the value "true".
You can set that system property on the command line, or you can edit the JRE installation file jre/lib/net.properties, that way you have to change it only once on a given system.