5.8.4. 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
).
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:
@ManagedBean("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.