/*
* 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.function;
import org.pentaho.reporting.engine.classic.core.DataRow;
import org.pentaho.reporting.engine.classic.core.wizard.DataSchema;
import org.pentaho.reporting.libraries.base.config.Configuration;
import org.pentaho.reporting.libraries.formula.EvaluationException;
import org.pentaho.reporting.libraries.formula.FormulaContext;
import org.pentaho.reporting.libraries.formula.LocalizationContext;
import org.pentaho.reporting.libraries.formula.function.FunctionRegistry;
import org.pentaho.reporting.libraries.formula.operators.OperatorFactory;
import org.pentaho.reporting.libraries.formula.typing.DefaultTypeRegistry;
import org.pentaho.reporting.libraries.formula.typing.Type;
import org.pentaho.reporting.libraries.formula.typing.TypeRegistry;
import org.pentaho.reporting.libraries.formula.typing.coretypes.AnyType;
import javax.swing.table.TableModel;
import java.util.Date;
/**
* The report formula context is a FormulaContext implementation that connects the formula evaluator with the current
* data-row of the report process.
* <p/>
* This is an internal class used by the FormulaExpression and FormulaFunction. It has no sensible usages outside of
* that scope.
*
* @author Thomas Morgner
*/
public class ReportFormulaContext implements FormulaContext {
/**
* The formula context provided from the LibFormula implementation.
*/
private FormulaContext backend;
/**
* The export-type as returned by the output-processor.
*/
private ProcessingContext processingContext;
private ExpressionRuntime runtime;
private DefaultTypeRegistry typeRegistry;
/**
* Creates a new ReportFormulaContext using the given FormulaContext as backend. All data is read from the data-row.
*
* @param backend
* the formula-context backend.
* @param runtime
* the ExpressionRuntime
*/
public ReportFormulaContext( final FormulaContext backend, final ExpressionRuntime runtime ) {
if ( runtime == null ) {
throw new NullPointerException( "Runtime is null." );
}
if ( backend == null ) {
throw new NullPointerException( "Backend-FormulaContext is null" );
}
this.runtime = runtime;
this.backend = backend;
this.typeRegistry = new DefaultTypeRegistry();
this.typeRegistry.initialize( this );
this.processingContext = runtime.getProcessingContext();
}
public DataSchema getDataSchema() {
return runtime.getDataSchema();
}
/**
* Returns the localization context of this formula. The localization context can be used to query locale specific
* configuration settings.
*
* @return the localization context.
*/
public LocalizationContext getLocalizationContext() {
return backend.getLocalizationContext();
}
/**
* Returns the local configuration of the formula.
*
* @return the local configuration.
*/
public Configuration getConfiguration() {
return backend.getConfiguration();
}
/**
* Returns the function registry. The function registry grants access to all formula-function implementations.
*
* @return the function registry.
*/
public FunctionRegistry getFunctionRegistry() {
return backend.getFunctionRegistry();
}
/**
* Returns the type registry. The type registry contains all type information and allows to convert values between
* different types.
*
* @return the function registry.
*/
public TypeRegistry getTypeRegistry() {
return typeRegistry;
}
/**
* Returns the operator registry. The Operator-registry contains all operator-implementations.
*
* @return the operator registry.
*/
public OperatorFactory getOperatorFactory() {
return backend.getOperatorFactory();
}
/**
* Checks whether the external object referenced by <code>name</code> has changed. This forwards the call to the
* data-row and checks, whether the value has changed since the last call to advance().
*
* @param name
* the name that identifies the reference.
* @return true, if the reference has changed, false otherwise.
* @throws EvaluationException
* if an error occurs.
*/
public boolean isReferenceDirty( final Object name ) throws EvaluationException {
return runtime.getDataRow().isChanged( (String) name );
}
/**
* Resolves the given reference. How the name is interpreted by the outside system is an implementation detail. This
* method always returns AnyType, as we do not interpret the values returned from the data-row.
*
* @param name
* the name that identifies the reference.
* @return the resolved object.
*/
public Type resolveReferenceType( final Object name ) {
return AnyType.TYPE;
}
/**
* Queries the type of the given reference. How the name is interpreted by the outside system is an implementation
* detail. This return a LibFormula type object matching the type of the object that would be returned by
* resolveReference.
*
* @param name
* the name that identifies the reference.
* @return the type of the resolved object.
* @throws EvaluationException
* if an error occurs.
*/
public Object resolveReference( final Object name ) throws EvaluationException {
if ( name == null ) {
throw new NullPointerException();
}
return runtime.getDataRow().get( String.valueOf( name ) );
}
/**
* Returns the current data-row.
*
* @return the current datarow.
*/
public DataRow getDataRow() {
return runtime.getDataRow();
}
/**
* Invalidates the formula context.
*/
public void close() {
this.runtime = null;
this.processingContext = null;
}
/**
* Return the export type of the current report processing run.
*
* @return the current export type.
*/
public String getExportType() {
return processingContext.getExportDescriptor();
}
public ProcessingContext getProcessingContext() {
return processingContext;
}
public boolean isResultSetEmpty() {
final TableModel data = runtime.getData();
return data == null || data.getRowCount() == 0 || data.getColumnCount() == 0;
}
public ExpressionRuntime getRuntime() {
return runtime;
}
public Date getCurrentDate() {
try {
final Object date = resolveReference( "report.date" );
if ( date instanceof Date ) {
return (Date) date;
}
} catch ( EvaluationException e ) {
// ignore
}
return new Date();
}
}