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

org.bonitasoft.engine.jobs.BPMEventHandlingJob Maven / Gradle / Ivy

There is a newer version: 7.8.0
Show newest version
/**
 * Copyright (C) 2015 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.jobs;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

import org.bonitasoft.engine.builder.BuilderFactory;
import org.bonitasoft.engine.commons.exceptions.SBonitaException;
import org.bonitasoft.engine.core.process.definition.ProcessDefinitionService;
import org.bonitasoft.engine.core.process.definition.model.SProcessDefinitionDeployInfo;
import org.bonitasoft.engine.core.process.instance.api.event.EventInstanceService;
import org.bonitasoft.engine.core.process.instance.api.exceptions.event.trigger.SEventTriggerInstanceReadException;
import org.bonitasoft.engine.core.process.instance.api.exceptions.event.trigger.SMessageModificationException;
import org.bonitasoft.engine.core.process.instance.api.exceptions.event.trigger.SWaitingEventModificationException;
import org.bonitasoft.engine.core.process.instance.model.builder.event.handling.SMessageInstanceBuilderFactory;
import org.bonitasoft.engine.core.process.instance.model.builder.event.handling.SWaitingMessageEventBuilderFactory;
import org.bonitasoft.engine.core.process.instance.model.event.handling.SBPMEventType;
import org.bonitasoft.engine.core.process.instance.model.event.handling.SMessageEventCouple;
import org.bonitasoft.engine.core.process.instance.model.event.handling.SMessageInstance;
import org.bonitasoft.engine.core.process.instance.model.event.handling.SWaitingMessageEvent;
import org.bonitasoft.engine.execution.work.WorkFactory;
import org.bonitasoft.engine.log.technical.TechnicalLoggerService;
import org.bonitasoft.engine.recorder.model.EntityUpdateDescriptor;
import org.bonitasoft.engine.scheduler.JobParameter;
import org.bonitasoft.engine.scheduler.JobService;
import org.bonitasoft.engine.scheduler.SchedulerService;
import org.bonitasoft.engine.scheduler.exception.SJobConfigurationException;
import org.bonitasoft.engine.scheduler.exception.SJobExecutionException;
import org.bonitasoft.engine.service.TenantServiceAccessor;
import org.bonitasoft.engine.transaction.UserTransactionService;
import org.bonitasoft.engine.work.WorkService;

/**
 * @author Elias Ricken de Medeiros
 * @author Matthieu Chaffotte
 * @author Emmanuel Duchastenier
 */
public class BPMEventHandlingJob extends InternalJob {

    private static final long serialVersionUID = 8929044925208984537L;

    private int maxCouples = 1000;

    private transient EventInstanceService eventInstanceService;

    private transient WorkService workService;

    private transient UserTransactionService transactionService;

    private transient JobService jobService;

    private transient SchedulerService schedulerService;

    private transient TechnicalLoggerService loggerService;
    private ProcessDefinitionService processDefinitionService;

    @Override
    public String getName() {
        return "BPMEventHandling";
    }

    @Override
    public String getDescription() {
        return "Handle BPM events";
    }

    @Override
    public void execute() throws SJobExecutionException {
        try {
            final List potentialMessageCouples = getMessageEventCouples();
            final List uniqueCouples = getMessageUniqueCouples(potentialMessageCouples);
            executeUniqueMessageCouplesWork(uniqueCouples);
            if (potentialMessageCouples.size() == maxCouples) {
                rescheduleJob();
            }
        } catch (final Exception e) {
            throw new SJobExecutionException(e);
        }
    }

    private void executeUniqueMessageCouplesWork(final List uniqueCouples) throws SBonitaException {
        for (final SMessageEventCouple couple : uniqueCouples) {
            final long messageInstanceId = couple.getMessageInstanceId();
            final long waitingMessageId = couple.getWaitingMessageId();
            final SBPMEventType waitingMessageEventType = couple.getWaitingMessageEventType();

            // Mark messages that will be treated as "treatment in progress":
            final SWaitingMessageEvent waitingMsg = eventInstanceService.getWaitingMessage(waitingMessageId);
            final SMessageInstance messageInstance = eventInstanceService.getMessageInstance(messageInstanceId);
            markMessageAsInProgress(messageInstance);

            //EVENT_SUB_PROCESS of type non-interrupted should be considered as well, as soon as we support them
            if (!SBPMEventType.START_EVENT.equals(waitingMessageEventType)) {
                markWaitingMessageAsInProgress(waitingMsg);
            }
            long processDefinitionId = waitingMsg.getProcessDefinitionId();
            SProcessDefinitionDeployInfo processDeploymentInfo = processDefinitionService.getProcessDeploymentInfo(processDefinitionId);
            workService.registerWork(WorkFactory.createExecuteMessageCoupleWork(messageInstance, waitingMsg));
        }
    }

