Plugins are an easy way to extend and customize VRaptor's functions. They are automatically executed after the web application has loaded and have access to VRaptors core data and functions.
Some of them are already included in VRaptor's jar file. The Hibernate Validator Plugin and the Testing Plugin are more advanced examples which show the possibilities and power of the plugin interface.
In this tutorial we will write our own plugin which logs the total number of logic method hits. So every time our web application calls a logic method the counter will increment.
This involves the following steps:
This tutorial is not meant for beginners. You should have some fair knowledge of Java and VRaptor.
In order to create our own plugin you will have to write a class which implements the VRaptorPlugin interface.
package org.vraptor.mydvds.plugin; public class MethodHitsPlugin implements VRaptorPlugin { ... }
This interface is the contract for any VRaptor plugin. It has only one method: init(). VRaptor will automatically call this method when the web application has finished loading.
package org.vraptor.mydvds.plugin; public class MethodHitsPlugin implements VRaptorPlugin { public void init(WebApplication application) { //... } }
The init() Method recieves a WebApplication reference as parameter. This is our door to VRaptor's core data. You will find lots different managers which give you access and information about components, logics, injected and outjected vars and much more.
This tutorial won't explain every detail of these functions, check out the Java doc and also look at the source code of the existing plugins for further help.
When you use VRaptor as your mvc controller you write primarily components (@Component) with logic methods. When VRaptor starts, it automatically registers these components.
The interface ComponentType represents a component. Our goal is to wrap these components in a custom object to register them using VRaptors ComponentManager.
A simple component wrapper should extend the ComponentWrapper class:
package org.vraptor.mydvds.plugin; class PluginComponentWrapper extends ComponentWrapper { public PluginComponentWrapper(ComponentType component) { super(component); }
ComponentWrapper implements the ComponentType interface and has already all necessary methods implemented. We just have to override the one we wish to customize.
For our purpose we will override the getLogic() method. Our final PluginComponentWrapper would look like:
package org.vraptor.mydvds.plugin; class PluginComponentWrapper extends ComponentWrapper { @Override public LogicMethod getLogic(String key) throws LogicNotFoundException { return new PluginLogicMethodWrapper(super.getLogic(key)); } public PluginComponentWrapper(ComponentType component) { super(component); } }
The getLogic() method will be called by VRaptor in order to recieve the logic method from a component. It returns the type LogicMethod which represents a logic in a component.
As you can see, we also have wrapped the logic method, which we create next.
We use the same principle as we did for PluginComponentWrapper. We want to write a logic method wrapper in order to customize the behaviour. So let's extends LogicMethodWrapper to create our custom PluginLogicMethodWrapper:
package org.vraptor.mydvds.plugin; class PluginLogicMethodWrapper extends LogicMethodWrapper{ public PluginLogicMethodWrapper(LogicMethod logicMethod) { super(logicMethod); } //.... }
LogicMethodWrapper has already every method implemented for us. We just want to override the execute() method and log when it is called.
package org.vraptor.mydvds.plugin; class PluginLogicMethodWrapper extends LogicMethodWrapper{ private static int numberOfMethodHits; public PluginLogicMethodWrapper(LogicMethod logicMethod) { super(logicMethod); } @Override public String execute(Object component, LogicRequest request) throws LogicException { System.out.printf("Method hits: %d ", ++numberOfMethodHits); return super.execute(component, request); } }
execute() will finally execute our logic method and we just have to output the counter numberOfMethodHits.
After playing around with component and logic wrappers let's return to our init() method from the beginning.
We have to register all components in order to put them in our PluginComponentWrapper. To register a component, VRaptor uses the ComponentManager. With the WebApplication reference we has access to the ComponentManager and we can register our new PluginComponentWrapper components.
So lets write simple for loop:
package org.vraptor.mydvds.plugin; public class MethodHitsPlugin implements VRaptorPlugin { public void init(WebApplication application) { //get all components from component manager Set<ComponentType> components = application.getComponentManager() .getComponents(); //register the wrapped components for (ComponentType component : components) { application.getComponentManager().register( new PluginComponentWrapper(component)); } } }
Nothing complicated here, get all components from ComponentManager and register them using our wrapper PluginComponentWrapper. Please observe that we pass the original component to PluginComponentWrapper constructor.
That's it. Any logic call will go through our component and then logic wrapper. We customized VRaptor.
Finally we have to register the plugin in the vraptor.xml:
<vraptor> ... <plugin>org.vraptor.mydvds.plugin.MethodHitsPlugin</plugin> ... </vraptor>
To write a plugin, you just need a class which implements VRaptorPlugin, but you have to know a little about VRaptor. This examples has shown how to access some core data and can be easily extend to create some useful functions such as logging, authentication or validation.