de.sub.goobi.forms.IndexingForm.java Source code

Java tutorial

Introduction

Here is the source code for de.sub.goobi.forms.IndexingForm.java

Source

/*
 * (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 de.sub.goobi.forms;

import de.sub.goobi.helper.IndexWorker;

import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.util.EnumMap;
import java.util.Map;
import java.util.Objects;

import javax.enterprise.context.ApplicationScoped;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import javax.inject.Named;

import org.apache.commons.io.IOUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import org.kitodo.config.ConfigMain;
import org.kitodo.data.database.exceptions.DAOException;
import org.kitodo.data.elasticsearch.exceptions.CustomResponseException;
import org.kitodo.data.elasticsearch.index.IndexRestClient;
import org.kitodo.enums.ObjectType;
import org.kitodo.services.ServiceManager;
import org.kitodo.services.data.base.SearchService;
import org.omnifaces.cdi.Push;
import org.omnifaces.cdi.PushContext;
import org.omnifaces.util.Ajax;

@Named
@ApplicationScoped
public class IndexingForm {

    private static IndexRestClient indexRestClient = new IndexRestClient();
    private static final String INDEXING_STARTED_MESSAGE = "indexing_started";
    private static final String INDEXING_FINISHED_MESSAGE = "indexing_finished";
    private static final String INDEXING_TABLE_ID = "indexing_form:indexingTable";
    private static final String POLLING_CHANNEL_NAME = "togglePollingChannel";

    public LocalDateTime getIndexingStartedTime() {
        return indexingStartedTime;
    }

    private int pause = 1000;

    class IndexAllThread extends Thread {

        @Override
        public void run() {
            resetGlobalProgress();
            indexingAll = true;

            startUserIndexing();
            startUserGroupIndexing();
            startProjectIndexing();
            startRulesetIndexing();
            startDocketIndexing();
            startTaskIndexing();
            startTemplateIndexing();
            startProcessIndexing();
            startBatchIndexing();
            startPropertyIndexing();
            startWorkpieceIndexing();
            startFilterIndexing();

            try {
                sleep(pause);
            } catch (InterruptedException e) {
                logger.error("Thread interrupted: " + e.getMessage());
            }

            currentIndexState = ObjectType.NONE;
            indexingAll = false;

            pollingChannel.send(INDEXING_FINISHED_MESSAGE);

            for (String id : FacesContext.getCurrentInstance().getPartialViewContext().getRenderIds()) {
                if (Objects.equals(id, INDEXING_TABLE_ID)) {
                    Ajax.update(INDEXING_TABLE_ID);
                    break;
                }
            }
        }
    }

    @Inject
    @Push(channel = POLLING_CHANNEL_NAME)
    private PushContext pollingChannel;

    private static final Logger logger = LogManager.getLogger(IndexingForm.class);

    private transient ServiceManager serviceManager = new ServiceManager();

    private ObjectType currentIndexState = ObjectType.NONE;

    private boolean indexingAll = false;

    private Map<ObjectType, LocalDateTime> lastIndexed = new EnumMap<>(ObjectType.class);

    private LocalDateTime indexingStartedTime;

    private int indexedBatches = 0;
    private int indexedDockets = 0;
    private int indexedProcesses = 0;
    private int indexedProjects = 0;
    private int indexedProperties = 0;
    private int indexedRulesetes = 0;
    private int indexedTasks = 0;
    private int indexedTemplates = 0;
    private int indexedUsers = 0;
    private int indexedUsergroups = 0;
    private int indexedWorkpieces = 0;
    private int indexedFilter = 0;

    private IndexWorker batchWorker;
    private IndexWorker docketWorker;
    private IndexWorker processWorker;
    private IndexWorker projectWorker;
    private IndexWorker propertyWorker;
    private IndexWorker rulesetWorker;
    private IndexWorker taskWorker;
    private IndexWorker templateWorker;
    private IndexWorker userWorker;
    private IndexWorker usergroupWorker;
    private IndexWorker workpieceWorker;
    private IndexWorker filterWorker;

    private Thread indexerThread = null;

    /**
     * Standard constructor.
     */
    public IndexingForm() {
        this.batchWorker = new IndexWorker(serviceManager.getBatchService());
        this.docketWorker = new IndexWorker(serviceManager.getDocketService());
        this.processWorker = new IndexWorker(serviceManager.getProcessService());
        this.projectWorker = new IndexWorker(serviceManager.getProjectService());
        this.propertyWorker = new IndexWorker(serviceManager.getPropertyService());
        this.rulesetWorker = new IndexWorker(serviceManager.getRulesetService());
        this.taskWorker = new IndexWorker(serviceManager.getTaskService());
        this.templateWorker = new IndexWorker(serviceManager.getTemplateService());
        this.userWorker = new IndexWorker(serviceManager.getUserService());
        this.usergroupWorker = new IndexWorker(serviceManager.getUserGroupService());
        this.workpieceWorker = new IndexWorker(serviceManager.getWorkpieceService());
        this.filterWorker = new IndexWorker(serviceManager.getFilterService());
    }

    private long getCount(SearchService searchService) {
        try {
            return searchService.countDatabaseRows();
        } catch (DAOException e) {
            logger.error(e.getMessage());
            return 0;
        }
    }

    /**
     * Return the number of batches.
     *
     * @return long number of batches
     */
    public long getBatchCount() {
        return getCount(serviceManager.getBatchService());
    }

    /**
     * Return the number of dockets.
     *
     * @return long number of dockets
     */
    public long getDocketCount() {
        return getCount(serviceManager.getDocketService());
    }

    /**
     * Return the number of processes.
     *
     * @return long number of processes
     */
    public long getProcessCount() {
        return getCount(serviceManager.getProcessService());
    }

    /**
     * Return the number of projects.
     *
     * @return long number of projects
     */
    public long getProjectCount() {
        return getCount(serviceManager.getProjectService());
    }

    /**
     * Return the number of properties.
     *
     * @return long number of properties
     */
    public long getPropertyCount() {
        return getCount(serviceManager.getPropertyService());
    }

    /**
     * Return the number of rulesets.
     *
     * @return long number of rulesets
     */
    public long getRulesetCount() {
        return getCount(serviceManager.getRulesetService());
    }

    /**
     * Return the number of tasks.
     *
     * @return long number of tasks
     */
    public long getTaskCount() {
        return getCount(serviceManager.getTaskService());
    }

    /**
     * Return the number of templates.
     *
     * @return long number of templates
     */
    public long getTemplateCount() {
        return getCount(serviceManager.getTemplateService());
    }

    /**
     * Return the number of users.
     *
     * @return long number of users
     */
    public long getUserCount() {
        return getCount(serviceManager.getUserService());
    }

    /**
     * Return the number of user groups.
     *
     * @return long number of user groups
     */
    public long getUserGroupCount() {
        return getCount(serviceManager.getUserGroupService());
    }

    /**
     * Return the number of workpieces.
     *
     * @return long number of workpieces
     */
    public long getWorkpieceCount() {
        return getCount(serviceManager.getWorkpieceService());
    }

    /**
     * Return the number of filters.
     *
     * @return long number of filters
     */
    public long getFilterCount() {
        return getCount(serviceManager.getFilterService());
    }

    /**
     * Return the total number of all objects that can be indexed.
     *
     * @return long number of all items that can be written to the index
     */
    public long getTotalCount() {
        return (getBatchCount() + getDocketCount() + getProcessCount() + getProjectCount() + getPropertyCount()
                + getRulesetCount() + getTaskCount() + getTemplateCount() + getUserCount() + getUserGroupCount()
                + getWorkpieceCount() + getFilterCount());
    }

    /**
     * Return the number of currently indexed batches.
     *
     * @return int number of currently indexed batches
     */
    public int getIndexedBatches() {
        if (currentIndexState == ObjectType.BATCH) {
            indexedBatches = batchWorker.getIndexedObjects();
        }
        return indexedBatches;
    }

    /**
     * Return the number of currently indexed dockets.
     *
     * @return int number of currently indexed dockets
     */
    public int getIndexedDockets() {
        if (currentIndexState == ObjectType.DOCKET) {
            indexedDockets = docketWorker.getIndexedObjects();
        }
        return indexedDockets;
    }

    /**
     * Return the number of currently indexed processes.
     *
     * @return int number of currently indexed processes
     */
    public int getIndexedProcesses() {
        if (currentIndexState == ObjectType.PROCESS) {
            indexedProcesses = processWorker.getIndexedObjects();
        }
        return indexedProcesses;
    }

    /**
     * Return the number of currently indexed projects.
     *
     * @return int number of currently indexed projects
     */
    public int getIndexedProjects() {
        if (currentIndexState == ObjectType.PROJECT) {
            indexedProjects = projectWorker.getIndexedObjects();
        }
        return indexedProjects;
    }

    /**
     * Return the number of currently indexed properties.
     *
     * @return int number of currently indexed properties
     */
    public int getIndexedProperties() {
        if (currentIndexState == ObjectType.PROPERTY) {
            indexedProperties = propertyWorker.getIndexedObjects();
        }
        return indexedProperties;
    }

    /**
     * Return the number of currently indexed rulesets.
     *
     * @return int number of currently indexed rulesets
     */
    public int getIndexedRulesets() {
        if (currentIndexState == ObjectType.RULESET) {
            indexedRulesetes = rulesetWorker.getIndexedObjects();
        }
        return indexedRulesetes;
    }

    /**
     * Return the number of currently indexed templates.
     *
     * @return int number of currently indexed templates
     */
    public int getIndexedTemplates() {
        if (currentIndexState == ObjectType.TEMPLATE) {
            indexedTemplates = templateWorker.getIndexedObjects();
        }
        return indexedTemplates;
    }

    /**
     * Return the number of currently indexed tasks.
     *
     * @return int number of currently indexed tasks
     */
    public int getIndexedTasks() {
        if (currentIndexState == ObjectType.TASK) {
            indexedTasks = taskWorker.getIndexedObjects();
        }
        return indexedTasks;
    }

    /**
     * Return the number of currently indexed users.
     *
     * @return int number of currently indexed users
     */
    public int getIndexedUsers() {
        if (currentIndexState == ObjectType.USER) {
            indexedUsers = userWorker.getIndexedObjects();
        }
        return indexedUsers;
    }

    /**
     * Return the number of currently indexed user groups.
     *
     * @return int number of currently indexed user groups
     */
    public int getIndexedUserGroups() {
        if (currentIndexState == ObjectType.USERGROUP) {
            indexedUsergroups = usergroupWorker.getIndexedObjects();
        }
        return indexedUsergroups;
    }

    /**
     * Return the number of currently indexed workpieces.
     *
     * @return int number of currently indexed workpieces
     */
    public int getIndexedWorkpieces() {
        if (currentIndexState == ObjectType.WORKPIECE) {
            indexedWorkpieces = workpieceWorker.getIndexedObjects();
        }
        return indexedWorkpieces;
    }

    /**
     * Return the number of currently indexed filters.
     *
     * @return int number of currently indexed filters
     */
    public int getIndexedFilter() {
        if (currentIndexState == ObjectType.FILTER) {
            indexedFilter = filterWorker.getIndexedObjects();
        }
        return indexedFilter;
    }

    /**
     * Return the number of all objects processed during the current indexing
     * progress.
     *
     * @return int number of all currently indexed objects
     */
    public int getAllIndexed() {
        return (getIndexedBatches() + getIndexedDockets() + getIndexedProcesses() + getIndexedProjects()
                + getIndexedProperties() + getIndexedRulesets() + getIndexedTasks() + getIndexedTemplates()
                + getIndexedUsers() + getIndexedUserGroups() + getIndexedWorkpieces() + getIndexedFilter());
    }

    /**
     * Return the date and time the last batch indexing process finished.
     *
     * @return LocalDateTime the timestamp of the last batch indexing process
     */
    public LocalDateTime getBatchesLastIndexedDate() {
        return lastIndexed.get(ObjectType.BATCH);
    }

    /**
     * Return the date and time the last docket indexing process finished.
     *
     * @return LocalDateTime the timestamp of the last docket indexing process
     */
    public LocalDateTime getDocketsLastIndexedDate() {
        return lastIndexed.get(ObjectType.DOCKET);
    }

    /**
     * Return the date and time the last process indexing process finished.
     *
     * @return LocalDateTime the timestamp of the last process indexing process
     */
    public LocalDateTime getProcessesLastIndexedDate() {
        return lastIndexed.get(ObjectType.PROCESS);
    }

    /**
     * Return the date and time the last project indexing process finished.
     *
     * @return LocalDateTime the timestamp of the last project indexing process
     */
    public LocalDateTime getProjectsLastIndexedDate() {
        return lastIndexed.get(ObjectType.PROJECT);
    }

    /**
     * Return the date and time the last properties indexing process finished.
     *
     * @return LocalDateTime the timestamp of the last properties indexing process
     */
    public LocalDateTime getPropertiesLastIndexedDate() {
        return lastIndexed.get(ObjectType.PROPERTY);
    }

    /**
     * Return the date and time the last ruleset indexing process finished.
     *
     * @return LocalDateTime the timestamp of the last ruleset indexing process
     */
    public LocalDateTime getRulsetsLastIndexedDate() {
        return lastIndexed.get(ObjectType.RULESET);
    }

    /**
     * Return the date and time the last template indexing process finished.
     *
     * @return LocalDateTime the timestamp of the last template indexing process
     */
    public LocalDateTime getTemplatesLastIndexedDate() {
        return lastIndexed.get(ObjectType.TEMPLATE);
    }

    /**
     * Return the date and time the last task indexing process finished.
     *
     * @return LocalDateTime the timestamp of the last task indexing process
     */
    public LocalDateTime getTasksLastIndexedDate() {
        return lastIndexed.get(ObjectType.TASK);
    }

    /**
     * Return the date and time the last user indexing process finished.
     *
     * @return LocalDateTime the timestamp of the last user indexing process
     */
    public LocalDateTime getUsersLastIndexedDate() {
        return lastIndexed.get(ObjectType.USER);
    }

    /**
     * Return the date and time the last user group indexing process finished.
     *
     * @return LocalDateTime the timestamp of the last user group indexing process
     */
    public LocalDateTime getUserGroupsLastIndexedDate() {
        return lastIndexed.get(ObjectType.USERGROUP);
    }

    /**
     * Return the date and time the last workpiece indexing process finished.
     *
     * @return LocalDateTime the timestamp of the last workpiece indexing process
     */
    public LocalDateTime getWorkpiecesLastIndexedDate() {
        return lastIndexed.get(ObjectType.WORKPIECE);
    }

    /**
     * Returns the progress of the current batch indexing process in percent.
     *
     * @return the batch indexing progress
     */
    public int getBatchIndexingProgress() {
        return getProgress(getBatchCount(), ObjectType.BATCH, getIndexedBatches());
    }

    /**
     * Returns the progress of the current docket indexing process in percent.
     *
     * @return the docket indexing progress
     */
    public int getDocketsIndexingProgress() {
        return getProgress(getDocketCount(), ObjectType.DOCKET, getIndexedDockets());
    }

    /**
     * Returns the progress of the current process indexing process in percent.
     *
     * @return the process indexing progress
     */
    public int getProcessIndexingProgress() {
        return getProgress(getProcessCount(), ObjectType.PROCESS, getIndexedProcesses());
    }

    /**
     * Returns the progress of the current project indexing process in percent.
     *
     * @return the project indexing progress
     */
    public int getProjectsIndexingProgress() {
        return getProgress(getProjectCount(), ObjectType.PROJECT, getIndexedProjects());
    }

    /**
     * Returns the progress of the current properties indexing process in percent.
     *
     * @return the properties indexing progress
     */
    public int getPropertiesIndexingProgress() {
        return getProgress(getPropertyCount(), ObjectType.PROPERTY, getIndexedProperties());
    }

    /**
     * Returns the progress of the current ruleset indexing process in percent.
     *
     * @return the ruleset indexing progress
     */
    public int getRulesetsIndexingProgress() {
        return getProgress(getRulesetCount(), ObjectType.RULESET, getIndexedRulesets());
    }

    /**
     * Returns the progress of the current template indexing process in percent.
     *
     * @return the template indexing progress
     */
    public int getTemplatesIndexingProgress() {
        return getProgress(getTemplateCount(), ObjectType.TEMPLATE, getIndexedTemplates());
    }

    /**
     * Returns the progress of the current task indexing process in percent.
     *
     * @return the task indexing progress
     */
    public int getTasksIndexingProgress() {
        return getProgress(getTaskCount(), ObjectType.TASK, getIndexedTasks());
    }

    /**
     * Returns the progress of the current user indexing process in percent.
     *
     * @return the user indexing progress
     */
    public int getUserIndexingProgress() {
        return getProgress(getUserCount(), ObjectType.USER, getIndexedUsers());
    }

    /**
     * Returns the progress of the current usergroup indexing process in percent.
     *
     * @return the usergroup indexing progress
     */
    public int getUserGroupIndexingProgress() {
        return getProgress(getUserGroupCount(), ObjectType.USERGROUP, getIndexedUserGroups());
    }

    /**
     * Returns the progress of the current workpiece indexing process in percent.
     *
     * @return the workpiece indexing progress
     */
    public int getWorkpieceIndexingProgress() {
        return getProgress(getWorkpieceCount(), ObjectType.WORKPIECE, getIndexedWorkpieces());
    }

    /**
     * Returns the progress of the current filter indexing process in percent.
     *
     * @return the filter indexing progress
     */
    public int getFilterIndexingProgress() {
        return getProgress(getFilterCount(), ObjectType.FILTER, getIndexedFilter());
    }

    private void startIndexing(ObjectType type, IndexWorker worker) {
        int attempts = 0;
        while (attempts < 10) {
            try {
                if (Objects.equals(currentIndexState, ObjectType.NONE)) {
                    indexingStartedTime = LocalDateTime.now();
                    currentIndexState = type;
                    pollingChannel.send(INDEXING_STARTED_MESSAGE + currentIndexState);
                    indexerThread = new Thread((worker));
                    indexerThread.setDaemon(true);
                    indexerThread.start();
                    indexerThread.join();
                    break;
                } else {
                    logger.debug("Cannot start '" + type
                            + "' indexing while a different indexing process running: '" + currentIndexState + "'");
                    Thread.sleep(pause);
                    attempts++;
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * Starts the process of indexing batches to the ElasticSearch index.
     */
    public void startBatchIndexing() {
        startIndexing(ObjectType.BATCH, batchWorker);
    }

    /**
     * Starts the process of indexing dockets to the ElasticSearch index.
     */
    public void startDocketIndexing() {
        startIndexing(ObjectType.DOCKET, docketWorker);
    }

    /**
     * Starts the process of indexing processes to the ElasticSearch index.
     */
    public void startProcessIndexing() {
        startIndexing(ObjectType.PROCESS, processWorker);
    }

    /**
     * Starts the process of indexing projects to the ElasticSearch index.
     */
    public void startProjectIndexing() {
        startIndexing(ObjectType.PROJECT, projectWorker);
    }

    /**
     * Starts the process of indexing properties to the ElasticSearch index.
     */
    public void startPropertyIndexing() {
        startIndexing(ObjectType.PROPERTY, propertyWorker);
    }

    /**
     * Starts the process of indexing rulesets to the ElasticSearch index.
     */
    public void startRulesetIndexing() {
        startIndexing(ObjectType.RULESET, rulesetWorker);
    }

    /**
     * Starts the process of indexing tasks to the ElasticSearch index.
     */
    public void startTaskIndexing() {
        startIndexing(ObjectType.TASK, taskWorker);
    }

    /**
     * Starts the process of indexing templates to the ElasticSearch index.
     */
    public void startTemplateIndexing() {
        startIndexing(ObjectType.TEMPLATE, templateWorker);
    }

    /**
     * Starts the process of indexing users to the ElasticSearch index.
     */
    public void startUserIndexing() {
        startIndexing(ObjectType.USER, userWorker);
    }

    /**
     * Starts the process of indexing user groups to the ElasticSearch index.
     */
    public void startUserGroupIndexing() {
        startIndexing(ObjectType.USERGROUP, usergroupWorker);
    }

    /**
     * Starts the process of indexing workpieces to the ElasticSearch index.
     */
    public void startWorkpieceIndexing() {
        startIndexing(ObjectType.WORKPIECE, workpieceWorker);
    }

    /**
     * Starts the process of indexing filters to the ElasticSearch index.
     */
    public void startFilterIndexing() {
        startIndexing(ObjectType.FILTER, filterWorker);
    }

    /**
     * Starts the process of indexing all objects to the ElasticSearch index.
     */
    public void startAllIndexing() {
        IndexAllThread indexAllThread = new IndexAllThread();
        indexAllThread.start();
    }

    /**
     * Return the overall progress in percent of the currently running indexing
     * process, incorporating the total number of indexed and all objects.
     *
     * @return the overall progress of the indexing process
     */
    public int getAllIndexingProgress() {
        return (int) ((getAllIndexed() / (float) getTotalCount()) * 100);
    }

    /**
     * Return whether any indexing process is currently in progress or not.
     *
     * @return boolean Value indicating whether any indexing process is currently in
     *         progress or not
     */
    public boolean indexingInProgress() {
        return (!Objects.equals(this.currentIndexState, ObjectType.NONE) || indexingAll);
    }

    /**
     * Create mapping which enables sorting and other aggregation functionalities.
     */
    public void createMapping() {
        try {
            indexRestClient.initiateClient();
            indexRestClient.setIndex(ConfigMain.getParameter("elasticsearch.index", "kitodo"));
            if (readMapping().equals("")) {
                indexRestClient.createIndex();
            } else {
                indexRestClient.createIndex(readMapping());
            }
        } catch (CustomResponseException | IOException | ParseException e) {
            logger.error(e);
        }
    }

    /**
     * Return server information provided by the searchService and gathered by the
     * rest client.
     *
     * @return String information about the server
     */
    public String getServerInformation() {
        return this.serviceManager.getBatchService().getServerInformation();
    }

    /**
     * Return the progress in percent of the currently running indexing process. If
     * the list of entries to be indexed is empty, this will return "0".
     *
     * @param numberOfObjects
     *            the number of existing objects of the given ObjectType in the
     *            database
     * @param currentType
     *            the ObjectType for which the progress will be determined
     * @param nrOfindexedObjects
     *            the number of objects of the given ObjectType that have already
     *            been indexed
     *
     * @return the progress of the current indexing process in percent
     */
    private int getProgress(long numberOfObjects, ObjectType currentType, long nrOfindexedObjects) {
        int progress = numberOfObjects > 0 ? (int) ((nrOfindexedObjects / (float) numberOfObjects) * 100) : 0;
        if (Objects.equals(currentIndexState, currentType)) {
            if (numberOfObjects == 0 || progress == 100) {
                lastIndexed.put(currentIndexState, LocalDateTime.now());
                currentIndexState = ObjectType.NONE;
                indexerThread.interrupt();
                pollingChannel.send(INDEXING_FINISHED_MESSAGE + currentType + "!");
            }
        }
        return progress;
    }

    private void resetGlobalProgress() {
        indexedBatches = 0;
        indexedDockets = 0;
        indexedProcesses = 0;
        indexedProjects = 0;
        indexedProperties = 0;
        indexedRulesetes = 0;
        indexedTasks = 0;
        indexedTemplates = 0;
        indexedUsers = 0;
        indexedUsergroups = 0;
        indexedWorkpieces = 0;
        indexedFilter = 0;
    }

    private static String readMapping() throws ParseException {
        JSONParser parser = new JSONParser();
        ClassLoader classloader = Thread.currentThread().getContextClassLoader();
        try (InputStream inputStream = classloader.getResourceAsStream("mapping.json")) {
            String mapping = IOUtils.toString(inputStream, "UTF-8");
            Object object = parser.parse(mapping);
            JSONObject jsonObject = (JSONObject) object;
            return jsonObject.toJSONString();
        } catch (IOException e) {
            logger.error(e);
            return "";
        }
    }
}