Jersey ContainerRequestFilter gets empty entitystream - java

To validate the api key I have employed ContainerRequestFilter to read the JSON payload and parse the api key. I have following method.
public ContainerRequest filter(ContainerRequest request) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
InputStream in = request.getEntityInputStream();
try {
int read;
final byte[] data = new byte[2048];
while ((read = in.read(data)) != -1)
out.write(data, 0, read);
byte[] requestEntity = out.toByteArray();
request.setEntityInputStream(new ByteArrayInputStream(requestEntity));
if (!validate(new String(data))) {
throw new WebApplicationException(401);
}
return request;
} catch (IOException ex) {
throw new WebApplicationException(401);
}
}
However, the data is getting always blank/empty. Without the filter the payload reaches the resource class and works just fine. Any clues as to why the payload is empty? I was testing this with Firefox's REST Client with JSON in the Body.

I assume you want to call
validate(new String(requestEntity))
instead of
validate(new String(data))
because in the second case you can get an invalid JSON (if your payload is big enough).
Also you might want to consider using MessageBodyReaders to read your entity for you:
public ContainerRequest filter(ContainerRequest request) {
// Buffer
InputStream in = request.getEntityInputStream();
if (in.getClass() != ByteArrayInputStream.class) {
// Buffer input
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
ReaderWriter.writeTo(in, baos);
} catch (IOException ex) {
throw new ContainerException(ex);
}
in = new ByteArrayInputStream(baos.toByteArray());
request.setEntityInputStream(in);
}
// Read entity as a string.
final String entity = request.getEntity(String.class);
if (!validate(entity) {
throw new WebApplicationException(401);
}
// Reset buffer
ByteArrayInputStream bais = (ByteArrayInputStream)in;
bais.reset();
return request;
}

The only thing I can think of is that, somehow, the input stream is being read before your filter gets the ContainerRequest. Are there any other classes that still read in the data or is your Jersey setup somehow misconfigured so that the resource class is reading the input stream before your filter?

Related

How to return multiple InputStream objects in rest API response?

I have one rest API developed in Java SpringBoot in which I am able to single InputStream object in a response using following code.
public ResponseEntity<StreamingResponseBody> export(request) throws FileNotFoundException {
InputStream inputStream = service.getDocumentObject();
StreamingResponseBody responseBody = outputStream -> {
int numberOfBytesToWrite;
byte[] data = new byte[1024];
while ((numberOfBytesToWrite = inputStream.read(data, 0, data.length)) != -1) {
System.out.println("Writing some bytes..");
outputStream.write(data, 0, numberOfBytesToWrite);
}
inputStream.close();
};
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=generic_file_name.bin")
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.body(responseBody);}
But now I have requirement where I have to return multiple InputStream Objects in the API response.
Is it possible to do the same? if yes then please share sample code snippet for referece.
Thanks in Advance.

Read a resource from URL and return directly those bytes as response of REST request, with no memory storing with Java 7 and spring MVC 3.2

