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

org.bonitasoft.engine.command.api.impl.CommandServiceImpl Maven / Gradle / Ivy

There is a newer version: 10.2.0
Show 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.command.api.impl;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.bonitasoft.engine.builder.BuilderFactory;
import org.bonitasoft.engine.command.CommandService;
import org.bonitasoft.engine.command.SCommandAlreadyExistsException;
import org.bonitasoft.engine.command.SCommandCreationException;
import org.bonitasoft.engine.command.SCommandDeletionException;
import org.bonitasoft.engine.command.SCommandGettingException;
import org.bonitasoft.engine.command.SCommandNotFoundException;
import org.bonitasoft.engine.command.SCommandUpdateException;
import org.bonitasoft.engine.command.api.record.SelectDescriptorBuilder;
import org.bonitasoft.engine.command.model.SCommand;
import org.bonitasoft.engine.command.model.SCommandCriterion;
import org.bonitasoft.engine.command.model.SCommandLogBuilder;
import org.bonitasoft.engine.command.model.SCommandLogBuilderFactory;
import org.bonitasoft.engine.command.model.SCommandUpdateBuilderImpl;
import org.bonitasoft.engine.commons.LogUtil;
import org.bonitasoft.engine.commons.exceptions.SBonitaException;
import org.bonitasoft.engine.events.EventService;
import org.bonitasoft.engine.log.technical.TechnicalLogSeverity;
import org.bonitasoft.engine.log.technical.TechnicalLoggerService;
import org.bonitasoft.engine.persistence.FilterOption;
import org.bonitasoft.engine.persistence.OrderByOption;
import org.bonitasoft.engine.persistence.OrderByType;
import org.bonitasoft.engine.persistence.QueryOptions;
import org.bonitasoft.engine.persistence.ReadPersistenceService;
import org.bonitasoft.engine.persistence.SBonitaReadException;
import org.bonitasoft.engine.persistence.SelectByIdDescriptor;
import org.bonitasoft.engine.persistence.SelectListDescriptor;
import org.bonitasoft.engine.persistence.SelectOneDescriptor;
import org.bonitasoft.engine.queriablelogger.model.SQueriableLog;
import org.bonitasoft.engine.queriablelogger.model.SQueriableLogSeverity;
import org.bonitasoft.engine.queriablelogger.model.builder.ActionType;
import org.bonitasoft.engine.queriablelogger.model.builder.HasCRUDEAction;
import org.bonitasoft.engine.queriablelogger.model.builder.SLogBuilder;
import org.bonitasoft.engine.queriablelogger.model.builder.SPersistenceLogBuilder;
import org.bonitasoft.engine.recorder.Recorder;
import org.bonitasoft.engine.recorder.SRecorderException;
import org.bonitasoft.engine.recorder.model.DeleteRecord;
import org.bonitasoft.engine.recorder.model.EntityUpdateDescriptor;
import org.bonitasoft.engine.recorder.model.InsertRecord;
import org.bonitasoft.engine.recorder.model.UpdateRecord;
import org.bonitasoft.engine.services.QueriableLoggerService;

/**
 * @author Zhang Bole
 * @author Matthieu Chaffotte
 * @author Hongwen Zang
 * @author Celine Souchet
 */
public class CommandServiceImpl implements CommandService {

    public static final int FETCH_SIZE = 1000;
    private final ReadPersistenceService persistenceService;

    private final Recorder recorder;

    private final EventService eventService;

    private final TechnicalLoggerService logger;

    private final QueriableLoggerService queriableLoggerService;
    private final CommandProvider defaultCommandProvider;
    private final int fetchSize;

    public CommandServiceImpl(final ReadPersistenceService persistenceService, final Recorder recorder,
            final EventService eventService, final TechnicalLoggerService logger,
            final QueriableLoggerService queriableLoggerService,
            CommandProvider defaultCommandProvider) {
        this(persistenceService, recorder, eventService, logger, queriableLoggerService, defaultCommandProvider,
                FETCH_SIZE);
    }

