I would like to print various .fo.ftl PDF forms automatically using ECA
services.  I have written (using modified Sun code) a PDF print writer.  All
I need as a way to get a ByteArrayOutputStream from the .fo.ftl.  Using
org.ofbiz.widget.screen.ScreenFopViewHandler.render as an example, I can
easily get a ByteArrayOutputStream and print it.  Unfortunately, this
routine requires a request and a response, although the response is never
really used and can probably be null.

The question is how to get the request in the eca service.  I read the
entries at:

http://ofbiz.markmail.org/message/54mvqvnmmhnwoahy?q=Session+in+Services

where Rishi Solanki sez to just add:
<attribute name="request" mode="IN"
type="javax.servlet.http.HttpServletRequest"/>

However, that did not work.  You get an error "The following required
parameter is missing: [IN] [printInvoicePDF.request]."

So, I modified the code in in
framework\webapp\src\org\ofbiz\webapp\event\ServiceEventHandler.java

around line 220:

// don't include locale, that is also taken care of below
if ("locale".equals(name)) continue;

//Added by skipd to set up a request and response
if ("request".equals(name))
{
serviceContext.put("request", request);
continue;
}
if ("response".equals(name))
{
serviceContext.put("responset", response);
continue;
}


This all works now, but there are two problems.  I am told that it breaks
the job sandbox.  Second, I have to modifiy the service definition of the
service on which the eca runs to also include the request which kind of
messes with the purpose of an ECA.

Here is the code in ScreenFopViewHandler.render


ScreenRenderer screens = new ScreenRenderer(writer, null,
htmlScreenRenderer);
screens.populateContextForRequest(request, response, servletContext);

...
screens.getContext().put("formStringRenderer", new FoFormRenderer(request,
response));
screens.render(page);
....

ByteArrayOutputStream out = new ByteArrayOutputStream();

TransformerFactory transFactory = TransformerFactory.newInstance();

Fop fop = fopFactory.newFop(contentType, out);
Transformer transformer = transFactory.newTransformer();

// set the input source (XSL-FO) and generate the output stream of
contentType
Reader reader = new StringReader(writer.toString());
Source src = new StreamSource(reader);

...

Then, instead of:
// write to the browser
try {
out.writeTo(response.getOutputStream());
response.getOutputStream().flush();
} catch (IOException e) {
throw new ViewHandlerException("Unable write to browser OutputStream", e);
}

This

PDFPrint(out, printerdefinition);

This all works. No browser is involved. The only issue is that the calls to
populateContextForRequest, and FoFormRenderer both require request and
response arguments. The response is only used (as far as I can tell) for
populating a beanshell, and it is never used in any of the .bsh scripts for
PDF generation. It is never used in FoFormRenderer. In any case, I would not
be writing to the browser, only capturing the output stream and sending it
on to the PDFPrint routine that I have written.

In other words, what I want to do is use the various ....fo.ftl screens for
the various forms, render them to a ByteArrayOutputStream, and send that
ByteArrayOutputStream to a routine that knows how to print the resulting PDF
stream directly to a printer.

I expect that this would be useful to lots of people. All of my customers
want it as it saves them several minutes per order, i.e., accounts payable
does not have to look up all the completed orders, and print invoices. Pick
and packing slips get printed automatically, when an ecommerce order is
placed, a pick slip is automatically printed, etc, etc.

I also would like to contribute the code back to the project and so would
like whatever method used to be "approved".

Skip

Reply via email to