Reading object in client side written in the HttpServletResponse - java

I am uploading a file through a com.google.gwt.user.client.ui.FileUpload, when the file arrives to the server I want to be able to tell the client what is the status of the upload. To this end I wrote a simple Message class that implements the java.io.Serializable interface and I write the object to the response this way:
outputStream = new ObjectOutputStream(response.getOutputStream());
outputStream.writeObject(object);
outputStream.flush();
outputStream.close();
The problem is that in the client I don't know how to deserialize this object. how can I access the outputstream to reconstruct the object, I have this method:
form.addSubmitCompleteHandler(new FormPanel.SubmitCompleteHandler()
{
public void onSubmitComplete(SubmitCompleteEvent event)
{
String result = event.getResults();
});
}
I know I can just write a simple String into the response and set the content type to "text/plain", but I would really like to know to do it with objects. Any help would be appreciated.

Related

AWS Java Lambda Function with API Gateway - POJO input and OutputStream output

I'm creating a simple AWS Lambda Function in Java that creates and returns a PDF. The function is invoked by an API Gateway. The input is a simple POJO class, but the output should be an OutputStream for the file.
For the input, I've tried creating a POJO class and just using the APIGatewayProxyRequestEvent and either works fine. Below is a simple example I used that takes in a input and prints back the query string parameters.
public class LambdaFunctionHandler implements RequestHandler<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> {
#Override
public APIGatewayProxyResponseEvent handleRequest( APIGatewayProxyRequestEvent input, Context context ) {
return new APIGatewayProxyResponseEvent()
.withStatusCode(200)
.withHeaders(Collections.emptyMap())
.withBody("{\"input\":\"" + input.getQueryStringParameters() + "\"}");
}
}
That works fine, but now I need to alter it to use an OutputStream as the the output. How can this be done? I see that I can use the RequestStreamHandler and AWS has some documentation on implementing this. However, that would force my input to be an InputStream, which I'm not sure how that would work with the API Gateway.
How can I serve this PDF back to the client requesting it?
Remember that the POJO method of the Lambda handler is a convenience only. Ultimately, you could do this yourself and use the InputStream/OutputStream Lambda pattern. Something like:
public void handleRequest(InputStream inputStream,
OutputStream outputStream,
Context context) throws IOException {
String inputString = new BufferedReader(new InputStreamReader(inputStream)).lines().collect(Collectors.joining("\n"));
ObjectMapper objectMapper = new ObjectMapper();
APIGatewayProxyRequestEvent request = objectMapper.readValue(inputString, APIGatewayProxyRequestEvent.class);
// do your thing, generate a PDF
byte[] thePDF = ...
// create headers
Map<String, String> headers = new HashMap<>();
headers.put("Content-type", "application/pdf");
APIGatewayProxyResponseEvent response = new APIGatewayProxyResponseEvent().
.withStatusCode(200)
.withHeaders(headers)
.withBody(Base64.Encoder.encode(thePDF))
.withIsBase64Encoded(Boolean.TRUE);
outputStream.write(objectMapper.writeValueAsString(response)
.getBytes(StandardCharsets.UTF_8));
}
However, I'm not convinced that this is really any better. If you want to return just the PDF without the APIGatewayProxyResponseEvent you can but now you'll have to update API Gateway to correctly send the Content-Type header.

Log JSON responses from JAX-RS web services

I have some JAX-RS web services that takes JSON input from clients, and return JSON outputs to clients. I need to log both the input and output JSON messages. I know how to do so for inputs, as shown in code below. This code will grab the exact JSON input that is coming in. How do I do the same for the outputs?
public class LogRequestFilter implements ContainerRequestFilter {
#Override
public void filter(ContainerRequestContext requestContext) throws IOException {
InputStream inputStream = requestContext.getEntityStream();
// Read the JSON request input from the input stream.
}
}
Use ContainerResponseFilter to get the exchanged Entity. Add the filter to the provider list of the JAX-RS server
public class LogResponseFilter implements ContainerResponseFilter {
public void filter(ContainerRequestContext inContext, ContainerResponseContext outContext) throws IOException{
Object entity = outContext.getEntity();
//log entity.toSgring()
//You can use the output stream to write a custom message
//OutputStream outputStream = outContext.getEntityStream();
}
}
To just log the payload, looking at this link https://stackoverflow.com/a/25337892/6371459 I see
The OutputStream is empty at the time the Filter is called because the JAX-RS runtime has not written to it. After your Filter the runtime will choose the correct MessageBodyWriter which will serialize the entity to the OutputStream
So it is needed to add a WriterInterceptor to be execuded after MessageBodyWriters write to desired content-type.
In the previous link you have the full code.

get values from server to applet [duplicate]

I have an applet and I must send a request to a web application to get data from the server that is in a database. I am working with objects and it is very useful that the server responses me with objects!!
How an applet can communicate with a server?
I think web services method, RMI and... make me happy, but which is the best and reliable?
As long as its only your applet communicating with the server you can use a serialized object. You just need to maintain the same version of the object class in both the applet jar and on the server. Its not the most open or expandable way to go but it is quick as far as development time and pretty solid.
Here is an example.
Instantiate the connection to the servlet
URL servletURL = new URL("<URL To your Servlet>");
URLConnection servletConnect = servletURL.openConnection();
servletConnect.setDoOutput(true); // to allow us to write to the URL
servletConnect.setUseCaches(false); // Write the message to the servlet and not from the browser's cache
servletConnect.setRequestProperty("Content-Type","application/x-java-serialized-object");
Get the output stream and write your object
MyCustomObject myObject = new MyCustomObject()
ObjectOutputStream outputToServlet;
outputToServlet = new ObjectOutputStream(servletConnection.getOutputStream());
outputToServlet.writeObject(myObject);
outputToServlet.flush(); //Cleanup
outputToServlet.close();
Now read in the response
ObjectInputStream in = new ObjectInputStream(servletConnection.getInputStream());
MyRespObject myrespObj;
try
{
myrespObj= (MyRespObject) in.readObject();
} catch (ClassNotFoundException e1)
{
e1.printStackTrace();
}
in.close();
In your servlet
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
MyRespObject myrespObj= processSomething(request);
response.reset();
response.setHeader("Content-Type", "application/x-java-serialized-object");
ObjectOutputStream outputToApplet;
outputToApplet = new ObjectOutputStream(response.getOutputStream());
outputToApplet.writeObject(myrespObj);
outputToApplet.flush();
outputToApplet.close();
}
private MyRespObject processSomething(HttpServletRequest request)
{
ObjectInputStream inputFromApplet = new ObjectInputStream(request.getInputStream());
MyCustomObject myObject = (MyCustomObject) inputFromApplet.readObject();
//Do Something with the object you just passed
MyRespObject myrespObj= new MyRespObject();
return myrespObj;
}
Just remember that both Objects that you are passing need to implement serializable
public Class MyCustomObject implements java.io.Serializable
{

Streaming bytes via HTTP PUT with JAX-RS

I have a workflow that involves doing a HTTP POST from my Java client to my web server. The body of the post has a specification object. I then pass that on from my webserver to Apache ZooKeeper (which runs in its own process on the server) that runs a big hairy calculation. I am struggling with figuring out how to send back the bytes to my webserver in streaming fashion. I need it to stream back because I have a HTTP GET request on my webserver from my Java client that is waiting to stream back the bytes. I cannot wait for the whole calculation to finish, I want bytes sent as soon as possible back to the client.
Most the examples online for JAX-RS that do a HTTP PUT from the client side and on the webserver side don't have examples for streaming code. I'll post what I have so far, but it doesn't work.
Here is my ZooKeeper Java code, which calls a JAX-RS client-side PUT. I am really unsure of how to do this, I have never tried streaming data with JAX-RS.
final Client client = ClientBuilder.newClient();
final WebTarget createImageTarget = client.target("groups/{imageGroupUuid:" + Regex.UUID + "}");
StreamingOutput imageResponse = createImageTarget.request(MediaType.APPLICATION_OCTET_STREAM).put(Entity.entity(createRandomImageDataBytes(imageConfigurationObject), MediaType.APPLICATION_OCTET_STREAM), StreamingOutput.class);
Here is my webserver code which handles the HTTP PUT. It is just a stub because I have no confidence in my client side HTTP PUT.
#PUT
#PATH("groups/{uuid:" + Regex.UUID + "}")
#Consumes(MediaType.APPLICATION_OCTET_STREAM)
public void updateData(StreamingOutput streamingOutput)
{
}
Try something like this:
#GET
#Produces(MediaType.TEXT_PLAIN)
#Path("/{arg}")
public Response get(#PathParam("arg") {
//get your data based on "arg"
StreamingOutput stream = new StreamingOutput() {
#Override
public void write(OutputStream os) throws IOException, WebApplicationException {
Writer writer = new BufferedWriter(new OutputStreamWriter(os));
for (org.neo4j.graphdb.Path path : paths) {
writer.write(path.toString() + "\n");
}
writer.flush();
}
};
return Response.ok(stream).build();
}
#PUT
#Consumes("application/octet-stream")
public Response putFile(#Context HttpServletRequest request,
#PathParam("fileId") long fileId,
InputStream fileInputStream) throws Throwable {
// Do something with the fileInputStream
// etc
}

Is it possible to read HttpRequest parameters without consuming stream?

I am looking at the implementation of the HiddenMethodFilter in sitebricks here:
At line 65 there is the following code:
try {
String methodName = httpRequest.getParameter(this.hiddenFieldName);
if ("POST".equalsIgnoreCase(httpRequest.getMethod()) && !Strings.empty(methodName)) {
....
It checks if a specific parameter was set and uses that to wrap the request. However, in reading that parameter it will consume the stream and the eventual servlet will not be able read any data.
What would be the best way to avoid this? I implemented the HttpServletRequestWrapper here which reads the contents of the stream into a byte array. This however may use a lot of memory to store the requests.
private HttpServletRequestWrapper getWrappedRequest(HttpServletRequest httpRequest, final byte[] reqBytes)
throws IOException {
final ByteArrayInputStream byteInput = new ByteArrayInputStream(reqBytes);
return new HttpServletRequestWrapper(httpRequest) {
#Override
public ServletInputStream getInputStream() throws IOException {
ServletInputStream sis = new ServletInputStream() {
#Override
public int read() throws IOException {
return byteInput.read();
}
};
return sis;
}
};
}
Is there a better way? can we read the parameter without consuming the stream? (Some thing similar to peek) can we reset the stream?
If you are using POST requests and read parameters from the httpRequest this will affect the InputStream and you will have problems in other parts needing to read it.
This is stated in ServletRequest#getParameterjavadoc:
If the parameter data was sent in the request body, such as occurs
with an HTTP POST request, then reading the body directly via
getInputStream() or getReader() can interfere with the execution of
this method.
The ServletInputStream is derived from InputStream and inherits the markSupported reset etc which are actually no-ops and so you can not reset a ServletInputStream.
This means that you will have to consume it.

Categories

Resources