Using ByteArrayLengthHeaderSerializer with java.net.Socket client - spring

I am trying to connect a simple java.net.Socket TCP client to a Spring Integration TCP server using a ByteArrayLengthHeaderSerializer.
Here is the relevant client code snippet:
Socket socket = null;
OutputStream out = null;
InputStream in = null;
try {
socket = new Socket(host, port);
out = new BufferedOutputStream(socket.getOutputStream());
in = new BufferedInputStream(socket.getInputStream());
byte[] lengthBuf = new byte[4];
int size = in.read(lengthBuf, 0, lengthBuf.length);
ByteArrayInputStream bis = new ByteArrayInputStream(lengthBuf);
ObjectInputStream ois = new ObjectInputStream(bis);
int dataSize = ois.readInt();
System.out.println("Got size: " + dataSize);
byte[] dataBuffer = new byte[dataSize];
int dataRead = in.read(dataBuffer, 0, dataBuffer.length);
bis = new ByteArrayInputStream(dataBuffer);
ois = new ObjectInputStream(bis);
String data = (String) ois.readObject();
System.out.println("read " + dataRead + " bytes, got data: " + data);
Here is the server side configuration:
#MessagingGateway(defaultRequestChannel="toTcp")
public interface Gateway {
void send(#Payload byte[] data, #Header(IpHeaders.CONNECTION_ID) String connectionId);
}
#Bean
public AbstractServerConnectionFactory serverFactory() {
AbstractServerConnectionFactory connectionFactory = new TcpNetServerConnectionFactory(port);
ByteArrayLengthHeaderSerializer serDeser = new ByteArrayLengthHeaderSerializer();
connectionFactory.setSerializer(serDeser);
connectionFactory.setDeserializer(serDeser);
return connectionFactory;
}
#Bean
public TcpReceivingChannelAdapter inboundAdapter(AbstractServerConnectionFactory connectionFactory) {
TcpReceivingChannelAdapter inbound = new TcpReceivingChannelAdapter();
inbound.setConnectionFactory(connectionFactory);
inbound.setOutputChannel(fromTcp());
return inbound;
}
and the calling code:
public void send(String data, String header) throws IOException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try (ObjectOutputStream oos = new ObjectOutputStream(bos)) {
System.out.println("data.length is " + data.length());
oos.writeObject(data);
byte[] bytes = bos.toByteArray();
gateway.send(bytes, header);
}
}
When I send the data (e.g. 'abc') I get (on the client side) this error:
invalid stream header: 0000000A
On the server side I get:
SoftEndOfStreamException: Stream closed between payloads
What am I doing wrong?

No - an ObjectOutputStream serializes java objects (and the input stream deserializes). You don't need a length header deserializer for that, just use a DefaultSerializer and DefaultDeserializer (from Spring Core) and don't add the header.
You are getting the error because the serialization adds more stuff at the beginning.
Or, if you are only sending a String, you can use String.getBytes() and send the length (4 bytes) followed by the byte[].

Related

upload file using rest services in spring mvc

I want to upload a file( any type of file ) into a forlder using web services and spring mvc so I have a sever side and a client side.
On my client side this is the code
#RequestMapping(value = "/uploadMultipleFile", method = RequestMethod.POST , produces="application/json")
public #ResponseBody
Boolean uploadMultipleFileHandler(
#RequestParam("name") MultipartFile[] files) {
MailService ms= new MailService();
Map<String, List<ByteArrayResource>>rval = new HashMap<String, List<ByteArrayResource>>();
String message = "";
MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
List<Object> files1 = new ArrayList<>();
List<Object> files2 = new ArrayList<>();
for (int i = 0; i < files.length; i++) {
MultipartFile file = files[i];
System.out.println(file.getOriginalFilename());
try {
byte[] bytes = file.getBytes();
files1.add(new ByteArrayResource(bytes));
files2.add(file.getOriginalFilename());
//System.out.println(map.toString());
} catch (IOException e) {
e.printStackTrace();
}
}
map.put("files", files1);
map.put("names", files2);
System.out.println(map.get("files").toString());
RestTemplate restTemplate = new RestTemplate();
String SERVER_URI="http://localhost:8080/BackEndFinalVersion";
Boolean p=restTemplate.postForObject(SERVER_URI+"/uploadMultipleFile", map, Boolean.class);
System.out.println(p.toString());
//message = message + ms.encodeFileToBase64Binary( bytes);
//rval.put("success",message);
return true;
}
and the server side code is
#RequestMapping(value = "/uploadMultipleFile", method = RequestMethod.POST, produces = "application/json")
public #ResponseBody Boolean uploadMultipleFileHandler(#RequestParam("files") List<Object> files , #RequestParam("names") List<Object> names) {
//MailService ms= new MailService();
//Map<String, Object> rval = new HashMap<String, Object>();
String message = "";
System.out.println("looool");
System.out.println(files);
System.out.println(names);
//System.out.println(files.get(0).toString());
for (int i = 0; i < files.size(); i++) {
System.out.println(files.get(i).getClass());
String file = (String)files.get(i);
try {
byte[] bytes = file.getBytes();
//FileUtils.writeStringToFile(new File("log.txt"), file, Charset.defaultCharset());
// Creating the directory to store file
String rootPath = "C:/Users/Wassim/Desktop/uploads";
File dir = new File(rootPath);
if (!dir.exists())
dir.mkdirs();
File serverFile = new File(dir.getAbsolutePath() + File.separator + ( names.get(i)));
BufferedOutputStream stream = new BufferedOutputStream(new FileOutputStream(serverFile));
stream.write(bytes);
stream.close();
//message = message + "You successfully uploaded file=" + ( (MultipartFile) files.get(i)).getOriginalFilename() + "<br />";
//FileUtils.writeByteArrayToFile(new File(dir.getAbsolutePath() + File.separator + files.get(i).getOriginalFilename()), ms.decodeFileToBase64Binary(ms.encodeFileToBase64Binary( bytes)));
//rval.put("success"+i, message);
System.out.println("noooo");
} catch (Exception e) {
message += "You failed to upload " + " => " + e.getMessage();
//rval.put("error", message);
return false;
}
}
return true;
My problem is that this code doesn't work only with .txt files
can any one support me ??

SSLException:Write error: ssl=0x7f8170c780: I/O error during system call, Connection timed out

I use okhttp and retrofit2 to post a audio file,but sometimes the file broken (server side),What is the reason?
File file = new File(path);
RequestBody requestFile = RequestBody.create(MediaType.parse("audio/*"), file);
body = MultipartBody.Part.createFormData("audio_file", file.getName(), requestFile);
HashMap<String,RequestBody> params = new HashMap<>();
params.put("lecture_id",RequestBody.create(MediaType.parse("multipart/form-data"), mId + ""));
params.put("duration",RequestBody.create(MediaType.parse("multipart/form-data"),attachment.getDuration() + ""));
params.put("reply_message_id",RequestBody.create(MediaType.parse("multipart/form-data"),msg.getReplyMsgId() + ""));
Subscription subscription = ApiService.getInstance().sendAudioMessage(body,params).subscribe(new HttpObserver<IMMessage>() {
#Override
protected void onError(ApiException ex) {
CrashReport.postCatchedException(ex);
ToastUtil.showToast(getActivity(),ex.getMsg());
onSendMessageFail(msg);
}
#Override
public void onNext(IMMessage imMessage) {
onSendMessageSuccess(msg);
}
});
mCompositeSubscription.add(subscription);

HttpsURLConnection for rest service call

i am using HttpsURLConnection for calling POST method and i am unable to add request payload to the call. same request works when i execute manually from soapui tool. does any one know how to do this?
Here is the java code is am using:
// Keystore
String jksFile = "/Users/......jks";
String password = "password";
System.setProperty("javax.net.ssl.keyStore", jksFile);
System.setProperty("javax.net.ssl.keyStorePassword", password);
String u = "https://example.com:443/private/loan-application";
URL url = new URL(u);
String version = "3";
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setDoOutput(true);
conn.setRequestMethod("POST");
conn.setUseCaches(false);
conn.setConnectTimeout(10000);
conn.setReadTimeout(10000);
conn.setRequestProperty("Accept", "application/json;v=" + version);
conn.setRequestProperty("Api-Key", "XYZ");
String jsonParamString = "{\"didNumber\":\"DI457\", \" .... ";
//Create JSONObject here
JSONObject jsonParam = new JSONObject();
byte[] postData = jsonParamString.toString().getBytes();
Map<String, List<String>> requestProperties = conn.getRequestProperties();
displayHeaders(requestProperties);
OutputStream out = conn.getOutputStream();
out.write(postData);
out.close();
int respCode = conn.getResponseCode();
System.out.println("Response headers:");
displayHeaders(
conn.getHeaderFields());
InputStream is = null;
if (respCode == 200 || respCode == 203) {
is = conn.getInputStream();
}
if (is == null) {
System.out.println("Using error stream");
is = conn.getErrorStream();
}
is.close();
One possible explanation for why your HttpsURLConnection call is failing is that you have not configured your SSL settings properly. Specifically, the domain example.com is presenting a certificate which is not in your trust store, and therefore your program is failing during the SSL handshake. Try adding the following code, which will configure your program to trust all certificates:
SSLContext sslContext = SSLContext.getInstance("TLS");
TrustManager tm = new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { }
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { }
public X509Certificate[] getAcceptedIssuers() { return null; }
};
sslContext.init(null, new TrustManager[]{tm}, null);
conn.setSSLSocketFactory(sslContext.getSocketFactory());
Note that you should probably not use this code in production, because it accepts any site as secure. In production, you should configure your program to only accept trusted certificates.

jaxrs.ResteasyClient download file

Request a webAPI that gives me a ZIP file. Now my question:
How to download that file with jaxrs.ResteasyClient. Here is what I have but it does not work for me.
// In
Reader reader = client.target(url).request().get().readEntity(Reader.class);
BufferedReader bufferedReader = new BufferedReader(reader);
// Out
File out = new File("C:\\tmp\\test.zip");
FileWriter fileWriter = new FileWriter(out);
BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
String s = null;
while (true) {
s = bufferedReader.readLine();
if (s == null) {
break;
}
bufferedWriter.write(s);
}
bufferedWriter.flush();
bufferedWriter.close();
bufferedReader.close();
I have no idea if this makes sense, but I do not find any good documentation about reading a file instead of a bean object.
Resolved this issue by not using jaxrs.ResteasyClient. Apache HTTPClient was my friend!
private void getFileByURL(String url, String target) throws URISyntaxException, IOException {
HttpClientBuilder builder = HttpClients.custom().build();
CloseableHttpClient client = builder.build();
HttpResponse response = client.execute(new HttpGet(new URI(url)));
BufferedInputStream bufferedInputStream = new BufferedInputStream(response.getEntity().getContent());
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(new File(target)));
int inByte;
while ((inByte = bufferedInputStream.read()) != -1) {
bufferedOutputStream.write(inByte);
}
bufferedInputStream.close();
bufferedOutputStream.close();
EntityUtils.consume(response.getEntity());
}

httpclient garbling extended characters

I'm using httpclient to retrieve remote urls and need to grab things such as titles.
In some cases, I get garbled extended characters as in the case of this url
http://olhardigital.uol.com.br/noticia/bilionaria-mais-jovem-da-historia-quer-revolucionar-exames-de-sangue/43586
I've tried playing around with all sorts of settings, to no avail. Any suggestions? My config is as follows:
private CloseableHttpClient httpclient = RemotePageUtils.getThreadSafeClient();
public String processMethod(String url, OutputStream out) throws IOException, IllegalArgumentException{
[...]
BufferedReader in = null;
HttpEntity entity = null;
HttpGet httpget = null;
CloseableHttpResponse resp = null;
try {
httpget = new HttpGet(url);
resp = httpclient.execute(httpget);
entity = resp.getEntity();
String inLine;
in = new BufferedReader(new InputStreamReader(entity.getContent(),"UTF-8"));
while ((inLine = in.readLine()) != null) {
out.write(inLine.getBytes("UTF-8"));
}
} finally {
[...]
}
return null;
}
private static CloseableHttpClient getThreadSafeClient() {
SocketConfig socketConfig = SocketConfig.custom()
.setTcpNoDelay(true)
.build();
RequestConfig config = RequestConfig.custom()
.setConnectTimeout(3000)
.setSocketTimeout(7000)
.setStaleConnectionCheckEnabled(false)
.build();
List<Header> headers = new ArrayList<Header>();
headers.add(new BasicHeader("Accept-Charset","ISO-8859-1,US-ASCII,UTF-8,UTF-16;q=0.7,*;q=0.7"));
//accept gzipped
headers.add(new BasicHeader("Accept-Encoding","gzip,x-gzip,deflate,sdch"));
CloseableHttpClient client = HttpClientBuilder.create()
.setDefaultHeaders(headers)
.setDefaultRequestConfig(config)
.setDefaultSocketConfig(socketConfig)
.build();
return client;
}
You are blindly interpreting all downloaded pages as UTF-8, but the example link you gave is not in UTF-8, but ISO-8859-1.
An accented letter in ISO-8859-1 is one byte >=128, where in UTF-8 such bytes have to follow specific patterns, in other case they are treated as damaged.
But why are you decoding bytes you have downloaded, just to write bytes to a file?
Instead of:
in = new BufferedReader(new InputStreamReader(entity.getContent(),"UTF-8"));
while ((inLine = in.readLine()) != null) {
out.write(inLine.getBytes("UTF-8"));
}
and converting bytes to strings and back, you should just copy the bytes.
You can do it with Apache Commons IO:
import org.apache.commons.io.IOUtils;
IOUtils.copy(entity.getContent(), out);
or manually, with pure Java:
byte[] buf = new byte[16 * 1024];
int len = 0;
InputStream in = entity.getContent();
while ((len = in.read(buf)) >= 0) {
out.write(buf, 0, len);
}

Resources