/*
* 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 - 2013 Object Refinery Ltd, Pentaho Corporation and Contributors.. All rights reserved.
*/
package org.pentaho.reporting.engine.classic.core.states;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import org.pentaho.reporting.engine.classic.core.InvalidReportStateException;
import org.pentaho.reporting.engine.classic.core.PerformanceTags;
import org.pentaho.reporting.engine.classic.core.ReportProcessingException;
import org.pentaho.reporting.engine.classic.core.event.PageEventListener;
import org.pentaho.reporting.engine.classic.core.event.ReportEvent;
import org.pentaho.reporting.engine.classic.core.function.ExpressionRuntime;
import org.pentaho.reporting.engine.classic.core.function.OutputFunction;
import org.pentaho.reporting.engine.classic.core.function.StructureFunction;
import org.pentaho.reporting.engine.classic.core.states.datarow.ExpressionEventHelper;
import org.pentaho.reporting.engine.classic.core.states.datarow.InlineDataRowRuntime;
import org.pentaho.reporting.engine.classic.core.states.datarow.LevelStorage;
import org.pentaho.reporting.engine.classic.core.states.datarow.OutputFunctionLevelStorage;
import org.pentaho.reporting.libraries.base.util.PerformanceLoggingStopWatch;
public class InitialLayoutProcess extends ExpressionEventHelper implements LayoutProcess
{
private class CloseListener implements ChangeListener
{
public void stateChanged(final ChangeEvent e)
{
stopWatch.close();
}
}
private static final StructureFunction[] EMPTY_FUNCTIONS = new StructureFunction[0];
private InlineDataRowRuntime inlineDataRowRuntime;
private OutputFunction outputFunction;
private boolean outputFunctionIsPageListener;
private PerformanceLoggingStopWatch stopWatch;
private PerformanceMonitorContext monitorContext;
public InitialLayoutProcess(final OutputFunction outputFunction,
final PerformanceMonitorContext monitorContext)
{
if (outputFunction == null)
{
throw new NullPointerException();
}
this.outputFunction = outputFunction;
this.outputFunctionIsPageListener = (outputFunction instanceof PageEventListener);
this.monitorContext = monitorContext;
this.monitorContext.addChangeListener(new CloseListener());
this.stopWatch = monitorContext.createStopWatch(PerformanceTags.REPORT_LAYOUT_GENERATE);
}
public LayoutProcess getParent()
{
return null;
}
public boolean isPageListener()
{
return outputFunctionIsPageListener;
}
public OutputFunction getOutputFunction()
{
return outputFunction;
}
public void restart(final ReportState state) throws ReportProcessingException
{
try
{
stopWatch.start();
if (inlineDataRowRuntime == null)
{
inlineDataRowRuntime = new InlineDataRowRuntime();
}
inlineDataRowRuntime.setState(state);
final ExpressionRuntime oldRuntime;
final OutputFunction outputFunction = getOutputFunction();
if (outputFunction != null)
{
oldRuntime = outputFunction.getRuntime();
outputFunction.setRuntime(inlineDataRowRuntime);
}
else
{
oldRuntime = null;
}
try
{
if (outputFunction != null)
{
outputFunction.restart(state);
}
}
finally
{
if (outputFunction != null)
{
outputFunction.setRuntime(oldRuntime);
}
}
}
finally
{
stopWatch.stop(true);
}
}
public StructureFunction[] getCollectionFunctions()
{
return EMPTY_FUNCTIONS;
}
public LayoutProcess deriveForStorage()
{
try
{
final InitialLayoutProcess lp = (InitialLayoutProcess) super.clone();
lp.inlineDataRowRuntime = null;
lp.outputFunction = outputFunction.deriveForStorage();
return lp;
}
catch (final CloneNotSupportedException e)
{
throw new IllegalStateException();
}
}
public LayoutProcess deriveForPagebreak()
{
try
{
final InitialLayoutProcess lp = (InitialLayoutProcess) super.clone();
lp.inlineDataRowRuntime = null;
lp.outputFunction = outputFunction.deriveForPagebreak();
return lp;
}
catch (final CloneNotSupportedException e)
{
throw new IllegalStateException();
}
}
public Object clone()
{
try
{
final InitialLayoutProcess lp = (InitialLayoutProcess) super.clone();
lp.inlineDataRowRuntime = null;
lp.outputFunction = (OutputFunction) outputFunction.clone();
return lp;
}
catch (CloneNotSupportedException cne)
{
throw new IllegalStateException(cne);
}
}
protected int getRunLevelCount()
{
return 1;
}
protected LevelStorage getRunLevel(final int index)
{
if (index != 0)
{
throw new IndexOutOfBoundsException();
}
return new OutputFunctionLevelStorage(LayoutProcess.LEVEL_PAGINATE, outputFunction, outputFunctionIsPageListener);
}
protected ExpressionRuntime getRuntime()
{
return inlineDataRowRuntime;
}
public void fireReportEvent(final ReportEvent event)
{
try
{
stopWatch.start();
if (inlineDataRowRuntime == null)
{
inlineDataRowRuntime = new InlineDataRowRuntime();
}
final ReportState state = inlineDataRowRuntime.getState();
inlineDataRowRuntime.setState(event.getState());
try
{
final int pageEventMask = ReportEvent.PAGE_STARTED | ReportEvent.PAGE_FINISHED;
if ((event.getType() & pageEventMask) == 0 &&
((event.getType() & ReportEvent.GROUP_BODY_FINISHED) == ReportEvent.GROUP_BODY_FINISHED))
{
fireGroupBodyFinishedEvent(event);
}
else
{
super.fireReportEvent(event);
}
}
catch (InvalidReportStateException exception)
{
throw exception;
}
catch (Throwable t)
{
throw new InvalidReportStateException("Failed to fire report event for sub-layout-process", t);
}
finally
{
inlineDataRowRuntime.setState(state);
}
}
finally
{
stopWatch.stop(true);
}
}
private void fireGroupBodyFinishedEvent(final ReportEvent event)
{
if (event.getLevel() != LayoutProcess.LEVEL_PAGINATE)
{
return;
}
final ExpressionRuntime runtime = getRuntime();
final OutputFunction expression = getOutputFunction();
final boolean deepTraversing = event.isDeepTraversing();
if (deepTraversing && expression.isDeepTraversing() == false)
{
return;
}
final ExpressionRuntime oldRuntime = expression.getRuntime();
expression.setRuntime(runtime);
try
{
expression.groupBodyFinished(event);
evaluateSingleExpression(expression);
}
catch (InvalidReportStateException rse)
{
throw rse;
}
catch (Exception ex)
{
evaluateToNull(expression);
}
expression.setRuntime(oldRuntime);
}
public void close()
{
stopWatch.close();
}
}