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

org.bonitasoft.engine.scheduler.impl.SchedulerServiceImpl Maven / Gradle / Ivy

The newest version!
/**
 * Copyright (C) 2019 Bonitasoft S.A.
 * Bonitasoft, 32 rue Gustave Eiffel - 38000 Grenoble
 * This library is free software; you can redistribute it and/or modify it under the terms
 * of the GNU Lesser General Public License as published by the Free Software Foundation
 * version 2.1 of the License.
 * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Lesser General Public License for more details.
 * You should have received a copy of the GNU Lesser General Public License along with this
 * program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
 * Floor, Boston, MA 02110-1301, USA.
 **/
package org.bonitasoft.engine.scheduler.impl;

import java.io.Serializable;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.stream.Collectors;

import lombok.extern.slf4j.Slf4j;
import org.bonitasoft.engine.commons.exceptions.SBonitaException;
import org.bonitasoft.engine.commons.exceptions.SObjectNotFoundException;
import org.bonitasoft.engine.events.EventService;
import org.bonitasoft.engine.events.model.SEvent;
import org.bonitasoft.engine.events.model.SFireEventException;
import org.bonitasoft.engine.persistence.SBonitaReadException;
import org.bonitasoft.engine.scheduler.*;
import org.bonitasoft.engine.scheduler.exception.SSchedulerException;
import org.bonitasoft.engine.scheduler.exception.jobLog.SJobLogDeletionException;
import org.bonitasoft.engine.scheduler.model.SJobDescriptor;
import org.bonitasoft.engine.scheduler.model.SJobParameter;
import org.bonitasoft.engine.scheduler.trigger.Trigger;
import org.bonitasoft.engine.service.ServicesResolver;
import org.bonitasoft.engine.services.PersistenceService;
import org.bonitasoft.engine.sessionaccessor.STenantIdNotSetException;
import org.bonitasoft.engine.sessionaccessor.SessionAccessor;
import org.bonitasoft.engine.transaction.TransactionService;

/**
 * @author Matthieu Chaffotte
 * @author Baptiste Mesta
 * @author Elias Ricken de Medeiros
 * @author Yanyan Liu
 * @author Celine Souchet
 */
@Slf4j
public class SchedulerServiceImpl implements SchedulerService {

    private final SchedulerExecutor schedulerExecutor;

    private final JobService jobService;

    private final EventService eventService;

    private final SEvent schedulerStarted;

    private final SEvent schedulerStopped;

    private final SEvent jobFailed;

    private final SessionAccessor sessionAccessor;

    private final TransactionService transactionService;

    private final ServicesResolver servicesResolver;
    private PersistenceService persistenceService;

    /**
     * Create a new instance of scheduler service.
     */
    public SchedulerServiceImpl(final SchedulerExecutor schedulerExecutor, final JobService jobService,
            final EventService eventService, final TransactionService transactionService,
            final SessionAccessor sessionAccessor,
            final ServicesResolver servicesResolver, final PersistenceService persistenceService) {
        this.schedulerExecutor = schedulerExecutor;
        this.jobService = jobService;
        this.servicesResolver = servicesResolver;
        this.persistenceService = persistenceService;
        schedulerStarted = new SEvent(SCHEDULER_STARTED);
        schedulerStopped = new SEvent(SCHEDULER_STOPPED);
        jobFailed = new SEvent(JOB_FAILED);
        this.eventService = eventService;
        this.transactionService = transactionService;
        this.sessionAccessor = sessionAccessor;
        schedulerExecutor.setBOSSchedulerService(this);
    }

    @Override
    public void schedule(final SJobDescriptor jobDescriptor, final Trigger trigger) throws SSchedulerException {
        final SJobDescriptor createdJobDescriptor = createJobDescriptor(jobDescriptor, Collections.emptyList());
        internalSchedule(createdJobDescriptor, trigger);
    }

    @Override
    public void schedule(final SJobDescriptor jobDescriptor, final List parameters,
            final Trigger trigger) throws SSchedulerException {
        if (trigger == null) {
            throw new SSchedulerException("The trigger is null");
        }
        final SJobDescriptor createdJobDescriptor = createJobDescriptor(jobDescriptor, parameters);
        internalSchedule(createdJobDescriptor, trigger);
    }

    @Override
    public void executeAgain(final long jobDescriptorId, int delayInMillis) throws SSchedulerException {
        final SJobDescriptor jobDescriptor = jobService.getJobDescriptor(jobDescriptorId);
        schedulerExecutor.executeAgain(jobDescriptorId, getTenantIdAsString(), jobDescriptor.getJobName(),
                false, delayInMillis);
    }

    @Override
    public void retryJobThatFailed(long jobDescriptorId) throws SSchedulerException {
        final SJobDescriptor jobDescriptor = jobService.getJobDescriptor(jobDescriptorId);
        deleteFailedJobs(jobDescriptorId);
        schedulerExecutor.executeAgain(jobDescriptorId, getTenantIdAsString(), jobDescriptor.getJobName(),
                false, 0);
    }

    @Override
    public void retryJobThatFailed(final long jobDescriptorId, final List parameters)
            throws SSchedulerException {
        final SJobDescriptor jobDescriptor = jobService.getJobDescriptor(jobDescriptorId);
        jobService.setJobParameters(getTenantId(), jobDescriptor.getId(), parameters);
        deleteFailedJobs(jobDescriptorId);
        schedulerExecutor.executeAgain(jobDescriptorId, getTenantIdAsString(), jobDescriptor.getJobName(),
                false, 0);
    }

    private void deleteFailedJobs(long jobDescriptorId) throws SSchedulerException {
        try {
            jobService.deleteJobLogs(jobDescriptorId);
        } catch (SJobLogDeletionException | SBonitaReadException e) {
            throw new SSchedulerException("Unable to delete failed jobs logs", e);
        }
    }

    private SJobDescriptor createJobDescriptor(final SJobDescriptor sJobDescriptor,
            final List parameters) throws SSchedulerException {
        final long tenantId = getTenantId();
        try {
            final SJobDescriptor createdJobDescriptor = jobService.createJobDescriptor(sJobDescriptor, tenantId);
            jobService.createJobParameters(parameters, tenantId, createdJobDescriptor.getId());
            return createdJobDescriptor;
        } catch (final SBonitaException sbe) {
            throw new SSchedulerException(sbe);
        }
    }

    private void internalSchedule(final SJobDescriptor jobDescriptor, final Trigger trigger)
            throws SSchedulerException {
        final String tenantId = getTenantIdAsString();
        try {
            schedulerExecutor.schedule(jobDescriptor.getId(), tenantId, jobDescriptor.getJobName(), trigger,
                    false);
        } catch (final Throwable e) {
            log.error("", e);
            try {
                eventService.fireEvent(jobFailed);
            } catch (final SFireEventException e1) {
                log.error("", e1);
            }
            throw new SSchedulerException(e);
        }
    }

    private long getTenantId() throws SSchedulerException {
        final long tenantId;
        try {
            tenantId = sessionAccessor.getTenantId();
        } catch (final STenantIdNotSetException e) {
            throw new SSchedulerException(e);
        }
        return tenantId;
    }

    private String getTenantIdAsString() throws SSchedulerException {
        return String.valueOf(getTenantId());
    }

    @Override
    public boolean isStarted() throws SSchedulerException {
        return schedulerExecutor.isStarted();
    }

    @Override
    public boolean isStopped() throws SSchedulerException {
        return schedulerExecutor.isShutdown();
    }

    @Override
    public void start() throws SSchedulerException, SFireEventException {
        log.info("Start scheduler");
        schedulerExecutor.start();
        eventService.fireEvent(schedulerStarted);
    }

    @Override
    public void stop() throws SSchedulerException, SFireEventException {
        schedulerExecutor.shutdown();
        eventService.fireEvent(schedulerStopped);
    }

