I have a Java EE project with a lot of beans and processing. I was asked to log every dangerous operation that a user can do, i.e. deleting a document.
I have a log method in userServices bean, so a call like this:
userService("is deleting the document with id: "+documentId);
will work, the bean will use jpa to store user, date, time and message in the log table.
Anyway with this method I have to add the injection
#EJB private UserService userService;
in every EJB where I want to log something, and I really don't like it. I'm trying to use annotations and interceptor to do something like that:
#Stateless
#Interceptors(LogUserInterceptor.class)
#LogUserModuleName("Documents")
class DocumentServices implements DocumentServiceRemote {
[...lot of code...]
#Override
#LogUserDangerousOperation("Delete a document")
public deleteDocument(int id) {
}
}
In my interceptor I combine the class annotation and the method annotation to create a message (in this case: "Document: Delete a document") and then I call userService.log(message).
The advantage is I only have to annotate methods and class, without have to inject UserService bean programmatically call it.
It's working fine, but the obvious point is that I have no way to pass the id of the document the user is deleting, so I cannot log "Document: Delete document 12345".
Is there a way to do it without injecting UserServices bean in almost every bean of my project?
Try using CDI Interceptors instead of EJB interceptors. They are much more powerful and flexible.
All you have to do is to declare them in beans.xml like this:
<beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
<interceptors>
<class>custom.interceptor.Logger</class>
</interceptors>
Create annotation binding #Logger and create LoggerInterceptor like described in documentation.
yes.
Maybe you can try https://github.com/yeecode/ObjectLogger
Its a powerful and easy-to-use object log system, supports writing and querying of object attribute changes.
you can log any changes of any objects by it.
Related
I want to define a annotation like #PlatformRelated, once it is marked in a interface, there will be a proxy bean at spring context, and this proxy bean should be #Priority.I want this proxy could invoke different implement according to key parameter #KeyPrameter.And I still wanna use spring features like #Async,#Trasaction,etc... at my Implement1 and Implement2.
#PlatformRelated
interface MyInterface {
method(#KeyPrameter String parameter);
}
#Component
class Implement1 implements MyInterface {
method(String parameter){
//do something 111
}
}
#Component
class Implement2 implements MyInterface {
method(String parameter){
//do something 222
}
}
#Service
class BusinessService{
#Autowired
private MyInterface myInterface;
public void doSomething() {
myInterface.method("key1");
//Implement1 work
myInterface.method("key2");
//Implement2 work
}
}
Do you guys have some good idea to complete it?
I must admit I haven't totally understood the meaning #Priority, however, I can say that if you want to implement this feature in spring, you should probably take a look at Bean Post Processors.
BeanPostProcessors are essentially a hook to Bean Creation process in spring intended for altering bean behavior.
Among other things, they allow wrapping the underlying bean into the proxy (CGLIB/java.lang.Proxy if you're working with interfaces, or even using programmatically Spring AOP), these proxies can provide a hook to the method execution that can read your annotations (like mentioned #KeyParameter) and execute a code in a way similar to Aspect's code that you already make use of.
Not all bean post processor wrap the bean into the proxy. For example, if you want to implement a BPP that uses "#Autowire", you will return the same bean, just "inject" (read, put by reflection) its dependencies. On the other hand, if you want to implement with BPP #Transactional behavior, then yes, you should wrap the bean into a proxy that would take care of transaction management capabilities before and after the method execution.
It's totally ok to have a spring bean that gets "altered" by many post processors, some of them would wrap it into a proxy other will just modify-and-return the same bean, If there are many BPP-s that wrap the bean into proxy we'll get "proxy inside proxy inside proxy" (you get the idea). Each layer of proxy will handle one specific behavior.
As an example, I suggest you take a look at existing Spring postprocessors, or, for instance, a source code of the following library: Spring Boot metering integration library
This library contains some implementations of post processors that allow metrics infrastructure integration by defining annotations on methods of Spring Beans.
I have a bunch of dependencies written as fast binary web services (aka Ejb3.1). Here is the service delcaration:
#Remote
public interface MyService {...}
You would inject an EJB into a servlet or managed bean with the following syntax:
#EJB
MyService myService;
I don't want to use the #EJB injection however. I'd like to use plain vanilla CDI:
#Inject
MyService myService;
One way to accomplish this would be to Create a #Produces method for every EJB:
#Produces MyService produceMyService(InjectionPoint ijp){
//jndi lookup for MyService interface
}
However, InjectionPoint is capable of giving you all the information you need, such as the target class name (MyService in this case).
Is there a way in CDI to do something like this? I'd want to call this producer last, if the required injection point couldn't be fulfilled in any other manner.
#Produces Object produce(InjectionPoint ijp){
Class ejbInterface = ijp.getType();
//jndi lookup for ejbInterface
}
This is a confusing post, so ask clarification questions. Thanks a ton!
Assuming that I understood your question (see comment): No, there is no API for this.
Good news is that there is a way to achieve this - but you probably don't want to do this at runtime, that's rather a task for application startup.
The CDI extension mechanism offers you some well defined hooks into bean processing at container startup. This is a perfect place for logic that decides about enabling / disabling of certain managed beans (probably based on static classpath information).
Have a look at function and implementation of Seam Solder's #Requires. That should be pretty close to your use case...
I am having bean AddressBean, which has some properties like addressLine1, city etc.
Before persisting it to DB using AddressBeanService, I am prevalidating it, and after saving, i am post validating it, using preValidate and postValidate function in ValidateAddressService. And all this i am triggering from a AddressBeanHelper class.
class AddressBeanHelper{
AddressBean bean =null;
AddressBeanHelper(AddressBean bean){
this.bean=bean;
}
ValidationService validate=new ValidateAddressService();
function doStuff(){
validate.preValidateAddressBean (bean);
//business logic for AddressBean
validate.preValidateAddressBean (bean);
}
}
class ValidateAddressService implements ValidationService <AddressBean>{
preValidateAddressBean (AddressBean bean){
//here is the issue
}
preValidateAddressBean (AddressBean bean){
//here is the issue
}
}
I want some framework or trick in spring by which i just need to write generic code in validation functions and externalize my validation rule outside the code itself.
Like a rule engine which can automatically validates each and every property of bean.
currently my application infrastructure is spring/hibernate for server side, jsp/jquery on client side and deployment server is on heroku.
Have a look at this one:
http://hillert.blogspot.com/2011/12/method-validation-with-hibernate.html
It supports JSR-303, so its a standard. Its very easy to implement, and it supports, custom and some predefined ready to use validators.
You can also find some references here:
http://java.dzone.com/articles/method-validation-spring-31
I am using Seam 3 Internationalization packages to implement messaging in my application.
In short, this is what I am doing:
Importing/Injecting required classes:
import org.jboss.seam.international.status.Messages;
import javax.inject.Inject;
#Inject
private Messages messages;
When an error occurs, I create a Message in my backing bean:
messages.error(new BundleKey("AppMsgResources", "errorMsgKey")).defaults("Error: Something bad happened!");
Lastly I display the message in my faces page like so:
<h:messages />
Very standard so far I think ...
The custom logic I want to implement is to be able to first check a database table (lets call this table MessageBundleOverride) for a matching message key. If it exists, I want to use the value from the MessageBundleOverride table and not the property file. If it doesnt exist or is empty, I want to use the value found in the property file.
I'm thinking there is a Weld/CDI way of doing this where I can implement the Messages interface and register it with seam somehow so that it picks up my messages implementation during "inject" and not the default MessagesImpl implementation that comes with Seam Internationalization package. I am a little new to Seam / Weld so not sure if this is a simple thing to do.
any help is much appreciated,
thanks!
Figured out one way of getting this done after reading Weld docs:
http://docs.jboss.org/weld/reference/latest/en-US/html/injection.html#alternatives
#Alternative
#RequestScoped
public class MyMessages extends MessagesImpl {
/*
* Override a method that you want to customize or write new code here
*/
#Override
public Set<Message> getAll() {
Set<Message> allMessages = super.getAll();
// do some custom logic here
applyOverrides(allMessages);
return allMessages;
}
...
// override any other method as needed
// You will probably have to override everything so it probably
// wouldnt make sense to extend the existing implementation)
...
}
In the beans.xml file, you will have to declare this new class as an alternative to the default:
<beans xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
<alternatives>
<class>com.company.project.view.messages.MyMessages</class>
</alternatives>
</beans>
And that should do it so long as weld is picking up the classes in the package you have MyMessages defined in.
In the grails doc, I read (something along the lines) that the implementation of a server class will bu automatically wired based on the naming convention.
If this is true, then how would one go about overriding this behavior down the road say if you have a new implementation?
do we have options? like:
use #annotations
if you don't want to re-compile, add the entry to the xml
I am assuming "server class" was meant to be typed as "service class" and "bu"->"be"?
If those assumptions are correct: yes, they are autowired.
You create a grails service called UserService in your grails-app/services directory, you can inject it into a controller using:
def userService
You can override this behavior using the Spring DSL in the resources.groovy file in your grails-app/conf/spring directory. Or if you prefer XML, you can add a resources.xml file in grails-app/conf/spring to configure your Spring Beans.