    public CommandServiceImpl(final ReadPersistenceService persistenceService, final Recorder recorder,
            final EventService eventService, final TechnicalLoggerService logger,
            final QueriableLoggerService queriableLoggerService,
            CommandProvider defaultCommandProvider, int fetchSize) {
        super();
        this.persistenceService = persistenceService;
        this.recorder = recorder;
        this.eventService = eventService;
        this.logger = logger;
        this.queriableLoggerService = queriableLoggerService;
        this.defaultCommandProvider = defaultCommandProvider;
        this.fetchSize = fetchSize;
    }

    private SCommandLogBuilder getQueriableLog(final ActionType actionType, final String message) {
        final SCommandLogBuilder logBuilder = BuilderFactory.get(SCommandLogBuilderFactory.class).createNewInstance();
        this.initializeLogBuilder(logBuilder, message);
        this.updateLog(actionType, logBuilder);
        return logBuilder;
    }

    private  void initializeLogBuilder(final T logBuilder, final String message) {
        logBuilder.actionStatus(SQueriableLog.STATUS_FAIL).severity(SQueriableLogSeverity.INTERNAL).rawMessage(message);
    }

    private  void updateLog(final ActionType actionType, final T logBuilder) {
        logBuilder.setActionType(actionType);
    }

    @Override
    public void create(final SCommand command) throws SCommandAlreadyExistsException, SCommandCreationException {
        if (logger.isLoggable(getClass(), TechnicalLogSeverity.TRACE)) {
            logger.log(this.getClass(), TechnicalLogSeverity.TRACE,
                    LogUtil.getLogBeforeMethod(this.getClass(), "create"));
        }
        try {
            this.get(command.getName());
            throw new SCommandAlreadyExistsException("Command '" + command.getName() + "' already exists");
        } catch (final SCommandNotFoundException scmfe) {
            final SCommandLogBuilder logBuilder = getQueriableLog(ActionType.CREATED,
                    "Creating a new command with name " + command.getName());
            try {
                recorder.recordInsert(new InsertRecord(command), COMMAND);
                log(command.getId(), SQueriableLog.STATUS_OK, logBuilder, "create");
                if (logger.isLoggable(getClass(), TechnicalLogSeverity.TRACE)) {
                    logger.log(this.getClass(), TechnicalLogSeverity.TRACE,
                            LogUtil.getLogAfterMethod(this.getClass(), "create"));
                }
            } catch (final SRecorderException re) {
                if (logger.isLoggable(getClass(), TechnicalLogSeverity.TRACE)) {
                    logger.log(this.getClass(), TechnicalLogSeverity.TRACE,
                            LogUtil.getLogOnExceptionMethod(this.getClass(), "create", re));
                }
                log(command.getId(), SQueriableLog.STATUS_FAIL, logBuilder, "create");
                throw new SCommandCreationException(re);
            }
        }
    }

    @Override
    public void delete(final long commandId) throws SCommandNotFoundException, SCommandDeletionException {
        final boolean isTraceEnable = logger.isLoggable(getClass(), TechnicalLogSeverity.TRACE);
        if (isTraceEnable) {
            logger.log(this.getClass(), TechnicalLogSeverity.TRACE,
                    LogUtil.getLogBeforeMethod(this.getClass(), "delete"));
        }
        final SCommandLogBuilder logBuilder = getQueriableLog(ActionType.DELETED,
                "Deleting command with id " + commandId);
        final SCommand command = this.get(commandId);
        delete(command, logBuilder);
    }

