Write to Browser

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
14 messages Options
Reply | Threaded
Open this post in threaded view
|

Write to Browser

cjhowe
I'm trying to create a zip file on the fly.  I've created it properly so that it will write to the file system, but I would prefer to write to the browser so that the user can download it.  This seems like it should be so simple, but I'm missing it.  TIA for any help!

Chris


Reply | Threaded
Open this post in threaded view
|

Re: Write to Browser

Adrian Crum
FileInputStream zipInStream = new FileInputStream(zipFile);
OutputStream browserOutStream = response.getOutputStream();
response.setContentLength((int)zipFile.length());
response.setContentType("application/zip");
// Call a routine to copy bytes from zipInStream to browserOutStream

-Adrian

Chris Howe wrote:
> I'm trying to create a zip file on the fly.  I've created it properly so that it will write to the file system, but I would prefer to write to the browser so that the user can download it.  This seems like it should be so simple, but I'm missing it.  TIA for any help!
>
> Chris
>
>
>

Reply | Threaded
Open this post in threaded view
|

Re: Write to Browser

cjhowe
In reply to this post by cjhowe
It won't let me do response.getOutputStream.  I get an error that says "getWriter() has already been called for this response"

----- Original Message ----
From: Adrian Crum <[hidden email]>
To: [hidden email]
Sent: Wednesday, November 21, 2007 9:45:47 AM
Subject: Re: Write to Browser


FileInputStream zipInStream = new FileInputStream(zipFile);
OutputStream browserOutStream = response.getOutputStream();
response.setContentLength((int)zipFile.length());
response.setContentType("application/zip");
// Call a routine to copy bytes from zipInStream to browserOutStream

-Adrian

Chris Howe wrote:
> I'm trying to create a zip file on the fly.  I've created it properly
 so that it will write to the file system, but I would prefer to write
 to the browser so that the user can download it.  This seems like it
 should be so simple, but I'm missing it.  TIA for any help!
>
> Chris
>
>
>




Reply | Threaded
Open this post in threaded view
|

Re: Write to Browser

Adrian Crum
You'll have to back up in the code some and see how the writer is being used. If nothing has been
written already, then you can copy the InputStream to the Writer.

If your code is being called from the screen widget, then things get tricky - since it has probably
already sent out HTML text to the browser.

It would be handy to have a generic view handler for this kind of scenario.


Chris Howe wrote:

> It won't let me do response.getOutputStream.  I get an error that says "getWriter() has already been called for this response"
>
> ----- Original Message ----
> From: Adrian Crum <[hidden email]>
> To: [hidden email]
> Sent: Wednesday, November 21, 2007 9:45:47 AM
> Subject: Re: Write to Browser
>
>
> FileInputStream zipInStream = new FileInputStream(zipFile);
> OutputStream browserOutStream = response.getOutputStream();
> response.setContentLength((int)zipFile.length());
> response.setContentType("application/zip");
> // Call a routine to copy bytes from zipInStream to browserOutStream
>
> -Adrian
>
> Chris Howe wrote:
>
>>I'm trying to create a zip file on the fly.  I've created it properly
>
>  so that it will write to the file system, but I would prefer to write
>  to the browser so that the user can download it.  This seems like it
>  should be so simple, but I'm missing it.  TIA for any help!
>
>>Chris
>>
>>
>>
>
>
>
>
>
>

Reply | Threaded
Open this post in threaded view
|

Re: Write to Browser

cjhowe
In reply to this post by cjhowe
Thanks for your help Adrian!  That helped me track down a workaround (big smile).  in ScreenWidgetViewHandler.java#render(..,..,..,...,.)
there is the section
            if (useOutputStreamNotWriter) {
                ServletOutputStream ros = response.getOutputStream();
                writer = new OutputStreamWriter(ros, "UTF-8");
            } else {
                writer = response.getWriter();
            }

I set useOutputStreamNotWriter to true based on the content type.  What should be the proper solution that can be put back into the community project?  Another ViewHandler or just additional flags to change whether .getWriter() or getOutputStream() is used?

----- Original Message ----
From: Adrian Crum <[hidden email]>
To: [hidden email]
Sent: Wednesday, November 21, 2007 10:16:39 AM
Subject: Re: Write to Browser


You'll have to back up in the code some and see how the writer is being
 used. If nothing has been
written already, then you can copy the InputStream to the Writer.

If your code is being called from the screen widget, then things get
 tricky - since it has probably
already sent out HTML text to the browser.

It would be handy to have a generic view handler for this kind of
 scenario.


Chris Howe wrote:

> It won't let me do response.getOutputStream.  I get an error that
 says "getWriter() has already been called for this response"

>
> ----- Original Message ----
> From: Adrian Crum <[hidden email]>
> To: [hidden email]
> Sent: Wednesday, November 21, 2007 9:45:47 AM
> Subject: Re: Write to Browser
>
>
> FileInputStream zipInStream = new FileInputStream(zipFile);
> OutputStream browserOutStream = response.getOutputStream();
> response.setContentLength((int)zipFile.length());
> response.setContentType("application/zip");
> // Call a routine to copy bytes from zipInStream to browserOutStream
>
> -Adrian
>
> Chris Howe wrote:
>
>>I'm trying to create a zip file on the fly.  I've created it properly
>
>  so that it will write to the file system, but I would prefer to
 write

>  to the browser so that the user can download it.  This seems like it
>  should be so simple, but I'm missing it.  TIA for any help!
>
>>Chris
>>
>>
>>
>
>
>
>
>
>




Reply | Threaded
Open this post in threaded view
|

Re: Write to Browser

Adrian Crum
Chris,

I'm not sure what the proper solution would be. Your case is very similar to the one I faced while
refactoring the FOP rendering - that's why I was thinking a generic file view handler would be
handy. It would work something like this:

   Render the specified screen to a temp file
   Branch to a conversion routine (temp file as arg) based on content type
   Conversion routine returns converted file
   Copy converted file to response OutputStream

Conversion routines could handle FOP, Zip, or any other file format that comes along.

-Adrian

Chris Howe wrote:

> Thanks for your help Adrian!  That helped me track down a workaround (big smile).  in ScreenWidgetViewHandler.java#render(..,..,..,...,.)
> there is the section
>             if (useOutputStreamNotWriter) {
>                 ServletOutputStream ros = response.getOutputStream();
>                 writer = new OutputStreamWriter(ros, "UTF-8");
>             } else {
>                 writer = response.getWriter();
>             }
>
> I set useOutputStreamNotWriter to true based on the content type.  What should be the proper solution that can be put back into the community project?  Another ViewHandler or just additional flags to change whether .getWriter() or getOutputStream() is used?
>
> ----- Original Message ----
> From: Adrian Crum <[hidden email]>
> To: [hidden email]
> Sent: Wednesday, November 21, 2007 10:16:39 AM
> Subject: Re: Write to Browser
>
>
> You'll have to back up in the code some and see how the writer is being
>  used. If nothing has been
> written already, then you can copy the InputStream to the Writer.
>
> If your code is being called from the screen widget, then things get
>  tricky - since it has probably
> already sent out HTML text to the browser.
>
> It would be handy to have a generic view handler for this kind of
>  scenario.
>
>
> Chris Howe wrote:
>
>
>>It won't let me do response.getOutputStream.  I get an error that
>
>  says "getWriter() has already been called for this response"
>
>>----- Original Message ----
>>From: Adrian Crum <[hidden email]>
>>To: [hidden email]
>>Sent: Wednesday, November 21, 2007 9:45:47 AM
>>Subject: Re: Write to Browser
>>
>>
>>FileInputStream zipInStream = new FileInputStream(zipFile);
>>OutputStream browserOutStream = response.getOutputStream();
>>response.setContentLength((int)zipFile.length());
>>response.setContentType("application/zip");
>>// Call a routine to copy bytes from zipInStream to browserOutStream
>>
>>-Adrian
>>
>>Chris Howe wrote:
>>
>>
>>>I'm trying to create a zip file on the fly.  I've created it properly
>>
>> so that it will write to the file system, but I would prefer to
>
>  write
>
>> to the browser so that the user can download it.  This seems like it
>> should be so simple, but I'm missing it.  TIA for any help!
>>
>>
>>>Chris
>>>
>>>
>>>
>>
>>
>>
>>
>>
>>
>
>
>
>
>

