Strange JSON-String distortion in Tomcat - java

Please explain to me, what is the cause of distortion of JSON-String sent from JavaFX application to Tomcat server. Part of symbols is replaced by strange square symbols:
Conversation to JSON pass correctly – I checked it by printing JSON-String to console in JavaFX app after serializing. But after transfer to Tomcat-server by DoPost method JSON-String is distorted. And I tried to transfer XML too – it distorts by the same way.
After small investigation, I got some result: String sent by DoPost stays correct if it's length is 7782 symbols or less. Plus one symbol – and squares appears:
Both the JavaFX app and Tomcat server starts on local machine under Intellij IDEA, so it's not a network problem.

Very thanks to user Nick on ru.stackoverflow.com:
https://ru.stackoverflow.com/users/216863/nick
He gave exact cause – length of inputStream. GZIP gives not correct value of inputStream length to Servlet.
And when I replaced this code:
`public String getInputString(HttpServletRequest req) {
String receivedString = "";
int len = req.getContentLength();
byte[] input = new byte[len];
try {
ServletInputStream sin = req.getInputStream();
int c = 0;
int count = 0;
while ((c = sin.read(input, count, (input.length - count))) > 0) {
count += 1;
}
sin.close();
} catch (IOException e) {
}
receivedString = new String(input);
return receivedString;
}`[PasteBin-1][1]
by this:
`public String getInputString(HttpServletRequest req) {
String receivedString = "";
try (BufferedReader reader = new BufferedReader(new InputStreamReader(req.getInputStream()))) {
StringBuilder sb = new StringBuilder("");
while (reader.ready()) {
sb.append(reader.readLine());
}
if (sb.length() > 0) {
receivedString = sb.toString();
}
} catch (IOException e) {
}
return receivedString;
}`[PasteBin-2][2]
everything started to work correctly.
This is same question thread on russian:
answer on ru.stackoverflow.com

Related

using JSSC to read from a serial port. How do I use inputstream

I am using JSSC to communicate with a serialport.
The data comes in 1 byte at a time. New string is started by carriage return/newline.
The string length is variable. (82 characters max)
Each string begins with #.
As the data comes in 1 byte at a time, I have to assemble the string. I tried using a bufferedreader and inputstreamreader from a RXTX example, but I was unsuccessful.
So my question is, how do I assemble the string byte by byte and refresh the string on ?
I need it to be 1 string at a time as it will be parsed.
I have tried googling various things:
"jssc inputreader bufferedreader example"
"jssc inputreader serialPort.readString()"
etc.
//Array list declaration
static List<String> datat = new ArrayList<String>();
...
...
public void serialEvent(SerialPortEvent event) {
try {
String getdata = serialPort.readString(event.getEventValue());
//System.out.print(getdata);
String[] parts= getdata.split("\\r");
if(!datat.isEmpty()){
datat.set(datat.size() - 1, datat.get(datat.size() - 1) + parts[0]);
}
for (int i=1; i<parts.length; i++) {
if (parts[i].contains("\n")) {
if(!datat.isEmpty()) {
datat.clear();
System.out.println("data cleared");
}
} else if (!parts[i].equals("\\r") | !parts[i].equals("\\n")) {
datat.add(parts[i]);
System.out.println(datat);
}
}
}
catch (SerialPortException ex) {
}
}
}
Declare an arraylist
Receive byte from serial port. If byte received is not new line add to arraylist otherwise convert arraylist into byte array
These steps needs to be done in a while loop

ChunkedInput not working in jersey

