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

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

/*
* 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 - 2009 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.IOException;
import java.io.ObjectInputStream;
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.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.parameters.DefaultParameterDefinition;
import org.pentaho.reporting.engine.classic.core.parameters.ReportParameterDefinition;
import org.pentaho.reporting.engine.classic.core.util.ReportParameterValues;
import org.pentaho.reporting.engine.classic.core.util.LibLoaderResourceBundleFactory;
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.docbundle.DocumentBundle;
import org.pentaho.reporting.libraries.docbundle.MemoryDocumentBundle;
import org.pentaho.reporting.libraries.docbundle.ODFMetaAttributeNames;
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
{
  private static final Log logger = LogFactory.getLog(MasterReport.class);

  /**
   * Key for the 'report name' property.
   */
  public static final String NAME_PROPERTY = "report.name";

  /**
   * 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 ModifiableConfiguration 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 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());
  }

  /**
   * 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)
  {
    if (resourceBundleFactory == null)
    {
      throw new NullPointerException("ResourceBundleFactory must not be null");
    }
    super.setResourceBundleFactory(resourceBundleFactory);
  }

  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 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 name of the report.
   * <p/>
   * You can reference the report name in your XML report template file using the key '<code>report.name</code>'.
   *
   * @return the name.
   */
  public String getName()
  {
    final Object nameFromProperties = getProperty(MasterReport.NAME_PROPERTY);
    if (nameFromProperties == null)
    {
      return super.getName();
    }
    return String.valueOf(nameFromProperties);
  }

  /**
   * Sets the name of the report.
   * <p/>
   * The report name is stored as a property (key {@link MasterReport#NAME_PROPERTY}) inside the report properties.  If
   * you supply <code>null</code> as the name, the property is removed.
   *
   * @param name the name of the report.
   */
  public void setName(final String name)
  {
    super.setName(name);
    super.setProperty(MasterReport.NAME_PROPERTY, name);
  }

  /**
   * 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.
   * @throws CloneNotSupportedException this should never happen.
   */
  public Object clone()
      throws CloneNotSupportedException
  {
    final MasterReport report = (MasterReport) super.clone();
    report.reportConfiguration = (ModifiableConfiguration) 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());

    return report;
  }

  public Element derive()
      throws CloneNotSupportedException
  {
    final MasterReport report = (MasterReport) super.derive();
    report.reportConfiguration = (ModifiableConfiguration) 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());

    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();
      resourceManager.registerDefaults();
      updateResourceBundleFactory();
    }
    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();
  }
 
  public ReportParameterValues getParameterValues()
  {
    return parameterValues;
  }

  /**
   * Adds a property to the report.
   * <p/>
   * If a property with the given name already exists, the property will be updated with the new value. If the supplied
   * value is <code>null</code>, the property will be removed.
   * <p/>
   * Developers are free to add any properties they want to a report, and then display those properties in the report.
   * For example, you might add a 'user.name' property, so that you can display the username in the header of a report.
   *
   * @param key   the key.
   * @param value the value.
   * @deprecated Properties should not be used. Use the master-report's parameters instead.
   */
  public void setProperty(final String key, final Object value)
  {
    super.setProperty(key, value);
    logger.warn("Use of deprecated features: Do not use Report-Properties, use the parameter-values directly.");
    parameterValues.put(key, value);
  }

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

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

    if (getBundle() == null)
    {
      final MemoryDocumentBundle documentBundle = new MemoryDocumentBundle(getContentBase());
      documentBundle.getWriteableDocumentMetaData().setBundleType(ClassicEngineBoot.BUNDLE_TYPE);
      documentBundle.getWriteableDocumentMetaData().setBundleAttribute
          (ODFMetaAttributeNames.Meta.NAMESPACE, ODFMetaAttributeNames.Meta.CREATION_DATE, new Date());
      setBundle(documentBundle);

      setContentBase(documentBundle.getBundleMainKey());
      setResourceManager(documentBundle.getResourceManager());
    }
    addReportModelListener(new DocumentBundleChangeHandler());
  }

  /**
   * 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.getParameter() instanceof AttributeChange == false || event.getElement() instanceof MasterReport == false)
      {
        return;
      }

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

        if (event.getElement() instanceof MasterReport)
        {
          // Insert the DocumentBundle's ResourceManager as the MasterReports resource manager
          log.debug("DocumentBundle change detected - changing the ResourceManager for the MasterReport");
          final MasterReport report = (MasterReport) event.getElement();
          final DocumentBundle newDocumentBundle = (DocumentBundle) value;
          final ResourceManager resourceManager = newDocumentBundle.getResourceManager();
          report.setResourceManager(resourceManager);
        }
        else
        {
          log.warn("Could not replace the ResourceKey on a DocumentBundle change - the element is not a MasterReport");
        }
      }
    }
  }


  public static ResourceBundleFactory computeAndInitResourceBundleFactory
      (final ResourceBundleFactory resourceBundleFactory,
       final ReportEnvironment environment) throws ReportProcessingException
  {
    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 ReportProcessingException("Cannot clone resource-bundle factory");
    }
  }
 
}
TOP

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

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.