    @Override
    public void pauseJobs(final long tenantId) throws SSchedulerException {
        schedulerExecutor.pauseJobs(String.valueOf(tenantId));
    }

    @Override
    public void resumeJobs(final long tenantId) throws SSchedulerException {
        schedulerExecutor.resumeJobs(String.valueOf(tenantId));
    }

    @Override
    public boolean delete(final String jobName) throws SSchedulerException {
        final boolean delete = schedulerExecutor.delete(jobName, String.valueOf(getTenantId()));
        jobService.deleteJobDescriptorByJobName(jobName);
        return delete;
    }

    @Override
    public void deleteJobs() throws SSchedulerException {
        schedulerExecutor.deleteJobs(String.valueOf(getTenantId()));
        jobService.deleteAllJobDescriptors();
    }

    @Override
    public List getJobs() throws SSchedulerException {
        return schedulerExecutor.getJobs(String.valueOf(getTenantId()));
    }

    @Override
    public List getAllJobs() throws SSchedulerException {
        return schedulerExecutor.getAllJobs();
    }

    /**
     * Get the persisted job from the database inside its own transaction.
     *
     * @return the newly created job
     * @throws SSchedulerException if the job cannot be created successfully
     */
    StatelessJob getPersistedJob(final JobIdentifier jobIdentifier) throws SSchedulerException {
        try {
            sessionAccessor.setTenantId(jobIdentifier.getTenantId());
            return transactionService.executeInTransaction(new PersistedJobCallable(jobIdentifier));
        } catch (final Exception e) {
            throw new SSchedulerException(e);
        } finally {
            sessionAccessor.deleteTenantId();
        }
    }

    private class PersistedJobCallable implements Callable {

        private final JobIdentifier jobIdentifier;

        PersistedJobCallable(final JobIdentifier jobIdentifier) {
            this.jobIdentifier = jobIdentifier;
        }

        @Override
        public JobWrapper call() throws Exception {
            final SJobDescriptor sJobDescriptor = jobService.getJobDescriptor(jobIdentifier.getId());
            if (sJobDescriptor == null) {
                throw new SObjectNotFoundException(String
                        .format("The job %s does not exist anymore. It might be already executed", jobIdentifier));
            }
            final String jobClassName = sJobDescriptor.getJobClassName();
            final Class jobClass = Class.forName(jobClassName);
            final StatelessJob statelessJob = (StatelessJob) jobClass.newInstance();

            Map parameters = jobService.getJobParameters(jobIdentifier.getId())
                    .stream()
                    .collect(Collectors.toMap(SJobParameter::getKey, SJobParameter::getValue));
            parameters.put(StatelessJob.JOB_DESCRIPTOR_ID, jobIdentifier.getId());
            statelessJob.setAttributes(parameters);
            if (servicesResolver != null) {
                servicesResolver.injectServices(jobIdentifier.getTenantId(), statelessJob);
            }
            return new JobWrapper(jobIdentifier, statelessJob, jobIdentifier.getTenantId(), eventService,
                    sessionAccessor, transactionService, persistenceService, jobService);
        }
    }

    @Override
    public void pause() throws SBonitaException {
        pauseJobs(getTenantId());
    }

    @Override
    public void resume() throws SBonitaException {
        resumeJobs(getTenantId());
    }

    @Override
    public void rescheduleErroneousTriggers() throws SSchedulerException {
        schedulerExecutor.rescheduleErroneousTriggers();
    }

    @Override
    public Date rescheduleJob(final String triggerName, final String groupName, final Date triggerStartTime)
            throws SSchedulerException {
        return schedulerExecutor.rescheduleJob(triggerName, groupName, triggerStartTime);
    }

    @Override
    public boolean isExistingJob(final String jobName) throws SSchedulerException {
        return schedulerExecutor.isExistingJob(jobName, String.valueOf(getTenantId()));
    }

    @Override
    public boolean mayFireAgain(String groupName, String jobName) throws SSchedulerException {
        return schedulerExecutor.mayFireAgain(groupName, jobName);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy