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

Source Code of org.pentaho.reporting.engine.classic.core.MasterReport$ResourceBundleChangeHandler

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

import java.awt.print.PageFormat;
import java.awt.print.PrinterJob;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Date;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.pentaho.reporting.engine.classic.core.designtime.AttributeChange;
import org.pentaho.reporting.engine.classic.core.designtime.StyleChange;
import org.pentaho.reporting.engine.classic.core.event.ReportModelEvent;
import org.pentaho.reporting.engine.classic.core.event.ReportModelListener;
import org.pentaho.reporting.engine.classic.core.filter.types.bands.MasterReportType;
import org.pentaho.reporting.engine.classic.core.function.Expression;
import org.pentaho.reporting.engine.classic.core.modules.parser.bundle.LegacyBundleResourceRegistry;
import org.pentaho.reporting.engine.classic.core.parameters.DefaultParameterDefinition;
import org.pentaho.reporting.engine.classic.core.parameters.ModifiableReportParameterDefinition;
import org.pentaho.reporting.engine.classic.core.parameters.ReportParameterDefinition;
import org.pentaho.reporting.engine.classic.core.style.css.ElementStyleDefinition;
import org.pentaho.reporting.engine.classic.core.util.LibLoaderResourceBundleFactory;
import org.pentaho.reporting.engine.classic.core.util.ReportParameterValues;
import org.pentaho.reporting.libraries.base.config.Configuration;
import org.pentaho.reporting.libraries.base.config.ExtendedConfiguration;
import org.pentaho.reporting.libraries.base.config.HierarchicalConfiguration;
import org.pentaho.reporting.libraries.base.config.ModifiableConfiguration;
import org.pentaho.reporting.libraries.base.util.ArgumentNullException;
import org.pentaho.reporting.libraries.docbundle.BundleUtilities;
import org.pentaho.reporting.libraries.docbundle.DocumentBundle;
import org.pentaho.reporting.libraries.docbundle.MemoryDocumentBundle;
import org.pentaho.reporting.libraries.docbundle.ODFMetaAttributeNames;
import org.pentaho.reporting.libraries.repository.ContentIOException;
import org.pentaho.reporting.libraries.resourceloader.Resource;
import org.pentaho.reporting.libraries.resourceloader.ResourceException;
import org.pentaho.reporting.libraries.resourceloader.ResourceKey;
import org.pentaho.reporting.libraries.resourceloader.ResourceManager;

/**
* A JFreeReport instance is used as report template to define the visual layout of a report and to collect all data
* sources for the reporting. Possible data sources are the {@link TableModel}, {@link Expression}s or {@link
* ReportParameterValues}. The report is made up of 'bands', which are used repeatedly as necessary to generate small
* sections of the report.
* <p/>
* <h2>Accessing the bands and the elements:</h2>
* <p/>
* The different bands can be accessed using the main report definition (this class):
* <p/>
* <ul> <li>the report header and footer can be reached by using <code>getReportHeader()</code> and
* <code>getReportFooter()</code>
* <p/>
* <li>the page header and page footer can be reached by using <code>getPageHeader()</code> and
* <code>getPageFooter()</code>
* <p/>
* <li>the item band is reachable with <code>getItemBand()</code>
* <p/>
* <li>the no-data band is reachable with <code>getNoDataBand()</code>
* <p/>
* <li>the watermark band is reachable with <code>getWaterMark()</code> </ul>
* <p/>
* Groups can be queried using <code>getGroup(int groupLevel)</code>. The group header and footer are accessible through
* the group object, so use <code>getGroup(int groupLevel).getGroupHeader()<code> and <code>getGroup(int
* groupLevel).getGroupFooter()<code>.
* <p/>
* All report elements share the same stylesheet collection. Report elements cannot be shared between two different
* report instances. Adding a report element to one band will remove it from the other one.
* <p/>
* For dynamic computation of content you can add {@link Expression}s and {@link org.pentaho.reporting.engine.classic.core.function.Function}s
* to the report.
* <p/>
* Creating a new instance of JFreeReport seems to lock down the JDK on some Windows Systems, where no printer driver is
* installed. To prevent that behaviour on these systems, you can set the {@link Configuration} key
* "org.pentaho.reporting.engine.classic.core.NoPrinterAvailable" to "false" and JFreeReport will use a hardcoded
* default page format instead.
* <p/>
* A JFreeReport object always acts as Master-Report. The JFreeReport object defines the global report-configuration,
* the report's datasource (through the DataFactory property) and the ResourceBundleFactory (for localization).
*
* @author David Gilbert
* @author Thomas Morgner
*/
public class MasterReport extends AbstractReportDefinition
{

  /**
   * Listens for changes to the DocumentBundle being used by a report and will update the ResourceManager to use that
   * DocumentBundle.
   */
  private static class ResourceBundleChangeHandler implements ReportModelListener
  {
    private ResourceBundleChangeHandler()
    {
    }

    public void nodeChanged(final ReportModelEvent event)
    {
      if (event.isNodeStructureChanged())
      {
        return;
      }
      if (event.getParameter() instanceof StyleChange)
      {
        return;
      }

      final Object element = event.getElement();
      if (element instanceof MasterReport == false)
      {
        return;
      }
      final MasterReport report = (MasterReport) element;
      report.updateResourceBundleFactoryInternal();
    }
  }

  /**
   * Listens for changes to the DocumentBundle being used by a report and will update the ResourceManager to use that
   * DocumentBundle.
   */
  private static class DocumentBundleChangeHandler implements ReportModelListener
  {
    private static final Log log = LogFactory.getLog(DocumentBundleChangeHandler.class);

    private DocumentBundleChangeHandler()
    {
    }

    public void nodeChanged(final ReportModelEvent event)
    {
      if (event.getElement() instanceof MasterReport == false)
      {
        return;
      }
      final MasterReport report = (MasterReport) event.getElement();

      if (event.getParameter() instanceof AttributeChange)
      {
        final AttributeChange attributeChange = (AttributeChange) event.getParameter();

        // This is an attribute change event on the master report ... see if it is one we are concerned about
        if (AttributeNames.Core.NAMESPACE.equals(attributeChange.getNamespace()) &&
            AttributeNames.Core.BUNDLE.equals(attributeChange.getName()))
        {
          final Object value = attributeChange.getNewValue();
          if ((value instanceof DocumentBundle) == false)
          {
            return;
          }

          // Insert the DocumentBundle's ResourceManager as the MasterReports resource manager
          log.debug("DocumentBundle change detected - changing the ResourceManager for the MasterReport");
          final DocumentBundle newDocumentBundle = (DocumentBundle) value;
          final ResourceManager resourceManager = newDocumentBundle.getResourceManager();
          report.setContentBase(newDocumentBundle.getBundleKey());
          report.setResourceManager(resourceManager);
        }
      }
      else if (event.getParameter() instanceof ResourceManager)
      {
        final ResourceManager mgr = report.getResourceManager();
        final ResourceBundleFactory resourceBundleFactory = report.getResourceBundleFactory();
        if (resourceBundleFactory instanceof LibLoaderResourceBundleFactory)
        {
          LibLoaderResourceBundleFactory ll = (LibLoaderResourceBundleFactory) resourceBundleFactory;
          ll.setResourceLoader(mgr, report.getContentBase());
        }
      }
    }
  }

  /**
   * Key for the 'report date' property.
   */
  public static final String REPORT_DATE_PROPERTY = "report.date";
  /**
   * The data factory is used to query data for the reporting.
   */
  private DataFactory dataFactory;
  /**
   * The report configuration.
   */
  private HierarchicalConfiguration reportConfiguration;
  /**
   * The resource manager is used to load the report resources.
   */
  private transient ResourceManager resourceManager;
  private ReportParameterDefinition parameterDefinition;
  private ReportEnvironment reportEnvironment;
  private ReportParameterValues parameterValues;
  /**
   * The resource bundle factory is used when generating localized reports.
   */
  private ResourceBundleFactory resourceBundleFactory;

