Differences between revisions 2 and 3
Revision 2 as of 2009-09-20 23:20:21
Size: 4556
Editor: localhost
Comment: converted to 1.6 markup
Revision 3 as of 2011-10-30 21:13:58
Size: 4617
Editor: NeemePraks
Comment: minor fixes
Deletions are marked like this. Additions are marked like this.
Line 15: Line 15:
import org.apache.tapestry5.StreamResponse;
Line 19: Line 20:
 * This class was inspired by {@link OutputStreamResponse} 
 * 
 * This class was inspired by {@link StreamResponse}
 *
Line 32: Line 33:
     * Implements a callback to directly write to the output stream. 
     * The stream will be closed after the callback was called. 
     * The provided stream will be wrapped in a {@link BufferedOutputStream} for efficiency.
     * Implements a callback to directly write to the output stream.
     * The stream will be closed after this method returns.
     * The provided stream is wrapped in a {@link BufferedOutputStream} for efficiency.
Line 37: Line 38:
Line 46: Line 46:
Line 66: Line 67:
 * ComponentEventResultProcessor that enables EventHandlers to return Callbacks   * ComponentEventResultProcessor that enables EventHandlers to return Callbacks
Line 68: Line 69:
 *   *
Line 70: Line 71:
 *   *
Line 73: Line 74:
public class OutputStreamResponseResulProcessor implements public class OutputStreamResponseResultProcessor implements
Line 75: Line 76:
 
Line 80: Line 81:
    public OutputStreamResponseResulProcessor(Response response) {     public OutputStreamResponseResultProcessor(Response response) {
Line 86: Line 87:
     * 
     * @param Callback for streaming arbitray data to the client using the response's OutputStream
     * 
     *
     * @param Callback for streaming arbitrary data to the client using the response {@link OutputStream}
     *
Line 91: Line 92:
Line 113: Line 113:
Line 116: Line 117:
== 3) Register the newly created ComponentEventResultProcessor == == 3) Register the newly created ComponentEventResultProcessor in your Module (e.g. AppModule) ==
Line 121: Line 122:
  *    *
Line 127: Line 128:
    configuration.add(OutputStreamResponse.class, new OutputStreamResponseResulProcessor(response));     configuration.add(OutputStreamResponse.class, new OutputStreamResponseResultProcessor(response));

When Tapestry receives an Event Request an Event Handler is called. The return type of the event handler can determine what is sent to the browser. The information of default accepted return types can be found here: http://tapestry.apache.org/tapestry5/guide/pagenav.html

If you want to create a custom return type you have to do the following steps (This example creates a Return Type that represents a callback handler for directly streaming to the output):

1) Define the interface of the return type you want to use

In this case an interface similar to the a StreamResponse is generated with the difference that no InputStream is returned for request handling but instead a callback writes to an OutputStream

package at.ac.uibk.dbisinformatik.services;

import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.OutputStream;

import org.apache.tapestry5.StreamResponse;
import org.apache.tapestry5.services.Response;

/**
 * Callback for directly writing to the outputstream from an action method
 * This class was inspired by {@link StreamResponse}
 *
 * @author robert.binna@uibk.ac.at
 *
 */
public interface OutputStreamResponse {

    /**
     * Returns the content type to be reported to the client.
     */
    String getContentType();

    /**
     * Implements a callback to directly write to the output stream.
     * The stream will be closed after this method returns.
     * The provided stream is wrapped in a {@link BufferedOutputStream} for efficiency.
     */
    public void writeToStream(OutputStream out) throws IOException;

    /**
     * Prepares the response before it is sent to the client. This is the place to set any response headers (e.g.
     * content-disposition).
     *
     * @param response Response that will be sent.
     */
    void prepareResponse(Response response);

}

2) Define the ComponentEventResultProcessor that is capable of handling the type created in step 1

For our example the ComponentEventResultProcessor only passes the OutputStream of the Response to the Callback.

package at.ac.uibk.dbisinformatik.services;

import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.OutputStream;

import org.apache.tapestry5.internal.services.StreamResponseResultProcessor;
import org.apache.tapestry5.services.ComponentEventResultProcessor;
import org.apache.tapestry5.services.Response;

/**
 * ComponentEventResultProcessor that enables EventHandlers to return Callbacks
 * that can stream arbitrary data to the client.
 *
 * The class was inspired by {@link StreamResponseResultProcessor}
 *
 * @author robert.binna@uibk.ac.at
 */
public class OutputStreamResponseResultProcessor implements
                ComponentEventResultProcessor<OutputStreamResponse> {

    private static final int BUFFER_SIZE = 5000;

    private final Response response;

    public OutputStreamResponseResultProcessor(Response response) {
        this.response = response;
    }

    /**
     * Handles OutputStreamResponse
     *
     * @param Callback for streaming arbitrary data to the client using the response {@link OutputStream}
     *
     * @see ComponentEventResultProcessor#processResultValue(Object)
     */
     @Override
     public void processResultValue(OutputStreamResponse streamResponse)
                throws IOException {
        OutputStream out = null;
        try {
                streamResponse.prepareResponse(response);
                out = new BufferedOutputStream(response.getOutputStream(streamResponse.getContentType()), BUFFER_SIZE);
                streamResponse.writeToStream(out);
                out.flush();
                out.close();
                out = null;
        } finally {
                if(out != null) { //can only be the case if an Exception was thrown because out was set to null before
                        try {
                                out.close();
                        } catch(IOException ioe) {
                                //ignores this IO exception because an exception is already on the way
                        }
                }
        }
     }

}

3) Register the newly created ComponentEventResultProcessor in your Module (e.g. AppModule)

 /**
  * Adds ComponentEventResultProcessors
  *
  * @param configuration the configuration where new ComponentEventResultProcessors are registered by the type they are processing
  * @param response the response that the event result processor handles
  */
  public void contributeComponentEventResultProcessor(MappedConfiguration<Class<?>, ComponentEventResultProcessor<?>> configuration, Response response)
  {
    configuration.add(OutputStreamResponse.class, new OutputStreamResponseResultProcessor(response));
  }

Tapestry5HowToCreateAComponentEventResultProcessor (last edited 2011-10-30 21:13:58 by NeemePraks)