blob: 8291de719b1e9998012e0dc31eb6d2d60992de9c [file] [log] [blame]
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
= Interceptor
Interceptor module is inspired from JavaEE/JakartaEE interceptor API but adapted to OSGi services.
It enables to proxy any service and execute code around the service methods.
== Dependencies
[source,xml]
----
<dependency>
<groupId>org.apache.karaf.services</groupId>
<artifactId>org.apache.karaf.services.interceptor.api</artifactId>
</dependency>
----
== Defining an interceptor
An interceptor is simply an OSGi service marked with `@Interceptor` and having an interceptor binding which is nothing more than an annotation marked with `@InterceptorBinding`.
Here is a binding:
[source,java]
----
@Target({TYPE, METHOD})
@Retention(RUNTIME)
@InterceptorBinding
public @interface Suffix {
}
----
And here is an associated interceptor:
[source,java]
----
@Suffix
@Interceptor
@Component(service = SuffixingInterceptor.class)
public class SuffixingInterceptor {
// ...
}
----
TIP: the examples are using SCR but there is no requirement to do so, you can do it with `context.registerService()` as well.
For the interceptor to do something, you must define an `@AroundInvoke` method which will intercept method calls in intercepted services.
It must takes a single parameter of type `InvocationContext`:
[source,java]
----
@AroundInvoke
public Object around(final InvocationContext context) throws Exception {
return context.proceed() + "(suffixed)";
}
----
== Using interceptors
Assuming you have an interceptor library (it is commong for transversal concerns like security, auditing, tracing, metrics, etc...), you can enable the interceptor usages with these few steps:
. Ensure you register your service as an OSGi service,
. Mark the service with `@EnableInterceptors`,
. Mark the class or method with the interceptor bindings you want
TIP: if you put a binding on a class is it available for all methods and is called after method level interceptors.
As an example speaks better than 1000 words, here is a service using our previous suffixing interceptor:
[source,java]
----
@EnableInterceptors
@Component(service = InterceptedService.class)
public class InterceptedService {
@Suffix
public String doStuff(final String value) {
return "'" + value + "'";
}
}
----
You can notice that it is equivalent to the following example which just moved the interceptor at class level:
[source,java]
----
@Suffix
@EnableInterceptors
@Component(service = InterceptedService.class)
public class InterceptedService {
public String doStuff(final String value) {
return "'" + value + "'";
}
}
----
== Proxying implementation
If possible, the proxying will use `java.lang.reflect.Proxy` but if there is a class to proxy and not only interfaces, `asm` must be available for the proxy to suceed to be created.