Coverage Summary for Class: MigrationForm (org.kitodo.production.forms)

Class Class, % Method, % Line, %
MigrationForm 100% (1/1) 23,9% (11/46) 27,6% (50/181)


 /*
  * (c) Kitodo. Key to digital objects e. V. <contact@kitodo.org>
  *
  * This file is part of the Kitodo project.
  *
  * It is licensed under GNU General Public License version 3 or later.
  *
  * For the full copyright and license information, please read the
  * GPL3-License.txt file that was distributed with this source code.
  */
 
 package org.kitodo.production.forms;
 
 import java.io.IOException;
 import java.security.InvalidAlgorithmParameterException;
 import java.security.InvalidKeyException;
 import java.security.NoSuchAlgorithmException;
 import java.security.spec.InvalidKeySpecException;
 import java.text.MessageFormat;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
 import java.util.stream.Collectors;
 
 import javax.crypto.BadPaddingException;
 import javax.crypto.IllegalBlockSizeException;
 import javax.crypto.NoSuchPaddingException;
 import javax.enterprise.context.ApplicationScoped;
 import javax.inject.Named;
 
 import org.apache.commons.lang3.StringUtils;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 import org.kitodo.config.ConfigCore;
 import org.kitodo.config.enums.ParameterCore;
 import org.kitodo.data.database.beans.Batch;
 import org.kitodo.data.database.beans.LdapServer;
 import org.kitodo.data.database.beans.Process;
 import org.kitodo.data.database.beans.Project;
 import org.kitodo.data.database.beans.Task;
 import org.kitodo.data.database.beans.Template;
 import org.kitodo.data.database.beans.Workflow;
 import org.kitodo.data.database.enums.WorkflowStatus;
 import org.kitodo.data.database.exceptions.DAOException;
 import org.kitodo.data.exceptions.DataException;
 import org.kitodo.exceptions.WorkflowException;
 import org.kitodo.production.enums.ObjectType;
 import org.kitodo.production.helper.Helper;
 import org.kitodo.production.helper.tasks.HierarchyMigrationTask;
 import org.kitodo.production.helper.tasks.MigrationTask;
 import org.kitodo.production.helper.tasks.TaskManager;
 import org.kitodo.production.migration.NewspaperProcessesMigrator;
 import org.kitodo.production.migration.TasksToWorkflowConverter;
 import org.kitodo.production.security.AESUtil;
 import org.kitodo.production.services.ServiceManager;
 import org.kitodo.production.services.migration.MigrationService;
 import org.kitodo.production.workflow.model.Converter;
 import org.primefaces.PrimeFaces;
 
 @Named("MigrationForm")
 @ApplicationScoped
 public class MigrationForm extends BaseForm {
 
     private static final Logger logger = LogManager.getLogger(MigrationForm.class);
     private List<Project> allProjects = new ArrayList<>();
     private List<Project> selectedProjects = new ArrayList<>();
     private boolean projectListRendered;
     private boolean processListRendered;
     private final Map<String, List<Process>> aggregatedProcesses = new HashMap<>();
     private Workflow workflowToUse;
     private String currentTasks;
     private Map<Template, List<Process>> templatesToCreate = new HashMap<>();
     private Map<Template, Template> matchingTemplates = new HashMap<>();
     private final MigrationService migrationService = ServiceManager.getMigrationService();
     private boolean metadataRendered;
     private boolean workflowRendered;
     private boolean newspaperMigrationRendered = false;
     private Collection<Integer> newspaperBatchesSelectedItems = new ArrayList<>();
     private List<Batch> newspaperBatchesItems;
     private boolean ldapManagerPasswordsMigrationRendered = false;
 
     /**
      * Migrates the meta.xml for all processes in the database (if it's in the
      * old format).
      *
      */
     public void migrateMetadata() {
         try {
             loadProjects();
             projectListRendered = true;
             metadataRendered = true;
             workflowRendered = false;
             newspaperMigrationRendered = false;
         } catch (DAOException e) {
             Helper.setErrorMessage("Error during database access", e.getLocalizedMessage(), logger, e);
         }
     }
 
     /**
      * Shows all projects for migration.
      */
     public void showPossibleProjects() {
         try {
             loadProjects();
             projectListRendered = true;
             workflowRendered = true;
             metadataRendered = false;
             newspaperMigrationRendered = false;
         } catch (DAOException e) {
             Helper.setErrorMessage("Error during database access", e.getLocalizedMessage(), logger, e);
         }
     }
 
     private void loadProjects() throws DAOException {
         allProjects = ServiceManager.getProjectService().getAll()
                 .stream().sorted(Comparator.comparing(Project::getTitle)).collect(Collectors.toList());
     }
 
     /**
      * Shows all processes related to the selected projects.
      */
     public void showAggregatedProcesses() {
         List<Process> processList = new ArrayList<>();
         aggregatedProcesses.clear();
         for (Project project : selectedProjects) {
             logger.trace("Listing processes from project \"{}\"...", project.getTitle());
             processList.addAll(project.getProcesses());
         }
         int numberOfProcesses = processList.size();
         long lastSystemSecond = System.nanoTime() / 1_000_000_000;
         for (int currentProcess = 0; currentProcess < processList.size(); currentProcess++) {
             Process process = processList.get(currentProcess);
             if (logger.isTraceEnabled()) {
                 long currentSystemSecond = System.nanoTime() / 1_000_000_000;
                 if (currentSystemSecond != lastSystemSecond) {
                     lastSystemSecond = currentSystemSecond;
                     logger.trace("Analyzing process {}/{} ({}% done)", currentProcess, numberOfProcesses,
                         100 * currentProcess / numberOfProcesses);
                 }
             }
             if (Objects.isNull(process.getTemplate())) {
                 addToAggregatedProcesses(aggregatedProcesses, process);
             }
         }
         processListRendered = true;
     }
 
     /**
      * Method for migrating hierarchical processes. This is done when the user
      * clicks the button to migrate hierarchical processes under the projects
      * selection.
      */
     public void convertHierarchys() {
         TaskManager.addTask(new HierarchyMigrationTask(selectedProjects));
         projectListRendered = false;
     }
 
     /**
      * Method for migrating the metadata. This is done when the user clicks the
      * button to migrate metadata under the projects selection.
      */
     public void convertMetadata() {
         for (Project project : selectedProjects) {
             TaskManager.addTask(new MigrationTask(project));
         }
         projectListRendered = false;
     }
 
     private void addToAggregatedProcesses(Map<String, List<Process>> aggregatedProcesses, Process process) {
         List<Task> processTasks = process.getTasks();
         processTasks.sort(Comparator.comparingInt(Task::getOrdering));
         for (String tasks : aggregatedProcesses.keySet()) {
             List<Task> aggregatedTasks = aggregatedProcesses.get(tasks).get(0).getTasks();
             aggregatedTasks.sort(Comparator.comparingInt(Task::getOrdering));
             if (checkForTitle(tasks, processTasks) && migrationService
                     .tasksAreEqual(aggregatedTasks, processTasks)) {
                 aggregatedProcesses.get(tasks).add(process);
                 return;
             }
         }
         aggregatedProcesses.put(migrationService.createTaskString(processTasks),
             new ArrayList<>(Collections.singletonList(process)));
     }
 
     private boolean checkForTitle(String aggregatedTasks, List<Task> processTasks) {
         return aggregatedTasks.equals(migrationService.createTaskString(processTasks));
     }
 
     /**
      * Get allProjects.
      *
      * @return value of allProjects
      */
     public List<Project> getAllProjects() {
         return allProjects;
     }
 
     /**
      * Set selectedProjects.
      *
      * @param selectedProjects
      *            as List of Project
      */
     public void setSelectedProjects(List<Project> selectedProjects) {
         this.selectedProjects = selectedProjects;
     }
 
     /**
      * Returns whether the switch for starting the metadata migration should be
      * displayed.
      *
      * @return whether the switch for starting the metadata migration should be
      *         displayed
      */
     public boolean isMetadataRendered() {
         return metadataRendered;
     }
 
     /**
      * Get projectListRendered.
      *
      * @return value of projectListRendered
      */
     public boolean isProjectListRendered() {
         return projectListRendered;
     }
 
     /**
      * Returns whether the switch for creating workflows should be displayed.
      *
      * @return whether the switch for creating workflows should be displayed
      */
     public boolean isWorkflowRendered() {
         return workflowRendered;
     }
 
     /**
      * Get selectedProjects.
      *
      * @return value of selectedProjects
      */
     public List<Project> getSelectedProjects() {
         return selectedProjects;
     }
 
     /**
      * Get processListRendered.
      *
      * @return value of processListRendered
      */
     public boolean isProcessListRendered() {
         return processListRendered;
     }
 
     /**
      * Get aggregatedTasks. Sorts them in descending order by count,
      * alphabetically for the same count.
      *
      * @return sorted keyset of aggregatedProcesses
      */
     public List<String> getAggregatedTasks() {
         ArrayList<String> aggregatedTasks = new ArrayList<>(aggregatedProcesses.keySet());
         aggregatedTasks.sort((one, another) -> {
             int oneSize = aggregatedProcesses.get(one).size();
             int anotherSize = aggregatedProcesses.get(another).size();
             return oneSize == anotherSize ? one.compareTo(another) : anotherSize - oneSize;
         });
         return aggregatedTasks;
     }
 
     /**
      * Get tasksWithoutHashCode.
      *
      * @return tasks without hash code
      */
     public String tasksWithoutHashCode(String tasks) {
         return tasks.substring(0, tasks.lastIndexOf(MigrationService.SEPARATOR));
     }
 
     /**
      * Get numberOfProcesses.
      *
      * @return size of aggregatedProcesses
      */
     public int getNumberOfProcesses(String tasks) {
         return aggregatedProcesses.get(tasks).size();
     }
 
     /**
      * Uses the aggregated processes to create a new Workflow.
      *
      * @param tasks
      *            the list of tasks found in the projects
      */
     public void convertTasksToWorkflow(String tasks) {
         currentTasks = tasks;
         PrimeFaces.current().executeScript("PF('confirmWorkflowPopup').show();");
     }
 
     /**
      * Use an existing Workflow instead of creating a new one.
      */
     public void useExistingWorkflow() {
         setRedirectFromWorkflow(workflowToUse.getId());
     }
 
     /**
      * Creates a new Workflow from the aggregated processes.
      *
      * @return a navigation path.
      */
     public String createNewWorkflow() {
 
         Process blueprintProcess = aggregatedProcesses.get(currentTasks).get(0);
         TasksToWorkflowConverter templateConverter = new TasksToWorkflowConverter();
         List<Task> processTasks = blueprintProcess.getTasks();
         processTasks.sort(Comparator.comparingInt(Task::getOrdering));
         String workflowTitle = "ChangeME_" + Helper.generateRandomString(3);
 
         try {
             templateConverter.convertTasksToWorkflowFile(workflowTitle, processTasks);
         } catch (IOException e) {
             Helper.setErrorMessage(e.getLocalizedMessage(), logger, e);
         }
 
         workflowToUse = new Workflow(workflowTitle);
         workflowToUse.setClient(blueprintProcess.getProject().getClient());
         workflowToUse.setStatus(WorkflowStatus.DRAFT);
         workflowToUse.getTemplates().add(null);
 
         try {
             ServiceManager.getWorkflowService().save(workflowToUse);
         } catch (DataException e) {
             Helper.setErrorMessage(ERROR_SAVING, new Object[] {ObjectType.WORKFLOW.getTranslationSingular() }, logger,
                 e);
             return this.stayOnCurrentPage;
         }
 
         return MessageFormat.format(REDIRECT_PATH, "workflowEdit") + "&id=" + workflowToUse.getId() + "&migration=true";
     }
 
     /**
      * When the navigation to the migration form is coming from a workflow
      * creation the URL contains a WorkflowId.
      *
      * @param workflowId
      *            the id of the created Workflow
      */
     public void setRedirectFromWorkflow(Integer workflowId) {
         if (Objects.nonNull(workflowId) && workflowId != 0) {
             // showPopup for Template
             try {
                 workflowToUse = ServiceManager.getWorkflowService().getById(workflowId);
                 createTemplates();
             } catch (DAOException e) {
                 Helper.setErrorMessage(ERROR_READING, new Object[] {ObjectType.TEMPLATE.getTranslationSingular() },
                     logger, e);
             }
         }
     }
 
     private void createTemplates() throws DAOException {
         templatesToCreate = migrationService.createTemplatesForProcesses(aggregatedProcesses.get(currentTasks),
             workflowToUse);
         matchingTemplates.clear();
         matchingTemplates = migrationService.getMatchingTemplates(templatesToCreate.keySet());
         PrimeFaces.current().executeScript("PF('createTemplatePopup').show();");
     }
 
     /**
      * Get templatesToCreate.
      *
      * @return value of templatesToCreate
      */
     public Set<Template> getTemplatesToCreate() {
         return templatesToCreate.keySet();
     }
 
     /**
      * Gets a matching template from matchingTemplates.
      *
      * @param template
      *            the template to match.
      * @return the matching template
      */
     public Template getMatchingTemplate(Template template) {
         return matchingTemplates.get(template);
     }
 
     /**
      * Uses the existing template to add processes to.
      *
      * @param template
      *            The template to which's matching template the processes should
      *            be added
      * @param existingTemplate
      *            the template to add the processes to
      */
     public void useExistingTemplate(Template template, Template existingTemplate) {
         List<Process> processesToAddToTemplate = templatesToCreate.get(template);
         try {
             migrationService.addProcessesToTemplate(existingTemplate, processesToAddToTemplate);
         } catch (DataException e) {
             Helper.setErrorMessage(ERROR_SAVING, new Object[] {ObjectType.PROCESS.getTranslationSingular() }, logger,
                 e);
         }
         templatesToCreate.remove(template);
     }
 
     /**
      * Creates a new template.
      *
      * @param template
      *            The template to create.
      */
     public void createNewTemplate(Template template) {
         if (migrationService.isTitleValid(template)) {
             try {
                 Converter converter = new Converter(template.getWorkflow().getTitle());
                 converter.convertWorkflowToTemplate(template);
             } catch (IOException | DAOException | WorkflowException e) {
                 Helper.setErrorMessage(ERROR_SAVING, new Object[]{ObjectType.PROCESS.getTranslationSingular()},
                         logger, e);
             }
 
             List<Process> processesToAddToTemplate = templatesToCreate.get(template);
             try {
                 ServiceManager.getTemplateService().save(template);
             } catch (DataException e) {
                 Helper.setErrorMessage(ERROR_SAVING, new Object[]{ObjectType.TEMPLATE.getTranslationSingular()}, logger,
                         e);
             }
             try {
                 migrationService.addProcessesToTemplate(template, processesToAddToTemplate);
             } catch (DataException e) {
                 Helper.setErrorMessage(ERROR_SAVING, new Object[]{ObjectType.PROCESS.getTranslationSingular()}, logger,
                         e);
             }
             templatesToCreate.remove(template);
         }
     }
 
     /**
      * Gets all workflows, possible to use in migration.
      * @return A list of workflows.
      */
     public List<Workflow> getAllWorkflows() {
         return ServiceManager.getWorkflowService().getAllActiveWorkflows();
     }
 
     /**
      * Get workflowToUse.
      *
      * @return value of workflowToUse
      */
     public Workflow getWorkflowToUse() {
         return workflowToUse;
     }
 
     /**
      * Set workflowToUse.
      *
      * @param workflowToUse as org.kitodo.data.database.beans.Workflow
      */
     public void setWorkflowToUse(Workflow workflowToUse) {
         this.workflowToUse = workflowToUse;
     }
 
     /**
      * Action performed when the migrateNewspaperBatches button is clicked.
      */
     public void showPossibleBatches() {
         newspaperMigrationRendered = true;
         projectListRendered = false;
     }
 
     /**
      * Returns whether the newspaperMigration panel group is rendered.
      *
      * @return whether the newspaperMigration panel group is rendered
      */
 
     public boolean isNewspaperMigrationRendered() {
         return newspaperMigrationRendered;
     }
 
     /**
      * Returns the selected items of the newspaperBatches select box.
      *
      * @return the selected items of the newspaperBatches select box
      */
     public Collection<Integer> getNewspaperBatchesSelectedItems() {
         return newspaperBatchesSelectedItems;
     }
 
     /**
      * Sets the selected items of the newspaperBatches select box.
      *
      * @param selectedItems
      *            elected items of the newspaperBatches select box to set
      */
     public void setNewspaperBatchesSelectedItems(Collection<Integer> selectedItems) {
         newspaperBatchesSelectedItems = selectedItems;
     }
 
     /**
      * Returns the items of the newspaperBatches select box.
      *
      * @return the items of the newspaperBatches select box
      */
     public List<Batch> getNewspaperBatchesItems() {
         if (Objects.isNull(newspaperBatchesItems)) {
             try {
                 newspaperBatchesItems = NewspaperProcessesMigrator.getNewspaperBatches();
             } catch (DAOException | IOException e) {
                 Helper.setErrorMessage(e.getLocalizedMessage(), logger, e);
                 return Collections.emptyList();
             }
         }
         return newspaperBatchesItems;
     }
 
     /**
      * Action performed when the startNewspaperMigration button is clicked.
      */
     public void startNewspaperMigration() {
         try {
             for (Integer batchId : newspaperBatchesSelectedItems) {
                 NewspaperProcessesMigrator.initializeMigration(batchId);
             }
             newspaperMigrationRendered = false;
             newspaperBatchesSelectedItems = new ArrayList<>();
         } catch (DAOException e) {
             Helper.setErrorMessage(e.getLocalizedMessage(), logger, e);
         }
     }
 
     /**
      * Action performed when the cancelNewspaperMigration button is clicked.
      */
     public void hideNewspaperMigration() {
         newspaperMigrationRendered = false;
     }
 
     /**
      * Action performed when the migrateLdapManagerPasswords button is clicked.
      */
     public void showLdapManagerPasswordsMigration() {
         ldapManagerPasswordsMigrationRendered = true;
     }
 
     /**
      * Returns whether the ldapManagerPasswordsMigration panel group is rendered.
      *
      * @return whether the ldapManagerPasswordsMigration panel group is rendered
      */
     public boolean isLdapManagerPasswordsMigrationRendered() {
         return ldapManagerPasswordsMigrationRendered;
     }
 
     /**
      * Action performed when the startLdapManagerPasswordsMigration button is
      * clicked.
      */
     public void startLdapManagerPasswordsMigration() {
 
         String securitySecret = ConfigCore.getParameterOrDefaultValue(ParameterCore.SECURITY_SECRET_LDAPMANAGERPASSWORD);
 
         if (StringUtils.isBlank(securitySecret)) {
             Helper.setErrorMessage(
                 "The security.secret.ldapManagerPassword parameter was not configured in kitodo_config.properties file.");
             return;
         }
 
         List<LdapServer> ldapServers = getLdapServers();
         ldapServers.parallelStream().forEach(ldapServer -> {
             String managerPassword = ldapServer.getManagerPassword();
             if (StringUtils.isNotBlank(managerPassword) && !AESUtil.isEncrypted(managerPassword)) {
                 try {
                     ldapServer.setManagerPassword(AESUtil.encrypt(managerPassword, securitySecret));
                     ServiceManager.getLdapServerService().saveToDatabase(ldapServer);
                 } catch (DAOException | NoSuchPaddingException | NoSuchAlgorithmException
                         | InvalidAlgorithmParameterException | InvalidKeyException | BadPaddingException
                         | IllegalBlockSizeException | InvalidKeySpecException e) {
                     Helper.setErrorMessage(e.getLocalizedMessage(), logger, e);
                 }
             }
         });
 
         Helper.setMessage("All uncrypted LDAP Manager passwords were successfully encrypted.");
     }
 
     /**
      * Action performed when the cancelLdapManagerPasswordMigration button is
      * clicked.
      */
     public void hideLdapManagerPasswordsMigrationRendered() {
         ldapManagerPasswordsMigrationRendered = false;
     }
 
     /**
      * Gets all ldap servers.
      *
      * @return list of LdapServer objects.
      */
     public List<LdapServer> getLdapServers() {
         try {
             return ServiceManager.getLdapServerService().getAll();
         } catch (DAOException e) {
             Helper.setErrorMessage(ERROR_LOADING_MANY, new Object[] {Helper.getTranslation("ldapServers") }, logger, e);
             return new ArrayList<>();
         }
     }
 }