Can anyone help me why the java code is having issue and printing all data in one go instead of prinitng each chunk as javascript code
Java Code :
import org.glassfish.jersey.client.ChunkedInput;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.core.GenericType;
import javax.ws.rs.core.Response;
public class RunClient {
public static void main(String args[]) throws InterruptedException {
Client client = ClientBuilder.newClient();
//2 is to increase amount of data and 3(seconds) is for time b/w chunked output ,can be changed
final Response response = client.target("http://jerseyexample-ravikant.rhcloud.com/rest/jws/streaming/2/3").request()
.get();
final ChunkedInput<String> chunkedInput = response.readEntity(new GenericType<ChunkedInput<String>>() {
});
String chunk;
while ((chunk = chunkedInput.read()) != null) {
System.err.println("Next chunk received: " );
System.out.println(chunk);
}
}
}
JavaScript : (Open Page http://jerseyexample-ravikant.rhcloud.com/rest/jws and then press F12 and run below in console as javascript call not allowed from other domain)
//2 is to increase amount of data and 3(seconds) is for time b/w chunked output ,can be changed
var xhr = new XMLHttpRequest()
xhr.open("GET", "http://jerseyexample-ravikant.rhcloud.com/rest/jws/streaming/2/3", true)
xhr.onprogress = function () {
console.log("PROGRESS:", xhr.responseText) ;console.log("\n");
}
xhr.send()
EDIT : Just for help it also works will normal java connection
String uri = "http://jerseyexample-ravikant.rhcloud.com/rest/jws/streaming/3/1";
URL url = new URL(uri);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setDoOutput(true);
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line;
while ((line = in.readLine()) != null) {
System.out.println(line);
}
in.close();
My WebService Code
#Path("streaming/{param}/{sleepTime}")
#GET
#Produces(MediaType.TEXT_PLAIN)
public ChunkedOutput<String> getChunkedStream(#PathParam("param") String loopcount,#PathParam("sleepTime") String sleepTime) throws Exception {
final ChunkedOutput<String> output = new ChunkedOutput<>(String.class);
final Integer val=Integer.parseInt(loopcount);
final Integer isleepTime=Integer.parseInt(sleepTime)*1000;
new Thread(new Runnable() {
#Override
public void run() {
try {
StringBuffer chunk = null;
for (int i = 0; i < 10; i++) {
chunk = new StringBuffer();
for (int j = 0; j < val; j++) {
chunk.append(" Message #" + i+ "#"+j);
}
output.write(chunk.toString()+"\n");
System.out.println("write");
Thread.sleep(isleepTime);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
System.out.println("output.close();");
output.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}).start();
return output;
}
Form jersey docs:
Writing chunks with ChunkedOutput is simple, you only call method write() which writes exactly one chunk to the output. With the input reading it is slightly more complicated. The ChunkedInput does not know how to distinguish chunks in the byte stream unless being told by the developer. In order to define custom chunks boundaries, the ChunkedInput offers possibility to register a ChunkParser which reads chunks from the input stream and separates them. Jersey provides several chunk parser implementation and you can implement your own parser to separate your chunks if you need. In our example above the default parser provided by Jersey is used that separates chunks based on presence of a \r\n delimiting character sequence.
So your server has to separate chunks with \r\n, or you have to register a ChunkParser.
Assuming you have a constant finalising each chunk you could try:
Client client = ClientBuilder.newClient();
//2 is to increase amount of data and 3(seconds) is for time b/w chunked output ,can be changed
final Response response = client.target("http://jerseyexample-ravikant.rhcloud.com/rest/jws/streaming/2/3").request()
.get();
final ChunkedInput<String> chunkedInput = response.readEntity(new GenericType<ChunkedInput<String>>() {
});
chunkedInput.setParser(ChunkedInput.createParser(BOUNDARY));
String chunk;
while ((chunk = chunkedInput.read()) != null) {
System.err.println("Next chunk received: " );
System.out.println(chunk);
}
While BOUNDARY is a finalizing string for each chunk.
The in.readLine solution in your edit will break down "chunks" by every newline, even if one chunk consist a \n, it will be interpreted as 2 chunks.

How to make fast data reading using socket in Java?

I'm using SocketChannel for single connection like this:
int sampleBufferSize = 50;
StringBuilder data = new StringBuilder();
ByteBuffer bf = ByteBuffer.allocate(sampleBufferSize);
SocketChannel sc = new SocketChannel();
while(true)
if(sc.read(bf) > 0){
bf.flip();
while(bf.hasRemaining())
data.append((char) bf.get());
bf.clear();
}else{
fireDataReceived(data.toString());
data.delete(0, data.length());
}
This code is not very efficient, but it reads HTTP POST request 130 KB from the same PC in 0.05 seconds. Now I'm trying to write a class with similar functionality but using Socket. Here is the code:
private static final int TIMEOUT_MILLIS = 50;
private boolean reading = false;
private long readBeginTime = 0;
private StringBuilder buffer = new StringBuilder();
private Thread thread = new Thread(){
public void run(){
while(!isInterrupted()){
try {
int b = getInputStream().read();
if(b == -1){
if(reading)
fireDataReceived();
close();
}else{
if(!reading){
reading = true;
readBeginTime = System.currentTimeMillis();
setSoTimeout(TIMEOUT_MILLIS);
}
buffer.append((char) b);
}
} catch (SocketTimeoutException e){
fireDataReceived();
} catch (IOException e) {
e.printStackTrace();
if(reading)
fireDataReceived();
close();
}
}
}
};
private void fireDataReceived(){
BufferedSocketEvent e = new BufferedSocketEvent(this, System.currentTimeMillis() - readBeginTime, buffer.toString());
buffer.setLength(0);
reading = false;
try {
setSoTimeout(0);
} catch (SocketException e1) {
e1.printStackTrace();
}
for(BufferedSocketListener listener: listeners)
listener.dataReceived(e);
}
And the problem is that it takes 0.4 seconds for the same request and I have no idea why does it take so long. Please, explain what is wrong with my code.
The problem with your streams code is that you're reading a byte at a time, which is slow, and also appending to the StringBuilder one at a time, ditto. Try this:
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream());
char[] chars = new char[8192];
int count;
while ((count = in.read(chars)) > 0)
{
buffer.append(chars, 0, count);
fireDataReceived();
}
Note that it isn't correct to use read timeouts as a means to separate requests. You need to parse the data to do that. TCP is a streaming protocol without message boundaries, and there are no guarantees about separate sends being received separately.
You have to use readLine() or similar method. End of HTTP header is marked by empty line. If you don't detect lines you cannot know when to stop reading data. Relying on timeouts or TCP fragments is not a correct solution. If request doesn't contain new line, you need to wait until one appears or the connection is terminated/timed out. You should wait at least a couple of seconds.
I would also get rid of those listeners. Being able to add multiple listeners for single socket might seem like a good idea but the only sensible thing to do with HTTP header is to parse it. The parser also needs to inform the reader when to stop reading.
I would start with something like this:
ServerSocket serverSocket = new ServerSocket(8888);
Socket clientSocket = serverSocket.accept();
BufferedReader reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream(), "ASCII"));
String[] r = reader.readLine().split(" ");
String type = r[0];
String resource = r[1];
String version = r[2];
Map<String, String> headers = new HashMap<String,String>();
while(true) {
String line = reader.readLine();
if(line.isEmpty()) {
break;
}
String headerLine[] = line.split(":",2);
headers.put(headerLine[0],headerLine[1].trim());
}
processHeader(type, resource, version, headers);

What is the least painful way to extract data at the protocol layer in Java?

I'm trying to implement an Android application to connect to the open source software Motion. The goal is to be able to check the status of the application and get the last image captured.
I do not program in Java very much, my background is principally in C and Python. I've not had any real issues with understanding the UI part of Android, but I've found it to be incredibly painful to work with any sort of byte buffer. The Motion software has an HTTP API that is very simple. Opening the URL connection is easy in Java. The response from the default page looks like this
Motion 3.2.12 Running [4] Threads
0
1
2
3
For my purposes the first thing the application needs to do it parse out the number of threads. At some point I can also retrieve the version number from the first line, but that's not really important presently.
Here's my code
package com.hydrogen18.motionsurveillanceviewer;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.List;
public class MotionHttpApi {
String host;
int port = 80;
boolean secure = false;
int numberOfThreads = -1;
String getBaseUrl()
{
StringBuilder sb = new StringBuilder();
sb.append(secure ? "https://" : "http://");
sb.append(host);
sb.append(':');
sb.append(port);
return sb.toString();
}
public int getNumberOfCameras() throws IOException
{
if(numberOfThreads == -1)
{
retrieveSplash();
}
if(numberOfThreads == 1)
{
return 1;
}
return numberOfThreads - 1;
}
void retrieveSplash () throws IOException
{
URL url = new URL(getBaseUrl());
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
if(conn.getResponseCode()!=HttpURLConnection.HTTP_OK)
{
throw new IOException("Got response code" + conn.getResponseCode());
}
try{
Byte[] buffer = new Byte[512];
byte[] sbuf = new byte[128];
int offset = 0;
InputStream in = new BufferedInputStream(conn.getInputStream());
boolean foundInfoString= false;
while( ! foundInfoString)
{
//Check to make sure we have not run out of space
if(offset == buffer.length)
{
throw new IOException("Response too large");
}
//Read into the smaller buffer since InputStream
//can't write to a Byte[]
final int result = in.read(sbuf,0,sbuf.length);
//Copy the data into the larger buffer
for(int i = 0; i < result;++i)
{
buffer[offset+i] = sbuf[i];
}
//Add to the offset
offset+=result;
//Wrap the array as a list
List<Byte> list = java.util.Arrays.asList(buffer);
//Find newline character
final int index = list.indexOf((byte) '\n');
//If the newline is present, extract the number of threads
if (index != -1)
{
//Find the number of threads
//Thread number is in the first lin like "[X]"
final int start = list.indexOf((byte)'[');
final int end = list.indexOf((byte)']');
//Sanity check the bounds
if(! (end > start))
{
throw new IOException("Couldn't locate number of threads");
}
//Create a string from the Byte[] array subset
StringBuilder sb = new StringBuilder();
for(int i = start+1; i != end; ++i)
{
final char c = (char) buffer[i].byteValue();
sb.append(c);
}
String numThreadsStr = sb.toString();
//Try and parse the string into a number
try
{
this.numberOfThreads = Integer.valueOf(numThreadsStr);
}catch(NumberFormatException e)
{
throw new IOException("Number of threads is NaN",e);
}
//No more values to extract
foundInfoString = true;
}
//If the InputStream got EOF and the into string has not been found
//Then an error has occurred.
if(result == -1 && ! foundInfoString )
{
throw new IOException("Never got info string");
}
}
}finally
{
//Close the connection
conn.disconnect();
}
}
public MotionHttpApi(String host,int port)
{
this.host = host;
this.port = port;
}
}
The code works just fine when you call getNumberOfCameras(). But I think I must not be really understandings omething in terms of java, because the retrieveSplash method is far too complex. I could do the same thing in just 10 or so lines of C or 1 line of Python. Surely there must be a saner way to manipulate bytes in java?
I think there are some style issues, like I probably should not be throwing IOException whenever the integer fails to parse. But that's a separate issue.
Read the first line as Gautam Tandon suggested and then use a regex.
You can then check if the regex matches and even easily extract the number.
Regex' can be created at http://txt2re.com. I've already done that for you.
The page even creates Java, Pyhton, C, etc. files for you to work with.
// URL that generated this code:
// http://txt2re.com/index-java.php3?s=Motion%203.2.12%20Running%20[4]%20Threads&-7&-19&-5&-20&-1&2&-22&-21&-62&-63&15
import java.util.regex.*;
class Main
{
public static void main(String[] args)
{
String txt="Motion 3.2.12 Running [4] Threads";
String re1="(Motion)"; // Word 1
String re2="( )"; // White Space 1
String re3="(3\\.2\\.12)"; // MMDDYY 1
String re4="( )"; // White Space 2
String re5="(Running)"; // Word 2
String re6="( )"; // White Space 3
String re7="(\\[)"; // Any Single Character 1
String re8="(\\d+)"; // Integer Number 1
String re9="(\\])"; // Any Single Character 2
String re10="( )"; // White Space 4
String re11="((?:[a-z][a-z]+))"; // Word 3
Pattern p = Pattern.compile(re1+re2+re3+re4+re5+re6+re7+re8+re9+re10+re11,Pattern.CASE_INSENSITIVE | Pattern.DOTALL);
Matcher m = p.matcher(txt);
if (m.find())
{
String word1=m.group(1);
String ws1=m.group(2);
String mmddyy1=m.group(3);
String ws2=m.group(4);
String word2=m.group(5);
String ws3=m.group(6);
String c1=m.group(7);
String int1=m.group(8);
String c2=m.group(9);
String ws4=m.group(10);
String word3=m.group(11);
System.out.print("("+word1.toString()+")"+"("+ws1.toString()+")"+"("+mmddyy1.toString()+")"+"("+ws2.toString()+")"+"("+word2.toString()+")"+"("+ws3.toString()+")"+"("+c1.toString()+")"+"("+int1.toString()+")"+"("+c2.toString()+")"+"("+ws4.toString()+")"+"("+word3.toString()+")"+"\n");
}
}
}
//-----
// This code is for use with Sun's Java VM - see http://java.sun.com/ for downloads.
//
// Paste the code into a new java application or a file called 'Main.java'
//
// Compile and run in Unix using:
// # javac Main.java
// # java Main
//
String int1=m.group(8); gives you the desired integer. Of course you can simplify the above code. It's way to verbose right now.
You can simplify the retrieveSplash method considerably by using BufferedReader. Here's a simpler version of your function:
void retrieveSplash_simpler() throws IOException {
URL url = new URL(getBaseUrl());
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
// open the connection
conn.connect();
// create a buffered reader to read the input stream line by line
BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
// find number of threads
String firstLine = reader.readLine();
int x = firstLine.indexOf("[");
int y = firstLine.indexOf("]");
if (x > 0 && y > 0 && x < y) {
try {
numberOfThreads = Integer.parseInt(firstLine.substring(x+1, y));
} catch (NumberFormatException nfe) {
// disconnect and throw exception
conn.disconnect();
throw new IOException("Couldn't locate number of threads");
}
} else {
// disconnect and throw exception
conn.disconnect();
throw new IOException("Couldn't locate number of threads");
}
// disconnect
conn.disconnect();
}
I'd further clean up the above method by using try/catch/finally blocks at the appropriate places so that I don't have to duplicate that "conn.disconnect()". But I didn't do that here to keep it simple (try/catch/finally do become tricky sometimes...).

How do you access posted form data in a servlet?

If I have a servlet running JVM1.4.2, and it is receiving a POST request with form data fields. I use req.getParameterNames() to get, what I would expect, all the query string and form data. However, all I ever get are the querystring parameters.
Literature I am reading from various sources says that getParameterNames() and getParameterValues(String) should be the way to get all query string and posted form data sent by the browser for JDK 1.4. Here is the method I use to extract all the parameters, which I expect would include posted form data :
public Map getParameterMap(HttpServletRequest req) {
Map params= new HashMap();
String name = null;
System.out.println("<< Getting Parameter Map.>>");
Enumeration enumParams = req.getParameterNames();
for (; enumParams.hasMoreElements(); ) {
// Get the name of the request parameter
name = (String)enumParams.nextElement();
// Get the value of the request parameters
// If the request parameter can appear more than once
// in the query string, get all values
String[] values = req.getParameterValues(name);
params.put(name, values);
String sValues = "";
for(int i=0;i<values.length;i++){
if(0<i) {
sValues+=",";
}
sValues +=values[i];
}
System.out.println("Param " + name + ": " + sValues);
}
System.out.println("<< END >>");
return params;
}
This question also agrees with my expectations, but the servlet is not picking up the form data. Obviously I am missing something....
Update: The post data is very straight forward and is not a Multipart form or rich media. Just plain'ol text submitted via an AJAX POST that looks like this in post body
c1=Value%20A&c2=Value%20B&c3=Value%20C
I managed to identify the problem. Because there is so much chatter from JDK 1.5+ and talk of getParameterMaps() method for 1.5, info on how 1.4 handles form post data was scarce and ambiguous. (Please post a comment if you find something that is specific for 1.4).
Pre-1.5 you have to manually get the form data via getInputStream, and then parse it out. I found this method, (posted below), from the java sun site that does a nice job using a Hashtable. I had to make a minor mod for deprecated methods. But seems to work quite robustly, "out of the box", so you should able to just cut-n-paste. I know it's "old tech" but I thought it worthwhile for those who may be in the same situation as me who are stuck on solving (what seems to be) straight forward problems.
public Hashtable parsePostData(int length, ServletInputStream instream) {
String valArray[] = null;
int inputLen, offset;
byte[] postedBytes = null;
boolean dataRemaining=true;
String postedBody;
Hashtable ht = new Hashtable();
//Vector paramOrder = new Vector(10);
StringBuffer sb = new StringBuffer();
if (length <=0) {
return null;
}
postedBytes = new byte[length];
try {
offset = 0;
while(dataRemaining) {
inputLen = instream.read (postedBytes, offset, length - offset);
if (inputLen <= 0) {
throw new IOException ("read error");
}
offset += inputLen;
if((length-offset) ==0) {
dataRemaining=false;
}
}
} catch (IOException e) {
System.out.println("Exception ="+e);
return null;
}
postedBody = new String (postedBytes);
StringTokenizer st = new StringTokenizer(postedBody, "&");
String key=null;
String val=null;
while (st.hasMoreTokens()) {
String pair = (String)st.nextToken();
int pos = pair.indexOf('=');
if (pos == -1) {
throw new IllegalArgumentException();
}
try {
key = URLDecoder.decode(pair.substring(0, pos),"UTF8");
val = java.net.URLDecoder.decode(pair.substring(pos+1,pair.length()),"UTF8");
} catch (Exception e) {
throw new IllegalArgumentException();
}
if (ht.containsKey(key)) {
String oldVals[] = (String []) ht.get(key);
valArray = new String[oldVals.length + 1];
for (int i = 0; i < oldVals.length; i++) {
valArray[i] = oldVals[i];
}
valArray[oldVals.length] = val;
} else {
valArray = new String[1];
valArray[0] = val;
}
ht.put(key, valArray);
String sValues = "";
for(int i=0;i<valArray.length;i++) {
if (0<i) {
sValues+=",";
}
sValues = valArray[i];
}
System.out.println("Form data field " + key + ":" +sValues);
//paramOrder.addElement(key);
}
return ht;
}
That's true. The getParameterNames(), getParameterValues(), and getParameter() methods are the way to access form data unless it's a multipart form, in which case you'll have to use something like Commons Fileupload to parse the multipart request before all the parameters are accessible to you.
Edit: You're probably not encoding the POST data properly in your AJAX call. POST data must carry a Content-Type of application/x-www-form-urlencoded or else multipart/form-data. If you're sending it as something else, it doesn't qualify as a request parameter, and I expect you'd see the behavior you're describing. The solution you've engineered essentially consists of setting up custom parsing of custom content.

Categories

Resources