  /**
   * The default constructor. Creates an empty but fully initialized report.
   */
  public MasterReport()
  {
    setElementType(new MasterReportType());
    setResourceBundleFactory(new LibLoaderResourceBundleFactory());

    this.reportConfiguration = new HierarchicalConfiguration
        (ClassicEngineBoot.getInstance().getGlobalConfig());
    this.parameterValues = new ReportParameterValues();

    setPageDefinition(null);

    final TableDataFactory dataFactory = new TableDataFactory();
    dataFactory.addTable("default", new DefaultTableModel());
    this.dataFactory = dataFactory;
    setQuery("default");

    // Add a listener that will handle keeping the ResourceManager in sync with changes to the Document Bundle
    addReportModelListener(new DocumentBundleChangeHandler());

    this.reportEnvironment = new DefaultReportEnvironment(getConfiguration());
    this.parameterDefinition = new DefaultParameterDefinition();
    final MemoryDocumentBundle documentBundle = new MemoryDocumentBundle();
    documentBundle.getWriteableDocumentMetaData().setBundleType(ClassicEngineBoot.BUNDLE_TYPE);
    documentBundle.getWriteableDocumentMetaData().setBundleAttribute
        (ODFMetaAttributeNames.Meta.NAMESPACE, ODFMetaAttributeNames.Meta.CREATION_DATE, new Date());
    setBundle(documentBundle);

    setContentBase(documentBundle.getBundleMainKey());

    addReportModelListener(new ResourceBundleChangeHandler());
    updateResourceBundleFactoryInternal();
  }

  public static ResourceBundleFactory computeAndInitResourceBundleFactory
      (final ResourceBundleFactory resourceBundleFactory,
       final ReportEnvironment environment)
  {
    if (resourceBundleFactory instanceof ExtendedResourceBundleFactory == false)
    {
      return resourceBundleFactory;
    }
    final ExtendedResourceBundleFactory rawResourceBundleFactory =
        (ExtendedResourceBundleFactory) resourceBundleFactory;
    try
    {
      final ExtendedResourceBundleFactory extendedResourceBundleFactory =
          (ExtendedResourceBundleFactory) rawResourceBundleFactory.clone();
      if (extendedResourceBundleFactory.getLocale() == null)
      {
        extendedResourceBundleFactory.setLocale(environment.getLocale());
      }
      if (extendedResourceBundleFactory.getTimeZone() == null)
      {
        extendedResourceBundleFactory.setTimeZone(environment.getTimeZone());
      }
      return extendedResourceBundleFactory;
    }
    catch (CloneNotSupportedException e)
    {
      throw new IllegalStateException("Cannot clone resource-bundle factory");
    }
  }


  /**
   * Returns the resource bundle factory for this report definition. The {@link ResourceBundleFactory} is used in
   * internationalized reports to create the resourcebundles holding the localized resources.
   *
   * @return the assigned resource bundle factory.
   */
  public ResourceBundleFactory getResourceBundleFactory()
  {
    return resourceBundleFactory;
  }

  /**
   * Redefines the resource bundle factory for the report.
   *
   * @param resourceBundleFactory the new resource bundle factory, never null.
   * @throws NullPointerException if the given ResourceBundleFactory is null.
   */
  public void setResourceBundleFactory(final ResourceBundleFactory resourceBundleFactory)
  {
    ArgumentNullException.validate("resourceBundleFactory", resourceBundleFactory);

    this.resourceBundleFactory = resourceBundleFactory;
    this.notifyNodePropertiesChanged();
  }

  public DocumentBundle getBundle()
  {
    final Object o = getAttribute(AttributeNames.Core.NAMESPACE, AttributeNames.Core.BUNDLE);
    if (o instanceof DocumentBundle)
    {
      return (DocumentBundle) o;
    }
    return null;
  }

  public void setBundle(final DocumentBundle bundle)
  {
    setAttribute(AttributeNames.Core.NAMESPACE, AttributeNames.Core.BUNDLE, bundle);
  }

  public ReportParameterDefinition getParameterDefinition()
  {
    return parameterDefinition;
  }

  public void setParameterDefinition(final ReportParameterDefinition parameterDefinition)
  {
    if (parameterDefinition == null)
    {
      throw new NullPointerException();
    }
    this.parameterDefinition = parameterDefinition;
    notifyNodePropertiesChanged();
  }

  public ModifiableReportParameterDefinition getModifiableParameterDefinition()
  {
    if (this.parameterDefinition instanceof ModifiableReportParameterDefinition)
    {
      return (ModifiableReportParameterDefinition) this.parameterDefinition;
    }
    return null;
  }

  public ReportEnvironment getReportEnvironment()
  {
    return reportEnvironment;
  }

  public void setReportEnvironment(final ReportEnvironment reportEnvironment)
  {
    if (reportEnvironment == null)
    {
      throw new NullPointerException();
    }
    this.reportEnvironment = reportEnvironment;
    notifyNodePropertiesChanged();
  }

  public String getTitle()
  {
    final DocumentBundle bundle = getBundle();
    if (bundle != null)
    {
      final Object o = bundle.getMetaData().getBundleAttribute
          (ODFMetaAttributeNames.DublinCore.NAMESPACE, ODFMetaAttributeNames.DublinCore.TITLE);
      if (o != null)
      {
        return o.toString();
      }
    }
    return null;
  }

  /**
   * Returns the logical page definition for this report.
   *
   * @return the page definition.
   */
  public PageDefinition getPageDefinition()
  {
    final PageDefinition pageDefinition = (PageDefinition)
        getAttribute(AttributeNames.Core.NAMESPACE, AttributeNames.Core.PAGE_DEFINITION);
    if (pageDefinition == null)
    {
      return createDefaultPageDefinition();
    }
    return pageDefinition;
  }

  /**
   * Defines the logical page definition for this report. If no format is defined the system's default page format is
   * used.
   * <p/>
   * If there is no printer available and the JDK blocks during the printer discovery, you can set the {@link
   * Configuration} key "org.pentaho.reporting.engine.classic.core.NoPrinterAvailable" to "false" and JFreeReport will
   * use a hardcoded default page format instead.
   *
   * @param format the default format (<code>null</code> permitted).
   */
  public void setPageDefinition(PageDefinition format)
  {
    if (format == null)
    {
      format = createDefaultPageDefinition();
    }
    setAttribute(AttributeNames.Core.NAMESPACE, AttributeNames.Core.PAGE_DEFINITION, format);
    notifyNodePropertiesChanged();
  }

  private PageDefinition createDefaultPageDefinition()
  {
    final PageDefinition format;
    final ExtendedConfiguration config = ClassicEngineBoot.getInstance().getExtendedConfig();
    if (config.getBoolProperty(ClassicEngineCoreModule.NO_PRINTER_AVAILABLE_KEY))
    {
      format = new SimplePageDefinition(new PageFormat());
    }
    else
    {
      format = new SimplePageDefinition(PrinterJob.getPrinterJob().defaultPage());
    }
    return format;
  }

  /**
   * Returns the data factory that has been assigned to this report. The data factory will never be null.
   *
   * @return the data factory.
   */
  public DataFactory getDataFactory()
  {
    return dataFactory;
  }

  /**
   * Sets the data factory for the report.
   *
   * @param dataFactory the data factory for the report, never null.
   */
  public void setDataFactory(final DataFactory dataFactory)
  {
    if (dataFactory == null)
    {
      throw new NullPointerException();
    }

    final DataFactory old = this.dataFactory;
    this.dataFactory = dataFactory;
    notifyNodeChildRemoved(old);
    notifyNodeChildAdded(dataFactory);
  }

  /**
   * Clones the report.
   *
   * @return the clone.
   */
  public MasterReport clone()
  {
    final MasterReport report = (MasterReport) super.clone();
    report.reportConfiguration = (HierarchicalConfiguration) reportConfiguration.clone();
    report.reportEnvironment = (ReportEnvironment) reportEnvironment.clone();
    if (report.reportEnvironment instanceof DefaultReportEnvironment)
    {
      // this is a ugly hack. Needs to be addressed in Sugar
      final DefaultReportEnvironment dre = (DefaultReportEnvironment) report.reportEnvironment;
      dre.update(report.reportConfiguration);
    }
    report.parameterDefinition = (ReportParameterDefinition) parameterDefinition.clone();
    report.parameterValues = (ReportParameterValues) parameterValues.clone();
    report.dataFactory = dataFactory.derive();

    // Add a listener that will handle keeping the ResourceManager in sync with changes to the Document Bundle
    report.addReportModelListener(new DocumentBundleChangeHandler());
    report.addReportModelListener(new ResourceBundleChangeHandler());

    return report;
  }

  public MasterReport derive(final boolean preserveElementInstanceIds)
  {
    final MasterReport report = (MasterReport) super.derive(preserveElementInstanceIds);
    report.reportConfiguration = (HierarchicalConfiguration) reportConfiguration.clone();
    report.reportEnvironment = (ReportEnvironment) reportEnvironment.clone();
    if (report.reportEnvironment instanceof DefaultReportEnvironment)
    {
      // this is a ugly hack. Needs to be addressed in Sugar
      final DefaultReportEnvironment dre = (DefaultReportEnvironment) report.reportEnvironment;
      dre.update(report.reportConfiguration);
    }
    report.parameterDefinition = (ReportParameterDefinition) parameterDefinition.clone();
    report.parameterValues = (ReportParameterValues) parameterValues.clone();
    report.dataFactory = dataFactory.derive();

    // Add a listener that will handle keeping the ResourceManager in sync with changes to the Document Bundle
    report.addReportModelListener(new DocumentBundleChangeHandler());
    report.addReportModelListener(new ResourceBundleChangeHandler());

    return report;
  }

  /**
   * Returns the report configuration.
   * <p/>
   * The report configuration is automatically set up when the report is first created, and uses the global JFreeReport
   * configuration as its parent.
   *
   * @return the report configuration.
   */
  public ModifiableConfiguration getReportConfiguration()
  {
    return reportConfiguration;
  }

  /**
   * Returns the report's configuration.
   *
   * @return the configuration.
   */
  public Configuration getConfiguration()
  {
    return reportConfiguration;
  }

  /**
   * Returns the resource manager that was responsible for loading the report. This method will return a default manager
   * if the report had been constructed otherwise.
   * <p/>
   * The resource manager of the report should be used for all resource loading activities during the report
   * processing.
   *
   * @return the resource manager, never null.
   */
  public ResourceManager getResourceManager()
  {
    if (resourceManager == null)
    {
      resourceManager = new ResourceManager();
      updateResourceBundleFactoryInternal();
    }
    return resourceManager;
  }

  /**
   * Assigns a new resource manager or clears the current one. If no resource manager is set anymore, the next call to
   * 'getResourceManager' will recreate one.
   *
   * @param resourceManager the new resource manager or null.
   */
  public void setResourceManager(final ResourceManager resourceManager)
  {
    this.resourceManager = resourceManager;
    notifyNodePropertiesChanged(resourceManager);
  }

  public ReportParameterValues getParameterValues()
  {
    return parameterValues;
  }

  protected void updateChangedFlagInternal(final ReportElement element, final int type, final Object parameter)
  {
    fireModelLayoutChanged(element, type, parameter);
  }

  /**
   * A helper method that serializes the element object.
   *
   * @param stream the stream to which the element should be serialized.
   * @throws IOException if an IO error occured or a property was not serializable.
   */
  private void writeObject(final ObjectOutputStream stream)
      throws IOException
  {
    stream.defaultWriteObject();
    try
    {
      final DocumentBundle bundle = getBundle();
      stream.writeObject(bundle.getMetaData().getBundleType());

      final MemoryDocumentBundle mem = new MemoryDocumentBundle();
      BundleUtilities.copyStickyInto(mem, bundle);
      BundleUtilities.copyInto(mem, bundle, LegacyBundleResourceRegistry.getInstance().getRegisteredFiles(), true);
      BundleUtilities.copyMetaData(mem, bundle);
      mem.getWriteableDocumentMetaData().setBundleType("application/vnd.pentaho.serialized-bundle");
      final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
      BundleUtilities.writeAsZip(outputStream, mem);
      stream.writeObject(outputStream.toByteArray());
    }
    catch (ContentIOException e)
    {
      throw new IOException("Unable to serialize the bundle", e);
    }
  }

  /**
   * A helper method that deserializes a object from the given stream.
   *
   * @param stream the stream from which to read the object data.
   * @throws IOException            if an IO error occured.
   * @throws ClassNotFoundException if an referenced class cannot be found.
   */
  private void readObject(final ObjectInputStream stream)
      throws IOException, ClassNotFoundException
  {
    stream.defaultReadObject();

    updateResourceBundleFactoryInternal();

    reportConfiguration.reconnectConfiguration(ClassicEngineBoot.getInstance().getGlobalConfig());
    addReportModelListener(new DocumentBundleChangeHandler());

    try
    {
      final String bundleType = (String) stream.readObject();

      final byte[] bundleRawZip = (byte[]) stream.readObject();
      final ResourceManager mgr = getResourceManager();
      final Resource bundleResource = mgr.createDirectly(bundleRawZip, DocumentBundle.class);
      final DocumentBundle bundle = (DocumentBundle) bundleResource.getResource();

      final MemoryDocumentBundle mem = new MemoryDocumentBundle(getContentBase());
      BundleUtilities.copyStickyInto(mem, bundle);
      BundleUtilities.copyInto(mem, bundle, LegacyBundleResourceRegistry.getInstance().getRegisteredFiles(), true);
      BundleUtilities.copyMetaData(mem, bundle);
      mem.getWriteableDocumentMetaData().setBundleType(bundleType);
      setBundle(mem);
    }
    catch (ResourceException e)
    {
      throw new IOException(e);
    }
  }

  private void updateResourceBundleFactoryInternal()
  {
    if (resourceBundleFactory instanceof ExtendedResourceBundleFactory)
    {
      final ExtendedResourceBundleFactory erbf = (ExtendedResourceBundleFactory) resourceBundleFactory;
      erbf.setResourceLoader(getResourceManager(), getContentBase());
    }
  }

  public Integer getCompatibilityLevel()
  {
    final Object definedCompatLevel =
        getAttribute(AttributeNames.Internal.NAMESPACE, AttributeNames.Internal.COMAPTIBILITY_LEVEL);
    if (definedCompatLevel instanceof Integer)
    {
      return (Integer) definedCompatLevel;
    }
    return null;
  }

  public void setCompatibilityLevel(final Integer level)
  {
    setAttribute(AttributeNames.Internal.NAMESPACE, AttributeNames.Internal.COMAPTIBILITY_LEVEL, level);
  }

  public void updateLegacyConfiguration()
  {
  }

  public ElementStyleDefinition getStyleDefinition()
  {
    return (ElementStyleDefinition) getAttribute(AttributeNames.Core.NAMESPACE, AttributeNames.Core.STYLE_SHEET);
  }

  public void setStyleDefinition(final ElementStyleDefinition styleDefinition)
  {
    setAttribute(AttributeNames.Core.NAMESPACE, AttributeNames.Core.STYLE_SHEET, styleDefinition);
  }

  public ResourceKey getStyleSheetReference()
  {
    return (ResourceKey) getAttribute(AttributeNames.Core.NAMESPACE, AttributeNames.Core.STYLE_SHEET_REFERENCE);
  }

  public void setStyleSheetReference(final ResourceKey styleSheetReference)
  {
    setAttribute(AttributeNames.Core.NAMESPACE, AttributeNames.Core.STYLE_SHEET_REFERENCE, styleSheetReference);
  }

  public boolean isStrictLegacyMode()
  {
    return "true".equals(getReportConfiguration().getConfigProperty
        ("org.pentaho.reporting.engine.classic.core.legacy.StrictCompatibility"));
  }

  public void setStrictLegacyMode(final boolean strict)
  {
    getReportConfiguration().setConfigProperty
        ("org.pentaho.reporting.engine.classic.core.legacy.StrictCompatibility", String.valueOf(strict));
  }

  public ReportDefinition getMasterReport()
  {
    return this;
  }
}
TOP

Related Classes of org.pentaho.reporting.engine.classic.core.MasterReport$ResourceBundleChangeHandler

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.