Package org.pentaho.reporting.engine.classic.core.states.datarow

Source Code of org.pentaho.reporting.engine.classic.core.states.datarow.ExpressionDataRow

/*
* 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.datarow;

import javax.swing.table.TableModel;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.pentaho.reporting.engine.classic.core.DataFactory;
import org.pentaho.reporting.engine.classic.core.DataRow;
import org.pentaho.reporting.engine.classic.core.ReportProcessingException;
import org.pentaho.reporting.engine.classic.core.ResourceBundleFactory;
import org.pentaho.reporting.engine.classic.core.event.ReportEvent;
import org.pentaho.reporting.engine.classic.core.function.Expression;
import org.pentaho.reporting.engine.classic.core.function.ExpressionRuntime;
import org.pentaho.reporting.engine.classic.core.function.Function;
import org.pentaho.reporting.engine.classic.core.function.ProcessingContext;
import org.pentaho.reporting.engine.classic.core.states.DefaultGroupingState;
import org.pentaho.reporting.engine.classic.core.states.GroupingState;
import org.pentaho.reporting.engine.classic.core.states.LayoutProcess;
import org.pentaho.reporting.engine.classic.core.states.ReportState;
import org.pentaho.reporting.engine.classic.core.wizard.DataSchema;
import org.pentaho.reporting.libraries.base.config.Configuration;

public final class ExpressionDataRow extends ExpressionEventHelper
{
  private static final Log logger = LogFactory.getLog(ExpressionDataRow.class);

  private static final Expression[] EMPTY_EXPRESSIONS = new Expression[0];

  private static class DataRowRuntime implements ExpressionRuntime
  {
    private ExpressionDataRow expressionDataRow;
    private GroupingState state;
    private boolean structuralComplex;
    private boolean crosstabActive;

    protected DataRowRuntime(final ExpressionDataRow dataRow)
    {
      this.expressionDataRow = dataRow;
      this.state = DefaultGroupingState.EMPTY;
    }

    public DataSchema getDataSchema()
    {
      return expressionDataRow.getMasterRow().getDataSchema();
    }

    public DataRow getDataRow()
    {
      return expressionDataRow.getMasterRow().getGlobalView();
    }

    public Configuration getConfiguration()
    {
      return getProcessingContext().getConfiguration();
    }

    public ResourceBundleFactory getResourceBundleFactory()
    {
      return expressionDataRow.getMasterRow().getResourceBundleFactory();
    }

    public DataFactory getDataFactory()
    {
      return expressionDataRow.getMasterRow().getDataFactory();
    }

    /**
     * Access to the tablemodel was granted using report properties, now direct.
     */
    public TableModel getData()
    {
      return expressionDataRow.getMasterRow().getReportData();
    }

    /**
     * Where are we in the current processing.
     */
    public int getCurrentRow()
    {
      return expressionDataRow.getMasterRow().getCursor();
    }

    public int getCurrentDataItem()
    {
      return expressionDataRow.getMasterRow().getRawDataCursor();
    }

    /**
     * The output descriptor is a simple string collections consisting of the following components:
     * exportclass/type/subtype
     * <p/>
     * For example, the PDF export would be: pageable/pdf The StreamHTML export would return table/html/stream
     *
     * @return the export descriptor.
     */
    public String getExportDescriptor()
    {
      return getProcessingContext().getExportDescriptor();
    }

    public ProcessingContext getProcessingContext()
    {
      return expressionDataRow.getProcessingContext();
    }

    public int getCurrentGroup()
    {
      return state.getCurrentGroup();
    }

    public int getGroupStartRow(final String groupName)
    {
      return state.getGroupStartRow(groupName);
    }

    public int getGroupStartRow(final int groupIndex)
    {
      return state.getGroupStartRow(groupIndex);
    }

    public boolean isStructuralComplexReport()
    {
      return structuralComplex;
    }

    public boolean isCrosstabActive()
    {
      return crosstabActive;
    }

    public GroupingState getState()
    {
      return state;
    }

    public void setState(final GroupingState state)
    {
      if (state == null)
      {
        throw new NullPointerException();
      }
      this.state = state;
    }

    public void setCrosstabInfo(final boolean structuralComplex, final boolean crosstabActive)
    {
      this.structuralComplex = structuralComplex;
      this.crosstabActive = crosstabActive;
    }
  }


  private MasterDataRowChangeHandler masterRowChangeHandler;
  private MasterDataRow masterRow;
  private ProcessingContext processingContext;
  private int length;
  private Expression[] expressions;
  private LevelStorageBackend[] levelData;
  private DataRowRuntime runtime;
  private boolean includeStructuralProcessing;

  public ExpressionDataRow(final MasterDataRowChangeHandler masterRowChangeHandler,
                           final MasterDataRow masterRow,
                           final ProcessingContext processingContext)
  {
    if (masterRow == null)
    {
      throw new NullPointerException();
    }
    if (processingContext == null)
    {
      throw new NullPointerException();
    }

    this.processingContext = processingContext;
    this.masterRow = masterRow;
    this.masterRowChangeHandler = masterRowChangeHandler;
    this.expressions = ExpressionDataRow.EMPTY_EXPRESSIONS;
    this.runtime = new DataRowRuntime(this);
    this.revalidate();
  }

  public boolean isIncludeStructuralProcessing()
  {
    return includeStructuralProcessing;
  }

  public void setIncludeStructuralProcessing(final boolean includeStructuralProcessing)
  {
    this.includeStructuralProcessing = includeStructuralProcessing;
    revalidate();
  }

  private void revalidate()
  {
    this.levelData = LevelStorageBackend.revalidate(this.expressions, length, includeStructuralProcessing);
  }

  private ExpressionDataRow(final MasterDataRowChangeHandler masterRowChangeHandler,
                            final MasterDataRow masterRow,
                            final ExpressionDataRow previousRow,
                            final boolean updateGlobalView)
      throws CloneNotSupportedException
  {
    final MasterDataRowChangeEvent chEvent = masterRowChangeHandler.getReusableEvent();
    chEvent.reuse(MasterDataRowChangeEvent.COLUMN_UPDATED, "", "");
    this.processingContext = previousRow.processingContext;
    this.masterRow = masterRow;
    this.masterRowChangeHandler = masterRowChangeHandler;
    this.expressions = new Expression[previousRow.expressions.length];
    this.length = previousRow.length;
    this.levelData = previousRow.levelData;
    this.runtime = new DataRowRuntime(this);
    this.runtime.setState(previousRow.runtime.getState());
    this.includeStructuralProcessing = previousRow.includeStructuralProcessing;

    for (int i = 0; i < length; i++)
    {
      final Expression expression = previousRow.expressions[i];
      if (expression == null)
      {
        ExpressionDataRow.logger.debug("Error: Expression is null...");
        throw new IllegalStateException();
      }

      if (expression instanceof Function)
      {
        expressions[i] = (Expression) expression.clone();
      }
      else
      {
        expressions[i] = expression;
      }

      if (updateGlobalView == false)
      {
        continue;
      }

      final String name = expression.getName();
      if (name != null)
      {
        chEvent.setColumnName(name);
      }
      Object value;

      final ExpressionRuntime oldRuntime = expression.getRuntime();
      try
      {
        expression.setRuntime(runtime);
        if (runtime.getProcessingContext().getProcessingLevel() <= expression.getDependencyLevel())
        {
          value = expression.getValue();
        }
        else
        {
          value = null;
        }
      }
      catch (Exception e)
      {
        if (ExpressionDataRow.logger.isDebugEnabled())
        {
          ExpressionDataRow.logger.warn("Failed to evaluate expression '" + name + '\'', e);
        }
        else
        {
          ExpressionDataRow.logger.warn("Failed to evaluate expression '" + name + '\'');
        }
        value = null;
      }
      finally
      {
        expression.setRuntime(oldRuntime);
      }
      if (name != null)
      {
        chEvent.setColumnValue(value);
        masterRowChangeHandler.dataRowChanged(chEvent);
      }
    }
  }

  /**
   * This adds the expression to the data-row and queries the expression for the first time.
   *
   * @param expressionSlot the expression that should be added.
   * @param preserveState  a flag indicating whether the expression is statefull and should preserve its internal
   *                       state.
   * @throws ReportProcessingException if the processing failed due to invalid function implementations.
   */
  private void pushExpression(final Expression expressionSlot,
                              final boolean preserveState)
      throws ReportProcessingException
  {
    if (expressionSlot == null)
    {
      throw new NullPointerException();
    }

    ensureCapacity(length + 1);

    if (preserveState == false)
    {
      this.expressions[length] = expressionSlot.getInstance();
    }
    else
    {
      try
      {
        this.expressions[length] = (Expression) expressionSlot.clone();
      }
      catch (final CloneNotSupportedException e)
      {
        throw new ReportProcessingException("Failed to clone the expression.", e);
      }
    }

    final String name = expressionSlot.getName();
    length += 1;

    // A manual advance to initialize the function.
    if (name != null)
    {
      final MasterDataRowChangeEvent event = masterRowChangeHandler.getReusableEvent();
      event.reuse(MasterDataRowChangeEvent.COLUMN_ADDED, name, null);
      masterRowChangeHandler.dataRowChanged(event);
    }
  }

  public void pushExpressions(final Expression[] expressionSlots,
                              final boolean preserveState)
      throws ReportProcessingException
  {
    if (expressionSlots == null)
    {
      throw new NullPointerException();
    }

    ensureCapacity(length + expressionSlots.length);
    for (int i = 0; i < expressionSlots.length; i++)
    {
      final Expression expression = expressionSlots[i];
      if (expression == null)
      {
        continue;
      }
      pushExpression(expression, preserveState);
    }

    revalidate();
  }

  public void popExpressions(final int counter)
  {
    for (int i = 0; i < counter; i++)
    {
      popExpression();
    }

    revalidate();
  }

  private void popExpression()
  {
    if (length == 0)
    {
      return;
    }
    final Expression removedExpression = this.expressions[length - 1];
    final String originalName = removedExpression.getName();
    removedExpression.setRuntime(null);

    this.expressions[length - 1] = null;
    this.length -= 1;
    if (originalName != null)
    {
      if (removedExpression.isPreserve() == false)
      {
        final MasterDataRowChangeEvent event = masterRowChangeHandler.getReusableEvent();
        event.reuse(MasterDataRowChangeEvent.COLUMN_REMOVED, originalName, null);
        masterRowChangeHandler.dataRowChanged(event);
      }
    }
  }

  private void ensureCapacity(final int requestedSize)
  {
    final int capacity = this.expressions.length;
    if (capacity > requestedSize)
    {
      return;
    }
    final int newSize = Math.max(capacity * 2, requestedSize + 10);

    final Expression[] newExpressions = new Expression[newSize];
    System.arraycopy(expressions, 0, newExpressions, 0, length);

    this.expressions = newExpressions;
  }

  /**
   * Returns the number of columns, expressions and functions and marked ReportProperties in the report.
   *
   * @return the item count.
   */
  public int getColumnCount()
  {
    return length;
  }

  public void fireReportEvent(final ReportEvent event)
  {
    final ReportState reportState = event.getState();
    runtime.setState(reportState.createGroupingState());
    runtime.setCrosstabInfo(reportState.isStructuralPreprocessingNeeded(), reportState.isCrosstabActive());
    super.fireReportEvent(event);
    super.reactivateExpressions(event.isDeepTraversing());
  }

  protected void updateMasterDataRow(final String name, final Object value)
  {
    final MasterDataRowChangeEvent event = masterRowChangeHandler.getReusableEvent();
    event.reuse(MasterDataRowChangeEvent.COLUMN_UPDATED, name, value);
    masterRowChangeHandler.dataRowChanged(event);
  }

  protected ExpressionRuntime getRuntime()
  {
    return runtime;
  }

  protected int getProcessingLevel()
  {
    final int activeLevel;
    final int rawLevel = runtime.getProcessingContext().getProcessingLevel();
    if (rawLevel == LayoutProcess.LEVEL_STRUCTURAL_PREPROCESSING)
    {
      // we are in the data-pre-processing stage. Include all common expressions, in case they
      // compute a group-break.
      if (levelData.length > 0)
      {
        activeLevel = levelData[0].getLevelNumber();
      }
      else
      {
        activeLevel = rawLevel;
      }
    }
    else
    {
      activeLevel = rawLevel;
    }
    return activeLevel;
  }

  public ExpressionDataRow derive(final MasterDataRowChangeHandler masterRowChangeHandler,
                                  final MasterDataRow masterRow,
                                  final boolean update)
  {
    try
    {
      return new ExpressionDataRow(masterRowChangeHandler, masterRow, this, update);
    }
    catch (final CloneNotSupportedException e)
    {
      logger.error("Error on derive(..): ", e);
      throw new IllegalStateException("Cannot clone? Cannot survive!");
    }
  }

  public boolean isValid()
  {
    return levelData != null;
  }

  public Expression[] getExpressions()
  {
    final Expression[] retval = new Expression[length];
    System.arraycopy(expressions, 0, retval, 0, length);
    return retval;
  }

  /**
   * Returns the current master-row instance to inner-classes.
   *
   * @return a reference to the master-row (to be used in inner classes).
   * @noinspection ProtectedMemberInFinalClass
   */
  protected MasterDataRow getMasterRow()
  {
    return masterRow;
  }

  /**
   * Returns the current processing context to inner-classes.
   *
   * @return a reference to the processing context (to be used in inner classes).
   * @noinspection ProtectedMemberInFinalClass
   */
  protected ProcessingContext getProcessingContext()
  {
    return processingContext;
  }

  public void refresh()
  {
    reactivateExpressions(false);
  }

  protected int getRunLevelCount()
  {
    return levelData.length;
  }

  protected LevelStorage getRunLevel(final int index)
  {
    final LevelStorageBackend backend = levelData[index];
    return LevelStorageBackend.getLevelStorage(backend, expressions);
  }
}
TOP

Related Classes of org.pentaho.reporting.engine.classic.core.states.datarow.ExpressionDataRow

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.