Reply | Threaded
Open this post in threaded view
|

Re: Write to Browser

jonwimp
Why render to a temp file? Why not simply render to a byte array like ScreenFopViewHandler (pdf)
does? Temp files need cleaning up.

The best way I can think of now is to have a generic ByteArrayViewHandler or similar, that outputs
any arbitrary byte array to the browser (via HttpServletResponse).

Don't render to a byte array nor a temp file, actually, because that will take up space. Instead,
do the following.

In <request-map>, have an <event> that will create an object that extends an interface say
GenericFileRenderer with at least a method like GenericFileRenderer.render(SomeContentPassedIn,
SomeOutputStream). For a somewhat analogous example, see ScreenFopViewHandler doing
"screens.render(page)".

The GenericFileRenderer object will be somehow passed to the ByteArrayViewHandler (in a
<view-map>), where a line like "renderer.render(content, outputStream)" will do the actual
rendering and outputting. It's a callback mechanism, where ByteArrayViewHandler "callback" our
special renderer (with standard interface GenericFileRenderer).

Well, the ScreenFopViewHandler is not a good example here, since it stores the rendered content
(could be large) in a StringWriter. But the idea I'm trying to put across is to perform the
rendering only *at the point of output*, so we won't be storing megabytes of data in memory or
temp files.

In effect, we will be able to output just about any byte content to the browser. The simplest
renderer could just "write out" a string, which might give us a content type of "text/plain". Any
number of renderer types could be created to handle zip, tar, bz2, whatever (it's a "plug-in"
architecture). In fact, even the ScreenFopViewHandler could be refactored to use this "render only
during output" method (later on).

If there *really* is a need for this, let me know. I'm feeling like I need a stretch, and may
implement this just for fun.

Jonathon

Adrian Crum wrote:

> Chris,
>
> I'm not sure what the proper solution would be. Your case is very
> similar to the one I faced while refactoring the FOP rendering - that's
> why I was thinking a generic file view handler would be handy. It would
> work something like this:
>
>   Render the specified screen to a temp file
>   Branch to a conversion routine (temp file as arg) based on content type
>   Conversion routine returns converted file
>   Copy converted file to response OutputStream
>
> Conversion routines could handle FOP, Zip, or any other file format that
> comes along.
>
> -Adrian
>
> Chris Howe wrote:
>
>> Thanks for your help Adrian!  That helped me track down a workaround
>> (big smile).  in ScreenWidgetViewHandler.java#render(..,..,..,...,.)
>> there is the section
>>             if (useOutputStreamNotWriter) {
>>                 ServletOutputStream ros = response.getOutputStream();
>>                 writer = new OutputStreamWriter(ros, "UTF-8");
>>             } else {
>>                 writer = response.getWriter();
>>             }
>>
>> I set useOutputStreamNotWriter to true based on the content type.  
>> What should be the proper solution that can be put back into the
>> community project?  Another ViewHandler or just additional flags to
>> change whether .getWriter() or getOutputStream() is used?
>>
>> ----- Original Message ----
>> From: Adrian Crum <[hidden email]>
>> To: [hidden email]
>> Sent: Wednesday, November 21, 2007 10:16:39 AM
>> Subject: Re: Write to Browser
>>
>>
>> You'll have to back up in the code some and see how the writer is being
>>  used. If nothing has been written already, then you can copy the
>> InputStream to the Writer.
>>
>> If your code is being called from the screen widget, then things get
>>  tricky - since it has probably already sent out HTML text to the
>> browser.
>>
>> It would be handy to have a generic view handler for this kind of
>>  scenario.
>>
>>
>> Chris Howe wrote:
>>
>>
>>> It won't let me do response.getOutputStream.  I get an error that
>>
>>  says "getWriter() has already been called for this response"
>>
>>> ----- Original Message ----
>>> From: Adrian Crum <[hidden email]>
>>> To: [hidden email]
>>> Sent: Wednesday, November 21, 2007 9:45:47 AM
>>> Subject: Re: Write to Browser
>>>
>>>
>>> FileInputStream zipInStream = new FileInputStream(zipFile);
>>> OutputStream browserOutStream = response.getOutputStream();
>>> response.setContentLength((int)zipFile.length());
>>> response.setContentType("application/zip");
>>> // Call a routine to copy bytes from zipInStream to browserOutStream
>>>
>>> -Adrian
>>>
>>> Chris Howe wrote:
>>>
>>>
>>>> I'm trying to create a zip file on the fly.  I've created it properly
>>>
>>> so that it will write to the file system, but I would prefer to
>>
>>  write
>>
>>> to the browser so that the user can download it.  This seems like it
>>> should be so simple, but I'm missing it.  TIA for any help!
>>>
>>>
>>>> Chris
>>>>
>>>>
>>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>
>>
>>
>>
>>
>
>

