public void testGoldRun() throws Exception {
    final File file = GoldTestBase.locateGoldenSampleReport("Prd-3239.prpt");
    final ResourceManager mgr = new ResourceManager();
    mgr.registerDefaults();
    final Resource directly = mgr.createDirectly(file, MasterReport.class);
    final MasterReport report = (MasterReport) directly.getResource();
    report.setCompatibilityLevel(ClassicEngineBoot.computeVersionId(3, 8, 0));

    DebugReportRunner.createXmlFlow(report);
  }
 public static int parseVersionId(final String text) {
   final StringTokenizer strtok = new StringTokenizer(text, ".");
   if (strtok.countTokens() == 3) {
     final int major = ParserUtil.parseInt(strtok.nextToken(), -1);
     final int minor = ParserUtil.parseInt(strtok.nextToken(), -1);
     final int patch = ParserUtil.parseInt(strtok.nextToken(), -1);
     if (major == -1 || minor == -1 || patch == -1) {
       return -1;
     } else {
       return (ClassicEngineBoot.computeVersionId(major, minor, patch));
     }
   } else {
     return -1;
   }
 }
  public String decrypt(final RootXmlReadHandler root, final String encryptedPassword) {
    if (StringUtils.isEmpty(encryptedPassword)) {
      // empty string vs. null may have significance.
      return encryptedPassword;
    }

    final Object helperObject = root.getHelperObject(ContentRootElementHandler.PRPT_SPEC_VERSION);
    final boolean legacyFix;
    if (helperObject instanceof Integer) {
      final Integer version = (Integer) helperObject;
      if (version == -1) {
        logger.warn("Decrypting password skipped, as we are dealing with an older version. ");
        return encryptedPassword;
      }

      legacyFix = (version.intValue() < ClassicEngineBoot.computeVersionId(5, 0, 0));
    } else {
      legacyFix = false;
    }

    final int separatorPos = encryptedPassword.indexOf(':');
    if (separatorPos == -1) {
      // assume legacy mode
      logger.warn("Decrypting password skipped, as the password-text has no service indicator. ");
      return encryptedPassword;
    }

    final String serviceName = encryptedPassword.substring(0, separatorPos);
    final String payload = encryptedPassword.substring(separatorPos + 1);
    final PasswordEncryptionServiceProvider provider = services.get(serviceName);

    if (legacyFix
        && ObscurificatePasswordEncryptionServiceProvider.SERVICE_TAG.equals(serviceName)) {
      return new Obscurificate48PasswordEncryptionServiceProvider().decrypt(payload);
    }
    if (provider != null) {
      return provider.decrypt(payload);
    }
    logger.debug("Decrypting password skipped, as the service indicator is not recognized. ");
    return encryptedPassword;
  }
/**
 * An utility class to safely boot and initialize the Pentaho-Reporting library. This class should
 * be called before using the Pentaho-Reporting classes, to make sure that all subsystems are
 * initialized correctly and in the correct order.
 *
 * <p>Application developers should make sure, that the booting is done before any Pentaho-Reporting
 * functions are used. If the system has not be initialized by booting this class, anything can
 * happen and the results of all functionality of this reporting engine will be undefined.
 *
 * <p>Additional modules can be specified by defining the system property <code>
 * "org.pentaho.reporting.engine.classic.core.boot.Modules"</code>. The property expects a
 * comma-separated list of {@link org.pentaho.reporting.libraries.base.boot.Module} implementations.
 *
 * <p>Booting should be done by aquirering a new boot instance using {@link
 * ClassicEngineBoot#getInstance()} and then starting the boot process with {@link
 * ClassicEngineBoot#start()}.
 *
 * @author Thomas Morgner
 */
public class ClassicEngineBoot extends AbstractBoot {
  public static final int VERSION_TRUNK = ClassicEngineBoot.computeVersionId(999, 999, 999);
  public static final int VERSION_3_8 = ClassicEngineBoot.computeVersionId(3, 8, 0);
  public static final int VERSION_3_9 = ClassicEngineBoot.computeVersionId(3, 9, 0);
  public static final int VERSION_4_0 = ClassicEngineBoot.computeVersionId(4, 0, 0);

  public static final String INDEX_COLUMN_PREFIX = "::column::";
  public static final String METADATA_NAMESPACE =
      "http://reporting.pentaho.org/namespaces/engine/classic/metadata/1.0";
  public static final String DATASCHEMA_NAMESPACE =
      "http://reporting.pentaho.org/namespaces/engine/classic/dataschema/1.0";
  public static final String BUNDLE_TYPE = "application/vnd.pentaho.reporting.classic";

  private static final Log logger = LogFactory.getLog(ClassicEngineBoot.class);

  /** A wrappper around the user supplied global configuration. */
  private static class UserConfigWrapper extends HierarchicalConfiguration {
    /** The wrapped configuration. */
    private Configuration wrappedConfiguration;

    /** Default constructor. */
    protected UserConfigWrapper() {
      this(null);
    }

    /**
     * Creates a new user-configuration wrapper for the given configuration.
     *
     * @param config the user-provided configuration that should be wrapped.
     */
    protected UserConfigWrapper(final Configuration config) {
      this.wrappedConfiguration = config;
    }

    /**
     * Sets a new configuration. This configuration will be inserted into the report configuration
     * hierarchy. Set this property to null to disable the user defined configuration.
     *
     * @param wrappedConfiguration the wrapped configuration.
     */
    public void setWrappedConfiguration(final Configuration wrappedConfiguration) {
      this.wrappedConfiguration = wrappedConfiguration;
    }

    /**
     * Returns the user supplied global configuration, if exists.
     *
     * @return the user configuration.
     */
    public Configuration getWrappedConfiguration() {
      return wrappedConfiguration;
    }

    /**
     * Returns the configuration property with the specified key.
     *
     * @param key the property key.
     * @return the property value.
     */
    public String getConfigProperty(final String key) {
      if (wrappedConfiguration == null) {
        return getParentConfig().getConfigProperty(key);
      }

      final String retval = wrappedConfiguration.getConfigProperty(key);
      if (retval != null) {
        return retval;
      }
      return getParentConfig().getConfigProperty(key);
    }

    /**
     * Returns the configuration property with the specified key (or the specified default value if
     * there is no such property).
     *
     * <p>If the property is not defined in this configuration, the code will lookup the property in
     * the parent configuration.
     *
     * @param key the property key.
     * @param defaultValue the default value.
     * @return the property value.
     */
    public String getConfigProperty(final String key, final String defaultValue) {
      if (wrappedConfiguration == null) {
        return getParentConfig().getConfigProperty(key, defaultValue);
      }

      final String retval = wrappedConfiguration.getConfigProperty(key, null);
      if (retval != null) {
        return retval;
      }
      return getParentConfig().getConfigProperty(key, defaultValue);
    }

    /**
     * Sets a configuration property.
     *
     * @param key the property key.
     * @param value the property value.
     */
    public void setConfigProperty(final String key, final String value) {
      if (wrappedConfiguration instanceof ModifiableConfiguration) {
        final ModifiableConfiguration modConfiguration =
            (ModifiableConfiguration) wrappedConfiguration;
        modConfiguration.setConfigProperty(key, value);
      }
    }

    /**
     * Returns all defined configuration properties for the report. The enumeration contains all
     * keys of the changed properties, properties set from files or the system properties are not
     * included.
     *
     * @return all defined configuration properties for the report.
     */
    public Enumeration<String> getConfigProperties() {
      if (wrappedConfiguration instanceof ModifiableConfiguration) {
        final ModifiableConfiguration modConfiguration =
            (ModifiableConfiguration) wrappedConfiguration;
        return modConfiguration.getConfigProperties();
      }
      return super.getConfigProperties();
    }
  }

  /** The singleton instance of the Boot class. */
  private static ClassicEngineBoot instance;
  /** The project info contains all meta data about the project. */
  private ProjectInformation projectInfo;

  /** Holds a possibly empty reference to a user-supplied Configuration implementation. */
  private static final UserConfigWrapper configWrapper = new UserConfigWrapper();

  /** Creates a new instance. */
  private ClassicEngineBoot() {
    projectInfo = ClassicEngineInfo.getInstance();
  }

  /**
   * Returns the singleton instance of the boot utility class.
   *
   * @return the boot instance.
   */
  public static synchronized ClassicEngineBoot getInstance() {
    if (instance == null) {
      instance = new ClassicEngineBoot();
    }
    return instance;
  }

  /**
   * Returns the current global configuration as modifiable instance. This is exactly the same as
   * casting the global configuration into a ModifableConfiguration instance.
   *
   * <p>This is a convinience function, as all programmers are lazy.
   *
   * @return the global config as modifiable configuration.
   */
  public ModifiableConfiguration getEditableConfig() {
    return (ModifiableConfiguration) getGlobalConfig();
  }

  /**
   * Returns the project info.
   *
   * @return The project info.
   */
  protected ProjectInformation getProjectInfo() {
    return projectInfo;
  }

  /**
   * Loads the configuration. This will be called exactly once.
   *
   * @return The configuration.
   */
  protected Configuration loadConfiguration() {
    final HierarchicalConfiguration globalConfig =
        createDefaultHierarchicalConfiguration(
            "/org/pentaho/reporting/engine/classic/core/classic-engine.properties",
            "/classic-engine.properties",
            false,
            ClassicEngineBoot.class);

    globalConfig.insertConfiguration(ClassicEngineBoot.configWrapper);

    final SystemPropertyConfiguration systemConfig = new SystemPropertyConfiguration();
    globalConfig.insertConfiguration(systemConfig);
    return globalConfig;
  }

