Developer Docs

SpringBot Seeding Data

Core Data

To seed this initial data, we first want to create a CoreData class. This class will contain everything we need to seed all of the data we need in our application.

For this example we will be seeding a workflow from the Workflow extension.

ApplicationRunner Interface

Using the @Component annotation allows this bean to be registered with SpringBoot.

Now to ensure this class runs on the application startup, we implement the ApplicationRunner interface. This interface does one thing, ensures the run method is executed at application start.

@Component
@Slf4j
public class CoreData implements ApplicationRunner {
   ...

Dependency Injection

Given we are working with data, we will need to inject all of the required repositories into our new class. This is allowed due to us declaring class as a SpringBoot component.

private final WorkflowRepository workflowRepository;
private final WorkflowVersionRepository workflowVersionRepository;
private final WorkflowStateRepository workflowStateRepository;
private final WorkflowTransitionRepository workflowTransitionRepository;

@Autowired
public CoreData(
        WorkflowRepository workflowRepository,
        WorkflowVersionRepository workflowVersionRepository,
        WorkflowStateRepository workflowStateRepository,
        WorkflowTransitionRepository workflowTransitionRepository) {
    this.workflowRepository = workflowRepository;
    this.workflowVersionRepository = workflowVersionRepository;
    this.workflowStateRepository = workflowStateRepository;
    this.workflowTransitionRepository = workflowTransitionRepository;
}

...

AnonymousHelper

Now, given everything is controlled by our security model and in our startup data class we are not registered within our authentication context, we in theory cannot access anything.

To bypass this, we can make use of the AnonymousHelper.runAnonymously helper method that bypasses our security.

WARNING As this completely bypasses security, be very careful where you use this.

@Override
public void run(ApplicationArguments args) throws Exception {
    AnonymousHelper.runAnonymously(() -> {
        this.injectRegistrationWorkflow();
    });
}

Injection

Given our class now runs on startup, we have the appropriate permissions, and we have our repositories injected and ready to use, we can begin to inject our data.

This example sets up the registration workflow, additional methods like this can be created and added to the run method to insert more data.

You will notice before we do anything in this method, we check to ensure it has not already been run with the this.workflowVersionRepository.count() == 0 conditional.

This workflow will operate as follows.

Image
/**
* Inject the workflow states and transitions for Registration entity
*/
private void injectRegistrationWorkflow() {

    // Check to see if any already exist, only create if it is a fresh install
    if (this.workflowVersionRepository.count() == 0) {

        /* Setup Workflow */
        var workflowName = "Registration Workflow";
        var registrationWorkFlow = new WorkflowEntity();
        registrationWorkFlow.setName(workflowName);

        registrationWorkFlow = this.workflowRepository.save(registrationWorkFlow);

        var registrationWorkflowVersion = new WorkflowVersionEntity();
        registrationWorkflowVersion.setRegistrationAssociation(true);
        registrationWorkflowVersion.setWorkflowDescription("Workflow for  a patients registration.");
        registrationWorkflowVersion.setWorkflowName(workflowName);
        registrationWorkflowVersion.setWorkflow(registrationWorkFlow);

        registrationWorkflowVersion = workflowVersionRepository.save(registrationWorkflowVersion);

        /* Create states */
        var pendingState = new WorkflowStateEntity();
        pendingState.setStepName("Pending");
        pendingState.setIsStartState(true);
        pendingState.setWorkflowVersion(registrationWorkflowVersion);
        this.workflowStateRepository.save(pendingState);

        var bookedState = new WorkflowStateEntity();
        bookedState.setStepName("Booked");
        bookedState.setWorkflowVersion(registrationWorkflowVersion);
        this.workflowStateRepository.save(bookedState);

        var cancelledState = new WorkflowStateEntity();
        cancelledState.setStepName("Cancelled");
        cancelledState.setWorkflowVersion(registrationWorkflowVersion);
        this.workflowStateRepository.save(cancelledState);

        var completedState = new WorkflowStateEntity();
        completedState.setStepName("Completed");
        completedState.setWorkflowVersion(registrationWorkflowVersion);
        this.workflowStateRepository.save(completedState);

        /** Create transitions **/
        var pendingToBookedTransition = new WorkflowTransitionEntity();
        pendingToBookedTransition.setTransitionName("Booked");
        pendingToBookedTransition.setSourceState(pendingState);
        pendingToBookedTransition.setTargetState(bookedState);
        this.workflowTransitionRepository.save(pendingToBookedTransition);

        var pendingToCancelledTransition = new WorkflowTransitionEntity();
        pendingToCancelledTransition.setTransitionName("Cancelled");
        pendingToCancelledTransition.setTargetState(cancelledState);
        pendingToCancelledTransition.setSourceState(pendingState);
        this.workflowTransitionRepository.save(pendingToCancelledTransition);

        var bookedToCancelledTransition = new WorkflowTransitionEntity();
        bookedToCancelledTransition.setTransitionName("Cancelled");
        bookedToCancelledTransition.setSourceState(bookedState);
        bookedToCancelledTransition.setTargetState(cancelledState);
        this.workflowTransitionRepository.save(bookedToCancelledTransition);

        var bookedToCompletedTransition = new WorkflowTransitionEntity();
        bookedToCompletedTransition.setTransitionName("Completed");
        bookedToCompletedTransition.setSourceState(bookedState);
        bookedToCompletedTransition.setTargetState(completedState);
        this.workflowTransitionRepository.save(bookedToCompletedTransition);
    }
}

Test Data

Often, you will have data you want to run when developing or testing that do not want in production. This can be achieved by creating another class like the CoreData one above called TestData.

To ensure this new class only runs when in test mode, add the annotation @Profile({"test"}) to the class signature.

@Component
@Profile({"test"})
public class TestData implements ApplicationRunner {
    ...
}

This annotation can used for the other run profile that SpringBot supports, dev.

Was this article helpful?

Thanks for your feedback!

If you would like to tell us more, please click on the link below to send us a message with more details.

Tool:

Generate

Iterate

Bot:

C#Bot

SpringBot

On this page

New to Codebots?

We know our software can be complicated, so we are always happy to have a chat if you have any questions.