    protected void delete(final SCommand command, final SCommandLogBuilder logBuilder)
            throws SCommandDeletionException {
        try {
            recorder.recordDelete(new DeleteRecord(command), COMMAND);
            if (logger.isLoggable(getClass(), TechnicalLogSeverity.TRACE)) {
                logger.log(this.getClass(), TechnicalLogSeverity.TRACE,
                        LogUtil.getLogAfterMethod(this.getClass(), "delete"));
            }
            log(command.getId(), SQueriableLog.STATUS_OK, logBuilder, "delete");
        } catch (final SRecorderException re) {
            if (logger.isLoggable(getClass(), TechnicalLogSeverity.TRACE)) {
                logger.log(this.getClass(), TechnicalLogSeverity.TRACE,
                        LogUtil.getLogOnExceptionMethod(this.getClass(), "delete", re));
            }
            log(command.getId(), SQueriableLog.STATUS_FAIL, logBuilder, "delete");
            throw new SCommandDeletionException(re);
        }
    }

    @Override
    public void delete(final String commandName) throws SCommandNotFoundException, SCommandDeletionException {
        final SCommandLogBuilder logBuilder = getQueriableLog(ActionType.DELETED,
                "Deleting command with name " + commandName);
        final boolean isTraceEnable = logger.isLoggable(getClass(), TechnicalLogSeverity.TRACE);
        if (isTraceEnable) {
            logger.log(this.getClass(), TechnicalLogSeverity.TRACE,
                    LogUtil.getLogBeforeMethod(this.getClass(), "delete"));
        }
        final SCommand command = this.get(commandName);
        delete(command, logBuilder);
    }

    @Override
    public void deleteAll() throws SCommandDeletionException {
        if (logger.isLoggable(getClass(), TechnicalLogSeverity.TRACE)) {
            logger.log(this.getClass(), TechnicalLogSeverity.TRACE,
                    LogUtil.getLogBeforeMethod(this.getClass(), "deleteAll"));
        }
        List commands;
        try {
            do {
                commands = getAllCommands(0, 1000, SCommandCriterion.NAME_ASC);
                for (final SCommand command : commands) {
                    final SCommandLogBuilder logBuilder = getQueriableLog(ActionType.DELETED,
                            "Deleting command with name " + command.getName());
                    delete(command, logBuilder);
                }
            } while (!commands.isEmpty());
        } catch (final SCommandGettingException scge) {
            throw new SCommandDeletionException(scge);
        }
        if (logger.isLoggable(getClass(), TechnicalLogSeverity.TRACE)) {
            logger.log(this.getClass(), TechnicalLogSeverity.TRACE,
                    LogUtil.getLogAfterMethod(this.getClass(), "deleteAll"));
        }
    }

    @Override
    public SCommand get(final String commandName) throws SCommandNotFoundException {
        final boolean trace = logger.isLoggable(getClass(), TechnicalLogSeverity.TRACE);
        try {
            if (trace) {
                logger.log(this.getClass(), TechnicalLogSeverity.TRACE,
                        LogUtil.getLogBeforeMethod(this.getClass(), "get"));
            }
            final SelectOneDescriptor descriptor = SelectDescriptorBuilder.getCommandByName(commandName);
            final SCommand scommand = persistenceService.selectOne(descriptor);
            if (scommand == null) {
                throw new SCommandNotFoundException("command '" + commandName + "' does not exist");
            }
            if (trace) {
                logger.log(this.getClass(), TechnicalLogSeverity.TRACE,
                        LogUtil.getLogAfterMethod(this.getClass(), "get"));
            }
            return scommand;
        } catch (final SBonitaReadException e) {
            if (trace) {
                logger.log(this.getClass(), TechnicalLogSeverity.TRACE,
                        LogUtil.getLogOnExceptionMethod(this.getClass(), "get", e));
            }
            throw new SCommandNotFoundException("Cannot get command: " + commandName, e);
        }
    }

