public void validateDoMapping(
      final JiraServiceContext jiraServiceContext,
      final ProjectImportOptions projectImportOptions,
      final BackupProject backupProject,
      final BackupSystemInformation backupSystemInformation) {
    Null.not("projectImportOptions", projectImportOptions);
    Null.not("backupSystemInformation", backupSystemInformation);
    validateJiraServiceContext(jiraServiceContext);
    final ErrorCollection errorCollection = jiraServiceContext.getErrorCollection();
    final I18nHelper i18n = jiraServiceContext.getI18nBean();

    // The user must have the system administrator permission to perform a project import
    if (!userHasSysAdminPermission(jiraServiceContext.getUser())) {
      errorCollection.addErrorMessage(getText(i18n, "admin.errors.project.import.must.be.admin"));
    }

    // Check the pathToBackupXml is valid
    if (StringUtils.isEmpty(projectImportOptions.getPathToBackupXml())) {
      errorCollection.addErrorMessage(
          getText(i18n, "admin.errors.project.import.provide.backup.path"));
    } else if (!pathExists(projectImportOptions.getPathToBackupXml(), true)) {
      errorCollection.addErrorMessage(
          getText(i18n, "admin.errors.project.import.invalid.backup.path"));
    }

    // Check that we are being provided a backup project
    if (backupProject == null) {
      errorCollection.addErrorMessage(
          getText(i18n, "admin.errors.project.import.no.backup.project"));
    }
  }
