How can I pass a customized value to a spring aop advice? - java

If I take a service method named public void delete(int id); as the pointcut, I want to add an after-returning advice on it, but I don't know what kind of object was deleted(however, the servlet which called the service knows the type value), so I was wondering if I can pass a customized value to this after-returning advice when it is activated, like 'user'. I've already checked the related document on Spring's website and I still know nothing. I'd appreciate your answer, THX.

One solution but its required refactoring in Service method
1) Refactoring
public class DeleteRequest {
String type;
Long id;
}
public boolean delete(DeleteRequest request){ // impl}
2) Use Around Advice
2.1) Before proceeding method execution, read passed parameter & get to be deleted object for "XYZ" requirement.
2.2) Capture result of delete method execution
IF its TRUE then DO your stuff
Note: I used this approach for deleted entity notification. So how we can get deleted entity information in after-advice, hence keep it entity information in before phase & use it in after-successful execution.

Related

Axon CQRS & EventSourcing deep validation in the db

I am migrating and existing crud application into Axon, and I have some concerns with the following scenario. I have an api given below to create groups,
#PostMapping
public Mono<IdDto> createGroup(#RequestBody #Valid CreateGroupCommand command) {
log.trace("Create GroupResponseInfoDto request {}", command);
return commandGateway.send(command)
.map((o) -> new IdDto((UUID) o));
}
The command looks like,
#Data
public class CreateGroupCommand {
#NotBlank
private String name;
#NotBlank
private String description;
}
and the main requirement here is that the group name must be unique.
Therefore, in the Aggregate I have the following code to check this logic.
#CommandHandler
public GroupAggregate(CreateGroupCommand command, GroupRepository groupRepository, ModelMapper mapper) {
log.trace("Handle create group command {}", command);
groupRepository.findByName(command.getName())
.ifPresent((g) -> {
throw new ApplicationException(UserMsError.GROUP_ALREADY_EXISTS.name());
});
GroupCreatedEvent event = mapper.map(command, GroupCreatedEvent.class);
event.setId(UUID.randomUUID());
AggregateLifecycle.apply(event);
}
And once the validation pareses, the event is persisted by a projector into the db.
#EventSourcingHandler
public void on(GroupCreatedEvent event) {
log.trace("Group create event {}", event);
groupRepository.findByName(event.getName())
.ifPresent((g) -> {
throw new ApplicationException(UserMsError.GROUP_ALREADY_EXISTS.name());
});
Group group = modelMapper.map(event, Group.class);
groupRepository.save(group);
}
The problem now is, there is some lap time between the command execution and the persistance of the event results into group table. If another user creates a group in that time, the command does not fail as the record does not exist in the db. Now, I see in Axon site there is a way to create a temporary table where we put the command execution into some temporary table which we can use for validation purpose, but that requires additional coding and quite extra effort for each such requirement. It also means, if we persist the details on command execution, and for some reason the process fails then the record will exist in our validation table but not on the system. If we try to validate the scenario on event execution, that extra effort might not be required but in this case the problem is I am not able to fail the API call so that the user knows the results. Could you please recommend if there is an alternative approach to validate the input without an intermediate check?
The problem you are looking at is set-based validation. Whenever you're dealing with CQRS, it's the sets that will require extra work to be validated.
Although uncertain, I assume you're talking about the Set-Based Consistency Validation blog? That is, for a reason, the suggested approach to deal with set validation. Note that the implementation used in the blog can be found here.
Added, it quite recently has seen an update that does not include the problem you describe as follows:
It also means, if we persist the details on command execution, and for some reason, the process fails, then the record will exist in our validation table but not on the system.
Axon's transaction logic, supported through the UnitOfWork, will roll back the entire transaction if something fails. This thus anything you'd do inside the UnitOfWork, including updates to another table for validation.
I get that it's some boilerplate code, but it is the predicament of having the uniqueness requirement on a set. What might be something you can look into is forcing the uniqueness through the Aggregate Identifier. Axon's Event Store logic ensures no two events are using the same aggregate identifier. So, if you try to input a new aggregate (hence a new event) for an already existing aggregate identifier, the operation will fail.
This approach is typically not feasible whenever the set-based consistency validation issue is described, though, so I am guessing it won't help you out.
Concluding, I'd take your win from the shared repository on the blog to minimize your personal effort on the matter.

Conditional Hibernate Interceptor

I have a Hibernate Interceptor that is persisting property changes of an entity and is working correctly. I am looking to update its current logic and only intercept when it's being triggered from a particular method, not just when Hibernate views it as being 'dirty'.
I am looking to implement something equivalent to:
#Override
public boolean onFlushDirty(Object entity, Serializableid, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types){
String callingMethod = // determined somehow...
if(callingMethod == MyService.updatePerson) {
// Only persist changes when calling method is updatePerson
}
return false
}
I've looked all around SO and the web, but I have not been able to find anything on the topic.
I've looked into controlling this behavior with AOP, however the interceptor fires blindly
Is anyone aware of being able to trigger an interceptor based on the calling method?
I ended up creating an Abstract class and Interface to support setting the 'isEditable' method I need.
I then wrote a custom annotation that I use within AspectJ to trap all executing code that I want. Within the pointcut, I update the entity, setting the 'isEditable' method.
Now, when my interceptor fires, I do a quick check to see if that entity is editable, if not, I dont persist the changes into the history table.

Spring MVC Binding Command Object Using Get Request

I need to implement a controller that has a command object that is backing a filtering form for a search across multiple entries.
The problem is that the i was asked to do that without using POST request, instead using GET request only, and there before loosing the functionality of the default data binding that springs makes happily for us.
So i tried to implement a method, inside my controller, that looks like this:
#Override
protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response)
throws Exception {
if (isSearchRequest(request)) {
MyCommandObject myCommandObject = (MyCommandObject) getCommand(request);
System.out.println(managePositionsForm);
}
return super.handleRequestInternal(request, response);
}
But the getCommand returns me a brand new CommandObject with no values, despite that the values are present in the request object (i could retrieve then using the getParameter method of HttpServletRequest). But there isn't any binding.
So the question :
1) Is there any way to archive this?
2) Also is very important, that all the values in the form, are lost and, eventually (if this problem is solved) i will need to "persist" the filters for the users in order to avoid re entering after the first search.
Auto Response : setSessionForm(true); looks like can do the work! (According to javadoc)
Thanks to all!
Greetings
Victor.
Okey, i found a way to archive what a was looking for.
I will explain for the sake of those have the same problem before, and hoping to find a experienced user to validate this method... some quiet common is there a multiple ways to do a same thing and as human beings is very difficult to know without proper acknowledge the right path.. so this i a found looking inside the AbstractFormController (that is excellently documented with javadoc).
So what i did was the following, on my controller constructor i add these lines at the end :
setSessionForm(true);
setBindOnNewForm(true);
That all the magic!
But is not enought with setSessionForm(true). According to javadoc the setBindOnNewForm(boolean) method does the following :
/**
* Set if request parameters should be bound to the form object
* in case of a non-submitting request, i.e. a new form.
*/
So my guess are that these two flags are necessary to be marked as true, because :
The setSessionForm makes posible to store as a session attribute the form object, so "is stored in the session to keep the form object instance between requests, instead of creating a new one on each request" (according to javadoc of the setSessionForm method).
The setBindOnNewForm allows the population of the form object with the initial request (despites what type of request method we have). According the javadoc found the AbstractFormController "Only if bindOnNewForm is set to true, then ServletRequestDataBinder gets applied to populate the new form object with initial request parameters..."
But still i noticed, following the controller flow with a debugger, that the population is happening inside the method "getErrorsForNewForm(HttpServletRequest request)".. that is where a concrete object of type ServletRequestDataBinder is used IF the setBindOnNewForm is true, and later (as the javadoc stated) the onBindOnNewForm method is invoked, allowing the programmer to overwrite it with custom behavior, the default behavior is just empty (again this was double checked against the code of AbstractFormController).
I have an strong felling to validate my thoughts here, so if anyone can help me, that would be alright, besides the problem is solved!
Thanks to all in advance!
Greetings.