I have a REST endpoint that has to be accessed to retrieve a resource (image, document, ...).
#RequestMapping(value = "/attachement", method = RequestMethod.GET)
#ResponseBody
public Object getTrademarkAttachement(HttpServletResponse response, HttpServletRequest request) {
//TODO : Retrieve bytes from microservice url
//TODO : Send bytes to frontend page
}
For retrieving this document, I want to do it via streaming . I don't want to store in memory the info . I want to , as I get the info, send the bytes as a response . My version of spring MVC is Spring MVC 3.2 and my version of java is java 7 . Is it possible to achieve this ? could you give any clue to start investigating ? . I know I'm giving little details about implementation but I'm starting with this point and I would want to get some ideas from you .
EDIT 1 :
I have achieved half of the problem . Retrieving different blocks of the url . I have used the following code
#Override
public byte[] getTrademarkAttachement() {
String urlSample = "http://testUrl.com";
HttpURLConnection httpConn = null;
String line = null;
try {
httpConn = (HttpURLConnection) new URL(urlSample).openConnection();
InputStream ins = httpConn.getInputStream();
BufferedReader is = new BufferedReader(new InputStreamReader(ins));
while ((line = is.readLine()) != null) {
System.out.println(line);
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
httpConn.disconnect();
}
return null;
}
Being able to have access to the inputstream , the part that is left is returning each of this lines that I'm reading , so I can stream the response . I have to look for a method in spring MVC that gives a partial response .
Since you can get the InputStream, you should be able to return an OutputStream as a response to the request. Take a look at this (https://stackoverflow.com/a/27742486/):
#RequestMapping(value = "/attachement", method = RequestMethod.GET)
#ResponseBody
public void getAttachment(OutputStream out) {
InputStream in = ; // Set this to the InputStream from HTTP as your provided example
byte[] buffer = new byte[1024]; // You will need a small buffer mem though
int len;
while ((len = in.read(buffer)) != -1) {
out.write(buffer, 0, len);
}
in.close();
out.flush();
}
Ok , I have solved my problem . I attach the solution . Maybe it's useful to anybody.
Controller
#RequestMapping(value="/eutm/{trademarkId}/snapshots/{historyId}/attachements/{attachementId}", method = RequestMethod.GET)
#ResponseBody
public void getTrademarkAttachement(HttpServletResponse response, #PathVariable String trademarkId, #PathVariable String historyId, #PathVariable String attachementId) {
try {
registerService.getTrademarkAttachement(trademarkId, historyId, attachementId, LanguageController.getLocale(), response.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
}
}
Service
#Override
public void getTrademarkAttachement(String trademarkId, String historyId, String attachementId, Locale locale, ServletOutputStream outputStream) {
URI uri = loadHistoryUri(generateUri(REGISTER_BASE_MS_URL, REGISTER_HISTORY_ENTRY_TM_ATTACHEMENT_WS_URL, trademarkId, historyId, attachementId), locale.getLanguage());
HttpURLConnection httpConn = null;
String line = null;
InputStream ins = null;
try {
httpConn = (HttpURLConnection) new URL(uri.toString()).openConnection();
ins = httpConn.getInputStream();
BufferedReader is = new BufferedReader(new InputStreamReader(ins));
while ((line = is.readLine()) != null) {
outputStream.write(line.getBytes());
}
outputStream.flush();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
httpConn.disconnect();
if(ins != null){
try {
ins.close();
} catch (IOException e) {
logger.error("Bad close of inputStream ins");
}
}
}
}
This way, as it reads lines from inputStream ( url to retrieve via GET connection ), it writes it directly to the response via outputStream . It doesn't send bit to bit as in reactive mode , so the user is not getting the info directly, but I think that with Spring MVC 3.2 and Java 7 is the most approximate way to avoid elements in memory .

Java Convert byte array to PDF returns "undefined"

I'm trying to convert a byte array to a PDF document, but the the PDF file seems to be corrupted. And if open the file with a text reader the file just say "Undefined" I have searched through various stack topics but no luck. And the way i do it should work according to other topics. Below is my code. The code is executed trough a rest controller. Would really appreciate if someone could help me :).
//Controller
#ResponseBody
#RequestMapping(value = "/orders/{orderCode}/receipt", method = RequestMethod.GET, produces = "application/pdf")
public void getOrderReceiptConroller(#PathVariable("orderCode") final String orderCode, final HttpServletResponse response)
{
response.setContentType(CoreConstants.MIME_TYPE_APPLICATION_PDF);
final InputStream inputStream = new ByteArrayInputStream(OrderFacade.getReceiptPdf(orderCode));
OutputStream outputStream = null;
try
{
outputStream = response.getOutputStream();
IOUtils.copy(inputStream, outputStream);
}
catch (final IOException e)
{
}
finally
{
IOUtils.closeQuietly(inputStream);
IOUtils.closeQuietly(outputStream);
}
}
// calls this code that returns the byteArray.
private byte[] getReceiptPdf()
{
Gson gson = new Gson();
Edwresults edwResult = gson.fromJson(new FileReader(mockResponsePath), Edwresults.class);
String response = edwResult.getResults().get(0).getData().get(0).getDigitalReceipt();
byte[] byteData = response.getBytes();
return byteData;
}

PlayFramework. How to upload a photo using an external endpoint?

How do I upload a photo using a URL in the playframework?
I was thinking like this:
URL url = new URL("http://www.google.ru/intl/en_com/images/logo_plain.png");
BufferedImage img = ImageIO.read(url);
File newFile = new File("google.png");
ImageIO.write(img, "png", newFile);
But maybe there's another way. In the end I have to get the File and file name.
Example controller:
public static Result uploadPhoto(String urlPhoto){
Url url = new Url(urlPhoto); //doSomething
//get a picture and write to a temporary file
File tempPhoto = myUploadPhoto;
uploadFile(tempPhoto); // Here we make a copy of the file and save it to the file system.
return ok('something');
}
To get that photo you can use The play WS API, the code behind is an example extracted from the play docs in the section Processing large responses, I recommend you to read the full docs here
final Promise<File> filePromise = WS.url(url).get().map(
new Function<WSResponse, File>() {
public File apply(WSResponse response) throws Throwable {
InputStream inputStream = null;
OutputStream outputStream = null;
try {
inputStream = response.getBodyAsStream();
// write the inputStream to a File
final File file = new File("/tmp/response.txt");
outputStream = new FileOutputStream(file);
int read = 0;
byte[] buffer = new byte[1024];
while ((read = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, read);
}
return file;
} catch (IOException e) {
throw e;
} finally {
if (inputStream != null) {inputStream.close();}
if (outputStream != null) {outputStream.close();}
}
}
}
);
Where url is :
String url = "http://www.google.ru/intl/en_com/images/logo_plain.png"
This is as suggested in play documentation for large files:
*
When you are downloading a large file or document, WS allows you to
get the response body as an InputStream so you can process the data
without loading the entire content into memory at once.
*
Pretty much the same as the above answer then some...
Route: POST /testFile 'location of your controller goes here'
Request body content: {"url":"http://www.google.ru/intl/en_com/images/logo_plain.png"}
Controller(using code from JavaWS Processing large responses):
public static Promise<Result> saveFile() {
//you send the url in the request body in order to avoid complications with encoding
final JsonNode body = request().body().asJson();
// use new URL() to validate... not including it for brevity
final String url = body.get("url").asText();
//this one's copy/paste from Play Framework's docs
final Promise<File> filePromise = WS.url(url).get().map(response -> {
InputStream inputStream = null;
OutputStream outputStream = null;
try {
inputStream = response.getBodyAsStream();
final File file = new File("/temp/image");
outputStream = new FileOutputStream(file);
int read = 0;
byte[] buffer = new byte[1024];
while ((read = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, read);
}
return file;
} catch (IOException e) {
throw e;
} finally {
if (inputStream != null) {
inputStream.close();
}
if (outputStream != null) {
outputStream.close();
}
}
}); // copy/paste ended
return filePromise.map(file -> (Result) ok(file.getName() + " saved!")).recover(
t -> (Result) internalServerError("error -> " + t.getMessage()));
}
And that's it...
In order to serve the file after the upload phase you can use this answer(I swear I'm not promoting myself...): static asset serving from absolute path in play framework 2.3.x

Audio file stream in HTTP Post Jersey using Java

I have been stuck on an issue for the last couple of days and frankly I am out of ideas. What I am trying to do is to host an rest service using Jersey that will accept a post request with stream of audio data in its payload.
Issue I have been running into is that that I loose data consistency (I am running CRC check on both client and server) and after 8 reads of with 1024 bytes buffer CRC between data sent and data received becomes inconsistent. It works just fine when I am dealing with text or content of smaller size. Code is attached, can anyone please tell me what I am doing wrong?
Server:
#POST
#Consumes("audio/wav")
#Produces(MediaType.TEXT_PLAIN)
public String streamCommand(#Context HttpServletRequest request ) throws Exception
{
CRC32 crc = new CRC32();
InputStream stream = request.getInputStream();
byte[] readBuffer = new byte[1024];
StringBuilder builder = new StringBuilder();
while (stream.read(readBuffer) > -1)
{
crc.update(readBuffer);
builder.append(new String(readBuffer));
System.out.println(crc.getValue());
}
return builder.toString();
}
Client:
static final String SOUND_FILE_NAME = "SoundTest.wav";
#BeforeClass
public static void setup() throws Exception
{
soundStream = classloader.getResourceAsStream(SOUND_FILE_NAME);
}
#Test
public void test() throws Exception {
PipedOutputStream stream = new PipedOutputStream();
DataStreamer data = new DataStreamer(stream, soundStream);
ExecutorService executor = Executors.newFixedThreadPool(1);
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost("http://localhost:8080/EVAFrontEnd/webapi/users/1/devices/1/command");
post.addHeader(HttpHeaders.CONTENT_TYPE, "audio/wav");
InputStreamEntity requestEntity = new InputStreamEntity(new PipedInputStream((PipedOutputStream) stream), -1);
post.setEntity(requestEntity);
executor.execute(data);
executor.shutdown();
HttpResponse r = client.execute(post);
assertNotNull(r);
}
Data Streamer:
public class DataStreamer implements Runnable {
OutputStream writeStream;
CheckedInputStream readStream;
static Logger logger = Logger.getLogger(DataStreamer.class);
public DataStreamer(OutputStream stream, InputStream readingStrem) {
this.writeStream = stream;
this.readStream = new CheckedInputStream(readingStrem, new Adler32());
}
#Override
public void run()
{
CRC32 crc = new CRC32();
try {
byte[] buffer = new byte[1024];
while (readStream.read(buffer) > -1) {
crc.update(buffer);
System.out.println(crc.getValue());
writeStream.write(buffer);
}
System.out.println("END CRC");
readStream.close();
writeStream.close();
}
catch (Exception e) {
logger.error("Unable to stream data.", e);
}
}
}
Thank you!
You need to always save the number of bytes written by
bytes_read = readStream.read(buffer);
into a variable, because that method sometimes gives a short result. Then use ArrayList.copyOfRange to create a subarray [0 ... bytes_read-1] from the buffer with only the valid bytes.

Categories

Resources