CampaignExecutionService

CampaignExecutionService

The CampaignExecutionService is responsible for all aspects of campaign execution, including:

  • Creating CampaignExecution entities

  • Filtering clients using an Expression

  • Executing the campaign

  • Handling exceptions

  • Saving execution results

This service integrates with ScriptManager, ClientRepository, and ExceptionEntityService.


🔧 CampaignExecution createExecution(Campaign campaign)

Creates a new CampaignExecution linked to the provided campaign.

@Transactional(propagation = Propagation.MANDATORY)
public CampaignExecution createExecution(Campaign campaign) {
    CampaignExecution execution = new CampaignExecution();
    execution.setCampaign(campaign);
    return executionRepository.saveAndFlush(execution);
}
  • Called both manually (via CampaignService) and automatically (via CampaignExecutionProducer)

  • Saves the execution to the DB with status = NEW


🔐 _runExecution(CampaignExecution execution)

Private method containing the main business logic for campaign execution.

private void _runExecution(CampaignExecution execution) {
    try {
        Set<Client> clients = getSuitedBorrowers(execution, clientRepository.getAllIds());
        execution.getClients().addAll(clients);
        execution.setException(null);
    } catch (Exception e) {
        ExceptionEntity exceptionEntity = exceptionEntityService.saveException(e, e.getMessage());
        execution.setException(exceptionEntity);
        execution.setStatus(CampaignExecutionStatus.EXCEPTION_OCCURRED);
    }
    execution.setStatus(CampaignExecutionStatus.FINISHED);
    executionRepository.saveAndFlush(execution);
}

What it does:

  • Retrieves a list of clients matching the Expression

  • Clears the exception if successful

  • On error, stores an ExceptionEntity and marks the execution as EXCEPTION_OCCURRED

  • Sets the final status to FINISHED


🔍 Set<Client> getSuitedBorrowers(...)

Filters clients based on the campaign expression.

private Set<Client> getSuitedBorrowers(CampaignExecution execution, Set<UUID> candidates) throws ScriptException {
    Script matchingScript = getClientMatchingScript(execution.getCampaign().getExpression());
    Set<Client> suitedBorrowers = new HashSet<>();
    for (UUID clientId : candidates) {
        Optional<Client> client = evaluateClient(matchingScript, clientId);
        client.ifPresent(suitedBorrowers::add);
    }
    return suitedBorrowers;
}

🔍 Optional<Client> evaluateClient(...)

Evaluates a single client using the script.

private Optional<Client> evaluateClient(Script script, UUID clientId) throws ScriptException {
    Client client = clientRepository.getReferenceById(clientId);
    Object result = script.eval(Map.of("client", client));
    return Boolean.TRUE.equals(result) ? Optional.of(client) : Optional.empty();
}
  • The script must return true or false

  • Only matching clients are included


🧰 Script getClientMatchingScript(...)

Compiles the Expression into a Script.

private Script getClientMatchingScript(Expression expression) {
    try {
        return scriptManager.compile(expression);
    } catch (ScriptException e) {
        throw new RuntimeException("Script doesn't compile", e);
    }
}
  • Throws a RuntimeException on compilation failure


💡 Object evaluateExpression(UUID clientId, Expression expression)

Allows manual evaluation of an expression for a single client — useful in the UI.

@Transactional
public Object evaluateExpression(UUID clientId, Expression expression)
        throws ScriptException, NotFoundException {

    Client client = clientRepository.getReferenceById(clientId);
    Script script = scriptManager.compile(expression);
    return script.eval(Map.of("client", client));
}
  • Used by CampaignController for real-time filtering checks in the UI


Example service

@Service
public class CampaignExecutionService {

    private static final String CLIENT_KEY = "client";

    @Autowired
    private CampaignExecutionRepository executionRepository;
    @Autowired
    private ClientRepository clientRepository;
    @Autowired
    private ScriptManager scriptManager;
    @Autowired
    private ExceptionEntityService exceptionEntityService;

    @Transactional(propagation = Propagation.MANDATORY)
    public CampaignExecution createExecution(Campaign campaign) {
        CampaignExecution execution = new CampaignExecution();
        execution.setCampaign(campaign);
        return executionRepository.saveAndFlush(execution);
    }

    @Transactional(propagation = Propagation.MANDATORY)
    public void runExecution(CampaignExecution execution) {
        _runExecution(execution);
    }

    @Transactional
    public void runExecution(Long executionId) {
        CampaignExecution execution = executionRepository.getSync(executionId);
        _runExecution(execution);
    }

    private void _runExecution(CampaignExecution execution) {
        try {
            Set<Client> clients = getSuitedBorrowers(execution, clientRepository.getAllIds());
            execution.getClients().addAll(clients);
            execution.setException(null);
        } catch (Exception e) {
            ExceptionEntity exceptionEntity = exceptionEntityService.saveException(e, e.getMessage());
            execution.setException(exceptionEntity);
            execution.setStatus(CampaignExecutionStatus.EXCEPTION_OCCURRED);
        }
        execution.setStatus(CampaignExecutionStatus.FINISHED);
        executionRepository.saveAndFlush(execution);
    }

    private Set<Client> getSuitedBorrowers(CampaignExecution execution, Set<UUID> candidates) throws ScriptException {
        Script matchingScript = getClientMatchingScript(execution.getCampaign().getExpression());
        Set<Client> suitedBorrowers = new HashSet<>();
        for (UUID clientId : candidates) {
            Optional<Client> client = evaluateClient(matchingScript, clientId);
            client.ifPresent(suitedBorrowers::add);
        }
        return suitedBorrowers;
    }

    private Optional<Client> evaluateClient(Script script, UUID clientId) throws ScriptException {
        Client client = clientRepository.getReferenceById(clientId);
        Object evaluationResult = script.eval(Map.of(CLIENT_KEY, client));
        return Boolean.TRUE.equals(evaluationResult) ? Optional.of(client) : Optional.empty();
    }

    private Script getClientMatchingScript(Expression expression) {
        try {
            return scriptManager.compile(expression);
        } catch (ScriptException e) {
            throw new RuntimeException("Script doesn't compile", e);
        }
    }

    @Transactional
    public Object evaluateExpression(UUID clientId, Expression expression) throws ScriptException, NotFoundException {
        Client client = clientRepository.getReferenceById(clientId);
        Script script = scriptManager.compile(expression);
        Map<String, Client> binding = Map.of(CLIENT_KEY, client);
        return script.eval(binding);
    }
}

Last updated

Was this helpful?