001/*
002 * Copyright (c) 2003-2010 The Regents of the University of California.
003 * All rights reserved.
004 *
005 * '$Author: crawl $'
006 * '$Date: 2018-05-25 18:38:49 +0000 (Fri, 25 May 2018) $' 
007 * '$Revision: 34695 $'
008 * 
009 * Permission is hereby granted, without written agreement and without
010 * license or royalty fees, to use, copy, modify, and distribute this
011 * software and its documentation for any purpose, provided that the above
012 * copyright notice and the following two paragraphs appear in all copies
013 * of this software.
014 *
015 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
016 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
017 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
018 * THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
019 * SUCH DAMAGE.
020 *
021 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
022 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
023 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
024 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
025 * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
026 * ENHANCEMENTS, OR MODIFICATIONS.
027 *
028 */
029
030package org.kepler.reporting.rio.fop;
031
032import java.awt.Component;
033import java.awt.Dimension;
034import java.io.BufferedOutputStream;
035import java.io.File;
036import java.io.FileInputStream;
037import java.io.FileOutputStream;
038import java.io.IOException;
039import java.io.InputStream;
040import java.io.OutputStream;
041import java.util.Iterator;
042
043import javax.imageio.ImageIO;
044import javax.imageio.ImageReader;
045import javax.imageio.spi.IIORegistry;
046import javax.swing.JFrame;
047import javax.xml.transform.Result;
048import javax.xml.transform.Source;
049import javax.xml.transform.Transformer;
050import javax.xml.transform.TransformerException;
051import javax.xml.transform.TransformerFactory;
052import javax.xml.transform.dom.DOMResult;
053import javax.xml.transform.sax.SAXResult;
054import javax.xml.transform.stream.StreamResult;
055import javax.xml.transform.stream.StreamSource;
056
057import org.apache.commons.logging.Log;
058import org.apache.commons.logging.LogFactory;
059import org.apache.fop.apps.FOPException;
060import org.apache.fop.apps.FOUserAgent;
061import org.apache.fop.apps.Fop;
062import org.apache.fop.apps.FopFactory;
063import org.apache.fop.apps.MimeConstants;
064import org.apache.fop.render.awt.AWTRenderer;
065import org.apache.fop.render.awt.viewer.PreviewPanel;
066import org.kepler.reporting.rio.ReportInstance;
067import org.kepler.reporting.rio.test.ReportTest;
068import org.kepler.reporting.roml.ReportLayout;
069
070/**
071 * This class converts a report object to XML, PDF, and AWT using JAXP (XSLT)
072 * and FOP (XSL:FO).
073 */
074public class ReportRenderer {
075
076        private static final String DEFAULT_XSLT = "/xslt/rio2fo.xsl";
077
078        public static Log log = LogFactory.getLog(ReportRenderer.class);
079
080        // configure fopFactory as desired
081        private static FopFactory fopFactory = FopFactory.newInstance();
082
083        static {
084                reorderPNGReaders();
085        }
086        
087        public static void reorderPNGReaders() {
088                Iterator<ImageReader> imageIter = ImageIO.getImageReadersByMIMEType("image/png");
089        
090                log.debug("--------- IMAGE READERS BEFORE ----------");
091        while (imageIter.hasNext()) {
092                ImageReader imageReader = imageIter.next();
093                log.debug(imageReader);
094        }
095        
096        /* com.sun.imageio.plugins.png.PNGImageReaderSpi.class no longer accessible in Java 9.
097
098
099        Class category = javax.imageio.spi.ImageReaderSpi.class;
100
101        Class firstProviderClass = com.sun.imageio.plugins.png.PNGImageReaderSpi.class;
102                Object firstProvider = IIORegistry.getDefaultInstance().getServiceProviderByClass(firstProviderClass);
103                
104                Class secondProviderClass = com.sun.media.imageioimpl.plugins.png.CLibPNGImageReaderSpi.class;
105                Object secondProvider = IIORegistry.getDefaultInstance().getServiceProviderByClass(secondProviderClass);
106                
107                if (firstProvider !=null && secondProvider != null) {
108                        IIORegistry.getDefaultInstance().setOrdering(category, firstProvider, secondProvider);
109                }
110        */
111                
112                //AFTER
113                imageIter = ImageIO.getImageReadersByMIMEType("image/png");
114        log.debug("--------- IMAGE READERS AFTER ----------");
115        while (imageIter.hasNext()) {
116                ImageReader imageReader = imageIter.next();
117                log.debug(imageReader);
118        }
119                
120        }
121        
122        /**
123         * Converts a Report object to a PDF file.
124         * 
125         * @param report
126         *            the Report object
127         * @param pdf
128         *            the target PDF file
129         * @param xsltStream
130         *            the stylesheet input stream
131         * @throws IOException
132         *             In case of an I/O problem
133         * @throws FOPException
134         *             In case of a FOP problem
135         * @throws TransformerException
136         *             In case of a XSL transformation problem
137         */
138        public static void convertReport2PDF(ReportInstance report, File pdf, InputStream xsltStream)
139                        throws IOException, FOPException, TransformerException {
140                
141                if (xsltStream == null) {
142                        // look up the stylesheet for generating the PDF
143                        xsltStream =  report.getClass().getResourceAsStream(DEFAULT_XSLT);
144                }
145                
146                FOUserAgent foUserAgent = fopFactory.newFOUserAgent();
147                // configure foUserAgent as desired
148
149                // Setup output
150                OutputStream out = new java.io.FileOutputStream(pdf);
151                out = new java.io.BufferedOutputStream(out);
152                try {
153                        // Construct fop with desired output format
154                        Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, foUserAgent,
155                                        out);
156
157                        // Setup XSLT
158                        TransformerFactory factory = TransformerFactory.newInstance();
159                        Transformer transformer = factory.newTransformer(new StreamSource(
160                                        xsltStream));
161
162                        // Set the value of a <param> in the stylesheet
163                        //TODO: this will be very useful, remember it!
164            //transformer.setParameter("myParamName", "myValue");
165            
166                        // Setup input for XSLT transformation
167                        Source src = ReportInputSource.getSourceForReport(report);
168
169                        // Resulting SAX events (the generated FO) must be piped through to
170                        // FOP
171                        Result res = new SAXResult(fop.getDefaultHandler());
172
173                        // Start XSLT transformation and FOP processing
174                        transformer.transform(src, res);
175                        
176                } finally {
177                        out.close();
178                }
179        }
180
181        
182        public static ReportLayout convertXML2Report(File xml) throws IOException,
183                TransformerException {
184                // Setup input
185                Source src = new StreamSource(xml);
186                return convertXML2Report(src);
187        }
188        
189        public static ReportLayout convertXML2Report(InputStream xml) throws IOException,
190                TransformerException {
191                // Setup input
192                Source src = new StreamSource(xml);
193                return convertXML2Report(src);
194        }
195        
196        /**
197         * Converts a Report object to XML.
198         * 
199         * @param report
200         *            the Report object
201         * @param xml
202         *            the target XML file
203         * @throws IOException
204         *             In case of an I/O problem
205         * @throws TransformerException
206         *             In case of a XSL transformation problem
207         * @throws ClassNotFoundException 
208         * @throws IllegalAccessException 
209         * @throws InstantiationException 
210         */
211        private static ReportLayout convertXML2Report(Source src) throws IOException,
212                        TransformerException {
213                        
214                // Setup XSLT
215                TransformerFactory factory = TransformerFactory.newInstance();
216                Transformer transformer = factory.newTransformer();
217                /*
218                 * Note: We use the identity transformer, no XSL transformation is done.
219                 * The transformer is basically just used to deserialize the XML to objects
220                 */
221        
222                // Setup output
223                DOMResult res = new DOMResult();
224        
225                // Start XSLT transformation
226                transformer.transform(src, res);
227                
228                ReportLayout report = null;
229                try {
230                        report = ReportParser.parse(res.getNode());
231                } catch (Exception e) {
232                        // TODO Auto-generated catch block
233                        e.printStackTrace();
234                } 
235                
236                return report;
237        }
238        
239        public static void convertReport2XML(ReportLayout report, File xml) throws IOException,
240                        TransformerException {
241                convertReport2XML(report, new FileOutputStream(xml));
242        }
243        
244        /**
245         * Converts a Report object to XML.
246         * 
247         * @param report
248         *            the Report object
249         * @param xml
250         *            the target XML file
251         * @throws IOException
252         *             In case of an I/O problem
253         * @throws TransformerException
254         *             In case of a XSL transformation problem
255         */
256        public static void convertReport2XML(ReportLayout report, OutputStream xml) throws IOException,
257                        TransformerException {
258
259                // Setup XSLT
260                TransformerFactory factory = TransformerFactory.newInstance();
261                Transformer transformer = factory.newTransformer();
262                /*
263                 * Note: We use the identity transformer, no XSL transformation is done.
264                 * The transformer is basically just used to serialize the generated
265                 * document to XML.
266                 */
267
268                // Setup input
269                Source src = ReportInputSource.getSourceForReport(report);
270
271                // Setup output
272                // Result res = new StreamResult(xml);
273                Result res = new StreamResult(new BufferedOutputStream(xml));
274
275                // Start XSLT transformation
276                transformer.transform(src, res);
277        }
278
279        /**
280         * Converts an XML file to an XSL-FO file using JAXP (XSLT).
281         * 
282         * @param xml
283         *            the XML file
284         * @param xslt
285         *            the stylesheet file
286         * @param fo
287         *            the target XSL-FO file
288         * @throws IOException
289         *             In case of an I/O problem
290         * @throws TransformerException
291         *             In case of a XSL transformation problem
292         */
293        public static void convertXML2FO(File xml, File xslt, File fo) throws IOException,
294                        TransformerException {
295
296                // Setup output
297                OutputStream out = new java.io.FileOutputStream(fo);
298                try {
299                        // Setup XSLT
300                        TransformerFactory factory = TransformerFactory.newInstance();
301                        Transformer transformer = factory.newTransformer(new StreamSource(
302                                        xslt));
303
304                        // Setup input for XSLT transformation
305                        Source src = new StreamSource(xml);
306
307                        // Resulting SAX events to XML
308                        Result res = new StreamResult(out);
309
310                        // Start XSLT transformation and FOP processing
311                        transformer.transform(src, res);
312                } finally {
313                        out.close();
314                }
315        }
316
317        public static void convertReport2FO(ReportInstance report, File xslt, File fo) throws IOException, TransformerException {
318                
319                // Setup output
320                OutputStream out = new java.io.FileOutputStream(fo);
321                try {
322                        // Setup XSLT
323                        TransformerFactory factory = TransformerFactory.newInstance();
324                        Transformer transformer = factory.newTransformer(new StreamSource(xslt));
325                
326                        // Setup input for XSLT transformation
327                        Source src = ReportInputSource.getSourceForReport(report);
328                
329                        // Resulting SAX events to FO
330                        Result res = new StreamResult(out);
331                
332                        // Start XSLT transformation and FOP processing
333                        transformer.transform(src, res);
334                } finally {
335                        out.close();
336                }
337        }
338        
339        /**
340         * Renders the Report object in the default FOP viewer. Not intended to be embedded.
341         * @deprecated
342         * @see convertReport2AWT() for an embedded soltion.
343         * 
344         * @param report Report to render
345         * @param xslt the transform to use for rendering the Report
346         * @throws IOException
347         * @throws FOPException
348         * @throws TransformerException
349         */
350        public void renderReportAsAWT(ReportInstance report, File xslt)
351                        throws IOException, FOPException, TransformerException {
352
353                FOUserAgent foUserAgent = fopFactory.newFOUserAgent();
354                // configure foUserAgent as desired
355
356                // Construct fop with desired output format
357                Fop fop = fopFactory.newFop(MimeConstants.MIME_FOP_AWT_PREVIEW, foUserAgent);
358
359                // Setup XSLT
360                TransformerFactory factory = TransformerFactory.newInstance();
361                Transformer transformer = factory.newTransformer(new StreamSource(xslt));
362
363                // Setup input for XSLT transformation
364                Source src = ReportInputSource.getSourceForReport(report);
365
366                // Resulting SAX events (the generated FO) must be piped through to
367                // FOP
368                Result res = new SAXResult(fop.getDefaultHandler());
369
370                // Start XSLT transformation and FOP processing
371                transformer.transform(src, res);
372
373        }
374
375        /**
376         * Used for embedding a viewer pane in swing applications
377         * @param report Report to render
378         * @param xslt transform to use for rendering Report
379         * @return PreviewPane component that can be added to any GUI
380         * @throws IOException
381         * @throws FOPException
382         * @throws TransformerException
383         */
384        public static Component convertReport2AWT(ReportInstance report, InputStream xslt)
385                throws IOException, FOPException, TransformerException {
386                                
387                FOUserAgent foUserAgent = fopFactory.newFOUserAgent();
388                // configure foUserAgent as desired
389        
390                AWTRenderer renderer = new AWTRenderer();
391                foUserAgent.setRendererOverride(renderer);
392                renderer.setPreviewDialogDisplayed(false);
393                renderer.setUserAgent(foUserAgent);
394                renderer.clearViewportList();
395                 
396                // Construct fop with no output format since we supply the renderer
397                Fop fop = fopFactory.newFop(foUserAgent);
398                
399                // Setup XSLT
400                TransformerFactory factory = TransformerFactory.newInstance();
401                Transformer transformer = factory.newTransformer(new StreamSource(xslt));
402        
403                // Setup input for XSLT transformation
404                Source src = ReportInputSource.getSourceForReport(report);
405        
406                // Resulting SAX events (the generated FO) must be piped through to FOP
407                Result res = new SAXResult(fop.getDefaultHandler());
408        
409                // Start XSLT transformation and FOP processing
410                transformer.transform(src, res);
411                
412                // construct the panel to render the processed FO
413                PreviewPanel previewPanel = new PreviewPanel(foUserAgent, null, renderer);
414                //double scale = previewPanel.getScaleToFitWindow();
415                //previewPanel.setScaleFactor(scale);
416                previewPanel.setDisplayMode(PreviewPanel.CONTINUOUS);
417
418                return previewPanel;
419        }
420        
421        /**
422         * Converts a Report object to a PDF file.
423         * 
424         * @param report
425         *            the Report object
426         * @param xslt
427         *            the stylesheet file
428         * @param html
429         *            the target HTML file
430         * @throws IOException
431         *             In case of an I/O problem
432         * @throws FOPException
433         *             In case of a FOP problem
434         * @throws TransformerException
435         *             In case of a XSL transformation problem
436         */
437        public static void convertReport2HTML(ReportInstance report, File xslt, File html)
438                        throws IOException, TransformerException {
439        
440                // Setup output
441                OutputStream out = new java.io.FileOutputStream(html);
442                out = new java.io.BufferedOutputStream(out);
443                try {
444                
445                        // Setup XSLT
446                        TransformerFactory factory = TransformerFactory.newInstance();
447                        Transformer transformer = factory.newTransformer(new StreamSource(xslt));
448        
449                        // Setup input for XSLT transformation
450                        Source src = ReportInputSource.getSourceForReport(report);
451        
452                        // Resulting SAX events sent to HTML
453                        Result res = new StreamResult(out);
454        
455                        // Start XSLT transformation
456                        transformer.transform(src, res);
457                        
458                } finally {
459                        out.close();
460                }
461        }
462
463        private static void showPreviewPanel(Component previewPanel) {
464                
465                //show the preview panel
466                JFrame frame = new JFrame("my frame");
467                
468                Dimension dim = new Dimension(612, 792);
469                frame.setPreferredSize(dim);
470                frame.setMaximumSize(dim);
471                frame.setMinimumSize(dim);
472                frame.setSize(dim);
473                
474                frame.add(previewPanel);
475                
476                frame.validate();
477                frame.setVisible(true);
478        }
479
480        /**
481         * Main method.
482         * 
483         * @param args
484         *            command-line arguments
485         */
486        public static void main(String[] args) {
487                try {
488                        log.debug("FOP Conversion");
489                        log.debug("Preparing...");
490
491                        // Setup directories
492                        File baseDir = new File(".");
493                        File outDir = new File(baseDir, "out");
494                        outDir.mkdirs();
495
496                        // Setup input and output
497                        File xsltfile = new File(baseDir, "lib/xslt/rio2fo.xsl");
498                        ///File xsltHTMLfile = new File(baseDir, "lib/xslt/rio2html.xsl");
499                        ///File xmlfile = new File(outDir, "Report2XML.xml");
500                        ///File htmlfile = new File(outDir, "Report2HTML.html");
501                        ///File fofile = new File(outDir, "Report2FO.fo");
502                        File pdffile = new File(outDir, "Report2PDF.pdf");
503
504                        log.debug("Input: a Report object");
505                        log.debug("Stylesheet: " + xsltfile);
506                        log.debug("Output: PDF (" + pdffile + ")");
507                        log.debug("Transforming...");
508
509                        //ReportInstance report = ReportTest.makeReport();
510                        ReportLayout reportLayout = ReportTest.makeReportLayout();
511                        ReportInstance report = new ReportInstance(reportLayout);
512                        // test that the copy constructor actually works
513                        reportLayout.setTitle("BLAH!");
514                        reportLayout.getSections().clear();
515//                      ReportRenderer.convertReport2XML(report, xmlfile);
516//                      ReportRenderer.convertReport2FO(report, xsltfile, fofile);
517//                      ReportConverter.convertXML2FO(xmlfile, xsltfile, fofile);
518//                      ReportRenderer.convertReport2PDF(report, pdffile, xsltfile);
519//                      ReportRenderer.convertReport2HTML(report, xsltHTMLfile, htmlfile);
520//                      ReportRenderer.convertXML2Report(xmlfile);
521                        showPreviewPanel(ReportRenderer.convertReport2AWT(report, new FileInputStream(xsltfile)));
522                        
523                        log.debug("Success!");
524                } catch (Exception e) {
525                        e.printStackTrace(System.err);
526                        System.exit(-1);
527                }
528        }
529}