  /** Performs the actual boot process. */
  protected void performBoot() {
    if (ClassicEngineBoot.isStrictFP() == false) {
      ClassicEngineBoot.logger.warn(
          "The used VM seems to use a non-strict floating point arithmetics"); // NON-NLS
      ClassicEngineBoot.logger.warn(
          "Layouts computed with this Java Virtual Maschine may be invalid."); // NON-NLS
      ClassicEngineBoot.logger.warn(
          "JFreeReport and the library 'iText' depend on the strict floating point rules"); // NON-NLS
      ClassicEngineBoot.logger.warn(
          "of Java1.1 as implemented by the Sun Virtual Maschines."); // NON-NLS
      ClassicEngineBoot.logger.warn(
          "If you are using the BEA JRockit VM, start the Java VM with the option"); // NON-NLS
      ClassicEngineBoot.logger.warn("'-Xstrictfp' to restore the default behaviour."); // NON-NLS
    }

    final PackageManager mgr = getPackageManager();

    mgr.addModule(ClassicEngineCoreModule.class.getName());
    mgr.load("org.pentaho.reporting.engine.classic.core.modules."); // NON-NLS
    mgr.load("org.pentaho.reporting.engine.classic.extensions.modules."); // NON-NLS
    mgr.load("org.pentaho.reporting.engine.classic.extensions.datasources."); // NON-NLS
    mgr.load("org.pentaho.reporting.engine.classic.core.userdefined.modules."); // NON-NLS

    bootAdditionalModules();
    mgr.initializeModules();

    if (mgr.isModuleAvailable(ClassicEngineCoreModule.class.getName()) == false) {
      throw new IllegalStateException("Booting the report-engine failed.");
    }

    StyleKey.lock();
  }

  /**
   * Boots modules, which have been spcified in the
   * "org.pentaho.reporting.engine.classic.core.boot.Modules" configuration parameter.
   */
  private void bootAdditionalModules() {
    try {
      final String bootModules =
          getGlobalConfig()
              .getConfigProperty(
                  "org.pentaho.reporting.engine.classic.core.boot.Modules"); // NON-NLS
      if (bootModules != null) {
        final CSVTokenizer csvToken = new CSVTokenizer(bootModules, ",");
        while (csvToken.hasMoreTokens()) {
          final String token = csvToken.nextToken();
          getPackageManager().load(token);
        }
      }
    } catch (SecurityException se) {
      // we'll ignore any Security exception ..
      ClassicEngineBoot.logger.info(
          "Security settings forbid to check the system properties for extension modules."); // NON-NLS
    } catch (Exception se) {
      ClassicEngineBoot.logger.error(
          "An error occured while checking the system properties for extension modules.", // NON-NLS
          se);
    }
  }

  /**
   * This method returns true on non-strict floating point systems.
   *
   * <p>Since Java 1.2 Virtual Maschines may implement the floating point arithmetics in a more
   * performant way, which does not put the old strict constraints on the floating point types
   * <code>float</code> and <code>double</code>.
   *
   * <p>As iText and this library requires strict (in the sense of Java1.1) floating point
   * operations, we have to test for that feature here.
   *
   * <p>The only known VM that seems to implement that feature is the JRockit VM. The strict mode
   * can be restored on that VM by adding the "-Xstrictfp" VM parameter.
   *
   * @return true, if the VM uses strict floating points by default, false otherwise.
   */
  private static boolean isStrictFP() {
    final double d = 8.0e+307;
    final double result1 = 4.0 * d * 0.5;
    final double result2 = 2.0 * d;
    return (result1 != result2 && (result1 == Double.POSITIVE_INFINITY));
  }

  /**
   * Returns the user supplied global configuration.
   *
   * @return the user configuration, if any.
   */
  public static Configuration getUserConfig() {
    return configWrapper.getWrappedConfiguration();
  }

  /**
   * Defines the global user configuration.
   *
   * @param config the user configuration.
   */
  public static void setUserConfig(final Configuration config) {
    configWrapper.setWrappedConfiguration(config);
  }

  /**
   * A helper method that checks, whether a given module is available. The result of this method is
   * undefined if the system has no been booted yet.
   *
   * @param moduleClass the class-name of the module that should be tested.
   * @return true, if the module is available and has been initialized correctly, false otherwise.
   */
  public boolean isModuleAvailable(final String moduleClass) {
    return getPackageManager()
        .isModuleAvailable(new DefaultModuleInfo(moduleClass, null, null, null));
  }

