Micronaut AOP on package to capture execution time of each method - java

To capture logTime of each controller call, I added #LogTime annotation for package level but it is not working. I am not able to figure out why it is working with ElementType.TYPE at class level annotation but not with ElementType.PACKAGE at package level. Could you please help?
package com.test.aop;
import io.micronaut.aop.Around;
import io.micronaut.context.annotation.Type;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.PACKAGE})
#Around
#Type(LogTimeInterceptor.class)
public #interface LogTime {
}
LogTimeInterceptor
package com.test.aop;
import io.micronaut.aop.MethodInterceptor;
import io.micronaut.aop.MethodInvocationContext;
import javax.inject.Singleton;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StopWatch;
#Singleton
public class LogTimeInterceptor implements MethodInterceptor<Object, Object> {
private static final Logger LOGGER = LoggerFactory.getLogger(LogTimeInterceptor.class);
#Override
public Object intercept(MethodInvocationContext<Object, Object> context) {
var timer = new StopWatch(context.getDeclaringType().getSimpleName() + "." + context.getName());
try {
timer.start();
return context.proceed();
} finally {
timer.stop();
LOGGER.info("StopWatch Task name:{} running time:{} sec", timer.getId(), timer.getTotalTimeSeconds());
}
}
}
package-info.java
#LogTime
package com.test.controllers;
import com.test.aop.LogTime;

Related

Integration testing for events in the Jersey container listener

I have an application based on Jersey JAX-RS. I need to refactor the event handler and therefore also write a test for it.
I'm trying to do this with the JerseyTest Framework. I created a configuration to extend ResourceConfig, but when I use the target () call the handler is not called.
I will present the situation using code.
Here is an example Resource class:
package com.my.page;
import org.glassfish.hk2.api.messaging.Topic;
import com.my.core.entity.Link;
import com.my.core.location.LinkHitLocationFactory;
import com.my.core.service.LinkService;
import com.my.core.service.link.LinkFinder;
import com.my.core.service.link.LinkFinderFactory;
import com.my.event.LinkHitEvent;
import com.my.exception.FragmentNotFoundException;
import javax.annotation.security.PermitAll;
import javax.inject.Inject;
import javax.ws.rs.*;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Response;
#PermitAll
#Path("/")
public class LinkResource {
#Inject
private LinkService linkService;
#Inject
private Topic<LinkHitEvent> linkHitPublisher;
#Inject
private LinkFinderFactory linkFinderFactory;
#Inject
private LinkHitLocationFactory linkHitLocationFactory;
#GET
#Path("/{fragment:[^ ]{1,32}}")
public Response redirect(
#PathParam("fragment") String fragment,
#HeaderParam("Range") String range,
#HeaderParam("User-Agent") String userAgent,
#Context HttpHeaders headers) throws Exception {
LinkFinder linkFinder = linkFinderFactory.getLinkFinder(fragment);
Link link = linkFinder.getLink(fragment);
if (link.isExpired()) {
throw new FragmentNotFoundException(fragment);
}
linkService.insertHit();
linkHitPublisher.publish(new LinkHitEvent(link));
return handlerFactory.getHandler(link).handleGet(link, range).build();
}
}
Event test:
package com.my.page;
import org.glassfish.hk2.extras.events.internal.TopicDistributionModule;
import org.glassfish.hk2.utilities.binding.AbstractBinder;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import pl.comvision.hk2.events.ThreadedEventDistributorService;
import com.my.client.CallbackTargetBuilder;
import com.my.core.entity.Link;
import com.my.core.mapper.LinkMapper;
import com.my.core.service.LinkService;
import com.my.page.resource.LinkResource;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.Response;
import static javax.ws.rs.core.Response.Status.TEMPORARY_REDIRECT;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.*;
#RunWith(MockitoJUnitRunner.class)
public class CallbackEventTest extends JerseyTest {
#Mock
private LinkMapper linkMapper;
#Mock
private LinkService linkService;
private CallbackTargetBuilder callbackTargetBuilder;
private final String callbackUrl = "";
#Override
protected Application configure() {
this.callbackTargetBuilder = spy(new CallbackTargetBuilder(this.callbackUrl));
ResourceConfig config = new ResourceConfig(LinkResource.class);
config.register(new TopicDistributionModule());
config.register(new AbstractBinder() {
#Override
protected void configure() {
addActiveDescriptor(ThreadedEventDistributorService.class).setRanking(100);
}
});
config.register(new EventsContainerListener(CallbackEventHandler.class));
config.register(new AbstractBinder() {
#Override
protected void configure() {
bind(linkMapper).to(LinkMapper.class);
bind(linkService).to(LinkService.class);
bind(mock(LinkService.class)).to(LinkService.class);
bind("").to(String.class).named("varPath");
bind("127.0.0.1").to(String.class).named("requestIP");
bind(callbackTargetBuilder).to(CallbackTargetBuilder.class);
}
});
return config;
}
#Test
public void publish_event() {
Link link = mock(Link.class);
when(link.getUrl()).thenReturn("example");
when(link.getName()).thenReturn("test");
when(linkMapper.getByName(anyString())).thenReturn(link);
Response response = target("/testY").property("jersey.config.client.followRedirects", false).request().get();
assertEquals(TEMPORARY_REDIRECT.getStatusCode(), response.getStatus());
verify(callbackTargetBuilder).build();
}
}
For testing purposes, I only injected callbackTargetBuilder into the handler, and called the build method on it to verify the call:
package com.my.page;
import org.glassfish.hk2.api.messaging.MessageReceiver;
import org.glassfish.hk2.api.messaging.SubscribeTo;
import org.jvnet.hk2.annotations.Service;
import com.my.client.CallbackTargetBuilder;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.Form;
import javax.ws.rs.core.MediaType;
#Service
#Singleton
#MessageReceiver
public class CallbackEventHandler {
#Named("callbackUrl")
private String url;
#Inject
private CallbackTargetBuilder callbackTargetBuilder;
#MessageReceiver
public void handle(#SubscribeTo LinkHitEvent event) {
Form form = new Form();
form.param("id", event.getLink().getId().toString());
form.param("name", event.getLink().getName());
callbackTargetBuilder.build();
Client client = ClientBuilder.newClient();
client.target(url).request().post(Entity.entity(form, MediaType.APPLICATION_FORM_URLENCODED_TYPE));
}
}
Edit:
I tried to register dependencies differently, but it does not bring satisfactory results. Each time verification fails:
verify (callbackTargetBuilder) .build ();
Looking for information I found that I can configure the DeploymentContext, but I don't know if this is the right direction.
Edit the second:
A quick test shows that I may have some more basic problem with mocking. Because the call:
verify (linkService) .insertHit (anyObject ());
It also fails.
I will write only for posterity that the above code is correct. The problem was a lot of small bugs in the tested code and how to mock it.

