/**
   * Encapsulates the logic of registering import handlers, generating the manifest, and performing
   * the export
   */
  public ZipExportProcessor(String path, IUnifiedRepository repository, boolean withManifest) {
    this.withManifest = withManifest;

    // set a default path at root if missing
    if (StringUtils.isEmpty(path)) {
      this.path = "/";
    } else {
      this.path = path;
    }

    this.unifiedRepository = repository;

    this.exportHandlerList = new ArrayList<ExportHandler>();

    this.exportManifest = new ExportManifest();

    // set created by and create date in manifest information
    IPentahoSession session = PentahoSessionHolder.getSession();

    Date todaysDate = new Date();
    SimpleDateFormat dateFormat = new SimpleDateFormat(EXPORT_INFO_DATE_FORMAT);
    SimpleDateFormat timeFormat = new SimpleDateFormat(EXPORT_INFO_TIME_FORMAT);

    exportManifest.getManifestInformation().setExportBy(session.getName());
    exportManifest
        .getManifestInformation()
        .setExportDate(dateFormat.format(todaysDate) + " " + timeFormat.format(todaysDate));
  }
 private void initializeAclManifest(IRepositoryFileBundle file) {
   try {
     byte[] bytes = IOUtils.toByteArray(file.getInputStream());
     ByteArrayInputStream in = new ByteArrayInputStream(bytes);
     getImportSession().setManifest(ExportManifest.fromXml(in));
   } catch (Exception e) {
     log.trace(e);
   }
 }
 /**
  * create an entry in the export manifest for this file or folder
  *
  * @param repositoryFile
  * @throws ExportException
  */
 private void addToManifest(RepositoryFile repositoryFile) throws ExportException {
   if (this.withManifest) {
     // add this entity to the manifest
     RepositoryFileAcl fileAcl = unifiedRepository.getAcl(repositoryFile.getId());
     try {
       exportManifest.add(repositoryFile, fileAcl);
     } catch (ExportManifestFormatException e) {
       throw new ExportException(e.getMessage());
     }
   }
 }
  protected void importMetaStore(ExportManifest manifest, boolean overwrite) {
    // get the metastore
    if (manifest != null) {
      ExportManifestMetaStore manifestMetaStore = manifest.getMetaStore();
      if (manifestMetaStore != null) {
        // get the zipped metastore from the export bundle
        RepositoryFileImportBundle.Builder bundleBuilder =
            new RepositoryFileImportBundle.Builder()
                .path(manifestMetaStore.getFile())
                .name(manifestMetaStore.getName())
                .withParam("description", manifestMetaStore.getDescription())
                .charSet("UTF-8")
                .overwriteFile(overwrite)
                .mime("application/vnd.pentaho.metastore");

        cachedImports.put(manifestMetaStore.getFile(), bundleBuilder);
      }
    }
  }
  public void importFile(IPlatformImportBundle bundle)
      throws PlatformImportException, DomainIdNullException, DomainAlreadyExistsException,
          DomainStorageException, IOException {

    RepositoryFileImportBundle importBundle = (RepositoryFileImportBundle) bundle;
    ZipInputStream zipImportStream = new ZipInputStream(bundle.getInputStream());
    SolutionRepositoryImportSource importSource =
        new SolutionRepositoryImportSource(zipImportStream);
    LocaleFilesProcessor localeFilesProcessor = new LocaleFilesProcessor();
    setOverwriteFile(bundle.overwriteInRepository());
    // importSession.set(ImportSession.getSession());

    IPlatformImporter importer = PentahoSystem.get(IPlatformImporter.class);

    cachedImports = new HashMap<String, RepositoryFileImportBundle.Builder>();

    // Process Manifest Settings
    ExportManifest manifest = getImportSession().getManifest();
    String manifestVersion = null;
    if (manifest != null) {
      manifestVersion = manifest.getManifestInformation().getManifestVersion();
    }
    // Process Metadata
    if (manifest != null) {

      // import the users
      Map<String, List<String>> roleToUserMap = importUsers(manifest.getUserExports());
      // import the roles
      importRoles(manifest.getRoleExports(), roleToUserMap);

      List<ExportManifestMetadata> metadataList = manifest.getMetadataList();
      for (ExportManifestMetadata exportManifestMetadata : metadataList) {

        String domainId = exportManifestMetadata.getDomainId();
        boolean overWriteInRepository = isOverwriteFile();
        RepositoryFileImportBundle.Builder bundleBuilder =
            new RepositoryFileImportBundle.Builder()
                .charSet("UTF-8")
                .hidden(false)
                // let the parent bundle control whether or not to preserve DSW settings
                .preserveDsw(bundle.isPreserveDsw())
                .overwriteFile(overWriteInRepository)
                .mime("text/xmi+xml")
                .withParam("domain-id", domainId);

        cachedImports.put(exportManifestMetadata.getFile(), bundleBuilder);
      }

      // Process Mondrian
      List<ExportManifestMondrian> mondrianList = manifest.getMondrianList();
      for (ExportManifestMondrian exportManifestMondrian : mondrianList) {

        String catName = exportManifestMondrian.getCatalogName();
        Parameters parametersMap = exportManifestMondrian.getParameters();
        StringBuilder parametersStr = new StringBuilder();
        for (String s : parametersMap.keySet()) {
          parametersStr.append(s).append("=").append(parametersMap.get(s)).append(sep);
        }

        RepositoryFileImportBundle.Builder bundleBuilder =
            new RepositoryFileImportBundle.Builder()
                .charSet("UTF_8")
                .hidden(false)
                .name(catName)
                .overwriteFile(isOverwriteFile())
                .mime("application/vnd.pentaho.mondrian+xml")
                .withParam("parameters", parametersStr.toString())
                .withParam("domain-id", catName); // TODO: this is
        // definitely
        // named wrong
        // at the very
        // least.
        // pass as param if not in parameters string
        String xmlaEnabled = "" + exportManifestMondrian.isXmlaEnabled();
        bundleBuilder.withParam("EnableXmla", xmlaEnabled);

        cachedImports.put(exportManifestMondrian.getFile(), bundleBuilder);

        String annotationsFile = exportManifestMondrian.getAnnotationsFile();
        if (annotationsFile != null) {
          RepositoryFileImportBundle.Builder annotationsBundle =
              new RepositoryFileImportBundle.Builder()
                  .path(
                      MondrianCatalogRepositoryHelper.ETC_MONDRIAN_JCR_FOLDER
                          + RepositoryFile.SEPARATOR
                          + catName)
                  .name("annotations.xml")
                  .charSet("UTF_8")
                  .overwriteFile(isOverwriteFile())
                  .mime("text/xml")
                  .hidden(false)
                  .withParam("domain-id", catName);
          cachedImports.put(annotationsFile, annotationsBundle);
        }
      }
    }

    importMetaStore(manifest, bundle.overwriteInRepository());

    for (IRepositoryFileBundle file : importSource.getFiles()) {
      String fileName = file.getFile().getName();
      String actualFilePath = file.getPath();
      if (manifestVersion != null) {
        fileName = ExportFileNameEncoder.decodeZipFileName(fileName);
        actualFilePath = ExportFileNameEncoder.decodeZipFileName(actualFilePath);
      }
      String repositoryFilePath =
          RepositoryFilenameUtils.concat(
              PentahoPlatformImporter.computeBundlePath(actualFilePath), fileName);

      if (this.cachedImports.containsKey(repositoryFilePath)) {

        byte[] bytes = IOUtils.toByteArray(file.getInputStream());
        RepositoryFileImportBundle.Builder builder = cachedImports.get(repositoryFilePath);
        builder.input(new ByteArrayInputStream(bytes));

        importer.importFile(build(builder));
        continue;
      }
      RepositoryFileImportBundle.Builder bundleBuilder = new RepositoryFileImportBundle.Builder();

      InputStream bundleInputStream = null;

      String decodedFilePath = file.getPath();
      RepositoryFile decodedFile = file.getFile();
      if (manifestVersion != null) {
        decodedFile =
            new RepositoryFile.Builder(decodedFile)
                .path(decodedFilePath)
                .name(fileName)
                .title(fileName)
                .build();
        decodedFilePath = ExportFileNameEncoder.decodeZipFileName(file.getPath());
      }

      if (file.getFile().isFolder()) {
        bundleBuilder.mime("text/directory");
        bundleBuilder.file(decodedFile);
        fileName = repositoryFilePath;
        repositoryFilePath = importBundle.getPath();
      } else {
        byte[] bytes = IOUtils.toByteArray(file.getInputStream());
        bundleInputStream = new ByteArrayInputStream(bytes);
        // If is locale file store it for later processing.
        if (localeFilesProcessor.isLocaleFile(file, importBundle.getPath(), bytes)) {
          log.trace("Skipping [" + repositoryFilePath + "], it is a locale property file");
          continue;
        }
        bundleBuilder.input(bundleInputStream);
        bundleBuilder.mime(solutionHelper.getMime(fileName));

        String filePath =
            (decodedFilePath.equals("/") || decodedFilePath.equals("\\")) ? "" : decodedFilePath;
        repositoryFilePath = RepositoryFilenameUtils.concat(importBundle.getPath(), filePath);
      }

      bundleBuilder.name(fileName);
      bundleBuilder.path(repositoryFilePath);

      String sourcePath;
      if (decodedFilePath.startsWith("/")) {
        sourcePath = RepositoryFilenameUtils.concat(decodedFilePath.substring(1), fileName);
      } else {
        if (file.getFile().isFolder()) {
          sourcePath = fileName;
        } else {
          sourcePath = RepositoryFilenameUtils.concat(decodedFilePath, fileName);
        }
      }

      // This clause was added for processing ivb files so that it would not try process acls on
      // folders that the user
      // may not have rights to such as /home or /public
      if (manifest != null
          && manifest.getExportManifestEntity(sourcePath) == null
          && file.getFile().isFolder()) {
        continue;
      }

      getImportSession().setCurrentManifestKey(sourcePath);

      bundleBuilder.charSet(bundle.getCharset());
      bundleBuilder.overwriteFile(bundle.overwriteInRepository());
      bundleBuilder.hidden(isFileHidden(bundle, sourcePath));
      bundleBuilder.applyAclSettings(bundle.isApplyAclSettings());
      bundleBuilder.retainOwnership(bundle.isRetainOwnership());
      bundleBuilder.overwriteAclSettings(bundle.isOverwriteAclSettings());
      bundleBuilder.acl(getImportSession().processAclForFile(sourcePath));
      IPlatformImportBundle platformImportBundle = build(bundleBuilder);
      importer.importFile(platformImportBundle);

      if (bundleInputStream != null) {
        bundleInputStream.close();
        bundleInputStream = null;
      }
    }
    if (manifest != null) {
      List<JobScheduleRequest> scheduleList = manifest.getScheduleList();
      if (scheduleList != null) {
        SchedulerResource schedulerResource = new SchedulerResource();
        for (JobScheduleRequest jobScheduleRequest : scheduleList) {
          try {
            Response response = createSchedulerJob(schedulerResource, jobScheduleRequest);
            if (response.getStatus() == Response.Status.OK.getStatusCode()) {
              if (response.getEntity() != null) {
                // get the schedule job id from the response and add it to the import session
                ImportSession.getSession()
                    .addImportedScheduleJobId(response.getEntity().toString());
              }
            }
          } catch (Exception e) {
            // there is a scenario where if the file scheduled has a space in the path, that it
            // won't work. the di server
            // replaces spaces with underscores and the export mechanism can't determine if it needs
            // this to happen or not
            // so, if we failed to import and there is a space in the path, try again but this time
            // with replacing the space(s)
            if (jobScheduleRequest.getInputFile().contains(" ")
                || jobScheduleRequest.getOutputFile().contains(" ")) {
              log.info(
                  "Could not import schedule, attempting to replace spaces with underscores and retrying: "
                      + jobScheduleRequest.getInputFile());

              jobScheduleRequest.setInputFile(
                  jobScheduleRequest.getInputFile().replaceAll(" ", "_"));
              jobScheduleRequest.setOutputFile(
                  jobScheduleRequest.getOutputFile().replaceAll(" ", "_"));
              try {
                Response response = createSchedulerJob(schedulerResource, jobScheduleRequest);
                if (response.getStatus() == Response.Status.OK.getStatusCode()) {
                  if (response.getEntity() != null) {
                    // get the schedule job id from the response and add it to the import session
                    ImportSession.getSession()
                        .addImportedScheduleJobId(response.getEntity().toString());
                  }
                }
              } catch (Exception ex) {
                throw new PlatformImportException(
                    Messages.getInstance()
                        .getString(
                            "SolutionImportHandler.ERROR_0001_ERROR_CREATING_SCHEDULE",
                            e.getMessage()));
              }
            } else {
              throw new PlatformImportException(
                  Messages.getInstance()
                      .getString(
                          "SolutionImportHandler.ERROR_0001_ERROR_CREATING_SCHEDULE",
                          e.getMessage()));
            }
          }
        }
      }

      // Add Pentaho Connections
      List<org.pentaho.database.model.DatabaseConnection> datasourceList =
          manifest.getDatasourceList();
      if (datasourceList != null) {
        IDatasourceMgmtService datasourceMgmtSvc = PentahoSystem.get(IDatasourceMgmtService.class);
        for (org.pentaho.database.model.DatabaseConnection databaseConnection : datasourceList) {
          if (databaseConnection.getDatabaseType() == null) {
            // don't try to import the connection if there is no type it will cause an error
            // However, if this is the DI Server, and the connection is defined in a ktr, it will
            // import automatically
            log.warn(
                "Can't import connection "
                    + databaseConnection.getName()
                    + " because it doesn't have a databaseType");
            continue;
          }
          try {
            IDatabaseConnection existingDBConnection =
                datasourceMgmtSvc.getDatasourceByName(databaseConnection.getName());
            if (existingDBConnection != null && existingDBConnection.getName() != null) {
              if (isOverwriteFile()) {
                databaseConnection.setId(existingDBConnection.getId());
                datasourceMgmtSvc.updateDatasourceByName(
                    databaseConnection.getName(), databaseConnection);
              }
            } else {
              datasourceMgmtSvc.createDatasource(databaseConnection);
            }
          } catch (Exception e) {
            e.printStackTrace();
          }
        }
      }
    }
    // Process locale files.
    localeFilesProcessor.processLocaleFiles(importer);
  }
  /**
   * Performs the export process, returns a zip File object
   *
   * @throws ExportException indicates an error in import processing
   */
  public File performExport(RepositoryFile exportRepositoryFile)
      throws ExportException, IOException {
    File exportFile = null;

    // create temp file
    exportFile = File.createTempFile(EXPORT_TEMP_FILENAME_PREFIX, EXPORT_TEMP_FILENAME_EXT);
    exportFile.deleteOnExit();

    // get the file path
    String filePath = new File(this.path).getParent();
    if (filePath == null) {
      filePath = "/";
    }

    // send a response right away if not found
    if (exportRepositoryFile == null) {
      // todo: add to messages.properties
      throw new FileNotFoundException("JCR file not found: " + this.path);
    }

    ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(exportFile));

    if (exportRepositoryFile.isFolder()) { // Handle recursive export
      exportManifest
          .getManifestInformation()
          .setRootFolder(path.substring(0, path.lastIndexOf("/") + 1));

      // don't zip root folder without name
      if (!ClientRepositoryPaths.getRootFolderPath().equals(exportRepositoryFile.getPath())) {
        zos.putNextEntry(new ZipEntry(getZipEntryName(exportRepositoryFile, filePath)));
      }
      exportDirectory(exportRepositoryFile, zos, filePath);

    } else {
      exportManifest
          .getManifestInformation()
          .setRootFolder(path.substring(0, path.lastIndexOf("/") + 1));
      exportFile(exportRepositoryFile, zos, filePath);
    }

    if (this.withManifest) {
      // write manifest to zip output stream
      ZipEntry entry = new ZipEntry(EXPORT_MANIFEST_FILENAME);
      zos.putNextEntry(entry);

      // pass output stream to manifest class for writing
      try {
        exportManifest.toXml(zos);
      } catch (Exception e) {
        // todo: add to messages.properties
        log.error("Error generating export XML");
      }

      zos.closeEntry();
    }

    zos.close();

    // clean up
    exportManifest = null;
    zos = null;

    return exportFile;
  }