    @Override
    public List getAllCommands(final int startIndex, final int maxResults,
            final SCommandCriterion sCommandCriterion) throws SCommandGettingException {
        if (logger.isLoggable(getClass(), TechnicalLogSeverity.TRACE)) {
            logger.log(this.getClass(), TechnicalLogSeverity.TRACE,
                    LogUtil.getLogBeforeMethod(this.getClass(), "getAllCommands"));
        }
        String field = null;
        OrderByType orderByType = null;
        switch (sCommandCriterion) {
            case NAME_ASC:
                orderByType = OrderByType.ASC;
                field = "name";
                break;
            case NAME_DESC:
                orderByType = OrderByType.DESC;
                field = "name";
                break;
            default:
                throw new IllegalStateException();
        }
        try {
            final SelectListDescriptor descriptor = SelectDescriptorBuilder.getCommands(field, orderByType,
                    startIndex, maxResults);
            if (logger.isLoggable(getClass(), TechnicalLogSeverity.TRACE)) {
                logger.log(this.getClass(), TechnicalLogSeverity.TRACE,
                        LogUtil.getLogAfterMethod(this.getClass(), "getAllCommands"));
            }
            return persistenceService.selectList(descriptor);
        } catch (final SBonitaReadException e) {
            if (logger.isLoggable(getClass(), TechnicalLogSeverity.TRACE)) {
                logger.log(this.getClass(), TechnicalLogSeverity.TRACE,
                        LogUtil.getLogOnExceptionMethod(this.getClass(), "getAllCommands", e));
            }
            throw new SCommandGettingException("can't get the commands", e);
        }
    }

    @Override
    public void update(final SCommand command, final EntityUpdateDescriptor updateDescriptor)
            throws SCommandUpdateException {
        final boolean trace = logger.isLoggable(getClass(), TechnicalLogSeverity.TRACE);
        if (trace) {
            logger.log(this.getClass(), TechnicalLogSeverity.TRACE,
                    LogUtil.getLogBeforeMethod(this.getClass(), "update"));
        }
        final SCommandLogBuilder logBuilder = getQueriableLog(ActionType.UPDATED,
                "Updating command with name " + command.getName());

        try {
            recorder.recordUpdate(UpdateRecord.buildSetFields(command, updateDescriptor), COMMAND);
            if (trace) {
                logger.log(this.getClass(), TechnicalLogSeverity.TRACE,
                        LogUtil.getLogAfterMethod(this.getClass(), "update"));
            }
            log(command.getId(), SQueriableLog.STATUS_OK, logBuilder, "update");
        } catch (final SRecorderException re) {
            if (trace) {
                logger.log(this.getClass(), TechnicalLogSeverity.TRACE,
                        LogUtil.getLogOnExceptionMethod(this.getClass(), "update", re));
            }
            log(command.getId(), SQueriableLog.STATUS_FAIL, logBuilder, "update");
            throw new SCommandUpdateException(re);
        }
    }

    @Override
    public List getUserCommands(final int startIndex, final int maxResults,
            final SCommandCriterion sCommandCriterion)
            throws SCommandGettingException {
        if (logger.isLoggable(getClass(), TechnicalLogSeverity.TRACE)) {
            logger.log(this.getClass(), TechnicalLogSeverity.TRACE,
                    LogUtil.getLogBeforeMethod(this.getClass(), "getUserCommands"));
        }
        String field;
        OrderByType orderByType;
        switch (sCommandCriterion) {
            case NAME_ASC:
                orderByType = OrderByType.ASC;
                field = "name";
                break;
            case NAME_DESC:
                orderByType = OrderByType.DESC;
                field = "name";
                break;
            default:
                throw new IllegalStateException();
        }
        try {
            final SelectListDescriptor descriptor = SelectDescriptorBuilder.getUserCommands(field,
                    orderByType, startIndex, maxResults);
            final List selectList = persistenceService.selectList(descriptor);
            if (logger.isLoggable(getClass(), TechnicalLogSeverity.TRACE)) {
                logger.log(this.getClass(), TechnicalLogSeverity.TRACE,
                        LogUtil.getLogAfterMethod(this.getClass(), "getUserCommands"));
            }
            return selectList;
        } catch (final SBonitaReadException e) {
            if (logger.isLoggable(getClass(), TechnicalLogSeverity.TRACE)) {
                logger.log(this.getClass(), TechnicalLogSeverity.TRACE,
                        LogUtil.getLogOnExceptionMethod(this.getClass(), "getUserCommands", e));
            }
            throw new SCommandGettingException("can't get the commands", e);
        }
    }

