How to use Spring AOP's Aspect to do very complex audit logging? - spring

I'm building a Spring web application. Using Spring AOP's aspect to do audit logging.
I've got business class with methods like the following and i want to audit log in certain cases
during method execution
after method returns
#Aspect
public class MyBusinessClass {...
public void registerUser() {
// do some business logic here...
userId = // userService.saveUser(...).getId(); // etc...
if(successful) {
// then send Email notification
audit.log(userId, "success sending email notification"... some other params);
else {
audit.log(userId, "fail to send email notification"...);
}
//do some more logic before returning method
audit.log(userId,"successfully registered user...." ...);
..// method returns
}
I've already got Aspects defined in a separate class.
I'm having problems because all the common simple examples i've seen on here and on other articles seemed to be very simple. For example, they work easily because the most complicated i've seen only go as far as extracting method params into the aspect's advice..
But my problem here is that i wan't to somehow not just extract local variables into the Aspect's advice but do the audit logging more than once and also based on certain conditions.
Don't get me wrong, we've already got Log4j logging to log to file in the same places but we also require to do these audit logging to DB too.
I just want to know what's the solution to achieve what i want to do in a high level.
Apologies for the slightly poor code formatting... (it's mostly pseudocode).
I just can't get this code formatting to work on StackOverflow. It's much easier on Github markdown.

Related

Putting Spring WebFlux Publisher inside Model, good or bad practice?

I'm working on a code audit on a SpringBoot Application with Spring WebFlux and the team is putting Publisher directly inside the Model and then resolve the view.
I'm wondering if it is a good or bad practice because it seems to be working but in that case, which component is in charge of executing the Publisher ?
I think that it's the ViewResolver and it should not be its job. What do you think ?
Moreover, if the Publisher is not executed by the Controller, the classes annotated by #ControllerAdvice such like ExceptionHandler won't work if these Publisher return an error, right ?
Extract of the Spring WebFlux documentation :
Spring WebFlux, unlike Spring MVC, explicitly supports reactive types in the model (for example, Mono or io.reactivex.Single). Such asynchronous model attributes can be transparently resolved (and the model updated) to their actual values at the time of #RequestMapping invocation, provided a #ModelAttribute argument is declared without a wrapper, as the following example shows:
#ModelAttribute
public void addAccount(#RequestParam String number) {
Mono<Account> accountMono = accountRepository.findAccount(number);
model.addAttribute("account", accountMono);
}
#PostMapping("/accounts")
public String handle(#ModelAttribute Account account, BindingResult errors) {
// ...
}
In addition, any model attributes that have a reactive type wrapper are resolved to their actual values (and the model updated) just prior to view rendering.
https://docs.spring.io/spring-framework/docs/current/reference/html/web-reactive.html#webflux-ann-modelattrib-methods
Doesn't come as a shock to me.
Actually seems to be a good trade off between complexity and efficiency when the Publisher is handling complex stuff.
It has the advantage of executing the Publisher only if and when needed.
Although it might be a problem if the ModelMap handler does not have the capacity to use it properly.
As for the exceptional cases, maybe you do not want it to be executed and just printed, thus failing faster.
As for the question about what is executing the Publisher, a specific ViewResolver can be used as it is the component responsible for the "rendering". IMHO that's it's job. I do not know if a standard ViewResolver can be used for detecting values vs publishers and handle those automagically, yet this seems completely doable and efficient.

Axon State-Stored Aggregate Test IllegalStateException

PROBLEM: Customer technical limitations force me to use Axon with state-stored Aggregates in PostgreSQL. I try a simple JPA-Entity Axon-Test and get IllegalStateException.
RESEARCH: A simplified project on the case is available at https://gitlab.com/ZonZonZon/simple-axon.git
In my test on
fixture.givenState(MyAggregate::new)
.when(command)
.expectState(state -> {
System.out.println();
});
I get
The state of this aggregate cannot be retrieved because it has been modified in a Unit of Work that was rolled back
java.lang.IllegalStateException: The state of this aggregate cannot be retrieved because it has been modified in a Unit of Work that was rolled back
at org.axonframework.common.Assert.state(Assert.java:44)
QUESTION: How to test an aggregate state using Axon and escape the error?
there are some missing parts in your project to let the test run properly. I will try to tackle them as concisely as possible:
your Command should contain the piece of information that connects it to the Aggregate. #TargetAggregateIdentifier is the annotation provided by the framework that connects a certain field to its #AggregateIdentifier counterpart into your Aggregate. You can read more here https://docs.axoniq.io/reference-guide/implementing-domain-logic/command-handling/aggregate#handling-commands-in-an-aggregate.
Said so, a UUID field needs to be added to your Create command.
This information will be then passed into the Created event : events are stored and can be processed both by a replay or an Aggregate re-hydration (upon client’s restart). (These) are the source of truth for our information.
#EventSourcingHandler annotated method will be responsible for applying the event and updating the #Aggregate values
public void on(Created event) {
uuid = event.getUuid();
login = event.getLogin();
password = event.getPassword();
token = event.getToken();
}
the test will then look like
public void a_VideochatAccount_Created_ToHaveData() {
Create command = Create.builder()
.uuid(UUID.randomUUID())
.login("123")
.password("333")
.token("d00a1f49-9e37-4976-83ae-114726938c73")
.build();
Created expectedEvent = Created.builder()
.uuid(command.getUuid())
.login(command.getLogin())
.password(command.getPassword())
.token(command.getToken())
.build();
fixture.givenNoPriorActivity()
.when(command)
.expectEvents(expectedEvent);
}
This test will validate your Command Part of your CQRS.
I will then suggest to separate the Query Part from your #Aggregate: you will then need to handle events with #EventHandler annotation placed on a method into a Projection #Component class, and implement the piece of logic that will take care of storing the information in the form that you need into PostgreSQL #Entity, using the #Repository JPA way, which I am sure you are familiar with.
You can find useful information on the ref guide https://docs.axoniq.io/reference-guide/implementing-domain-logic/event-handling following the video example on The Query Model based on code that you can be found in this repo https://github.com/AxonIQ/food-ordering-demo/tree/master
Hope that all is clear,
Corrado.

Keep record of what users do in Spring MVC

I have a very large application written in Spring MVC. I want to keep an "activity record" that tracks into a database what users do in my application.
In the first stage I just want an activity log, it can be just a list of the controller methods that get called during user's actions, but later on I would like this info to be more "human readable", i.e. instead of "modifyAccount(accountId = 5, accountBalance =500) something like "user X updates balance for account 5 to 500".
The problem I see is, since my application is very large, I would not like to modify each of my actions to add this logging mechanism. Is there a more flexible, declarative way to do this?
You can make use of Aspect Oriented Programming (AOP) to automate the logging.
http://static.springsource.org/spring/docs/2.0.8/reference/aop.html
In the above page shows many examples on how to use AOP with spring. One example is the use of annotations to find methods you're interested in. The use of such annotation is an easy way to determine what methods should be logged.
The #Audit annotation
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface Auditable {
...
}
The auditing method
#After("#annotation(auditable)", argNames="joinPoint")
public void audit(JoinPoint joinPoint) {
logger.info("Called {} with arguments {}",
joinPoint.getSignature().getLongString(), joinPoint.getArgs());
}
I did not test this code but it gets the point across.

Check preconditions in Controller or Service layer

I'm using Google's Preconditions class to validate user's input data.
But I'm worried about where is the best point of checking user's input data using Preconditions class.
First, I wrote validation check code in Controller like below:
#Controller
...
public void register(ProductInfo data) {
Preconditions.checkArgument(StringUtils.hasText(data.getName()),
"Empty name parameter.");
productService.register(data);
}
#Service
...
public void register(ProductInfo data) {
productDao.register(data);
}
But I thought that register method in Service layer would be using another Controller method like below:
#Controller
...
public void register(ProductInfo data) {
productService.register(data);
}
public void anotherRegister(ProductInfo data) {
productService.register(data);
}
#Service
...
public void register(ProductInfo data) {
Preconditions.checkArgument(StringUtils.hasText(data.getName()),
"Empty name parameter.");
productDao.register(data);
}
On the other hand, the method of service layer would be used in just one controller.
I was confused. Which is the better way of checking preconditions in controller or service?
Thanks in advance.
Ideally you would do it in both places. But you are confusing two different things:
Validation (with error handling)
Defensivie Programming (aka assertions, aka design by contract).
You absolutely should do validation in the controller and defensive programming in your service. And here is why.
You need to validate for forms and REST requests so that you can send a sensible error back to the client. This includes what fields are bad and then doing localization of the error messages, etc... (your current example would send me a horrible 500 error message with a stack trace if ProductInfo.name property was null).
Spring has a solution for validating objects in the controller.
Defensive programming is done in the service layer BUT NOT validation because you don't have access to locale to generate proper error messages. Some people do but Spring doesn't really help you there.
The other reason why validation is not done in the service layer is that the ORM already typically does this through the JSR Bean Validation spec (hibernate) but it doesn't generate sensible error messages.
One strategy people do is to create their own preconditions utils library that throws custom derived RuntimeExceptions instead of guava's (and commons lang) IllegalArgumentException and IllegalStateException and then try...catch the exceptions in the controller converting them to validation error messages.
There is no "better" way. If you think that the service is going to be used by multiple controllers (or other pieces of code), then it may well make sense to do the checks there. If it's important to your application to check invalid requests while they're still in the controller, it may well make sense to do the checks there. These two, as you have noticed, are not mutually exclusive. You might have to check twice to cover both scenarios.
Another possible solution: use Bean Validation (JSR-303) to put the checks (preconditions) onto the ProductInfo bean itself. That way you only specify the checks once, and anything that needs to can quickly validate the bean.
Preconditions, validations, whether simple or business should be handled at the filter layer or by interceptors, even before reaching the controller or service layer.
The danger if you check it in your controller layer, you are violating the single responsibility principle of a controller, whose sole purpose is to delegate request and response.
Putting preconditions in service layer is introducing cross cutting concerns to the core business.
Filter or inceptor is built for this purpose. Putting preconditions at the filter layer or in interceptors also allow you to “pick and match” rules you can place in the stack for each servlet request, thus not confining a particular rule to only one servlet request or introduce duplication.
I think in your special case you need to to check it on Service layer and return exception to Controller in case of data integrity error.
#controller
public class MyController{
#ExceptionHandler(MyDataIntegrityExcpetion.class)
public String handleException(MyDataIntegrityExcpetion ex, HttpServletRequest request) {
//do someting on exception or return some view.
}
}
It also depend on what you are doing in controller. whether you return View or just using #ResponseBody Annotation. Spring MVC has nice "out of the box" solution for input/dat validation I recommend you to check this libraries out.
http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/validation.html

Spring - Best approach to provide specific error messages in a validator from a DAO?

What is the best way to implement a validator in Spring that accesses a DAO object but needs to return different error messages based on the DAO error? Should the DAO method throw different exceptions that the validator turns into proper error messages? Should the DAO return an enumeration so the validator can handle each return type separately if necessary? I suppose the validator can pass the org.springframework.validation.Errors object to the DAO, but that seems to tie the two classes too closely together.
I believe the best approach is the enumeration approach to avoid the overhead of exceptions. Is there another way I should be considering?
Update
Actually, the enumeration would probably have to be a reference passed into the DAO as that method had to return the actual object. Is this still the best approach?
Update 2
The issue is I need to retrieve information from the database in this particular case, not store it. In the validation class, I was checking if the value already exists (which is why it needed the DAO), and if it already exists that is an error that I would show to the user on the page. I do need to validate that all fields on the form were filled in, so maybe that's the only thing I use the validator for. Then, how do I handle the error where the value already exists in the database? The DAO is the only thing that will know that - what is the best way to communicate that error from the DAO to the web layer?
The DAO method is currently returning the user object it is retrieving from the database - I can return null if there is an error, but that doesn't give me any granularity into the error details - it's essentially a boolean at that point indicating if the record was found or not, but not why.
Validator accessing DAO is valid.
I Would suggest throwing exception over passing enumeration.
If given one more option I would suggest not throwing exception but returning null.
You may design your DAO methods in such a way that they would return the populated object if available, if not just returns null.
Take following example:
DAO layer :
class UserInfoProvider {
public void createUser(User user) throws UserCreationException {
// throws UserCreationException when something goes wrong while updating database
}
public User findUser(String username) {
// return user object if found
// else just return null
}
}
Validation :
class UserValidator {
public void validate(command, errors) {
String username = command.getUsername();
UserInfoProvider userInfoProvider;
User user = userInfoProvider.findUser(username);
if (user == null) {
errors.rejectValue("username","User not found");
return;
}
}
}
You might consider using Spring security when you are using Spring MVC.
I suppose the validator can pass the org.springframework.validation.Errors object to the DAO, but that seems to tie the two classes too closely together.
I'm not understanding this. Why would you pass Errors to the DAO?
The point of validation is to prevent bad data from ever getting within sniffing distance of your database. You should be sending a response back to the source of the request informing them about any Errors you've encountered.
The only reason I can think of for passing such a thing to a database would be to track requests and responses as an auditing/tracking function.
If there are errors, the use case is done. The user needs to be informed, not your database.
UPDATE:
If you're checking something like a username that has to be unique in a database, by all means do that check. But I'd do it as an AJAX call, as soon as it was entered, and if it already existed I'd simply tell the user so.
DAO should not know about web tiers. Bad design - too coupled.
Let the web tier inquire through an intermediary. The intermediary will make the query and send back the appropriate result. Your web page should have a controller and/or service of some kind that can be that intermediary.
Checking the database in your validator is a valid thing to do.
I am a bit confused about what sort of errors you are expecting your DAO to return though. Typically it will either return the requested object or NULL, and it is up to the caller (your validator) to know the reason why.
If you need to check that multiple fields don't already exist in the database, then just make multiple DAO calls.

Resources