You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@tapestry.apache.org by Steven Porter <st...@site-intelligence.co.uk> on 2005/03/16 12:40:37 UTC

suppressing page response

Hi All,

I'm looking into a simple mechanism to stream some arbitrary file back to
the client.

I'm aware of the approach whereby I could create my own service to stream
the file back, and that's fine, and for whatever reason, don't want to do
that.

However, I want to be able to do this within a listener method of, say, a
direct service request...and the key here is that I need to be able to take
control of the HttpServletResponse directly, to stream, say, some XML
response, and do not want any rendered page HTML to be part of that
response.

The FAQ on this notionally works
(http://jakarta.apache.org/tapestry/faq.html,  number 2.7 ("How do I stream
a file to the user from tapestry?").

However, when I take the approach given in the FAQ above, and inspect the
http response using a sniffer, the page response is always included after my
file (within the same response), hence corrupting the file.

Looking through the code, this is not that surprising: most of the tapestry
standard services (DirectService, for example) attempt to render the
response using engine.renderResponse(...), after the body of the service
method is done...which picks up the cycle's active page.

I have "hacked" it to work by closing the response.getOutputStream()
directly, but I don't much like that.  Also, the response.flushBuffer() in
the FAQ does not suppress the page response being added either.

I could rewrite or extend the DirectService to check to see if the cycle's
active page is null, and then only conditionally cause the page response to
be rendered.

Is there a recommended way in general from within the direct service (or any
service in general) to suppress a page response?

Cheers
Steve



---------------------------------------------------------------------
To unsubscribe, e-mail: tapestry-user-unsubscribe@jakarta.apache.org
For additional commands, e-mail: tapestry-user-help@jakarta.apache.org


Re: suppressing page response

Posted by Kent Tong <ke...@cpttm.org.mo>.
Steven Porter <steven.porter <at> site-intelligence.co.uk> writes:

> I decided that I'd like to add support for calling
> 
> cycle.activate((IPage)null); // cast is needed
> 
> within any listener method.  This ought to cause the suppression of the page
> response.

I think this is a good feature to be incorporated into
Tapestry. This is far more elegant than using a service.
For example, if I have a form that will trigger the
download, with a service I'll have to manually pack
the parameters into an Object array (compared that to
bucket brigate!). It is even worse if the form has
an Upload component, because it is very hard to pass
the uploaded file to the service.

An alternative is to allow the response page to output
with something rather than a markup writer (which allows 
only text output).



---------------------------------------------------------------------
To unsubscribe, e-mail: tapestry-user-unsubscribe@jakarta.apache.org
For additional commands, e-mail: tapestry-user-help@jakarta.apache.org


RE: suppressing page response

Posted by Steven Porter <st...@site-intelligence.co.uk>.
Hi Mike,

This is the approach we took first, which does indeed work without too much
effort.

However, we just didn't feel this mechanism was exactly right.

- We had to provide dummy page templates that were not used (I think we
could get round this by overriding some of the rendering methods on the page
which handle template loading etc).

- Also, in our particular case, the stuff we were streaming back might have
been binary - with which associating a markup (ie, XML) writer just didn't
feel correct.

My general feeling with the Tapestry framework is that pages are intended to
be XML (or XHTML...whatever) output, and that non-markup output ought to be
served by some other mechanism.

Additionally, in one of our use cases, we are making some XML/HTTP requests
in java script from a tapestry page: ideally, we'd like the same page itself
(or a component on that page) to handle the request/response (as is the
tapestry paradigm).  We wanted to remove the separate pages that were
handling the request, when it really ought to be the same page (or component
on the page) itself.

Thanks - it's reassuring to hear we were on the right tracks with some of
our ideas.

Cheers
Steve

> -----Original Message-----
> From: Michael Henderson [mailto:mhinca@mac.com]
> Sent: 16 March 2005 15:50
> To: Tapestry users
> Subject: Re: suppressing page response
> 
> Hi,
>     Why not just create a page component that streams your file content
> and sets appropriate http headers:
> 
> 
> public void myListenerMethod(IRequestCycle cycle)
> {
> 	//do something to find out what content to return
> 	Object content = findSpecialContent();
> 
> 	cycle.activate("MySpecialContentPage");
> 
> 
> 	MySpecialContentPage page = (MySpecialContentPage)cycle.getPage();
> 
> 	page.setSpecialContent(content);
> 
> }
> 
> 
> The page will have to provide it's own markup writer class  in
> getResponseWriter() and override renderResponse()
> 
> No engines, no services, no special behavior in listeners, no problems
> with HTML mixed into a binary response.
> 
> I've done this over and over again in WebObjects applications, it
> should work in Tapestry.
> 
> Mike
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: tapestry-user-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: tapestry-user-help@jakarta.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: tapestry-user-unsubscribe@jakarta.apache.org
For additional commands, e-mail: tapestry-user-help@jakarta.apache.org


Re: suppressing page response

Posted by Michael Henderson <mh...@mac.com>.
Hi,
    Why not just create a page component that streams your file content 
and sets appropriate http headers:


public void myListenerMethod(IRequestCycle cycle)
{
	//do something to find out what content to return
	Object content = findSpecialContent();

	cycle.activate("MySpecialContentPage");


	MySpecialContentPage page = (MySpecialContentPage)cycle.getPage();
	
	page.setSpecialContent(content);

}


The page will have to provide it's own markup writer class  in 
getResponseWriter() and override renderResponse()

No engines, no services, no special behavior in listeners, no problems 
with HTML mixed into a binary response.

I've done this over and over again in WebObjects applications, it 
should work in Tapestry.

Mike


---------------------------------------------------------------------
To unsubscribe, e-mail: tapestry-user-unsubscribe@jakarta.apache.org
For additional commands, e-mail: tapestry-user-help@jakarta.apache.org


RE: suppressing page response

Posted by Steven Porter <st...@site-intelligence.co.uk>.
Hi Andreas,

Your approach is similar to what I have gone ahead and done.

I decided that I'd like to add support for calling

cycle.activate((IPage)null); // cast is needed

within any listener method.  This ought to cause the suppression of the page
response.

To do this, I extended the engine to override engine.renderResponse(...) to
handle the case where the page was null (and basically, do nothing in that
case).

And I also needed to override engine.createRequestCycle(...) to plug in an
extended version of the RequestCycle that handles
cycle.activate((IPage)null) as well.

And thereafter, in the listener method calling cycle.activate((IPage)null)
takes care of it.

I still think a separate service is the more elegant way forward, but in the
case where you really need to handle the non-page-response from via a
DirectService etc, your approach or mine both seem sensible.

Cheers
Steve

> -----Original Message-----
> From: Andreas Andreou [mailto:andyhot@di.uoa.gr]
> Sent: 16 March 2005 14:26
> To: Tapestry users
> Subject: Re: suppressing page response
> 
> I once wanted to do the same thing and noticed the exact same behavior
> (i.e. page content was also included in the response, in my case a png
> image)
> By looking at the tapestry source i came to the following solution:
> 1) Create a StopProcessingException that extends PageRedirectException
> 2) Create a subclass of  BaseEngine that overrides the
> handlePageRedirectException method, i.e. :
> 
>     protected void handlePageRedirectException(PageRedirectException e,
>                                                IRequestCycle
> iRequestCycle,
>                                                ResponseOutputStream
> responseOutputStream)
>             throws IOException, ServletException
>     {
>         // if a StopProcessingException was thrown, do nothing!
>         if (e instanceof StopProcessingException)
>         {
>             return;
>         }
>         else
>         {
>             super.handlePageRedirectException(e, iRequestCycle,
> responseOutputStream);
>         }
>     }
> 
> 3) In the listener that renders its own response (in your case the XML),
> add at the very end a
>     throw new StopProcessingException();
> 
> 4) Register the Engine subclass in the .application file so that it is
> used by tapestry, i.e.
> <application  name="My Tapestry App"
> engine-class="andyhot.tapestry.StopableEngine">
> 
> Steven Porter wrote:
> 
> >Hi All,
> >
> >I'm looking into a simple mechanism to stream some arbitrary file back to
> >the client.
> >
> >I'm aware of the approach whereby I could create my own service to stream
> >the file back, and that's fine, and for whatever reason, don't want to do
> >that.
> >
> >However, I want to be able to do this within a listener method of, say, a
> >direct service request...and the key here is that I need to be able to
> take
> >control of the HttpServletResponse directly, to stream, say, some XML
> >response, and do not want any rendered page HTML to be part of that
> >response.
> >
> >The FAQ on this notionally works
> >(http://jakarta.apache.org/tapestry/faq.html,  number 2.7 ("How do I
> stream
> >a file to the user from tapestry?").
> >
> >However, when I take the approach given in the FAQ above, and inspect the
> >http response using a sniffer, the page response is always included after
> my
> >file (within the same response), hence corrupting the file.
> >
> >Looking through the code, this is not that surprising: most of the
> tapestry
> >standard services (DirectService, for example) attempt to render the
> >response using engine.renderResponse(...), after the body of the service
> >method is done...which picks up the cycle's active page.
> >
> >I have "hacked" it to work by closing the response.getOutputStream()
> >directly, but I don't much like that.  Also, the response.flushBuffer()
> in
> >the FAQ does not suppress the page response being added either.
> >
> >I could rewrite or extend the DirectService to check to see if the
> cycle's
> >active page is null, and then only conditionally cause the page response
> to
> >be rendered.
> >
> >Is there a recommended way in general from within the direct service (or
> any
> >service in general) to suppress a page response?
> >
> >Cheers
> >Steve
> >
> >
> >
> >---------------------------------------------------------------------
> >To unsubscribe, e-mail: tapestry-user-unsubscribe@jakarta.apache.org
> >For additional commands, e-mail: tapestry-user-help@jakarta.apache.org
> >
> >
> >
> >
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: tapestry-user-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: tapestry-user-help@jakarta.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: tapestry-user-unsubscribe@jakarta.apache.org
For additional commands, e-mail: tapestry-user-help@jakarta.apache.org


Re: suppressing page response

Posted by Andreas Andreou <an...@di.uoa.gr>.
I once wanted to do the same thing and noticed the exact same behavior
(i.e. page content was also included in the response, in my case a png 
image)
By looking at the tapestry source i came to the following solution:
1) Create a StopProcessingException that extends PageRedirectException
2) Create a subclass of  BaseEngine that overrides the 
handlePageRedirectException method, i.e. :

    protected void handlePageRedirectException(PageRedirectException e,
                                               IRequestCycle iRequestCycle,
                                               ResponseOutputStream 
responseOutputStream)
            throws IOException, ServletException
    {
        // if a StopProcessingException was thrown, do nothing!
        if (e instanceof StopProcessingException)
        {
            return;
        }
        else
        {
            super.handlePageRedirectException(e, iRequestCycle, 
responseOutputStream);
        }
    }

3) In the listener that renders its own response (in your case the XML), 
add at the very end a
    throw new StopProcessingException();

4) Register the Engine subclass in the .application file so that it is 
used by tapestry, i.e.
<application  name="My Tapestry App"  
engine-class="andyhot.tapestry.StopableEngine">   

Steven Porter wrote:

>Hi All,
>
>I'm looking into a simple mechanism to stream some arbitrary file back to
>the client.
>
>I'm aware of the approach whereby I could create my own service to stream
>the file back, and that's fine, and for whatever reason, don't want to do
>that.
>
>However, I want to be able to do this within a listener method of, say, a
>direct service request...and the key here is that I need to be able to take
>control of the HttpServletResponse directly, to stream, say, some XML
>response, and do not want any rendered page HTML to be part of that
>response.
>
>The FAQ on this notionally works
>(http://jakarta.apache.org/tapestry/faq.html,  number 2.7 ("How do I stream
>a file to the user from tapestry?").
>
>However, when I take the approach given in the FAQ above, and inspect the
>http response using a sniffer, the page response is always included after my
>file (within the same response), hence corrupting the file.
>
>Looking through the code, this is not that surprising: most of the tapestry
>standard services (DirectService, for example) attempt to render the
>response using engine.renderResponse(...), after the body of the service
>method is done...which picks up the cycle's active page.
>
>I have "hacked" it to work by closing the response.getOutputStream()
>directly, but I don't much like that.  Also, the response.flushBuffer() in
>the FAQ does not suppress the page response being added either.
>
>I could rewrite or extend the DirectService to check to see if the cycle's
>active page is null, and then only conditionally cause the page response to
>be rendered.
>
>Is there a recommended way in general from within the direct service (or any
>service in general) to suppress a page response?
>
>Cheers
>Steve
>
>
>
>---------------------------------------------------------------------
>To unsubscribe, e-mail: tapestry-user-unsubscribe@jakarta.apache.org
>For additional commands, e-mail: tapestry-user-help@jakarta.apache.org
>
>
>  
>

---------------------------------------------------------------------
To unsubscribe, e-mail: tapestry-user-unsubscribe@jakarta.apache.org
For additional commands, e-mail: tapestry-user-help@jakarta.apache.org