Пример #2
0
 public void doValidation(
     String key, Map<String, String> parameters, JiraServiceContext jiraServiceContext) {
   // JRA-13808: Need to check whether or not the user CF has a searcher set.
   String customFieldOption = parameters.get(getType());
   if (StringUtils.isEmpty(customFieldOption)) {
     String localisedMessage =
         jiraServiceContext
             .getI18nBean()
             .getText("admin.permissions.errors.please.select.user.customfield");
     jiraServiceContext.getErrorCollection().addErrorMessage(localisedMessage);
   } else {
     // passed in parameters names a Custom Field - lets investigate.
     CustomField customField = customFieldManager.getCustomFieldObject(customFieldOption);
     if (customField != null && customField.getCustomFieldSearcher() == null) {
       // In order to use a Custom Field it must be indexed in Lucene Index. Currently we only
       // index custom fields if they have a Searcher.
       // Message: "Custom field '{0}' is not indexed for searching - please add a searcher to this
       // Custom Field."
       String localisedMessage =
           jiraServiceContext
               .getI18nBean()
               .getText("admin.permissions.errors.customfieldnotindexed", customField.getName());
       jiraServiceContext.getErrorCollection().addErrorMessage(localisedMessage);
     }
   }
 }
  @Override
  public WhitelistUpdateValidationResult validateUpdateRules(
      final JiraServiceContext context, final List<String> rules, final boolean disabled) {
    notNull("context", context);
    notNull("rules", rules);

    if (checkInvalidPermissions(context)) {
      return new WhitelistUpdateValidationResult(context.getErrorCollection());
    }

    for (String rule : rules) {
      if (rule.startsWith(REGEX_PREFIX)) {
        try {
          Pattern.compile(rule.substring(REGEX_PREFIX.length()));
        } catch (PatternSyntaxException e) {
          final I18nHelper i18n = beanFactory.getInstance(context.getLoggedInUser());
          context
              .getErrorCollection()
              .addErrorMessage(i18n.getText("whitelist.admin.errors.bad.pattern", e.getMessage()));
        }
      }
    }

    return new WhitelistUpdateValidationResult(context.getErrorCollection(), rules, disabled);
  }
  @Override
  public WhitelistResult getRules(final JiraServiceContext context) {
    notNull("context", context);

    if (checkInvalidPermissions(context)) {
      return new WhitelistResult(context.getErrorCollection());
    }
    return new WhitelistResult(context.getErrorCollection(), whitelistManager.getRules());
  }
 boolean checkInvalidPermissions(final JiraServiceContext context) {
   if (!permissionManager.hasPermission(Permissions.SYSTEM_ADMIN, context.getLoggedInUser())) {
     final I18nHelper i18n = beanFactory.getInstance(context.getLoggedInUser());
     context
         .getErrorCollection()
         .addErrorMessage(i18n.getText("whitelist.service.permission.error"));
     return true;
   }
   return false;
 }
  private void showPopularTab() {
    final JiraServiceContext serviceContext = getJiraServiceContext();
    final Collection<PortalPage> portalPages =
        getPortalPageViewHelper().getPopularFilters(serviceContext);
    if (!serviceContext.getErrorCollection().hasAnyErrors()) {
      pages = transformToDisplayBeans(portalPages);
    }

    view = Tab.POPULAR;
  }
  public MessageSet validateBackupProjectImportableSystemLevel(
      final JiraServiceContext jiraServiceContext,
      final BackupProject backupProject,
      final BackupSystemInformation backupSystemInformation) {
    validateJiraServiceContext(jiraServiceContext);
    // No need to check if backupProject has null members, we will never create backup project like
    // that.
    Null.not("backupSystemInformation", backupSystemInformation);

    final MessageSet messageSet = new MessageSetImpl();
    final I18nHelper i18n = jiraServiceContext.getI18nBean();

    // Need to provide a backupProject
    if (backupProject == null) {
      messageSet.addErrorMessage(getText(i18n, "admin.error.project.import.null.project"));
      jiraServiceContext
          .getErrorCollection()
          .addErrorMessage(getText(i18n, "admin.error.project.import.null.project"));
      return messageSet;
    }

    // The user must have the system administrator permission to perform a project import
    if (!userHasSysAdminPermission(jiraServiceContext.getUser())) {
      messageSet.addErrorMessage(getText(i18n, "admin.errors.project.import.must.be.admin"));
    } else {
      // Verify that if the backup projects custom field plugins exist that they are of the right
      // version in this JIRA instance
      // NOTE: warnings, such as the plugin not existing or the custom field being not importable or
      // out of context
      // are not checked here, that is handled by the next phase of the import.
      validateCustomFieldPluginVersions(
          backupProject, backupSystemInformation.getPluginVersions(), messageSet, i18n);

      final String projectKey = backupProject.getProject().getKey();
      final Project existingProject = projectManager.getProjectObjByKey(projectKey);
      if (existingProject == null) {
        // It does not really make sense to warn that we will create a project for them if there are
        // already errors.
        if (!messageSet.hasAnyErrors()) {
          messageSet.addWarningMessage(
              getText(i18n, "admin.warning.project.import.no.existing.project", projectKey));
        }
      } else {
        // We need to make sure that the project does not contain issues, versions, components,
        // etc...
        validateExistingProjectHasValidStateForImport(
            backupProject, backupSystemInformation, existingProject, i18n, messageSet);
      }
    }

    // Copy the errors into the service context error collection
    jiraServiceContext.getErrorCollection().addErrorMessages(messageSet.getErrorMessages());
    return messageSet;
  }
  public MappingResult doMapping(
      final JiraServiceContext jiraServiceContext,
      final ProjectImportOptions projectImportOptions,
      final ProjectImportData projectImportData,
      final BackupProject backupProject,
      final BackupSystemInformation backupSystemInformation,
      final TaskProgressInterval taskProgressInterval) {
    Null.not("backupProject", backupProject);
    Null.not("projectImportOptions", projectImportOptions);
    Null.not("backupSystemInformation", backupSystemInformation);
    Null.not("projectImportData", projectImportData);
    validateJiraServiceContext(jiraServiceContext);

    // The user must have the system administrator permission to perform a project import
    if (!userHasSysAdminPermission(jiraServiceContext.getUser())) {
      jiraServiceContext
          .getErrorCollection()
          .addErrorMessage(
              getText(
                  jiraServiceContext.getI18nBean(), "admin.errors.project.import.must.be.admin"));
      return null;
    }

    // Now that we have the initial mapper we need to auto map all the fields and their values and
    // validate that our
    // mappings are correct.
    final MappingResult mappingResult =
        validateAndAutoMapFields(
            jiraServiceContext,
            projectImportOptions,
            projectImportData,
            backupProject,
            backupSystemInformation,
            taskProgressInterval);
    if ((mappingResult != null) && !mappingResult.canImport()) {
      jiraServiceContext
          .getErrorCollection()
          .addErrorMessage(
              jiraServiceContext
                  .getI18nBean()
                  .getText("admin.errors.project.import.mapping.error"));
    }
    // We have log messages in the mapping Result that we didn't write to the log straight away as
    // you could get ltos of repeat messages. We log these now.

    writeLogMessages(mappingResult);
    return mappingResult;
  }
 protected boolean validateSearchParameters(
     final JiraServiceContext ctx,
     final SharedEntitySearchParameters searchParameters,
     final int pageOffset,
     final int pageWidth) {
   portalPageService.validateForSearch(ctx, searchParameters);
   return !ctx.getErrorCollection().hasAnyErrors();
 }
 private void showSearchTab() {
   // if they have pressed the 'Search' button then
   boolean searchPerformed = isSearchRequested();
   if (searchPerformed) {
     final JiraServiceContext ctx = getJiraServiceContext();
     searchResults = getPortalPageViewHelper().search(ctx);
     if (ctx.getErrorCollection().hasAnyErrors()) {
       searchPerformed = false;
     } else {
       pages = transformToDisplayBeans(searchResults.getResults());
     }
   }
   if (!searchPerformed) {
     searchEmptyMessageKey = KEY_NO_SEARCH;
   }
   view = Tab.SEARCH;
 }
 /**
  * @see UserPickerSearchService#canShowEmailAddresses(com.atlassian.jira.bc.JiraServiceContext)
  */
 @Override
 public boolean canShowEmailAddresses(final JiraServiceContext jiraServiceContext) {
   if (canPerformAjaxSearch(jiraServiceContext)) {
     final String emailVisibility =
         applicationProperties.getDefaultBackedString(APKeys.JIRA_OPTION_EMAIL_VISIBLE);
     if (VISIBILITY_PUBLIC.equals(emailVisibility)
         || (VISIBILITY_MASKED.equals(emailVisibility))
         || (VISIBILITY_USER.equals(emailVisibility)
             && (jiraServiceContext.getLoggedInUser() != null))) {
       return true;
     }
   }
   return false;
 }
  @Override
  public List<User> findUsersAllowEmptyQuery(
      final JiraServiceContext jiraServiceContext, final String query) {
    // is it allowed?  How did they get here anyway??
    if (!canPerformAjaxSearch(jiraServiceContext)) {
      return Collections.emptyList();
    }

    StopWatch stopWatch = new StopWatch();
    final String convertedQuery = (query == null) ? "" : query.toLowerCase().trim();
    if (log.isDebugEnabled()) log.debug("Running user-picker search: '" + convertedQuery + "'");
    List<User> returnUsers = new ArrayList<User>();
    final boolean canShowEmailAddresses = canShowEmailAddresses(jiraServiceContext);
    final Collection<User> allUsers = userManager.getUsers();
    if (log.isDebugEnabled())
      log.debug("Found all " + allUsers.size() + " users in " + stopWatch.getIntervalTime() + "ms");

    final Predicate<User> userMatcher =
        new UserMatcherPredicate(convertedQuery, canShowEmailAddresses);
    for (final User user : allUsers) {
      if (user.isActive() && userMatcher.apply(user)) {
        returnUsers.add(user);
      }
    }
    if (log.isDebugEnabled())
      log.debug(
          "Matched " + returnUsers.size() + " users in " + stopWatch.getIntervalTime() + "ms");
    Collections.sort(
        returnUsers, new UserBestNameComparator(jiraServiceContext.getI18nBean().getLocale()));
    if (log.isDebugEnabled()) {
      log.debug(
          "Sorted top " + returnUsers.size() + " users in " + stopWatch.getIntervalTime() + "ms");
      log.debug("User-picker search completed in " + stopWatch.getTotalTime() + "ms");
    }
    return returnUsers;
  }
  public void validateGetBackupOverview(
      final JiraServiceContext jiraServiceContext,
      final ProjectImportOptions projectImportOptions) {
    Null.not("projectImportOptions", projectImportOptions);
    validateJiraServiceContext(jiraServiceContext);

    final ErrorCollection errorCollection = jiraServiceContext.getErrorCollection();
    final I18nHelper i18n = jiraServiceContext.getI18nBean();

    // The user must have the system administrator permission to perform a project import
    if (!userHasSysAdminPermission(jiraServiceContext.getUser())) {
      errorCollection.addErrorMessage(getText(i18n, "admin.errors.project.import.must.be.admin"));
      // Don't care to check any more validity
      return;
    }

    if (StringUtils.isEmpty(projectImportOptions.getPathToBackupXml())) {
      errorCollection.addError(
          "backupXmlPath", getText(i18n, "admin.errors.project.import.provide.backup.path"));
    } else if (!pathExists(projectImportOptions.getPathToBackupXml(), true)) {
      errorCollection.addError(
          "backupXmlPath", getText(i18n, "admin.errors.project.import.invalid.backup.path"));
    }

    // Check if the user has supplied an attachment path
    if (!StringUtils.isEmpty(projectImportOptions.getAttachmentPath())) {
      // Check that attachments are enabled for the current JIRA
      if (!attachmentManager.attachmentsEnabled()) {
        errorCollection.addError(
            "backupAttachmentPath",
            getText(i18n, "admin.errors.project.import.attachments.not.enabled"));
      }
      // Now check if the path exists
      else if (pathExists(projectImportOptions.getAttachmentPath(), false)) {
        // Path Exists, but it is not allowed to be the current system's Attachment Path.
        // Get the configured attachment path for this JIRA instance.
        final String attachmentPathString = attachmentPathManager.getAttachmentPath();
        // Create a File object with it.
        final File attachmentPathFile = new File(attachmentPathString);
        // Create a File object with the attachment path
        final File backupAttachmentPathFile = new File(projectImportOptions.getAttachmentPath());
        // Compare the canonical paths to see if the directories are the same.
        try {
          if (attachmentPathFile
              .getCanonicalPath()
              .equals(backupAttachmentPathFile.getCanonicalPath())) {
            errorCollection.addError(
                "backupAttachmentPath",
                getText(i18n, "admin.errors.project.import.attachment.backup.path.same.as.system"));
          }
        } catch (final IOException e) {
          // This would be rather strange, but see the javadoc for getCanonicalFile():
          // "If an I/O error occurs, which is possible because the construction of the canonical
          // pathname may require filesystem queries"
          errorCollection.addErrorMessage(
              getText(i18n, "admin.errors.project.import.attachment.ioexception", e.getMessage()));
        }
      } else {
        // Path doesn't exist
        errorCollection.addError(
            "backupAttachmentPath",
            getText(i18n, "admin.errors.project.import.invalid.attachment.backup.path"));
      }
    }
  }
 @Override
 public boolean canPerformAjaxSearch(final JiraServiceContext jiraServiceContext) {
   User loggedInUser = (jiraServiceContext != null) ? jiraServiceContext.getLoggedInUser() : null;
   return canPerformAjaxSearch(loggedInUser);
 }
  public ProjectImportResults doImport(
      final JiraServiceContext jiraServiceContext,
      final ProjectImportOptions projectImportOptions,
      final BackupProject backupProject,
      final BackupSystemInformation backupSystemInformation,
      final ProjectImportData projectImportData,
      final TaskProgressInterval taskProgressInterval) {
    Null.not("projectImportOptions", projectImportOptions);
    Null.not("backupSystemInformation", backupSystemInformation);
    Null.not("projectImportData", projectImportData);
    Null.not("backupProject", backupProject);
    validateJiraServiceContext(jiraServiceContext);
    final ErrorCollection errorCollection = jiraServiceContext.getErrorCollection();
    final I18nHelper i18n = jiraServiceContext.getI18nBean();

    // Get the expected number of users that we will create
    final int usersToCreate =
        (isExternalUserManagementEnabled())
            ? 0
            : projectImportData
                .getProjectImportMapper()
                .getUserMapper()
                .getUsersToAutoCreate()
                .size();

    final ProjectImportResults projectImportResults =
        getInitialImportResults(projectImportData, i18n, usersToCreate);

    // The user must have the system administrator permission to perform a project import
    if (!userHasSysAdminPermission(jiraServiceContext.getUser())) {
      errorCollection.addErrorMessage(getText(i18n, "admin.errors.project.import.must.be.admin"));
      return projectImportResults;
    }

    try {
      log.info(
          "Starting project import for project '" + backupProject.getProject().getKey() + "'.");
      if (isExternalUserManagementEnabled()) {
        log.info("External user management is enabled. No users will be imported.");
      } else {
        log.info(
            "Creating missing users. Attempting to create "
                + projectImportResults.getExpectedUsersCreatedCount()
                + " users.");
        // External User Management is OFF - create missing users that we can.
        // This will fill in subtask progress from 0% - 10% of the doImport task
        final TaskProgressInterval subInterval = getSubInterval(taskProgressInterval, 0, 10);
        projectImportManager.createMissingUsers(
            projectImportData.getProjectImportMapper().getUserMapper(),
            projectImportResults,
            subInterval);
        log.info(
            "Finished creating missing users. "
                + projectImportResults.getUsersCreatedCount()
                + " users created.");
      }

      // Create/Update the project, its details, components, versions, role membership
      try {
        // This will fill in subtask progress from 10% - 20% of the doImport task (Allow for
        // creating lots of Project Role members)
        final TaskProgressInterval subInterval = getSubInterval(taskProgressInterval, 10, 20);
        projectImportManager.importProject(
            projectImportOptions,
            projectImportData.getProjectImportMapper(),
            backupProject,
            projectImportResults,
            subInterval);
      } catch (final AbortImportException e) {
        // Add an error message
        errorCollection.addErrorMessage(
            i18n.getText("admin.error.project.import.project.update.error"));
        throw e;
      }

      // Import the issues and all their related values and reIndex the project once it is done
      try {
        // This will fill in subtask progress from 20% - 100% of the doImport task (Allow for
        // creating lots of Project Role members)
        final TaskProgressInterval subInterval = getSubInterval(taskProgressInterval, 20, 100);
        projectImportManager.doImport(
            projectImportOptions,
            projectImportData,
            backupProject,
            backupSystemInformation,
            projectImportResults,
            subInterval,
            i18n,
            jiraServiceContext.getUser());
        // Only set the completed flag once everything has finished
        projectImportResults.setImportCompleted(true);
      } catch (final IOException e) {
        log.error(
            "There was a problem accessing the partitioned XML files when performing a project import.",
            e);
        errorCollection.addErrorMessage(
            getText(
                i18n,
                "admin.errors.project.import.problem.reading.partitioned.xml",
                e.getMessage()));
      } catch (final AbortImportException aie) {
        // Note that AbortImportException extends SAXException, so we need to catch and handle
        // AbortImportException first.
        log.error("The import was aborted because there were too many errors.");
        errorCollection.addErrorMessage(i18n.getText("admin.errors.project.import.import.error"));
      } catch (final SAXException e) {
        log.error(
            "There was a problem accessing the partitioned XML files when performing a project import.",
            e);
        errorCollection.addErrorMessage(
            getText(
                i18n, "admin.errors.project.import.sax.problem.partitioned.xml", e.getMessage()));
      } catch (final IndexException e) {
        log.error("There was a problem reIndexing the newly imported project.", e);
        errorCollection.addErrorMessage(
            i18n.getText("admin.errors.project.import.reindex.problem", e.getMessage()));
      }
      log.info(
          "Finished project import for project '" + backupProject.getProject().getKey() + "'.");

    } catch (final AbortImportException aie) {
      log.error("The import was aborted because there were too many errors.");
      errorCollection.addErrorMessage(i18n.getText("admin.errors.project.import.import.error"));
    }

    // Clean up the temporary "partitioned" XML files.
    projectImportData.getTemporaryFiles().deleteTempFiles();

    // Always record the end of the import.
    projectImportResults.setEndTime(System.currentTimeMillis());
    logImportResults(projectImportResults);
    return projectImportResults;
  }
  public ProjectImportData getProjectImportData(
      final JiraServiceContext jiraServiceContext,
      final ProjectImportOptions projectImportOptions,
      final BackupProject backupProject,
      final BackupSystemInformation backupSystemInformation,
      final TaskProgressInterval taskProgressInterval) {
    Null.not("backupProject", backupProject);
    Null.not("projectImportOptions", projectImportOptions);
    Null.not("backupSystemInformation", backupSystemInformation);
    validateJiraServiceContext(jiraServiceContext);

    // The user must have the system administrator permission to perform a project import
    if (!userHasSysAdminPermission(jiraServiceContext.getUser())) {
      jiraServiceContext
          .getErrorCollection()
          .addErrorMessage(
              getText(
                  jiraServiceContext.getI18nBean(), "admin.errors.project.import.must.be.admin"));
      return null;
    }

    final ErrorCollection errorCollection = jiraServiceContext.getErrorCollection();
    final I18nHelper i18n = jiraServiceContext.getI18nBean();
    final ProjectImportData projectImportData;
    try {
      // First step is to go through the import file again, populating our mappers and creating
      // partitioned XML files.
      // Create the Task Progress Processor for this subtask.
      EntityCountTaskProgressProcessor taskProgressProcessor = null;
      if (taskProgressInterval != null) {
        taskProgressProcessor =
            new EntityCountTaskProgressProcessor(
                taskProgressInterval,
                i18n.getText(
                    "admin.message.project.import.manager.do.mapping.extracting.project.data"),
                backupSystemInformation.getEntityCount(),
                i18n);
      }
      projectImportData =
          projectImportManager.getProjectImportData(
              projectImportOptions, backupProject, backupSystemInformation, taskProgressProcessor);
    } catch (final IOException e) {
      log.error(
          "There was a problem accessing the file '"
              + projectImportOptions.getPathToBackupXml()
              + "' when performing a project import.",
          e);
      errorCollection.addErrorMessage(
          getText(
              i18n,
              "admin.errors.project.import.problem.reading.backup",
              projectImportOptions.getPathToBackupXml()));
      return null;
    } catch (final SAXException e) {
      log.error(
          "There was a problem with the SAX parsing of the file '"
              + projectImportOptions.getPathToBackupXml()
              + "' when performing a project import.");
      errorCollection.addErrorMessage(
          getText(
              i18n,
              "admin.errors.project.import.sax.problem",
              projectImportOptions.getPathToBackupXml(),
              e.getMessage()));
      return null;
    }
    return projectImportData;
  }
  private MappingResult validateAndAutoMapFields(
      final JiraServiceContext jiraServiceContext,
      final ProjectImportOptions projectImportOptions,
      final ProjectImportData projectImportData,
      final BackupProject backupProject,
      final BackupSystemInformation backupSystemInformation,
      final TaskProgressInterval taskProgressInterval) {
    log.info(
        "Project Import: Mapping the backed up data to data in the current system, and validating the mappings...");
    final MappingResult mappingResult = buildMappingResult();
    final I18nHelper i18n = jiraServiceContext.getI18nBean();

    // Step 2 Map and validate the Issue Types
    projectImportManager.autoMapAndValidateIssueTypes(
        projectImportData, mappingResult, backupProject, jiraServiceContext.getI18nBean());

    // If there is a problem processing the issue types then we don't want to do any further
    // mappings or validation
    if ((mappingResult.getIssueTypeMessageSet() != null)
        && !mappingResult.getIssueTypeMessageSet().hasAnyErrors()) {
      // Try to map the custom fields
      projectImportManager.autoMapAndValidateCustomFields(
          projectImportData, mappingResult, backupProject, i18n);

      if (!mappingResult.getCustomFieldMessageSet().hasAnyErrors()) {
        // Only map the system fields if we can move forward with the custom fields
        projectImportManager.autoMapSystemFields(projectImportData, backupProject);

        // Only map the project roles if we can move forward with the custom fields
        projectImportManager.autoMapProjectRoles(projectImportData);

        // Only map the custom field values once we know that the custom fields are good
        projectImportManager.autoMapCustomFieldOptions(projectImportData, backupProject);

        final boolean importAttachments =
            !StringUtils.isEmpty(projectImportOptions.getAttachmentPath());
        final int customFieldValuePercentage = (importAttachments) ? 60 : 90;
        // if we can successfully map the custom fields then lets validate the custom field values
        try {
          // Create a TaskProgressProcessor for validateCustomFieldValues
          final TaskProgressInterval subInterval =
              getSubInterval(taskProgressInterval, 0, customFieldValuePercentage);
          EntityCountTaskProgressProcessor taskProgressProcessor = null;
          if (taskProgressInterval != null) {
            taskProgressProcessor =
                new EntityCountTaskProgressProcessor(
                    subInterval,
                    i18n.getText(
                        "admin.message.project.import.manager.do.mapping.validate.custom.field.values"),
                    projectImportData.getCustomFieldValuesEntityCount(),
                    i18n);
          }
          projectImportManager.validateCustomFieldValues(
              projectImportData, mappingResult, backupProject, taskProgressProcessor, i18n);
        } catch (final IOException e) {
          log.error(
              "There was a problem accessing the file '"
                  + projectImportData.getPathToCustomFieldValuesXml()
                  + "' when performing a project import.",
              e);
          jiraServiceContext
              .getErrorCollection()
              .addErrorMessage(
                  getText(
                      i18n,
                      "admin.errors.project.import.problem.reading.custom.field.xml",
                      projectImportData.getPathToCustomFieldValuesXml()));
          return null;
        } catch (final SAXException e) {
          log.error(
              "There was a problem accessing the file '"
                  + projectImportData.getPathToCustomFieldValuesXml()
                  + "' when performing a project import.",
              e);
          jiraServiceContext
              .getErrorCollection()
              .addErrorMessage(
                  getText(
                      i18n,
                      "admin.errors.project.import.custom.field.sax.problem",
                      projectImportData.getPathToCustomFieldValuesXml(),
                      e.getMessage()));
          return null;
        }

        // Only validate the system field mappings after we have done all the rest
        // Create a sub interval of the taskProgressInterval we were given.
        TaskProgressInterval sysFieldSubInterval = null;
        if (taskProgressInterval != null) {
          sysFieldSubInterval =
              taskProgressInterval.getSubInterval(
                  customFieldValuePercentage, customFieldValuePercentage + 10);
        }
        projectImportManager.validateSystemFields(
            projectImportData,
            mappingResult,
            projectImportOptions,
            backupProject,
            sysFieldSubInterval,
            i18n);

        // Validate the attachments if we are importing attachments
        if (!importAttachments) {
          final MessageSet messageSet = new MessageSetImpl();
          messageSet.addWarningMessage(
              getText(i18n, "admin.warning.project.import.mapping.no.backup.atttachment.path"));
          log.warn(
              "File attachments will not be imported because you have not provided a backup attachment path.");
          mappingResult.setFileAttachmentMessageSet(messageSet);
        } else {
          try {
            // Create a TaskProgressProcessor for validateFileAttachments
            final TaskProgressInterval attachmentSubInterval =
                getSubInterval(taskProgressInterval, 70, 100);
            EntityCountTaskProgressProcessor taskProgressProcessor = null;
            if (taskProgressInterval != null) {
              taskProgressProcessor =
                  new EntityCountTaskProgressProcessor(
                      attachmentSubInterval,
                      i18n.getText(
                          "admin.message.project.import.manager.do.mapping.validate.file.attachment.values"),
                      projectImportData.getFileAttachmentEntityCount(),
                      i18n);
            }
            projectImportManager.validateFileAttachments(
                projectImportOptions,
                projectImportData,
                mappingResult,
                backupProject,
                backupSystemInformation,
                taskProgressProcessor,
                i18n);
          } catch (final IOException e) {
            log.error(
                "There was a problem accessing the file '"
                    + projectImportData.getPathToFileAttachmentXml()
                    + "' when performing a project import.",
                e);
            jiraServiceContext
                .getErrorCollection()
                .addErrorMessage(
                    getText(
                        i18n,
                        "admin.errors.project.import.problem.reading.attachment.xml",
                        projectImportData.getPathToFileAttachmentXml()));
            return null;
          } catch (final SAXException e) {
            log.error(
                "There was a problem accessing the file '"
                    + projectImportData.getPathToFileAttachmentXml()
                    + "' when performing a project import.",
                e);
            jiraServiceContext
                .getErrorCollection()
                .addErrorMessage(
                    getText(
                        i18n,
                        "admin.errors.project.import.custom.field.sax.problem",
                        projectImportData.getPathToFileAttachmentXml(),
                        e.getMessage()));
            return null;
          }
        }
      } else {
        // When the required custom fields have not passed validation we still want to show that
        // validation has
        // not happened for each of the custom field values.
        addCustomFieldValuesNotCheckedMessageSets(projectImportData, mappingResult);
      }
    } else {
      // When the required issue types have not passed validation we still want to show that
      // validation has
      // not happened for each of the custom field values.
      addCustomFieldValuesNotCheckedMessageSets(projectImportData, mappingResult);
    }

    // We want to populate the message list of the results. This puts the message results into order
    // and gives
    // them i18n header labels
    createValidationMessageList(mappingResult, projectImportData, i18n);

    if (mappingResult.canImport()) {
      log.info("Project Import: No validation errors were found and the import can continue.");
    } else {
      log.info("Project Import: Validation errors were found. The import cannot continue.");
    }
    return mappingResult;
  }
  public BackupOverview getBackupOverview(
      final JiraServiceContext jiraServiceContext,
      final ProjectImportOptions projectImportOptions,
      final TaskProgressSink taskProgressSink) {
    Null.not("projectImportOptions", projectImportOptions);
    validateJiraServiceContext(jiraServiceContext);
    final ErrorCollection errorCollection = jiraServiceContext.getErrorCollection();
    final I18nHelper i18n = jiraServiceContext.getI18nBean();

    // The user must have the system administrator permission to perform a project import
    if (!userHasSysAdminPermission(jiraServiceContext.getUser())) {
      errorCollection.addErrorMessage(getText(i18n, "admin.errors.project.import.must.be.admin"));
      return null;
    }

    try {
      final String backupPath = projectImportOptions.getPathToBackupXml();
      log.info(
          "Project Import: Parsing the backup file '"
              + backupPath
              + "' to obtain a Backup Overview.");
      final BackupOverview backupOverview =
          projectImportManager.getBackupOverview(backupPath, taskProgressSink, i18n);
      log.debug("Project count for backup file = " + backupOverview.getProjects().size());
      log.debug(
          "Entity count for backup file = "
              + backupOverview.getBackupSystemInformation().getEntityCount());

      // Now do some further validation
      // BuildNumbers must be exactly the same.
      if (!getBuildNumber()
          .equalsIgnoreCase(backupOverview.getBackupSystemInformation().getBuildNumber())) {
        final String errorMessage =
            getText(
                i18n,
                "admin.errors.project.import.wrong.build.number",
                getBuildNumber(),
                backupOverview.getBackupSystemInformation().getBuildNumber());
        errorCollection.addErrorMessage(errorMessage);
        log.error(
            "This data appears to be from an older version of JIRA. Please upgrade the data and try again. The current version of JIRA is at build number '"
                + getBuildNumber()
                + "', but the supplied backup file was for build number '"
                + backupOverview.getBackupSystemInformation().getBuildNumber()
                + "'.");
      }

      // Only return the backupOverview if we do not have any errors, otherwise we want to fall
      // through and return null
      if (!errorCollection.hasAnyErrors()) {
        log.info(
            "Project Import: Backup Overview was successfully extracted from '"
                + backupPath
                + "'.");

        return backupOverview;
      }
    } catch (final IOException e) {
      log.error(
          "There was a problem accessing the file '"
              + projectImportOptions.getPathToBackupXml()
              + "' when performing a project import.",
          e);
      errorCollection.addErrorMessage(
          getText(
              i18n,
              "admin.errors.project.import.problem.reading.backup",
              projectImportOptions.getPathToBackupXml()));
    } catch (final SAXException e) {
      log.error(
          "There was a problem with the SAX parsing of the file '"
              + projectImportOptions.getPathToBackupXml()
              + "' when performing a project import.");
      errorCollection.addErrorMessage(
          getText(
              i18n,
              "admin.errors.project.import.sax.problem",
              projectImportOptions.getPathToBackupXml(),
              e.getMessage()));
    }
    return null;
  }