    @Override
    public SCommand get(final long commandId) throws SCommandNotFoundException {
        final SelectByIdDescriptor selectByIdDescriptor = SelectDescriptorBuilder.getCommandById(commandId);
        try {
            final SCommand command = persistenceService.selectById(selectByIdDescriptor);
            if (command == null) {
                throw new SCommandNotFoundException(commandId + " does not refer to any command");
            }
            return command;
        } catch (final SBonitaReadException bre) {
            throw new SCommandNotFoundException(bre);
        }
    }

    @Override
    public long getNumberOfCommands(final QueryOptions options) throws SBonitaReadException {
        logger.log(this.getClass(), TechnicalLogSeverity.TRACE,
                LogUtil.getLogBeforeMethod(this.getClass(), "getNumberOfCommands"));
        try {
            final long number = persistenceService.getNumberOfEntities(SCommand.class, options, null);
            logger.log(this.getClass(), TechnicalLogSeverity.TRACE,
                    LogUtil.getLogAfterMethod(this.getClass(), "getNumberOfCommands"));
            return number;
        } catch (final SBonitaReadException bre) {
            logger.log(this.getClass(), TechnicalLogSeverity.TRACE,
                    LogUtil.getLogOnExceptionMethod(this.getClass(), "getNumberOfCommands", bre));
            throw new SBonitaReadException(bre);
        }
    }

    @Override
    public List searchCommands(final QueryOptions options) throws SBonitaReadException {
        final boolean trace = logger.isLoggable(getClass(), TechnicalLogSeverity.TRACE);
        if (trace) {
            logger.log(this.getClass(), TechnicalLogSeverity.TRACE,
                    LogUtil.getLogBeforeMethod(this.getClass(), "searchCommands"));
        }
        try {
            final List commands = persistenceService.searchEntity(SCommand.class, options, null);
            if (trace) {
                logger.log(this.getClass(), TechnicalLogSeverity.TRACE,
                        LogUtil.getLogAfterMethod(this.getClass(), "searchCommands"));
            }
            return commands;
        } catch (final SBonitaReadException bre) {
            if (trace) {
                logger.log(this.getClass(), TechnicalLogSeverity.TRACE,
                        LogUtil.getLogOnExceptionMethod(this.getClass(), "searchCommands", bre));
            }
            throw new SBonitaReadException(bre);
        }
    }

    private void log(final long objectId, final int sQueriableLogStatus, final SPersistenceLogBuilder logBuilder,
            final String callerClassName) {
        logBuilder.actionScope(String.valueOf(objectId));
        logBuilder.actionStatus(sQueriableLogStatus);
        logBuilder.objectId(objectId);
        final SQueriableLog log = logBuilder.build();
        if (queriableLoggerService.isLoggable(log.getActionType(), log.getSeverity())) {
            queriableLoggerService.log(this.getClass().getName(), callerClassName, log);
        }
    }

    @Override
    public void start() throws SBonitaException {
        Map commandDeployments = toCommandDeploymentMap(
                defaultCommandProvider.getDefaultCommands());
        Map availableSystemCommands = getAllAvailableSystemCommands();
        createAndUpdateCommands(commandDeployments, availableSystemCommands);
        deleteSystemCommandsNotPresentInDeployments(commandDeployments, availableSystemCommands);
    }

    private void createAndUpdateCommands(final Map commandDeployements,
            final Map availableSystemCommands) throws SBonitaException {
        for (String commandName : commandDeployements.keySet()) {
            if (!availableSystemCommands.keySet().contains(commandName)) {
                createMissingCommand(commandDeployements.get(commandName),
                        logger.isLoggable(this.getClass(), TechnicalLogSeverity.INFO));
            } else {
                SCommand sCommand = availableSystemCommands.get(commandName);
                updateExistingCommandIfNecessary(sCommand, commandDeployements.get(commandName),
                        logger.isLoggable(this.getClass(), TechnicalLogSeverity.INFO));
            }
        }
    }

