/*
* 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) 2001 - 2016 Object Refinery Ltd, Pentaho Corporation and Contributors.. All rights reserved.
*/
package org.pentaho.reporting.engine.classic.core.modules.output.table.base;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.pentaho.reporting.engine.classic.core.ReportDefinition;
import org.pentaho.reporting.engine.classic.core.function.ProcessingContext;
import org.pentaho.reporting.engine.classic.core.layout.model.LogicalPageBox;
import org.pentaho.reporting.engine.classic.core.layout.output.AbstractOutputProcessor;
import org.pentaho.reporting.engine.classic.core.layout.output.ContentProcessingException;
import org.pentaho.reporting.engine.classic.core.layout.output.FlowSelector;
import org.pentaho.reporting.engine.classic.core.layout.output.IterativeOutputProcessor;
import org.pentaho.reporting.engine.classic.core.layout.output.LogicalPageKey;
import org.pentaho.reporting.engine.classic.core.layout.output.OutputProcessorFeature;
import org.pentaho.reporting.libraries.base.util.MemoryUsageMessage;
import org.pentaho.reporting.libraries.formatting.FastMessageFormat;
import java.util.ArrayList;
/**
* The Table-Output processor uses the pagination stage to build a list of table-layouts.
*
* @author Thomas Morgner
*/
public abstract class AbstractTableOutputProcessor extends AbstractOutputProcessor implements IterativeOutputProcessor {
private static final Log logger = LogFactory.getLog( AbstractTableOutputProcessor.class );
public static final OutputProcessorFeature.BooleanOutputProcessorFeature STRICT_LAYOUT =
new OutputProcessorFeature.BooleanOutputProcessorFeature( "strict-layout" );
public static final OutputProcessorFeature.BooleanOutputProcessorFeature TREAT_ELLIPSE_AS_RECTANGLE =
new OutputProcessorFeature.BooleanOutputProcessorFeature( "treat-ellipse-as-rectangle" );
public static final OutputProcessorFeature.BooleanOutputProcessorFeature SHAPES_CONTENT =
new OutputProcessorFeature.BooleanOutputProcessorFeature( "shape-content" );
public static final OutputProcessorFeature.BooleanOutputProcessorFeature ROTATED_TEXT_AS_IMAGES =
new OutputProcessorFeature.BooleanOutputProcessorFeature( "rotated-text-as-images" );
private ArrayList<TableLayoutProducer> sheetLayouts;
private TableLayoutProducer currentLayout;
private TableContentProducer currentContent;
private long lastTime;
protected AbstractTableOutputProcessor() {
this.sheetLayouts = new ArrayList<TableLayoutProducer>();
}
public void processingStarted( final ReportDefinition report, final ProcessingContext processingContext ) {
super.processingStarted( report, processingContext );
lastTime = System.currentTimeMillis();
}
public boolean isNeedAlignedPage() {
return getMetaData().isFeatureSupported( OutputProcessorFeature.UNALIGNED_PAGEBANDS ) == false;
}
protected final void processPaginationContent( final LogicalPageKey logicalPageKey, final LogicalPageBox logicalPage ) {
if ( currentLayout == null ) {
currentLayout = new TableLayoutProducer( getMetaData() );
}
currentLayout.update( logicalPage, false );
currentLayout.pageCompleted();
// ModelPrinter.print(logicalPage);
final long rowCount = currentLayout.getLayout().getRowCount();
logPerformance( "Pagination done: ", rowCount, true );
sheetLayouts.add( currentLayout );
currentLayout = null;
}
protected final void processPageContent( final LogicalPageKey logicalPageKey, final LogicalPageBox logicalPage )
throws ContentProcessingException {
// this one is only called after the pagination is complete. In that case we have a valid table.
final FlowSelector tableInterceptor = getFlowSelector();
if ( tableInterceptor == null ) {
return;
}
if ( tableInterceptor.isLogicalPageAccepted( logicalPageKey ) == false ) {
return;
}
if ( currentContent == null ) {
final int pageCursor = getPageCursor();
final TableLayoutProducer sheetLayout = sheetLayouts.get( pageCursor );
currentContent = createTableContentProducer( sheetLayout.getLayout() );
}
currentContent.compute( logicalPage, false );
// ModelPrinter.print(logicalPage);
processTableContent( logicalPageKey, logicalPage, currentContent );
currentContent.clearFinishedBoxes();
final long rowCount = currentContent.getContentRowCount();
logPerformance( "Content done: ", rowCount, true );
currentContent = null;
}
protected abstract void processTableContent( final LogicalPageKey logicalPageKey, final LogicalPageBox logicalPage,
final TableContentProducer contentProducer ) throws ContentProcessingException;
public final void processIterativeContent( final LogicalPageBox logicalPageBox, final boolean performOutput )
throws ContentProcessingException {
if ( isContentGeneratable() == false ) {
// In pagination mode.
if ( currentLayout == null ) {
currentLayout = new TableLayoutProducer( getMetaData() );
}
currentLayout.update( logicalPageBox, true );
final long rowCount = currentLayout.getLayout().getRowCount();
logPerformance( "Still Iterating: ", rowCount, false );
} else {
// In content generation mode.
final int pageCursor = getPageCursor();
final LogicalPageKey logicalPageKey = getLogicalPage( pageCursor );
final FlowSelector tableInterceptor = getFlowSelector();
if ( tableInterceptor == null ) {
return;
}
if ( tableInterceptor.isLogicalPageAccepted( logicalPageKey ) == false ) {
return;
}
if ( currentContent == null ) {
final TableLayoutProducer sheetLayout = sheetLayouts.get( pageCursor );
currentContent = createTableContentProducer( sheetLayout.getLayout() );
}
currentContent.compute( logicalPageBox, true );
updateTableContent( logicalPageKey, logicalPageBox, currentContent, performOutput );
currentContent.clearFinishedBoxes();
final long rowCount = currentContent.getContentRowCount();
logPerformance( "Still Iterating: ", rowCount, false );
}
}
private void logPerformance( final String message, final long rowCount, final boolean force ) {
final long time = System.currentTimeMillis();
final double deltaTime = time - lastTime;
if ( force || deltaTime > 30000 ) {
lastTime = time;
if ( logger.isDebugEnabled() ) {
final double rowsPerSec = ( rowCount * 1000.0 / deltaTime );
final FastMessageFormat messageFormat =
new FastMessageFormat(
"{0} - Rows: {1} - Time: {2,number,0.000}sec - Throughput: ({3,number,0.000} rows/sec) " );
logger.debug( new MemoryUsageMessage( messageFormat.format( new Object[] { message, rowCount,
deltaTime / 1000.0, rowsPerSec } ) ) );
}
}
}
protected TableContentProducer createTableContentProducer( final SheetLayout layout ) {
return new TableContentProducer( layout, getMetaData() );
}
protected void updateTableContent( final LogicalPageKey logicalPageKey, final LogicalPageBox logicalPageBox,
final TableContentProducer tableContentProducer, final boolean performOutput ) throws ContentProcessingException {
throw new UnsupportedOperationException(
"This output processor does not implement the iterative content processing protocol." );
}
protected abstract FlowSelector getFlowSelector();
}