the objective I'm trying to reach is to save a PDF into an Oracle database into a BLOB.
Currently, the servlet i'm using only sends back a pdf via HttpServletResponse.
Printers.getPDFPrinter(0).printToResponse(myTemplate, response, 0, TemplateA.PDF);
I don't have access to printToResponse script, so I don't know what it does.
All I know is that response has a HttpServletResponse type from which I can get the OutputStream, and myTemplate implements an IDocument Interface which I have not access either.
If I could get either myTemplate or response into a byte array (in order to save it as a blob), it would be OK.
However, in all my searches, I only found code to create a byte array from an input stream, and not an output stream.
Can anyone help please ?
That code probably requires the full HttpResponse because it also needs to set the content-type and some other bits. For as awful as it may sound, you can create a "mock" response object and override the relevant methods in order to intercept its writes to the output stream. You can provide the PDFWriter a ByteArrayOutputStream so that you can then get the byte[] and write it into your DB.
I am not sure which library the servlet uses accessing Printers.getPDFPrinter(0) but:
the library may offer other methods than printToResponse (printToStream, printToFile, ...?)
you may pass your own HttpServletResponse returning an dummy ServletOutputStream on getOutputStream(). This dummy subclass has to implement write(int b) by delegating to the result of Blob.setBinaryStream(1).
If you want to write your own HttpServletResponse, I would prefer inheriting from HttpServletResponseWrapper if the servlet should also return the PDF your ServletOutputStream needs to delegate the original and the Blob stream.
If you wand the servlet just to return an id to retrieve the PDF from the database later, you need to implement your own HttpServletResponse. In this case I would use a Proxy and the InvocationHandler handles getOutputStream().
Related
I am trying to upload a Flux object into azure blob storage, but I'm not sure how to send a Flux pojo using BlobAsyncClient. BlobAsyncClient has upload methods that take Flux or BinaryData but I have no luck trying to convert CombinedResponse to BYteBuffer or BinaryData. Does anyone have any suggestions or know how to upload a flux object to blob storage?
You will need an asynch blob container client:
#Bean("blobServiceClient")
BlobContainerAsyncClient blobServiceClient(ClientSecretCredential azureClientCredentials, String storageAccount, String containerName) {
BlobServiceClientBuilder blobServiceClientBuilder = new BlobServiceClientBuilder();
return blobServiceClientBuilder
.endpoint(format("https://%s.blob.core.windows.net/", storageAccount))
.credential(azureClientCredentials)
.buildAsyncClient()
.getBlobContainerAsyncClient(containerName);
}
And in your code you can use it to get a client, and save your Flux to it:
Flux<ByteBuffer> content = getContent();
blobServiceClient.getBlobAsyncClient(id)
.upload(content, new ParallelTransferOptions(), true);
I get that the getContent() step is the part you are struggling with. You can save either a BinaryData object or a Flux<ByteBuffer> stream.
To turn your object into a BinaryData object, use the static helper method:
BinaryData foo = BinaryData.fromObject(myObject);
BinaryData is meant for exactly what the name says: binary data. For example the content of an image file.
If you want to turn it into a ByteBuffer, keep in mind that you're trying to turn an object into a stream of data here. You will probably want to use some standardized way of doing that, so it can be reliably reversed, so rather than a stream of bytes that may break if you ever load the data in a different client, or even just a different version of the same, we usually save a json or xml representation of the object.
My go-to tool for this is Jackson:
byte[] myBytes = new ObjectMapper().writeValueAsBytes(myObject);
var myByteBuffer = ByteBuffer.wrap(myBytes);
And return it as a Flux:
Flux<ByteBuffer> myFlux = Flux.just(myByteBuffer);
By the way, Azure uses a JSON serializer under the hood in the BinaryData.fromObject() method. From the JavaDoc:
Creates an instance of BinaryData by serializing the Object using the default JsonSerializer.
Note: This method first looks for a JsonSerializerProvider
implementation on the classpath. If no implementation is found, a
default Jackson-based implementation will be used to serialize the object
I want to send across resource(say a image) from some URL to front-end.
The typical way of doing this is to create a File and build the response. Is there any way in which I don't have to create the File in java code and still send the resource to front-end.
Front-end cannot access the URL due to some constraints.
Currently the Pseudo code looks like this.
File file = new File(fullPath);
FileUtils.copyURLToFile(url, file);
ResponseBuilder response = Response.ok(modulePDF);
I want to send content of URL to front-end without creating file. Is there any way?
What way did have in mind to actually obtain the file without creating a File object?
Not sure I fully understand the complete requirement, but you don't have to create a File object. You can send out a byte[], or simply write it to the response output stream by returning StreamingOutput.
#GET
public StreamingOutput getString() {
return new StreamingOutput(){
#Override
public void write(OutputStream out)
throws IOException, WebApplicationException {
// write to the `out` stream
}
};
}
For anything more than that, you will have to greatly elaborate on your requirement. The information you've provided, (especially the highlighted line) doesn't quite paint a clear enough problem as to what actual problem is you are facing.
I would like to send OutputStream object, which has pdf data, as file to the webbrowser.
The code is as follows.
#RequestMapping(value="/issue", method=RequestMethod.POST)
public void issue(HttpServletResponse response, TimeStampIssueParam param) throws JsonGenerationException, JsonMappingException, IOException {
OutputStream pdfOuput = issue(input);
response.setContentType("application/pdf");
ServletOutputStream respOutput = response.getOutputStream();
....
}
The problem is I already have the outputstream, and I do not want to convert it to byte array.
Any comment would be appreciated.
You can't: you can only copy an InputStream to an OutputStream. Then, you'll can use: org.springframework.util.FileCopyUtils.copy(InputStream, OutputStream)
First, I would say it is wrong to say that the OutputStream has any data. A stream just lets the data through to some destination. Sometimes (SocketOutputStream) this destination may be on a completely different computer, and sometimes (ByteArrayOutputStream) it will be closely related to the stream and even obtainable through it. But this is a detail of a specific stream, not something you can count on from an arbitrary one.
So, not knowing exactly where the result of the issue method comes from it is hard to provide a solution, but a generic OutputStream is not what it should return.
Guessing that the method generates some PDF data and writes it somewhere via an OutputStream, then returns the stream:
If it creates a File and the stream happens to be a FileOutputStream, it should return the file, file path or a FileInputStream for the same file instead.
If it creates eg. a ByteArrayOutputStream, then you already have a byte array, and additionally this stream type has a writeTo method that can be used directly to write the data to the ServletOutputStream; issue just has to return the stream as the proper type not hiding it behind the general interface.
For other OutputStream types, well, it depends on what exactly they are.
I have a library function as follows:
public static InputStream getResource(String url) throws MalformedURLException,
IOException {
return new URL(url).openConnection().getInputStream();
}
What would be the best way to add logging to this method to record the actual url response. Will I have to read the InputStream and then reset it?
(You can assume that I just want to print the results to the console for the sake of this example.)
If you would use a logger library and requests are small, then you could read whole InputStream into memory (e.g. into ByteArrayOutputStream), then log it, then construct ByteArrayInputStream as the method result.
If requests are big, you should dump it somewhere into a file or into a database blob. You could subclass the FilterInputStream and dump the data flow.
You cannot reset http stream in most cases.
You might copy the contents of the stream to a byte array, using a ByteArrayOutputStream, log the content of the byte array, and then return a ByteArrayInputStream constructed from the byte array. This puts the whole contents in memory, though.
In jsp/java how can you call a page that outputs a xml file as a result and save its result (xml type) into a xml file on server. Both files (the file that produces the xml and the file that we want to save/overwrite) live on the same server.
Basically I want to update my test.xml every now and then by calling generate.jsp that outputs a xml type result.
Thank you.
If the request is idempotent, then just use java.net.URL to get an InputStream of the JSP output. E.g.
InputStream input = new URL("http://example.com/context/page.jsp").openStream();
If the request is not idempotent, then you need to replace the PrintWriter of the response with a custom implementation which copies the output into some buffer/builder. I've posted a code example here before: Capture generated dynamic content at server side
Once having the output, just write it to disk the usual java.io way, assuming that JSP's are already in XHTML format.
Register a filter that adds a wrapper to your response. That is, it returns to the chain a new HttpServletResponse objects, extending the original HttpServletResponse, and returning your custom OutputStream and PrintWriter instead of the original ones.
Your OutputStream and PrintWriter calls the original OutputStream and PrintWriter, but also write to a your file (using a new FileOutputStream)
Why don't you use a real template engine like FreeMarker? That would be easier.