    /**
     * From a list of couples that may contain duplicate waiting message candidates, select only one waiting message for each message instance: the first
     * matching waiting message is arbitrary chosen.
     * In the case of SWaitingMessageEvent of types {@link SBPMEventType#START_EVENT} or {@link SBPMEventType#EVENT_SUB_PROCESS}, it can be
     * selected several times to trigger multiple instances.
     *
     * @param potentialMessageCouples
     *        all the possible couples that match the potential correlation.
     * @return the reduced list of couple, where we insure that a unique message instance is associated with a unique waiting message.
     */
    protected List getMessageUniqueCouples(List potentialMessageCouples) throws SEventTriggerInstanceReadException {
        final List takenMessages = new ArrayList();
        final List takenWaitings = new ArrayList();
        final List uniqueMessageCouples = new ArrayList();

        for (final SMessageEventCouple couple : potentialMessageCouples) {
            final long messageInstanceId = couple.getMessageInstanceId();
            final long waitingMessageId = couple.getWaitingMessageId();
            final SBPMEventType waitingMessageEventType = couple.getWaitingMessageEventType();
            if (!takenMessages.contains(messageInstanceId) && !takenWaitings.contains(waitingMessageId)) {
                takenMessages.add(messageInstanceId);
                // Starting events and Starting event sub-processes must not be considered as taken if they appear several times
                //EVENT_SUB_PROCESS of type non-interrupted should be considered as well, as soon as we support them
                if (!SBPMEventType.START_EVENT.equals(waitingMessageEventType)) {
                    takenWaitings.add(waitingMessageId);
                }
                uniqueMessageCouples.add(couple);
            }
        }
        return uniqueMessageCouples;
    }

    List getMessageEventCouples() throws SEventTriggerInstanceReadException {
        return eventInstanceService.getMessageEventCouples(0, maxCouples);
    }

    @Override
    public void setAttributes(final Map attributes) throws SJobConfigurationException {
        final TenantServiceAccessor tenantServiceAccessor = getTenantServiceAccessor();
        setAttributes(tenantServiceAccessor, attributes);
    }

    void setAttributes(final TenantServiceAccessor tenantServiceAccessor, final Map attributes) {
        eventInstanceService = tenantServiceAccessor.getEventInstanceService();
        processDefinitionService = tenantServiceAccessor.getProcessDefinitionService();
        workService = tenantServiceAccessor.getWorkService();
        transactionService = tenantServiceAccessor.getUserTransactionService();
        jobService = tenantServiceAccessor.getJobService();
        schedulerService = tenantServiceAccessor.getSchedulerService();
        loggerService = tenantServiceAccessor.getTechnicalLoggerService();

        final Integer batchSize = (Integer) attributes.get(JobParameter.BATCH_SIZE.name());
        if (batchSize != null) {
            maxCouples = batchSize;
        }
    }

    private void markMessageAsInProgress(final SMessageInstance messageInstance) throws SMessageModificationException {
        final EntityUpdateDescriptor descriptor = new EntityUpdateDescriptor();
        descriptor.addField(BuilderFactory.get(SMessageInstanceBuilderFactory.class).getHandledKey(), true);
        eventInstanceService.updateMessageInstance(messageInstance, descriptor);
    }

    private void markWaitingMessageAsInProgress(final SWaitingMessageEvent waitingMsg) throws SWaitingEventModificationException {
        final EntityUpdateDescriptor descriptor = new EntityUpdateDescriptor();
        descriptor.addField(BuilderFactory.get(SWaitingMessageEventBuilderFactory.class).getProgressKey(),
                SWaitingMessageEventBuilderFactory.PROGRESS_IN_TREATMENT_KEY);
        eventInstanceService.updateWaitingMessage(waitingMsg, descriptor);
    }

    private void rescheduleJob() throws Exception {
        final ExecuteAgainJobSynchronization jobSynchronization = new ExecuteAgainJobSynchronization(getName(), jobService, schedulerService, loggerService);
        transactionService.registerBonitaSynchronization(jobSynchronization);
    }

    protected int getMaxCouples() {
        return maxCouples;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy