/*! * This program is free software; you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software * Foundation. * * You should have received a copy of the GNU Lesser General Public License along with this * program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html * or from the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * Copyright (c) 2002-2013 Pentaho Corporation.. All rights reserved. */ package org.pentaho.reporting.engine.classic.core.modules.parser.bundle.writer; import org.pentaho.reporting.engine.classic.core.ClassicEngineBoot; import org.pentaho.reporting.engine.classic.core.MasterReport; import org.pentaho.reporting.libraries.docbundle.BundleUtilities; import org.pentaho.reporting.libraries.docbundle.DocumentBundle; import org.pentaho.reporting.libraries.docbundle.DocumentMetaData; import org.pentaho.reporting.libraries.docbundle.MemoryDocumentBundle; import org.pentaho.reporting.libraries.docbundle.WriteableDocumentBundle; import org.pentaho.reporting.libraries.docbundle.WriteableDocumentMetaData; import org.pentaho.reporting.libraries.repository.ContentIOException; import java.io.File; import java.io.IOException; import java.io.OutputStream; import java.util.Arrays; import java.util.Comparator; /** * The bundle-frontend. This class orchestrates the writing process. * <p/> * In the absence of template files, it will simply serialize the whole report into a XML file and will fail if there * are non-serializable or unrecognized elements. Unlike the old ext-writer, this class does not try to write all * report-definitions. The report definitions fed into this writer must use ElementType implementation to be written * correctly. * <p/> * In this very first implementation, we ignore the global bundle and write everything into the target bundle. To make * selective writing work, we have to tag each shared element as shared. * * @author Thomas Morgner */ public class BundleWriter { private static final String MASTER_HANDLER_PREFIX = "org.pentaho.reporting.engine.classic.core.modules.parser.bundle.writer.handler.master."; private static final String SUBREPORT_HANDLER_PREFIX = "org.pentaho.reporting.engine.classic.core.modules.parser.bundle.writer.handler.subreport."; private BundleWriterHandler[] masterWriter; private BundleWriterHandler[] subreportWriter; public BundleWriter() { masterWriter = BundleWriterHandlerRegistry.getInstance().getWriteHandlers( true ); if ( masterWriter.length == 0 ) { throw new IllegalStateException( "Bundle-Writer configuration is invalid." ); } // Sort the list of BundleWriterHandlers so the processing occurs in a better defined order sortBundleWriterHandlers( masterWriter ); subreportWriter = BundleWriterHandlerRegistry.getInstance().getWriteHandlers( false ); if ( subreportWriter.length == 0 ) { throw new IllegalStateException( "Bundle-Writer configuration is invalid." ); } // Sort the list of BundleWriterHandlers so the processing occurs in a better defined order sortBundleWriterHandlers( subreportWriter ); } public void writeReport( final WriteableDocumentBundle bundle, final MasterReport report ) throws IOException, BundleWriterException { if ( bundle == null ) { throw new NullPointerException(); } if ( report == null ) { throw new NullPointerException(); } if ( bundle == report.getBundle() ) { throw new IllegalArgumentException( "Cannot write to the originating bundle." ); } final DocumentBundle reportBundle = report.getBundle(); if ( reportBundle == null ) { this.writeReport( bundle, report, new MemoryDocumentBundle() ); } else { this.writeReport( bundle, report, reportBundle ); } } public void writeReport( final WriteableDocumentBundle bundle, final MasterReport report, final DocumentBundle globalBundle ) throws IOException, BundleWriterException { if ( bundle == null ) { throw new NullPointerException(); } if ( report == null ) { throw new NullPointerException(); } if ( globalBundle == null ) { throw new NullPointerException(); } final WriteableDocumentMetaData data = bundle.getWriteableDocumentMetaData(); data.setBundleType( ClassicEngineBoot.BUNDLE_TYPE ); final MasterReport clone = (MasterReport) report.derive(); final BundleWriterState state = new BundleWriterState( clone, globalBundle, this ); for ( int i = 0; i < masterWriter.length; i++ ) { final BundleWriterHandler handler = masterWriter[i]; handler.writeReport( bundle, state ); } } public void writeSubReport( final WriteableDocumentBundle bundle, final BundleWriterState state ) throws IOException, BundleWriterException { if ( state == null ) { throw new NullPointerException(); } if ( bundle == null ) { throw new NullPointerException(); } for ( int i = 0; i < subreportWriter.length; i++ ) { final BundleWriterHandler handler = subreportWriter[i]; handler.writeReport( bundle, state ); } } public static void writeReportToZipFile( final MasterReport report, final String file ) throws BundleWriterException, ContentIOException, IOException { writeReportToZipFile( report, new File( file ) ); } public static void writeReportToZipFile( final MasterReport report, final File file ) throws IOException, BundleWriterException, ContentIOException { if ( report == null ) { throw new NullPointerException(); } if ( file == null ) { throw new NullPointerException(); } final MemoryDocumentBundle outputBundle = new MemoryDocumentBundle(); final BundleWriter writer = new BundleWriter(); writer.writeReport( outputBundle, report ); BundleUtilities.writeAsZip( file, outputBundle ); } public static void writeReportToZipStream( final MasterReport report, final OutputStream out ) throws IOException, BundleWriterException, ContentIOException { if ( report == null ) { throw new NullPointerException(); } if ( out == null ) { throw new NullPointerException(); } final MemoryDocumentBundle documentBundle = new MemoryDocumentBundle(); final BundleWriter writer = new BundleWriter(); writer.writeReport( documentBundle, report ); BundleUtilities.writeAsZip( out, documentBundle ); } public static void writeReportToZipStream( final MasterReport report, final OutputStream out, final DocumentMetaData metaData ) throws IOException, BundleWriterException, ContentIOException { if ( report == null ) { throw new NullPointerException(); } if ( out == null ) { throw new NullPointerException(); } final MemoryDocumentBundle documentBundle = new MemoryDocumentBundle(); final BundleWriter writer = new BundleWriter(); writer.writeReport( documentBundle, report ); // restore the metadata to match the metadata of the original bundle. final WriteableDocumentMetaData targetMetaData = (WriteableDocumentMetaData) documentBundle.getMetaData(); for ( final String namespace : metaData.getMetaDataNamespaces() ) { for ( final String name : metaData.getMetaDataNames( namespace ) ) { targetMetaData.setBundleAttribute( namespace, name, metaData.getBundleAttribute( namespace, name ) ); } } BundleUtilities.writeAsZip( out, documentBundle ); } public static void writeReportToDirectory( final MasterReport report, final File file ) throws IOException, BundleWriterException, ContentIOException { if ( report == null ) { throw new NullPointerException(); } if ( file == null ) { throw new NullPointerException(); } final MemoryDocumentBundle documentBundle = new MemoryDocumentBundle(); final BundleWriter writer = new BundleWriter(); writer.writeReport( documentBundle, report ); BundleUtilities.writeToDirectory( file, documentBundle ); } /** * Sorts the BundleWriterHandlers so that they are processed in the correct order * * @param masterWriter * the array of BundleWriterHandlers to sort */ private static void sortBundleWriterHandlers( final BundleWriterHandler[] masterWriter ) { Arrays.sort( masterWriter, new BundleWriterHandlerComparator() ); } /** * Simple comparator class which is used to compare BundleWriterHandlers for sorting purposes */ private static class BundleWriterHandlerComparator implements Comparator<BundleWriterHandler> { private BundleWriterHandlerComparator() { } public int compare( final BundleWriterHandler o1, final BundleWriterHandler o2 ) { // We should not have to worry about type checking here return o1.getProcessingOrder() - o2.getProcessingOrder(); } } }