Best way to log java.net.URL results - java

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.

Related

Is there any way to start reading from specific position of an URL byte stream?

My idea is to divide a big response text into small parts to load them concurrently.
The following code helps me open stream from an URL but I want to load its whole content from multithreads to optimize performance, then I will merge them into a single result. However, the method return a ReadableByteChannel which cannot specify the start position and I have to transfer it linearly:
URL url = new URL("link");
InputStream fromStream = url.openStream();
ReadableByteChannel fromChannel = Channels.newChannel(fromStream);
Is there any way to specify the position like SeekableByteChannel (seem likes this interface only works with file)? Thanks you :D
If you can manipulate the request before it's a stream then yes, you would use the Range http header to specify the chunk of data you wanted...
See Downloading a portion of a File using HTTP Requests
If not then you will manually have to read past the data you don't need.
See Given a Java InputStream, how can I determine the current offset in the stream?

OutputStream to byte[]

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().

Spring OuputStream as File Download?

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.

Checking if a stream is a zip file

We have a requirement to determine whether an incoming InputStream is a reference to an zip file or zip data. We do not have reference to the underlying source of the stream. We aim to copy the contents of this stream into an OutputStream directed at an alternate location.
I tried reading the stream using ZipInputStream and extracting a ZipEntry. The ZipEntry is null if the stream is a regular file - as expected - however, in checking for a ZipEntry I loose the initial couple of bytes from the stream. Hence, by the time I know that the stream is a regular stream, I have already lost initial data from the stream.
Any thoughts around how to check if the InputStream is an archive without data loss would be helpful.
Thanks.
Assuming your original inputstream is not buffered, I would try wrapping the original stream in a BufferedInputStream, before wrapping that in a ZipInputStream to check. You can use "mark" and "reset" in the BufferedInputStream to return to the initial position in the stream, after your check.
This is how I did it.
Using mark/reset to restore the stream if the GZIPInputStream detects incorrect zip format (throws the ZipException).
/**
* Wraps the input stream with GZIPInputStream if needed.
* #param inputStream
* #return
* #throws IOException
*/
private InputStream wrapIfZip(InputStream inputStream) throws IOException {
if (!inputStream.markSupported()) {
inputStream = new BufferedInputStream(inputStream);
}
inputStream.mark(1000);
try {
return new GZIPInputStream(inputStream);
} catch (ZipException e) {
inputStream.reset();
return inputStream;
}
}
You can check first bytes of stream for ZIP local header signature (PK 0x03 0x04), that would be enough for most cases. If you need more precision, you should take last ~100 bytes and check for central directory locator fields.
You have described a java.io.PushbackInputStream - in addition to read(), it has an unread(byte[]) which allows you push them bck to the front of the stream, and to re-read() them again.
It's in java.io since JDK1.0 (though I admit I haven't seen a use for it until today).
It sounds a bit like a hack, but you could implement a proxy java.io.InputStream to sit between ZipInputStream and the stream you originally passed to ZipInputStream's constructor. Your proxy would stream to a buffer until you know whether it's a ZIP file or not. If not, then the buffer saves your day.

Using an InputStream for Logging and then XML parsing

What I want to do is log the output from an inputstream that I go using
org.apache.http.HttpEntity entity = response.getEntity();
org.apache.http.HttpResponse content =entity.getContent();
//Print the result to the screen for debugging
//puroposes
if(Logging.DEBUG) {
InputStream content =entity.getContent();
int i;
StringBuilder b = new StringBuilder();
while( (i=content.read()) != -1 ) {
b.append((char)i);
}
Log.d(TAG, b.toString());
}
Now after I have finished logging, I want to use the exact same stream through an XML parser. The problem is that it tells me that the steam has already been used.
I tried to the use mark() and reset() calls before and after debugging but it didn't work.
It depends whether the inputstream that is returned supports it. The default implementation in the InputStream class does nothing, as described in the API. So you can't be sure whether the returned Stream actually supports it. To be sure of this, you should wrap it in a BufferedInputStream, which does supports these methods.
In general mark() and reset() won't work on an arbitrary InputStream. They only work on subclasses like FileInputStream where the underlying data source supports these operations.
For something like a SocketInputStream or a console InputStream, your only option will be to read and buffer the entire stream contents somewhere; e.g. in memory or by writing it to a temporary file.

Categories

Resources