- Java EE 8 and Angular
- Prashant Padmanabhan
- 496字
- 2021-07-02 19:22:35
Ordered events
This basically orders the observers using the @Priority annotation. This feature can be made use of when there are multiple observer methods and you need to control which ones are called first and which ones are called later:
- The lowest value would be the first observer method that gets called
- The highest value would be called last
- If there's no priority specified then this event will be considered mid-range priority
- For observer methods with the same priority, the ordering is undefined
- No priority is applicable for asynchronous events, since they're not sequential
The usage of the ordered event is shown here:
public void observer1(@Observes @Priority(1) Payload event) { }
public void observer2 (@Observes @Priority(2) Payload event) { }
Given the behavior of ordered events using @Priority, along with the mutable state of the payload, one could utilize this feature for certain use cases. Consider a fairly common scenario in which the system should lock the user account based on the number of failed login attempts. Additionally, send out a notification to the user, such as an SMS, if the account gets locked in the process. In this case, we could define two ordered observers for this type of event, with the first observer checking for failed attempts and setting the lock status on the payload object. The second observer would then be able to see the changes made to the payload by the first observer and thus, based on this change in status, it would send the notification. Let us see, how this can be tackled in the sample code explained next.
A login service will raise a LoginEvent containing a user's ID and attempt count. Take a look at the LoginEvent code:
public class LoginEvent {
private final Integer attemptsMade;
private final String userId;
private boolean lockAccount = false;
public LoginEvent(Integer count, String userId) {
this.attemptsMade = count;
this.userId = userId;
}
...
}
The relevant code snippet for the AccountService, a class responsible for signing in the user and raising an event, is shown here:
@Inject private Event<LoginEvent> event;
/* A login method on this class, raises the event for failed login attempts using below line. */
event.fire(new LoginEvent(attemptsMadeCount, byUserId ));
The first observer is responsible for checking and locking the account based on attempts made:
public class MonitorAccountAccess {
public static final Integer MAX_ATTEMPTS = 3;
public void lockForFailedAttempts(
@Observes @Priority(1) LoginEvent event) {
if(event.getAttemptsMade() >= MAX_ATTEMPTS) {
event.setLockAccount(true);
//do more work to push status in database
}
}
}
The second observer is responsible for sending an SMS when an account gets locked. This code relies on the lock account status update being changed in the MonitorAccountAccess code block:
public class AccountLockNotification {
public void sendSmsOnAccountLock(@Observes @Priority(2) LoginEvent event) {
if(event.isLockAccount() == false) return;
sendAccountLockSms(event.getUserId());
}
}
When the event is fired synchronously from the AccountService code, MonitorAccountAccess will be called first, as it has @Priority(1). Later, the AccountLockNotification code gets called, along with @Priority(2) and the updated LoginEvent object.