All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.sakaiproject.tool.assessment.services.BackfillItemHashesJob Maven / Gradle / Ivy

There is a newer version: 23.3
Show newest version
/**
 * Copyright (c) 2005-2017 The Apereo Foundation
 *
 * Licensed under the Educational Community License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *             http://opensource.org/licenses/ecl2
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.sakaiproject.tool.assessment.services;

import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.quartz.JobExecutionException;
import org.sakaiproject.api.app.scheduler.ConfigurableJobPropertyValidationException;
import org.sakaiproject.api.app.scheduler.ConfigurableJobPropertyValidator;
import org.sakaiproject.component.api.ServerConfigurationService;
import org.sakaiproject.component.app.scheduler.jobs.AbstractConfigurableJob;
import org.sakaiproject.email.api.EmailService;
import org.sakaiproject.tool.api.Session;
import org.sakaiproject.tool.api.SessionManager;
import org.sakaiproject.tool.assessment.facade.BackfillItemHashResult;

@Slf4j
public class BackfillItemHashesJob extends AbstractConfigurableJob {

    private static final String BATCH_SIZE = "batch.size";
    private static final String BATCH_SIZE_NON_NUMERIC = "batch.size.non.numeric";
    private static final String BACKFILL_ITEMS = "backfill.items";
    private static final String BACKFILL_PUBLISHED_ITEMS = "backfill.published.items";
    private static final String BACKFILL_PUBLISHED_ITEMS_BASELINE_HASH = "backfill.published.items.baseline.hash";
    private static final String NOTIFICATION_EMAIL_ADDR = "notification.email.address";
    private static final String INVALID_NOTIFICATION_EMAIL_ADDR = "invalid.notification.email.address";
    private static final String UNRECOGNIZED_JOB_CONFIG_PROPERTY = "unrecognized.job.config.property";
    private static final int DEFAULT_BATCH_SIZE = 100;

    private SessionManager sessionManager;
    private ServerConfigurationService serverConfigurationService;
    private EmailService emailService;

    @Override
    public void runJob() throws JobExecutionException {
        final long start = System.currentTimeMillis();
        log.info("Backfill question hashing - Job start");

        BackfillItemHashResult itemBackfillResult = null;
        BackfillItemHashResult publishedItemBackfillResult = null;
        RuntimeException error = null;
        try {
            logIn();
            final int batchSize = getBatchSize();
            final boolean backfillItemHashes = getBackfillItemHashes();
            if ( backfillItemHashes ) {
                final ItemService itemService = new ItemService();
                itemBackfillResult = itemService.backfillItemHashes(batchSize, true);
            }
            final boolean backfillPublishedItemHashes = getBackfillPublishedItemHashes();
            if ( backfillPublishedItemHashes ) {
                final boolean backfillPublishedItemBaselineHashes = getBackfillPublishedItemBaselineHashes();
                final PublishedItemService publishedItemService = new PublishedItemService();
                publishedItemBackfillResult = publishedItemService.backfillItemHashes(batchSize, backfillPublishedItemBaselineHashes);
            }
        } catch (RuntimeException e) {
            error = e;
        } finally {
            try {
                if (error == null) {
                    log.info("Backfill question hashing - Job exiting " + elapsedTimeMessage(start)
                            + " " + jobResultMessage(itemBackfillResult, publishedItemBackfillResult, " "));
                } else {
                    // we know Quartz will not log exceptions by default, so we do it here
                    log.info("Backfill question hashing - Job exiting with error. " + elapsedTimeMessage(start)
                            + " " + jobResultMessage(itemBackfillResult, publishedItemBackfillResult, " "), error);
                }
                sentNotification(itemBackfillResult, publishedItemBackfillResult, error);
            } catch ( RuntimeException e ) {
                log.warn("Failed to send job completion email notification", e);
            } finally {
                try {
                    logOut();
                } catch (Exception e) {
                    log.warn("Backfill question hashing - Failed to cleanup Sakai session.", e);
                }
            }
            if ( error != null ) {
                throw new JobExecutionException(error);
            }
        }
    }

    private void sentNotification(BackfillItemHashResult itemBackfillResult, BackfillItemHashResult publishedItemBackfillResult, RuntimeException error) {
        final String to = getNotificationEmailAddress();
        if ( to == null ) {
            return;
        }
        final String from = "<"+ serverConfigurationService.getString("setup.request","no-reply@" + serverConfigurationService.getServerName()) + ">";
        final StringBuilder body = new StringBuilder();
        if ( error != null ) {
            body.append("Job failed with following error message. See logs for full details.").append("\n\n")
                    .append(error.getMessage())
                    .append("\n\n");
        }
        body.append(jobResultMessage(itemBackfillResult, publishedItemBackfillResult, "\n\n"));
        emailService.send(from,
                to,
                "Backfill Item Hash Job: " + (error == null ? "Success" : "Failure"),
                body.toString(),
                to,
                null,
                null);
    }

    private int getBatchSize() {
        String val = StringUtils.trimToNull(getConfiguredProperty(BATCH_SIZE));
        if ( val == null ) {
            return DEFAULT_BATCH_SIZE;
        }
        int valInt = Integer.parseInt(val);
        return valInt <= 0 ? DEFAULT_BATCH_SIZE : valInt;
    }

    private boolean getBackfillItemHashes() {
        return getBooleanConfig(BACKFILL_ITEMS, true);
    }

    private boolean getBackfillPublishedItemHashes() {
        return getBooleanConfig(BACKFILL_PUBLISHED_ITEMS, true);
    }

    private boolean getBackfillPublishedItemBaselineHashes() {
        return getBooleanConfig(BACKFILL_PUBLISHED_ITEMS_BASELINE_HASH, false);
    }

    private boolean getBooleanConfig(String name, boolean defaultTo) {
        String val = StringUtils.trimToNull(getConfiguredProperty(name));
        if ( val == null ) {
            return defaultTo;
        }
        return Boolean.parseBoolean(val);
    }

    private String getNotificationEmailAddress() {
        return StringUtils.trimToNull(getConfiguredProperty(NOTIFICATION_EMAIL_ADDR));
    }

    private String jobResultMessage(BackfillItemHashResult itemBackfillResult, BackfillItemHashResult publishedItemBackfillResult, String separator) {
        final StringBuilder sb = new StringBuilder();
        if ( itemBackfillResult != null ) {
            sb.append("Item backfill results: [").append(itemBackfillResult).append("]");
            if ( publishedItemBackfillResult != null ) {
                sb.append(separator);
            }
        }
        if ( publishedItemBackfillResult != null ) {
            sb.append("Published item backfill results: [").append(publishedItemBackfillResult).append("]");
        }
        return sb.toString();
    }

    private String elapsedTimeMessage(long start) {
        return "Elapsed time: [" + (System.currentTimeMillis() - start) + "ms]";
    }

    private void logIn() {
        Session sakaiSession = sessionManager.getCurrentSession();
        sakaiSession.setUserId("admin");
        sakaiSession.setUserEid("admin");
    }

    private void logOut() {
        final Session currentSession = sessionManager.getCurrentSession();
        currentSession.invalidate(); // includes removing from ThreadLocal storage
    }

    public void setSessionManager(SessionManager sessionManager) {
        this.sessionManager = sessionManager;
    }

    public void setServerConfigurationService(ServerConfigurationService serverConfigurationService) {
        this.serverConfigurationService = serverConfigurationService;
    }

    public void setEmailService(EmailService emailService) {
        this.emailService = emailService;
    }

    public static class BackfillItemHashesConfigurationValidator implements ConfigurableJobPropertyValidator {

        public void assertValid(String propertyLabel, String value)
                throws ConfigurableJobPropertyValidationException {
            value = StringUtils.trimToNull(value);
            if ( BATCH_SIZE.equals(propertyLabel) ) {
                if ( value == null ) {
                    return;
                }

                try {
                    Integer.parseInt(value);
                } catch (NumberFormatException e) {
                    throw new ConfigurableJobPropertyValidationException(BATCH_SIZE_NON_NUMERIC);
                }
            } else if ( BACKFILL_ITEMS.equals(propertyLabel)
                    || BACKFILL_PUBLISHED_ITEMS.equals(propertyLabel)
                    || BACKFILL_PUBLISHED_ITEMS_BASELINE_HASH.equals(propertyLabel)) {
                // parsing booleans never fails
            } else if ( NOTIFICATION_EMAIL_ADDR.equals(propertyLabel) ) {
                if ( value == null ) {
                    return;
                }
                try {
                    new InternetAddress(value, true);
                } catch (AddressException e) {
                    throw new ConfigurableJobPropertyValidationException(INVALID_NOTIFICATION_EMAIL_ADDR);
                }
            } else {
                throw new ConfigurableJobPropertyValidationException(UNRECOGNIZED_JOB_CONFIG_PROPERTY);
            }
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy