org.opensingular.flow.core.SingularFlowConfigurationBean.java Source code

Java tutorial

Introduction

Here is the source code for org.opensingular.flow.core.SingularFlowConfigurationBean.java

Source

/*
 * Copyright (C) 2016 Singular Studios (a.k.a Atom Tecnologia) - www.opensingular.com
 *
 * Licensed under the Apache 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://www.apache.org/licenses/LICENSE-2.0
 *
 * 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.opensingular.flow.core;

import net.vidageek.mirror.dsl.Mirror;
import org.apache.commons.lang3.StringUtils;
import org.opensingular.flow.core.defaults.NullViewLocator;
import org.opensingular.flow.core.entity.IEntityProcessInstance;
import org.opensingular.flow.core.renderer.IFlowRenderer;
import org.opensingular.flow.core.service.IPersistenceService;
import org.opensingular.flow.core.service.IProcessDataService;
import org.opensingular.flow.core.service.IProcessDefinitionEntityService;
import org.opensingular.flow.core.service.IUserService;
import org.opensingular.flow.core.view.IViewLocator;
import org.opensingular.flow.schedule.IScheduleService;
import org.opensingular.flow.schedule.ScheduleDataBuilder;
import org.opensingular.flow.schedule.ScheduledJob;
import org.opensingular.flow.schedule.quartz.QuartzScheduleService;
import org.opensingular.lib.commons.base.SingularException;
import org.opensingular.lib.commons.util.Loggable;

import javax.annotation.Nonnull;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.stream.Collectors;

public abstract class SingularFlowConfigurationBean implements Loggable {

    public static final String PREFIXO = "SGL";

    private String processGroupCod;

    private List<ProcessNotifier> notifiers = new ArrayList<>();

    /**
     * @param processGroupCod - chave do sistema cadastrado no em <code>TB_GRUPO_PROCESSO</code>
     */
    protected SingularFlowConfigurationBean(String processGroupCod) {
        super();
        this.processGroupCod = processGroupCod;
    }

    protected SingularFlowConfigurationBean() {
        super();
    }

    final void start() {
        for (final ProcessDefinition<?> processDefinition : getDefinitions()) {
            for (STaskJava task : processDefinition.getFlowMap().getJavaTasks()) {
                if (!task.isImmediateExecution()) {
                    getScheduleService().schedule(new ScheduledJob(task.getCompleteName(), task.getScheduleData(),
                            () -> executeTask(task)));
                }
            }
            for (ProcessScheduledJob scheduledJob : processDefinition.getScheduledJobs()) {
                getScheduleService().schedule(scheduledJob);
            }
        }
        configureWaitingTasksJobSchedule();
        init();
    }

    protected void configureWaitingTasksJobSchedule() {
        getScheduleService().schedule(new ExecuteWaitingTasksJob(ScheduleDataBuilder.buildHourly(1)));
    }

    protected void init() {

    }

    public final void setProcessGroupCod(String processGroupCod) {
        this.processGroupCod = processGroupCod;
    }

    @Nonnull
    public final String getProcessGroupCod() {
        if (processGroupCod == null) {
            throw new SingularFlowException("No foi definido o ProcessGroupCod");
        }
        return processGroupCod;
    }

    // ------- Mtodo de recuperao de definies --------------------

    protected ProcessDefinitionCache getDefinitionCache() {
        return ProcessDefinitionCache.get(getDefinitionsPackages());
    }

    protected abstract String[] getDefinitionsPackages();

    @Nonnull
    public <K extends ProcessDefinition<?>> K getProcessDefinition(@Nonnull Class<K> processClass) {
        return ProcessDefinitionCache.getDefinition(processClass);
    }

    /**
     * @throws SingularFlowException <code> if there is no ProcessDefinition associated with key</code>
     */
    @Nonnull
    protected ProcessDefinition<?> getProcessDefinition(@Nonnull String key) {
        return getDefinitionCache().getDefinition(key);
    }

    /**
     * <code> this method does not throw a exception if there is no ProcessDefinition associated with key</code>
     */
    @Nonnull
    protected Optional<ProcessDefinition<?>> getProcessDefinitionOpt(@Nonnull String key) {
        return getDefinitionCache().getDefinitionOpt(key);
    }

    public List<ProcessDefinition<?>> getDefinitions() {
        return getDefinitionCache().getDefinitions();
    }

    // ------- Mtodo de recuperao de instncias --------------------

    /** Retorna a ProcessInstance referente a cdigo infomado ou dispara exception seno encontrar. */
    @Nonnull
    private ProcessInstance getProcessInstance(@Nonnull Integer entityCod) {
        return getProcessInstanceOpt(entityCod)
                .orElseThrow(() -> new SingularFlowException(msgNotFound(entityCod)));
    }

    /** Retorna a ProcessInstance referente a entidade infomado ou dispara exception seno encontrar. */
    @Nonnull
    protected ProcessInstance getProcessInstance(@Nonnull IEntityProcessInstance entityProcessInstance) {
        Objects.requireNonNull(entityProcessInstance);
        return getProcessInstance(entityProcessInstance.getCod());
    }

    @Nonnull
    protected final <X extends ProcessInstance, T extends ProcessDefinition<X>> X getProcessInstance(
            @Nonnull Class<T> processClass, @Nonnull IEntityProcessInstance entityProcessInstance) {
        Objects.requireNonNull(entityProcessInstance);
        return (X) getProcessInstance(getProcessDefinition(processClass), entityProcessInstance.getCod());
    }

    public <X extends ProcessInstance, K extends ProcessDefinition<X>> X getProcessInstance(
            @Nonnull K processDefinition, @Nonnull Integer cod) {
        return getProcessInstanceOpt(processDefinition, cod)
                .orElseThrow(() -> new SingularFlowException(msgNotFound(cod)));
    }

    @Nonnull
    protected final <X extends ProcessInstance, T extends ProcessDefinition<X>> X getProcessInstance(
            @Nonnull Class<T> processClass, @Nonnull Integer cod) {
        return getProcessInstanceOpt(processClass, cod)
                .orElseThrow(() -> new SingularFlowException(msgNotFound(cod)));
    }

    @Nonnull
    protected final <X extends ProcessInstance, T extends ProcessDefinition<X>> X getProcessInstance(
            @Nonnull Class<T> processClass, @Nonnull String id) {
        return getProcessInstanceOpt(processClass, id)
                .orElseThrow(() -> new SingularFlowException(msgNotFound(id)));
    }

    @Nonnull
    protected <X extends ProcessInstance> X getProcessInstance(@Nonnull String id) {
        return (X) getProcessInstanceOpt(id).orElseThrow(() -> new SingularFlowException(msgNotFound(id)));
    }

    @Nonnull
    protected final <X extends ProcessInstance, T extends ProcessDefinition<X>> Optional<X> getProcessInstanceOpt(
            @Nonnull Class<T> processClass, @Nonnull Integer cod) {
        Objects.requireNonNull(processClass);
        return getProcessInstanceOpt(getProcessDefinition(processClass), cod);
    }

    @Nonnull
    public <X extends ProcessInstance, K extends ProcessDefinition<X>> Optional<X> getProcessInstanceOpt(
            @Nonnull K processDefinition, @Nonnull Integer cod) {
        Objects.requireNonNull(processDefinition);
        Objects.requireNonNull(cod);
        return processDefinition.getDataService().retrieveInstanceOpt(cod);
    }

    @Nonnull
    protected final <X extends ProcessInstance, T extends ProcessDefinition<X>> Optional<X> getProcessInstanceOpt(
            @Nonnull Class<T> processClass, @Nonnull String id) {
        if (StringUtils.isNumeric(id)) {
            return getProcessInstanceOpt(processClass, Integer.valueOf(id));
        }
        Optional<ProcessInstance> instance = getProcessInstanceOpt(id);
        if (instance.isPresent()) {
            getProcessDefinition(processClass).checkIfCompatible(instance.get());
        }
        return (Optional<X>) instance;
    }

    @Nonnull
    protected <X extends ProcessInstance> Optional<X> getProcessInstanceOpt(@Nonnull String processInstanceID) {
        Objects.requireNonNull(processInstanceID);
        MappingId mapeamento = parseId(processInstanceID);
        Optional<ProcessInstance> instance = getProcessInstanceOpt(mapeamento.cod);
        if (instance.isPresent() && mapeamento.abbreviation != null) {
            getProcessDefinition(mapeamento.abbreviation).checkIfCompatible(instance.get());
        }
        return (Optional<X>) instance;
    }

    /** Retorna a ProcessInstance referente a cdigo infomado. */
    @Nonnull
    private Optional<ProcessInstance> getProcessInstanceOpt(@Nonnull Integer entityCod) {
        return getPersistenceService().retrieveProcessInstanceByCod(entityCod).map(entity -> {
            ProcessDefinition<?> def = getProcessDefinition(entity.getProcessVersion().getAbbreviation());
            return def.convertToProcessInstance(entity);
        });
    }

    private static String msgNotFound(Object id) {
        return "Nao foi encontrada a instancia de processo com id=" + id;
    }

    // ------- Manipulao de ID --------------------------------------

    // TODO rever generateID e parseId, deveria ser tipado, talvez nem devesse
    // estar nesse lugar
    protected String generateID(ProcessInstance instancia) {
        return new StringBuilder(50).append(PREFIXO).append('.').append(instancia.getProcessDefinition().getKey())
                .append('.').append(instancia.getId()).toString();
    }

    // TODO rever generateID e parseId, deveria ser tipado, talvez nem devesse
    // estar nesse lugar

    protected String generateID(TaskInstance instanciaTarefa) {
        ProcessInstance instanciaProcesso = instanciaTarefa.getProcessInstance();
        return new StringBuilder(generateID(instanciaProcesso)).append('.').append(instanciaTarefa.getId())
                .toString();
    }

    // TODO rever generateID e parseId, deveria ser tipado, talvez nem devesse
    // estar nesse lugar
    protected MappingId parseId(String instanciaID) {
        if (instanciaID == null || instanciaID.length() < 1) {
            throw SingularException.rethrow("O ID da instncia no pode ser nulo ou vazio");
        }
        String parts[] = instanciaID.split("\\.");
        String sigla = parts[parts.length - 2];
        String id = parts[parts.length - 1];
        return new MappingId(sigla, Integer.parseInt(id));
    }

    // TODO rever generateID e parseId, deveria ser tipado, talvez nem devesse
    // estar nesse lugar
    protected static class MappingId {
        public final String abbreviation;
        public final Integer cod;

        public MappingId(String abbreviation, int cod) {
            this.abbreviation = abbreviation;
            this.cod = cod;
        }
    }

    // ------- Gerao de link ----------------------------------------
    protected IViewLocator getViewLocator() {
        return new NullViewLocator();
    }

    // ------- Manipulao de Usurio ---------------------------------
    public abstract IUserService getUserService();

    /**
     * Notifica os listeners registrados sobre um evento.
     * 
     * @param operation
     */
    public void notifyListeners(Consumer<ProcessNotifier> operation) {
        for (ProcessNotifier n : notifiers) {
            operation.accept(n);
        }
    }

    /**
     * Registra um listener para receber notificaes do Engine
     * 
     * @param p
     */
    public void addListener(ProcessNotifier p) {
        notifiers.add(p);
    }

    // ------- Consultas ----------------------------------------------

    public final List<? extends ProcessDefinition<?>> getEnabledProcessForCreationBy(SUser user) {
        return getDefinitions().stream().filter(d -> d.canBeCreatedBy(user)).sorted().collect(Collectors.toList());
    }

    // ------- Outros -------------------------------------------------

    public IFlowRenderer getFlowRenderer() {
        try {
            Class<?> yfilesRendeder = Class.forName("com.opensingular.flow.extras.renderer");
            return (IFlowRenderer) new Mirror().on(yfilesRendeder).invoke().method("getInstance").withoutArgs();
        } catch (ClassNotFoundException e) {
            getLogger().info(e.getMessage(), e);
        }
        return null;
    }

    protected abstract IPersistenceService<?, ?, ?, ?, ?, ?, ?, ?, ?, ?> getPersistenceService();

    protected abstract IProcessDefinitionEntityService<?, ?, ?, ?, ?, ?, ?, ?> getProcessEntityService();

    protected IScheduleService getScheduleService() {
        return new QuartzScheduleService();
    }

    public final Object executeTask(STaskJava task) {
        final IProcessDataService<?> dataService = task.getFlowMap().getProcessDefinition().getDataService();
        final Collection<? extends ProcessInstance> instancias = dataService.retrieveAllInstancesIn(task);
        if (task.isCalledInBlock()) {
            return task.executarByBloco(instancias);
        } else {
            for (final ProcessInstance instanciaProcessoMBPM : instancias) {
                FlowEngine.executeScheduledTransition(task, instanciaProcessoMBPM);
            }
            return null;
        }
    }
}