    private void updateExistingCommandIfNecessary(final SCommand command, final CommandDeployment commandDeployment,
            final boolean infoEnabled)
            throws SCommandUpdateException {
        SCommandUpdateBuilderImpl updateBuilder = new SCommandUpdateBuilderImpl();
        if (!command.getDescription().equals(commandDeployment.getDescription())) {
            updateBuilder.updateDescription(commandDeployment.getDescription());
        }
        if (!command.getImplementation().equals(commandDeployment.getImplementation())) {
            updateBuilder.updateImplementation(commandDeployment.getImplementation());
        }
        EntityUpdateDescriptor updateDescriptor = updateBuilder.done();
        if (!updateDescriptor.getFields().isEmpty()) {
            if (infoEnabled) {
                logger.log(getClass(), TechnicalLogSeverity.INFO,
                        "Updating system command. Before update: " + command + ". After update: " + commandDeployment);
            }
            update(command, updateDescriptor);
        }
    }

    private void createMissingCommand(final CommandDeployment commandDeployment, final boolean infoEnabled)
            throws SCommandAlreadyExistsException,
            SCommandCreationException {
        if (infoEnabled) {
            logger.log(this.getClass(), TechnicalLogSeverity.INFO,
                    "Creating missing system command: " + commandDeployment);
        }
        create(SCommand.builder()
                .name(commandDeployment.getName())
                .description(commandDeployment.getDescription())
                .implementation(commandDeployment.getImplementation())
                .isSystem(true).build());
    }

    private void deleteSystemCommandsNotPresentInDeployments(final Map commandDeployments,
            final Map availableSystemCommands) throws SCommandDeletionException {
        boolean infoEnabled = logger.isLoggable(getClass(), TechnicalLogSeverity.INFO);
        for (String commandName : availableSystemCommands.keySet()) {
            if (!commandDeployments.keySet().contains(commandName)) {
                final SCommandLogBuilder logBuilder = getQueriableLog(ActionType.DELETED,
                        "Deleting command with name " + commandName);
                SCommand command = availableSystemCommands.get(commandName);
                if (infoEnabled) {
                    logger.log(getClass(), TechnicalLogSeverity.INFO,
                            "The following system command is not used any more and will be deleted: " + command);
                }
                delete(command, logBuilder);
            }
        }
    }

    private Map getAllAvailableSystemCommands() throws SBonitaReadException {
        Map commands = new HashMap<>();
        List currentPage;
        int fromIndex = 0;
        do {
            currentPage = getSystemCommands(fromIndex, fetchSize);
            commands.putAll(toCommandMap(getSystemCommands(fromIndex, fetchSize)));
            fromIndex += fetchSize;
        } while (currentPage.size() == fetchSize);
        return commands;
    }

    private List getSystemCommands(int fromIndex, int maxResults) throws SBonitaReadException {
        QueryOptions queryOptions = new QueryOptions(fromIndex, maxResults,
                Collections.singletonList(new OrderByOption(SCommand.class, SCommand.ID,
                        OrderByType.ASC)),
                Collections.singletonList(new FilterOption(SCommand.class, SCommand.SYSTEM, true)), null);
        return searchCommands(queryOptions);
    }

    private Map toCommandMap(List commands) {
        Map map = new HashMap<>(commands.size());
        for (SCommand command : commands) {
            map.put(command.getName(), command);
        }
        return map;
    }

    private Map toCommandDeploymentMap(List commandDeployments) {
        Map map = new HashMap<>(commandDeployments.size());
        for (CommandDeployment deployment : commandDeployments) {
            map.put(deployment.getName(), deployment);
        }
        return map;
    }

    @Override
    public void stop() throws SBonitaException {
        // nothing to do
    }

    @Override
    public void pause() throws SBonitaException {
        // nothing to do
    }

    @Override
    public void resume() throws SBonitaException {
        // nothing to do
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy