I want to have a Stateless session bean in JAKARTA EE9 where I print "hello" on the console every 10 seconds. This is achieved by the following code.
@jakarta.ejb.Stateless(name = "MyTimerEJB")
public class MyTimerBean {
@Schedule(hour ="*", minute = "*", second = "*/10")
public void printTime() {
System.out.println("good day");
}
}
But now, I also want to add an interceptor that intercepts this on saturdays and sundays and then prints "good weekend". I've tried a bunch of things, but nothing seems to be working. The documentation is also a little bit limited unfortunately.
If you check out the EJB specs, section 7.4, you will find about the AroundTimeout
annotation.
In short, all you need is a normal, enabled interceptor for the bean you are interested in, with a method annotated with @AroundTimeout
.
Having said that, I hope that the use case you describe is only an example. As a matter of fact I find it bad practice to use an interceptor to change the behavior of the program as radically as you describe. I would find it very hard to reason about the functionality of such a program. Interceptors are good to implement cross-cutting concerns (e.g. transactions, logging, authorization) that do not mess with the core logic of the intercepted code.
If I were to implement this use case I would:
SayHello
bean that can knows how to decide what message to output depending on the day (or whatever)
SayHello
, nothing moreSince it proved to be useful, I am briefly re-iterating the main points of the JEE tutorial on interceptors:
WARNING: the following is a brief summary, please follow the tutorials and documentation for concrete usage
To define an interceptor, use one of the interceptor metadata annotations: javax.interceptor.AroundConstruct
, javax.interceptor.AroundInvoke
, javax.interceptor.AroundTimeout
, javax.annotation.PostConstruct
, javax.annotation.PreDestroy
on a method defined on a component that the container will recognize. Could be the same component as the one containing the intercepted method or a different one.
If the interceptor is in a different class, use javax.interceptor.Interceptors
to activate it. This annotation can go to a specific method, or on an entire class, in which case all business methods are intercepted. Remember, interceptors do not take effect on non-business methods (private/protected ones are definitely NOT business and a common mistake). Interceptors do NOT take effect when business calling methods of this
object, another very common mistake, beware!
Alternatively you can define an interceptor binding annotation, e.g. (from the tutorial):
@InterceptorBinding // this makes it an interceptor binding annotation
@Target({TYPE, METHOD})
@Retention(RUNTIME)
@Inherited
pubic @interface Logged { ... }
Now annotating a class or method with @Logged
will activate the interceptor defined as:
@Logged
@Interceptor
public class LoggingInterceptor {
@AroundInvoke
public Object logInvocation(InvocationContext ctx) throws Exception {
...
}
...
}
To actually activate the interceptor you have to use the deployment descriptor (depending on whether you are using it on EJB or CDI or both) or use the @Priority
annotation.