ContainerRequestFilter dont work in a external package

I built a package to give a authentication handler. That engine will be triggered when a method/class as annotated with #Secured so the ContainerRequestFilter will be triggered.
But I'm using this library in another package and when I annoted a method with the #Secured the ContainerRequestFilter` engine is not triggered. So I need help with that.
I tried to import manually with #Inject and #EJB but when I deployed that application in weblogic container I got some errors about dependency.
AuthenticatePackage -
The interceptor:
import javax.annotation.Priority;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.ws.rs.Priorities;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.ResourceInfo;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.Provider;
import java.io.IOException;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
#Secured
#Provider
#Priority(Priorities.AUTHORIZATION)
public class SecurityInterceptor implements ContainerRequestFilter {
#Context private ResourceInfo resourceInfo;
#Inject private JWTService jwtService;
public static final String AUTHENTICATION_SCHEME = "Bearer";
....
The Annotation
import javax.ws.rs.NameBinding;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
#NameBinding
#Retention(RUNTIME)
#Target({TYPE, METHOD})
public #interface Secured {
String[] roles() default {};
}
Package when I use that engine
#GET
#Path("/getSignedUser")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
#Secured
public Response getSignedUser(#HeaderParam("Authorization") String token) {
UserSchema userSchema = this.authenticationService.getSignedUser(token.substring(SecurityInterceptor.AUTHENTICATION_SCHEME.length()).trim());
return Response.status(Response.Status.OK).entity(userSchema).build();
}

Validated by Class(Constraint class) for Custom Annotation not getting invoked

I have recently started working on custom Annotations. I created a sample spring boot project where it works fine, but When I try to integrate with my project code, the validation class is not getting invoked.
ValidateField.java
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.validation.Constraint;
import javax.validation.Payload;
#Documented
#Target(value = { ElementType.METHOD, ElementType.FIELD, ElementType.TYPE })
#Constraint(validatedBy = { RequestDataValidator.class })
#Retention(value = RetentionPolicy.RUNTIME)
public #interface ValidateField {
String message() default "invalid or value not present";
int revision() default 1;
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
RequestDataValidator.java
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
public class RequestDataValidator implements ConstraintValidator<ValidateField, String>{
#Override
public void initialize(ValidateField constraintAnnotation) {
System.out.println("in Initialize method");
}
#Override
public boolean isValid(String value, ConstraintValidatorContext context) {
System.out.println("in Initialize method");
return (value != null && !value.isEmpty());
}
}
The controller class is as follows.
Please note that the #Valid annotation is used with #RequestBody
import javax.validation.Valid;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.springframework.web.bind.annotation.RequestBody;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
#Api
#Produces({MediaType.APPLICATION_JSON})
#Path("/service")
public interface UIController {
#POST
#Path("/getRules")
#Produces({MediaType.APPLICATION_JSON})
#ApiOperation(
value = "Respond Hello <name>!",
response = Response.class
)
#ApiResponses(
value = {
#ApiResponse(code = 404, message = "Service not available"),
#ApiResponse(code = 500, message = "Unexpected Runtime error")
})
public Response getRules(#Valid#RequestBody SampleRequest discountPromoDetailsRequest);
}
I have checked if the annotation gets applied to the field. Turns out it does. I checked it by using
field.getDeclaredAnnotations()
SampleRequest.java
public class SampleRequest {
private String name;
#ValidateField
private String lastName;
private Long phNum;
private String address;
.
.
//getters and setters of the same.
}
I am now not sure what can be the cause for the RequestDataValidator not getting called.
I am working on this from last 3 days and I still don't have it working in the project.
Any Help is highly appreciated.

Spring AOP - Intercepting a class that its ancestor has an annotation

I have the following hierarchy:
#Validated
public class BaseResource
and
public class DeviceResource extends BaseResource
The #Validated annotation is as follows:
package com.redbend.validation.annotation;
import static java.lang.annotation.ElementType.TYPE;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.inject.Scope;
#Scope
#Target(TYPE)
#Retention(RetentionPolicy.RUNTIME)
#Inherited
public #interface Validated {
}
And I have a Spring Aspect with the following advice:
package com.redbend.validation.aspect;
import java.lang.annotation.Annotation;
import java.util.HashMap;
import java.util.Map;
import javax.validation.constraints.NotNull;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import com.redbend.exceptions.EExceptionMsgID;
import com.redbend.exceptions.runtime.MissingMandatoryParameterException;
import com.redbend.validation.annotation.MandatoryOneOfParams;
import com.redbend.validation.annotation.MandatoryParams;
import com.redbend.validation.annotation.NotEmpty;
import com.redbend.validation.annotation.OneOfParamsForValue;
import com.redbend.validation.annotation.OneOfParamsForValueMap;
import com.redbend.validation.annotation.ParamsForValue;
import com.redbend.validation.annotation.ParamsForValueMap;
#Aspect
#Component
#Order(2)
public class ValidationInterceptor {
private static Logger logger = LoggerFactory.getLogger(ValidationInterceptor.class);
public ValidationInterceptor() {
// TODO Auto-generated constructor stub
}
#Before("within(com.redbend..*) && #within(com.redbend.validation.annotation.Validated) ")
public void validate(JoinPoint joinPoint) throws Exception {
validateParams(joinPoint);
}
When I call a method in DeviceResource, it is not caught by the aspect, even thought it inherits from BaseResource which is annotated with #Validated, and #Validated is annotated with #Inherited.
When I annotate DeviceResource with #Validated it works fine. How can I make the aspect intercept my method in DeviceResource without annotating it with #Validated?
Thanks,
Amir
within(#com.redbend.validation.annotation.Validated)
is incorrect, it should be
#within(com.redbend.validation.annotation.Validated)
I eventually solved it by changing the pointcut expression in my aspect:
#Before("within(com.redbend..*) && within(#com.redbend.validation.annotation.Validated *)")
I still don't know why it didn't work before or why #within(com.redbend.validation.annotation.Validated)
didn't work...

Custom annotation not being detected by Spring AOP

So, I've been trying to play with Spring AOP, but as soon as I start using custom method annotations, the AOP stops working.
Here is the annotation:
package com.test.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface Performance {
}
The Aspect:
package com.test.aspects;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
#Component
#Aspect
public class Audience {
#Pointcut("#annotation(com.test.annotations.Performance)")
public void performance() {
}
#Around("performance()")
public void beforePerformance(ProceedingJoinPoint jointPoint) throws Throwable{
System.out.println("The audience is getting ready for the show");
jointPoint.proceed();
System.out.println("The show is over, audience's leaving");
}
}
The class using custom annotations:
package com.test.performers;
import com.test.annotations.Performance;
import com.test.exceptions.PerformanceException;
public interface Performer {
#Performance
void perform() throws PerformanceException;
}
Finally, the relevant part of the main method.
Performer kenny = (Performer) context.getBean("guitarist");
kenny.perform();
The Guitarist class is implementing the performer interface.
I've been looking around for a few hours, I can't see what I'm doing wrong. Thank you !
There is no inheritance in annotations. In Guitaritst class, when overriding the perform() method, you should annotate it as well.

Categories

Resources