Reply | Threaded
Open this post in threaded view
|

RE: Write to Browser

SkipDever
"I'm feeling like I need a stretch, and may implement this just for fun."

Gads Jonathon, your are worse than me.

Skip

Reply | Threaded
Open this post in threaded view
|

Re: Write to Browser

jonwimp
Skip,

If you're talking about being retarded and working many projects for fun without money, then yes,
I'm worse than you. If it's just about being retarded, I think I'm in some hall of fame.

I've been watching your personality, Skip. Pardon me. Are you a techie? I bet you are great with
customer-facing, though. Any chance you will work with me?

Jonathon

skip@thedevers wrote:
> "I'm feeling like I need a stretch, and may implement this just for fun."
>
> Gads Jonathon, your are worse than me.
>
> Skip
>
>

Reply | Threaded
Open this post in threaded view
|

RE: Write to Browser

SkipDever
Jonathon

Oh, there is a never ending supply of clients who want to pay for your
hamburger tomorrow (cartoon character of great fame in the US in case you
have never heard that expression) and I have happily, to my great
misfortune, worked for what I am sure is the majority of them.

Not sure what techie means, but I don't carry a cell phone (although I have
one some place), and generally speaking, hate gizmos like iPod and
Blackberry.   But, I love writing software, so I guess that makes me a
techie in some sense.

I would love working with you, but only because I like working with people
who are so obviously brighter than me.  Unfortunately, I have two Ofbiz
clients breathing down my neck to get into production (and these guys are
actually paying my outrageous hourly rates) and another commitment for some
mainframe stuff in a few weeks that looks to add 10 hours to my already 16
hour day.

But if I can help or colaborate on anything, I'll find some time.

Skip

-----Original Message-----
From: Jonathon -- Improov [mailto:[hidden email]]
Sent: Wednesday, November 21, 2007 9:01 PM
To: [hidden email]
Subject: Re: Write to Browser


Skip,

If you're talking about being retarded and working many projects for fun
without money, then yes,
I'm worse than you. If it's just about being retarded, I think I'm in some
hall of fame.

I've been watching your personality, Skip. Pardon me. Are you a techie? I
bet you are great with
customer-facing, though. Any chance you will work with me?

Jonathon

skip@thedevers wrote:
> "I'm feeling like I need a stretch, and may implement this just for fun."
>
> Gads Jonathon, your are worse than me.
>
> Skip
>
>


Reply | Threaded
Open this post in threaded view
|

Re: Write to Browser

Adrian Crum
In reply to this post by jonwimp
Jonathon -- Improov wrote:
> Why render to a temp file? Why not simply render to a byte array like
> ScreenFopViewHandler (pdf) does? Temp files need cleaning up.

Because there is no way of knowing in advance how large the document will be. A good example is the
entity reference xsl-fo file I created recently using ScreenFopViewHandler - 16 MB. How many 16 MB
Strings can a server hold? Not very many I would think.

-Adrian

Reply | Threaded
Open this post in threaded view
|

Re: Write to Browser

jonwimp
Adrian,

The rest of my email (of which you quoted a part) highlighted how to rewire the
ScreenFopViewHandler to "output via stream without storing in large byte array". Yes, the way it
is done now can be improved on a lot. Some PDF screens do take quite a bit of memory.

Using that same method, it would solve your issue with serving up large files of arbitrary binary
data.

Jonathon

Adrian Crum wrote:

> Jonathon -- Improov wrote:
>> Why render to a temp file? Why not simply render to a byte array like
>> ScreenFopViewHandler (pdf) does? Temp files need cleaning up.
>
> Because there is no way of knowing in advance how large the document
> will be. A good example is the entity reference xsl-fo file I created
> recently using ScreenFopViewHandler - 16 MB. How many 16 MB Strings can
> a server hold? Not very many I would think.
>
> -Adrian
>
>

Reply | Threaded
Open this post in threaded view
|

Re: Write to Browser

Adrian Crum
Maybe I missed something. It sounded like you were proposing sending the rendered screen directly to
the response's output stream. That wouldn't work because in the two file formats mentioned - xsl-fo
and zip - there needs to be an intermediate document that is parsed and converted.

-Adrian

Jonathon -- Improov wrote:

> Adrian,
>
> The rest of my email (of which you quoted a part) highlighted how to
> rewire the ScreenFopViewHandler to "output via stream without storing in
> large byte array". Yes, the way it is done now can be improved on a lot.
> Some PDF screens do take quite a bit of memory.
>
> Using that same method, it would solve your issue with serving up large
> files of arbitrary binary data.
>
> Jonathon
>
> Adrian Crum wrote:
>
>> Jonathon -- Improov wrote:
>>
>>> Why render to a temp file? Why not simply render to a byte array like
>>> ScreenFopViewHandler (pdf) does? Temp files need cleaning up.
>>
>>
>> Because there is no way of knowing in advance how large the document
>> will be. A good example is the entity reference xsl-fo file I created
>> recently using ScreenFopViewHandler - 16 MB. How many 16 MB Strings
>> can a server hold? Not very many I would think.
>>
>> -Adrian
>>
>>
>
>

Reply | Threaded
Open this post in threaded view
|

Re: Write to Browser

jonwimp
Well, maybe I missed saying it in typing.

Pipe the stream from the screen renderer to the zip compressor. Pipe the zip compressor's output
to the browser.

The screen renderer will need to be changed to allow the above. I'm hoping the zip compressor
allows streaming output, or we will have to change the zip compressor as well. Unlikely, because
the authors of the zip compressor should know that any arbitrarily large files could be piped
through the zip compressor.

Jonathon

Adrian Crum wrote:

> Maybe I missed something. It sounded like you were proposing sending the
> rendered screen directly to the response's output stream. That wouldn't
> work because in the two file formats mentioned - xsl-fo and zip - there
> needs to be an intermediate document that is parsed and converted.
>
> -Adrian
>
> Jonathon -- Improov wrote:
>
>> Adrian,
>>
>> The rest of my email (of which you quoted a part) highlighted how to
>> rewire the ScreenFopViewHandler to "output via stream without storing
>> in large byte array". Yes, the way it is done now can be improved on a
>> lot. Some PDF screens do take quite a bit of memory.
>>
>> Using that same method, it would solve your issue with serving up
>> large files of arbitrary binary data.
>>
>> Jonathon
>>
>> Adrian Crum wrote:
>>
>>> Jonathon -- Improov wrote:
>>>
>>>> Why render to a temp file? Why not simply render to a byte array
>>>> like ScreenFopViewHandler (pdf) does? Temp files need cleaning up.
>>>
>>>
>>> Because there is no way of knowing in advance how large the document
>>> will be. A good example is the entity reference xsl-fo file I created
>>> recently using ScreenFopViewHandler - 16 MB. How many 16 MB Strings
>>> can a server hold? Not very many I would think.
>>>
>>> -Adrian
>>>
>>>
>>
>>
>
>