5.8.5. Running Code at Application Start

Sometimes you may need to run certain code immediately after the application start at the moment when all application functionality is already initialized and ready to work. For this, you can use the AppContext.Listener.

Assume we have the following task: a project has an Employee entity that should be linked one-to-one to a platform entity (User).

init values recipe 2

If the name attribute of the User entity is changed, for example, through a standard user management screen, the name attribute of the related Employee should change as well. This is a common task for "denormalized" data, which is typically solved using entity listeners. Our case is more complex, since we need to track changes of the platform’s User entity, and thus we cannot add an entity listener using @Listeners annotation. However, we can add a listener dynamically using the EntityListenerManager bean, and it is better to do this on application start.

Let us create the AppLifecycle bean implementing the AppContext.Listener interface in the application core module and register it by invoking AppContext.addListener() method in the object constructor:

@Component("sample_AppLifecycle")
public class AppLifecycle implements AppContext.Listener {

    @Inject
    private EntityListenerManager entityListenerManager;

    public AppLifecycle() {
        AppContext.addListener(this);
    }

    @Override
    public void applicationStarted() {
        entityListenerManager.addListener(User.class, UserEntityListener.class);
    }

    @Override
    public void applicationStopped() {
    }

    public static class UserEntityListener implements BeforeUpdateEntityListener<User> {
        @Override
        public void onBeforeUpdate(User user) {
            Persistence persistence = AppBeans.get(Persistence.class);
            if (persistence.getTools().getDirtyFields(user).contains("name")) {
                EntityManager em = persistence.getEntityManager();
                TypedQuery<Employee> query = em.createQuery(
                        "select e from sample$Employee e where e.user.id = ?1", Employee.class);
                query.setParameter(1, user.getId());
                Employee employee = query.getFirstResult();
                if (employee != null) {
                    employee.setName(user.getName());
                }
            }
        }
    }
}

As a result, the applicationStarted() method of this bean will be invoked immediately after the start of the Middleware block. In this method, the internal UserEntityListener class is registered as an entity listener for the User entity.

The onBeforeUpdate() method of the UserEntityListener class will be invoked every time before the changes in the User instances are saved to the database. The method checks if the name attribute exists among the updated attributes. If yes, a related Employee instance is loaded and its name is updated with the new value.