I am developing an Android application which suppose to call Axis2 Web Service (already implemented and running) where the previous developer made in such a way that Byte[] is the common form of passing Object around. Suppose there is a need to invoke web service in the Axis2 which should return List, the web service will convert the instance into Byte[] and return the Byte[], where the client will convert it back.
Here is the snippet from the service:
public byte[] getMyPersonList() throws Exception {
java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream();
java.io.ObjectOutputStream oos = new java.io.ObjectOutputStream(baos);
oos.writeObject(new List<Person>());
return (baos.toByteArray());
}
In the client (not my android application but the existing desktop application which are developed by the same people making the web service)
byte[] buffer = (byte[]) serviceClient.invokeBlocking(methodName,
new Object[] {}, new Class[] { byte[].class })[0];
java.io.ObjectInputStream ois = new java.io.ObjectInputStream(
new java.io.ByteArrayInputStream(buffer));
return (List<Person>) ois.readObject();
The invokeBlocking() method seems to automatically convert the returned value from the service automatically back to byte[], but I am having trouble doing the same thing in my application.
This is what the return value looks like when I invoke the service manually over browser:
<return>
rO0ABXNyABNqYXZhLnV0aWwuQXJyYXlMaXN0eIHSHZnHYZ0DAAFJAARzaXpleHAAAAAJdwQAAAAKc3IAJ3dvcmtmbG9.......................
</return>
And what I have done so far is to directly get the return as string and use getBytes():
byte [] soapReturnBytes = resultsRequestSOAP.getPropertyAsString("return").getBytes();
ObjectInputStream ois = new ObjectInputStream(bais);
myPersonList= (List<Person>) ois.readObject();
But I received stream corrupted error which could mean that it simply not the same content when I convert it back.
So my question is:
When returning Byte[], what does Axis2 engine do to convert the values to fit it into the SOAP return
What are the methods of converting this 'stringified' value back to Byte[], in case I can't do anything about the web service (no modification on the web service)
Any suggestion is greatly appreciated.
EDIT:
As suggested, I am using a decoder to get the result, however still no luck:
String result = resultsRequestSOAP.getPropertyAsString("return");
byte[] soapReturnBytes = Base64.decode(result, Base64.DEFAULT);
ByteArrayInputStream bais = new ByteArrayInputStream(soapReturnBytes);
ObjectInputStream ois = new ObjectInputStream(bais);
orgs = (List<Person>) ois.readObject();
I still received the same error:
java.io.StreamCorruptedException: Wrong format: 0
Any suggestion? getting frustrated
EDIT 2:
I created another service which returns String as byte[], and in my Android application I received the byte[] and convert it back to the original String. So perhaps it has something to do with the way I am using the Stream to convert my Object <=> byte [].
When returning Byte[], what does Axis2 engine do to convert the values to fit it into the SOAP return
The Java type byte[] is mapped to the XML Schema type xsd:base64Binary. The transformation is called Base64 encoding.
What are the methods of converting this 'stringified' value back to Byte[], in case I can't do anything about the web service (no modification on the web service)
You need to use a Base64 decoder. There are numerous Java implementations available, e.g. Commons Codec.
Related
I'm trying to send JSON from a Python client to a Java server
The JSON data type is bytes (in Python) and when I deserialize it (in Python) and print it, it looks perfect. The server works fine when a Java client connects and when I deserialize the JSON and print it in Java it looks exactly the same as in Python and the actual JSON files. The JSON all looks good, but the data isn't accepted by the Java server.
data = open(file_path, 'r').read() # reading JSON object as string
serialized_data = pickle.dumps(data)
s.send(serialized_data)
When I send a JSON file the Java server acknowledges the connection but the JSON data for whatever reason isn't accepted.
Java Client
String sentence = new String(readFile());
if(!sentence.equals("fileNotFound")) {
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
oos.writeObject(sentence);
}
Java Server
ObjectInputStream inFromClient = new ObjectInputStream(socket.getInputStream());
String clientString = null;
try {
clientString = (String) inFromClient.readObject();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
inFromClient.close();
You appear to be doing this:
Read JSON from file as a String
Pickle the string
Send the pickle to Java.
That won't work. A pickle is a Python-specific serialization format. Java doesn't understand it.
The data you are reading from the file is already serialized .... as JSON.
Solution: send the string containing the JSON without pickling it.
On the other hand, if the Java server expects to receive something that has been serialized using ObjectOutputStream, then you have a bigger problem. The Java Object Serialization protocol is Java specific. Python doesn't support it. But if you are actually sending JSON to the server you should need to do that. Change the server to accept JSON, and get rid of the ObjectInputStream / ObjectOutputStream code on both sides.
On the third hand, if you can't get rid of the ObjectInputStream / ObjectOutputStream stuff, then maybe you need to modify the server side to either provide a separate API for python to call, or get the server to check the request's "content-type" header and handle either form of data serialization (JSON and Object Serialization protocol)
Hi I'm currently creating a proxy server and I need to implement a cache within the proxy server.
The cache is a hashmap with the URL being the key and the byte array of the URL will be the value.
Currently I am running into a problem when I am trying to write the byte array into the output stream of the client.
try{
if(!myCache.containsKey(urladdr))
{
IOUtils.copy(serverInput,toClient);
byte[] byteArray = IOUtils.toByteArray(connection);
myCache.addToCache(urladdr, byteArray);
}
else{
toClient.write(myCache.getValue(urladdr));
System.out.println("got from cache");
}
}
So basically if the URL is not in the cache yet, I will load the page using IOUtils.copy and then add the url + byte array to my cache.
If the URL is in my cache, I will get the byte array of the URL from the hashmap and write to the client. That is where my programme gets stuck, it just doesn't load the byte array into the client output stream.
Is it maybe a problem due to not sending any headers?
Help appreciated thanks
My grails 2.2.4 app needs to support accepting files over HTTP from a third party application and sending the file, after making some tweaks to it, back out as a response to the third party application.
I want to convert the data sent by the third party application to a file using InputStream and then send the file back out using OutputStream
So I built this code:
API Classes
class ApiResponse {
ApiMeta meta
ApiObject apiObj
}
class ApiMeta {
int code
String errorType
List msgs = []
}
class ApiObject {
OutputStream os
}
//Object Marshaller
JSON.registerObjectMarshaller( ApiObject ) { ApiObject obj ->
//How can I send output stream as json?
}
Controller
//controller
def save() {
request.withFormat {
json {
ApiResponse resp
//How can I convert the JSON data in params to a file?
response.status = 201
resp = new ApiResponse(
meta: new ApiMeta(code: 201),
apiObj: new ApiObject(os: transfers))
render resp as JSON
}
multipartForm {
}
}
Question
How can I convert JSON payload sent by the third party service into a file?
Is it ok to put OutputStream in my ApiObject class so that I can send the JSON payload back to the service?
My grails 2.2.4 app needs to support accepting InputStream over HTTP
from a third party application and sending OutputStream as a response
back.
That does not really make sense. Third party apps can't really send an InputStream to your app and your app can't really send an OutputStream back. The third party app can send you data in the body of the request and you can read the body by retrieving an InputStream from the request, and the same sort of thing could happen when you put data in the response. At first read I thought maybe you were just wording things in a way that doesn't make sense but then when I saw your domain class, that suggests that maybe you really are confused about how this works.
class Request {
InputStream instream
OutputStream outstream
static constraints = {
instream nullable: false, blank: false
}
}
You can't do that. You cannot persist an InputStream or an OutputStream to the database.
EDIT:
If you have a controller like this:
class MyController {
def someAction(Widget w) {
// do whatever you need to do with the Widget
}
}
class Widget {
String name
String category
}
And you send a request to that controller action with a JSON body which looks like this...
{"name":"Robert","category":"Prog Rocker"}
Grails will automatically read the body of the request and do the corresponding binding. You would never have to directly interact with any input stream to make that happen. Is that the sort of thing you are looking for?
I'm having a problem to post a image to my wcf rest service. I'm posting some parameters of which one of them is a base64 utf-8 encoded string (the image).
My problem is that every time I post I get "bad request". Here is the code
public String PostImage(Drawable img) throws Exception
{
HttpPost httpost = new HttpPost("http://10.0.2.2:1374/uploaditem");
JSONStringer json = JSONStringer()
.object()
.key("ipm")
.object()
.key("name").value("test")
.key("description").value("asfa")
.key("categoryid").value(1)
.key("data").value(ConvertImgToBase64Str(img))
.key("imagetype").value(2)
.key("tags").value("test;test")
.endObject()
.endObject();
StringEntity entity = new StringEntity(json.toString());
entity.setContentType("application/json;charset=UTF-8");//text/plain;charset=UTF-8
entity.setContentEncoding(new BasicHeader(HTTP.CONTENT_TYPE,"application/json;charset=UTF-8"));
httpost.setEntity(entity);
return ExcecutePostRequest(httpclient,httpost);
}
//Method to convert the image to base64encoded string
private String ConvertImgToBase64Str(Drawable img) {
Bitmap bitmap = ((BitmapDrawable)img).getBitmap();
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[] bitmapdata = stream.toByteArray();
return Base64.encodeToString(bitmapdata, Base64.URL_SAFE);
}
It is something with the encoded string, but what?
I don't see why it should be a problem with the encoded string.
Firstly, try removing the data attribute in the string object and see if you get the same problem. This way you can eliminate the possibility it is due to the the encoding and ensure you are making the request correctly.
Secondly print the http message being sent and format check it. If you have access to the server log the message being received and any details that may elaborate on the Bad Request. I would have thought WCF will be printing something to stderr if it is responding with a bad request so try just checking the existing logs first.
EDIT
I don't think there should be problems with strange characters because the character used in base64 encoding don't fall outside the ASCi range.
You should check the size of the request being sent. If you images are big you will get a big base64 encoded string which might exceed the server post limit.
If you can't get to the server logs which I think would clarify this if it was the problem you could test it by sending a smaller image.
I have a GWT page where user enter data (start date, end date, etc.), then this data goes to the server via RPC call. On the server I want to generate Excel report with POI and let user save that file on their local machine.
This is my test code to stream file back to the client but for some reason I think it does not know how to stream file to the client when I'm using RPC:
public class ReportsServiceImpl extends RemoteServiceServlet implements ReportsService {
public String myMethod(String s) {
File f = new File("/excelTestFile.xls");
String filename = f.getName();
int length = 0;
try {
HttpServletResponse resp = getThreadLocalResponse();
ServletOutputStream op = resp.getOutputStream();
ServletContext context = getServletConfig().getServletContext();
resp.setContentType("application/octet-stream");
resp.setContentLength((int) f.length());
resp.setHeader("Content-Disposition", "attachment; filename*=\"utf-8''" + filename + "");
byte[] bbuf = new byte[1024];
DataInputStream in = new DataInputStream(new FileInputStream(f));
while ((in != null) && ((length = in.read(bbuf)) != -1)) {
op.write(bbuf, 0, length);
}
in.close();
op.flush();
op.close();
}
catch (Exception ex) {
ex.printStackTrace();
}
return "Server says: " + filename;
}
}
I've read somewhere on internet that you can't do file stream with RPC and I have to use Servlet for that. Is there any example of how to use Servlet and how to call that servlet from ReportsServiceImpl. Do I really need to make a servlet or it is possible to stream it back with my RPC?
You have to make a regular Servlet, you cannot stream binary data from ReportsServiceImpl. Also, there is no way to call the servlet from ReportsServiceImpl - your client code has to directly invoke the servlet.
On the client side, you'd have to create a normal anchor link with the parameters passed via the query string. Something like <a href="http://myserver.com/myservlet?parm1=value1&.."</a>.
On the server side, move your code to a standard Servlet, one that does NOT inherit from RemoteServiceServlet. Read the parameters from the request object, create the excel and send it back to the client. The browser will automatically popup the file download dialog box.
You can do that just using GWT RPC and Data URIs:
In your example, make your myMethod return the file content.
On the client side, format a Data URI with the file content received.
Use Window.open to open a file save dialog passing the formatted DataURI.
Take a look at this reference, to understand the Data URI usage:
Export to csv in jQuery
It's possible to get the binary data you want back through the RPC channel in a number of ways... uuencode, for instance. However, you would still have to get the browser to handle the file as a download.
And, based on your code, it appears that you are trying to trigger the standard browser mechanism for handling the given mime-type by modifying the response in the server so the browser will recognize it as a download... open a save dialog, for instance. To do that, you need to get the browser to make the request for you and you need the servlet there to handle the request. It can be done with rest urls, but ultimately you will need a serviet to do even that.
You need, in effect, to set a browser window URL to the URL that sends back the modified response object.
So this question (about streaming) is not really compatible with the code sample. One or the other (communication protocols or server-modified response object) approach has to be adjusted.
The easiest one to adjust is the communication method.