enhance remove 'final' keyword from org.apache.wicket.Resource to support 
builder style content generation
----------------------------------------------------------------------------------------------------------

                 Key: WICKET-964
                 URL: https://issues.apache.org/jira/browse/WICKET-964
             Project: Wicket
          Issue Type: Improvement
          Components: wicket
            Reporter: Peter Ertl


I run into the following problem recently:

In order to create ad-hoc PDF documents I decided on using the iText library 
(http://www.lowagie.com/iText).

iText is capable of producing easily a 10000 pages PDF document on the fly 
without getting a scary OutOfMemoryException on the web server. This is because 
it's not buffering the result of creating a PDF but instantly writing the PDF 
data stream _while_ you build your PDF.

Code looks something like this:

  Document doc = new Document();
  PdfWriter.getInstance(doc, outputStream);
  doc.addAuthor("Mr. Foobar");
  doc.open();  
  doc.add(...); // some stuff -> will write directly to stream
  doc.add(...); // even more stuff -> will again write directly to stream
  doc.close();

Of course I wanted to use org.apache.wicket.Resource to deliver the content to 
the browser in the very wicket way. However, Resource and all it's children 
have one similar problem:

You need to implement 

  IResourceStream getResourceStream()
  
  which in turn demands you to implement

    InputStream getInputStream() throws ResourceStreamNotFoundException

So, whatever resource you would like to implement, you need an 
java.io.InputStream !

However, as iText immediately writes to an java.io.OutputStream you would have 
to do one of these to successfully implement a Resource:

  (1) iText -> ByteArrayOutputStream -> byte[] -> ByteArrayInputStream -> 
Resource::getInputStream
  (2) iText -> FileOutputStream -> temp file -> FileInputStream -> 
Resource::getInputStream
  (3) iText -> PipedOutputStream (thread #1) -> PipedInputStream (thread #2) -> 
Resource::getInputStream

However I don't like any of these (1)-(3) because this requirement is purely 
caused by the current design but technically you could just write direcly to 
the ServletOutputStream

  (4) PdfWriter.getInstance(doc, 
getWebResponse().getOutputStream(outputStream)));

this would be the best performing and low memory solution, but Resource stream 
will no cooperate and still wants an InputStream.

I wrote a simple proof-of-concept class called ResponseWriterResource (which 
currently will not work unless the issue gets resolved):

  public abstract class ResponseWriterResource extends Resource
  {
    @Override
    public void onResourceRequested()
    {
      RequestCycle.get().setRequestTarget(new IRequestTarget()
      {
        public void respond(RequestCycle requestCycle)
        {
          write(requestCycle.getResponse());
        }

        public void detach(RequestCycle requestCycle)
        {
        }
      });
    }

    @Override
    public IResourceStream getResourceStream()
    {
      // ignore
      return null;
    }

    protected abstract void write(Response response);
  }

in the case of creating a pdf the code would look like this:

  Resource resource = new ResponseWriterResource()
  {
    write(Response response)
    {
      Document doc = new Document();
      PdfWriter.getInstance(doc, response.getOutputStream());
      //
      // ... create the pdf here
      // ... (and write it directly! to the servlet output stream)
    }
  }

So the resource could immediately be rendered to the client without the need of 
buffering the response first.

There's only one tiny change that I would need inside wicket:

In order to override

  @Override
  public void onResourceRequested()

I would need the removal of the final keyword from onResourceRequested()

class Resource
{
  // ...
  public final(*) void onResourceRequested()          // (*) please remove the 
final keyword
  // ...
}

The benefit of this would be that any kind of very large resource could be 
created in the web application without the need of ugly solutions like (1)-(3).

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.

Reply via email to