What does `Client.findById(id)` mean?

Looking through the Play documentation for Java I noticed the following block of code:
public static Result show(Long id) {
Client client = Client.findById(id);
return ok(views.html.Client.show(client));
}
Source: http://www.playframework.com/documentation/2.1.0/JavaRouting
I am having some trouble understanding the second line, my understanding of Java Object creation is a typical constructor looks like the following:
Person john = new Person();
What is the second line doing? Creating a Object called client from Class called Client, also what is Client? It doesn't appear to be a part of the Play Framework, certainly I cannot find anything in JavaDocs.
Thanks
Edit:
I found this to be a good point of reference for the answer (http://docs.oracle.com/javase/tutorial/java/javaOO/classvars.html)
Also I think the class Client comes from the following documentation (http://www.playframework.com/documentation/1.1.1/controllers) with Client being just a example model class, the new documentation probably needs updating to clear up this confusion.
Pretty clearly, the class Client has a static function of findById, which takes a Long and returns a Client. Static functions are functions that are defined without any access to object properties, and therefore can be accessed through the class name, rather than having to be accessed through an object. Most likely, the class has a static property containing a collection of all clients in the system by index, and findById grabs an existing Client from that list.
I really have no idea where the class Client is defined, however. I've also made a quick look around for it, and couldn't find it in the obvious places.
There must be a static method called show(Client) on the views.html.Client class that returns some object. That object is passed into an ok(whatever) method, and that ok method returns a Result object.
You're missing some basic knowledge/experience. The sample you gave has nothing to do with routes and in this snippet only first line is important, second is just some hypothetical usage. De facto it could be just...
public static Result show(Long id) {
return ok("You want to display details of client with ID: " + id);
}
Although #BenBarden explained what is that mean correctly , this static method isn't declared anywhere, it's (again) hyphotetical usage of some ORM. For an example the real usage with Ebean's model will be:
Client = Client.find.byId(id);
Of course you can also declare own method in your Client model and name it the same as in the sample, however it will be just only wrapper:
public static Finder<Long, Client> find
= new Finder<>(Long.class, Client.class);
public Client findById(Long id) {
return find.byId(id);
}
Conclusions
You need to examine some samples available with your Play sources to get familiar with some basic syntax, fortunately you'll find it easy.
DO NOT MIX documentation from Play 1.x with Play 2.x they are not compatible!

Seam/Hibernate validator listener

We use a standard SEAM setup here ... complete with the validation system that uses hibernate.
Basically what happens is a user enters a value into an html input and seam validates the value they entered using the hibernate validation.
Works fine for the most part except here's my problem: We need to record the results of validation on each field and I can't figure out a good way to do it ... ideally it would be done through communicating with the seam/hibernate validation system and just recording the validation results but as far as I can tell there isn't a way to do this?
Has anyone done anything like this in the past? There are a couple nasty work arounds but I'd prefer to do it cleanly.
Just a quick overview of the process that we have happening right now for context:
1) user enters field value
2) onblur value is set with ajax (a4j:support) at this point the validators fire and the div is re-rendered, if any validation errors occured they're now visible on the page
What I'd like to have happen at step2 is a 'ValidationListener' or something similar is called which would allow us to record the results of the validation.
Thanks if anyone is able to help :o
You should be able to do it by creating a Bean that has a method observing the org.jboss.seam.validationFailed event. That method can then do whatever logging you want.
#Name("validationObserver")
public class ValidationObserver() {
#Observer("org.jboss.seam.validationFailed")
public void validationFailed() {
//Do stuff
}
}
The validationFailed event doesn't pass any parameters so you'll have to interrogate the FacesMessages or possibly the Hibernate Validation framework itself if you want to record what the error was.
I you are only using Hibernate for validation, you can use the Hibernate ClassValidator in the validationFailed() method, as recommended by Damo.
Example:
public <T> InvalidValue[] validateWithHibernate(T object) {
ClassValidator<T> validator = new ClassValidator(object.getClass());
InvalidValue[] invalidValues = validator.getInvalidValues(object);
return invalidValues;
}

Categories