  public enum VersionValidity {
    VALID,
    INVALID_RELEASE,
    INVALID_PATCH
  }

  public static int parseVersionId(final String text) {
    final StringTokenizer strtok = new StringTokenizer(text, ".");
    if (strtok.countTokens() == 3) {
      final int major = ParserUtil.parseInt(strtok.nextToken(), -1);
      final int minor = ParserUtil.parseInt(strtok.nextToken(), -1);
      final int patch = ParserUtil.parseInt(strtok.nextToken(), -1);
      if (major == -1 || minor == -1 || patch == -1) {
        return -1;
      } else {
        return (ClassicEngineBoot.computeVersionId(major, minor, patch));
      }
    } else {
      return -1;
    }
  }

  public static String printVersion(final int versionId) {
    if (versionId <= 0 || versionId > 999000000) {
      return "TRUNK";
    }

    final int patch = versionId % 1000;
    final int minor = (versionId / 1000) % 1000;
    final int major = (versionId / 1000000);
    return String.format("%d.%d.%d", major, minor, patch);
  }

  public static int computeCurrentVersionId() {
    final int releaseMajor =
        ParserUtil.parseInt(ClassicEngineInfo.getInstance().getReleaseMajor(), 999);
    final int releaseMinor =
        ParserUtil.parseInt(ClassicEngineInfo.getInstance().getReleaseMinor(), 999);
    final int releasePatch =
        ParserUtil.parseInt(ClassicEngineInfo.getInstance().getReleaseMilestone(), 999);
    final int version = computeVersionId(releaseMajor, releaseMinor, releasePatch);
    if (version == 0) {
      return VERSION_TRUNK;
    }
    return version;
  }

  public static int computeVersionId(
      final int prptVersionMajorRaw, final int prptVersionMinorRaw, final int prptVersionPatchRaw) {
    return prptVersionMajorRaw * 1000000 + prptVersionMinorRaw * 1000 + prptVersionPatchRaw;
  }

  public static VersionValidity isValidVersion(
      final int prptVersionMajorRaw, final int prptVersionMinorRaw, final int prptVersionPatchRaw) {
    return getInstance()
        .isValidVersion(
            prptVersionMajorRaw,
            prptVersionMinorRaw,
            prptVersionPatchRaw,
            ClassicEngineInfo.getInstance());
  }

  protected VersionValidity isValidVersion(
      final int prptVersionMajorRaw,
      final int prptVersionMinorRaw,
      final int prptVersionPatchRaw,
      final ProjectInformation info) {
    final int releaseMajor = ParserUtil.parseInt(info.getReleaseMajor(), 999);
    final int releaseMinor = ParserUtil.parseInt(info.getReleaseMinor(), 999);
    final int releasePatch = ParserUtil.parseInt(info.getReleaseMilestone(), 999);
    if (computeVersionId(prptVersionMajorRaw, prptVersionMinorRaw, prptVersionPatchRaw)
        == VERSION_TRUNK) {
      return VersionValidity.VALID;
    }

    if ((prptVersionMajorRaw * 1000 + prptVersionMinorRaw) > (releaseMajor * 1000 + releaseMinor)) {
      return VersionValidity.INVALID_RELEASE;
    }

    if ((prptVersionMajorRaw * 1000 + prptVersionMinorRaw)
        == (releaseMajor * 1000 + releaseMinor)) {
      if (prptVersionPatchRaw > releasePatch) {
        return VersionValidity.INVALID_PATCH;
      }
    }
    return VersionValidity.VALID;
  }

  public static boolean isEnforceCompatibilityFor(
      final int level, final int prptVersionMajorRaw, final int prptVersionMinorRaw) {
    return isEnforceCompatibilityFor(level, prptVersionMajorRaw, prptVersionMinorRaw, 999);
  }

  public static boolean isEnforceCompatibilityFor(
      final int level,
      final int prptVersionMajorRaw,
      final int prptVersionMinorRaw,
      final int prptVersionPatchRaw) {
    if (level == -1) {
      return false;
    }
    return level <= computeVersionId(prptVersionMajorRaw, prptVersionMinorRaw, prptVersionPatchRaw);
  }
}
 public void testOrphan1Crash() throws Exception {
   final MasterReport masterReport =
       DebugReportRunner.parseGoldenSampleReport("Prd-2087-Orphan-0.prpt");
   masterReport.setCompatibilityLevel(ClassicEngineBoot.computeVersionId(3, 8, 0));
   DebugReportRunner.createXmlTablePageable(masterReport);
 }
 protected MasterReport tuneForLegacyMode(final MasterReport report) {
   report.setCompatibilityLevel(ClassicEngineBoot.computeVersionId(3, 8, 0));
   return report;
 }