You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@ofbiz.apache.org by "skip@thedevers" <sk...@thedevers.org> on 2011/02/17 19:43:11 UTC

Automatic PDF Printing

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


Re: Automatic PDF Printing

Posted by David E Jones <de...@me.com>.
Did you look at the ScreenRenderer class? There is another populate context there that is meant for rendering a screen from a service, use that one.

Also, for examples of how this is meant to be done take a look at the send mail from screen service that uses screen definitions for both the HTML in the email and PDF attachments, all called from services and not using any of the web stuff.

-David


On Feb 17, 2011, at 10:43 AM, skip@thedevers wrote:

> 
> 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
>