Customizing Seam3 internationalization Messages - java

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.

Related

How (and when) to initialize a Spring bean which needs to access other beans only known in runtime?

I have a Spring webapp running on Java 5. This is was my applicationContext.xml file:
<bean id="child1" class="foo.ChildOne" />
<bean id="child2" class="foo.ChildTwo" />
<bean id="main" class="foo.Main">
<property name="childrenList">
<list value-type="foo.IChildren">
<ref bean="child1" />
<ref bean="child2" />
</list>
</property>
</bean>
Both ChildOne and ChildTwo classes implement the IChildren interface. And in my Main class, I have defined a childrenList which gets populated with child1 and child2 beans. Easy, right?
But in the future, there might be no child1, and instead, we will maybe have a child81 based on another unknown class. And it still has to work without touching the current code or XML files, only through configuration. This child81 would be defined on its own applicationContext file (in a JAR), and we will list the bean names in a database field (child2,child81,etc).
I guess that's not a good design pattern; most likely it's a terrible, horrible, painful, you-better-run-while-you-can design, which will haunt me in the years to come. But I didn't define it, and I can't change it, so please lets assume it's OK for the purpose of this question.
Instead of injecting the beans myself using the applicationContext.xml, I have to retrieve them somehow, in runtime. I can't use autowiring either, because I don't know what class the beans are, all I know is all of their classes implement IChildren.
So I have made my main bean class ApplicationContextAware and I have added this method:
public void loadChildren() {
if (childrenList == null) {
childrenList = new LinkedList<IChildren>();
for (String name : theListOfBeanNames) {
childrenList.add((IChildren) context.getBean(name));
}
}
}
It works alright; each bean is defined in its own applicationContext, and then I retrieve them by name. But... when do I call loadChildren()? So far, I'm doing it in the first line of each one of my methods. Since there is a null-check, it will initialize the list only once. But surely, there must be an easier/cleaner/better way of doing this?
I don't think I can just use the init-method="loadChildren" property in my applicationContext, because then it would fail if my main bean is being loaded before all the children have been... and I can't control the loading order. Or can I?
This is from my web.xml file:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/application-context/applicationContext-*.xml
,classpath*:WEB-INF/application-context/applicationContext-children.xml
</param-value>
</context-param>
(We use the "classpath* notation" to load every applicationContext-children.xml file from within the JARs). If I invert the order and place the children XML before the main ones, would it ensure they will be loaded in that specific order? No matter what version of what application server we use?
I've also seen a #PostConstruct annotation which would be useful if I could add it to my loadChildren method. But when would it be called then? I've read that it's after the injections have been done, but... only for the current bean, right? It doesn't ensure that all the other beans are already loaded?
Is there any other option?
Spring can do this for you:
#Component
public class MyComponent {
#Autowired
private final List<IChildren> children;
...
}
That will autowire in everything than implements IChildren.
Mr Spoon's answer does exactly what I asked, so I'm marking it as the correct answer. However, I forgot to mention that the children order in the list does matter, so I still can't use autowiring. Here is what I ended up doing instead, in case anybody else finds it useful.
As stated in the answers to this question, another option is to catch the ContextRefreshedEvent by implementing the ApplicationListener<ContextRefreshedEvent> interface. That ensures that the loadChildren method is executed only after all the initialization is done.
Since we are using a very old Spring version (2.0.7), our ApplicationListener interface is slightly different, for example it doesn't support generic types. So, instead of doing this, my class looks like this:
public class Main implements ApplicationListener {
public void loadChildren(ApplicationContext context) {
//...
}
public void onApplicationEvent(ApplicationEvent ev) {
if (ev instanceof ContextRefreshedEvent) {
loadChildren(((ContextRefreshedEvent) ev).getApplicationContext());
}
}
}

Java: using annotations for logging user operation instead of injection?

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.

Should dependency be injected once or in every object

I'm trying to change some legacy code to use DI with Spring framework. I have a concrete case for which I'm wondering which is the most proper way to implement it.
It is a java desktop application. There is a DataManager interface used to query / change data from the data store. Currently there is only one implementation using a XML file for store, but in the future it is possible to add SQL implementation. Also for unit testing I may need to mock it.
Currently every peace of code that needs the data manager retrieves it by using a factory. Here is the source code of the factory:
public class DataManagerFactory
{
private static DataManagerIfc dataManager;
public static DataManagerIfc getInstance()
{
// Let assume synchronization is not needed
if(dataManager == null)
dataManager = new XMLFileDataManager();
return dataManager;
}
}
Now I see 3 ways to change the application to use DI and Spring.
I. Inject the dependency only in the factory and do not change any other code.
Here is the new code:
public class DataManagerFactory
{
private DataManagerIfc dataManager;
public DataManagerFactory(DataManagerIfc dataManager)
{
this.dataManager = dataManager;
}
public DataManagerIfc getDataManager()
{
return dataManager;
}
public static DataManagerIfc getInstance()
{
return getFactoryInstance().getDataManager();
}
public static DataManagerFactory getFactoryInstance()
{
ApplicationContext context =
new ClassPathXmlApplicationContext(new String[] {"com/mypackage/SpringConfig.xml"});
return context.getBean(DataManagerFactory.class);
}
}
And the XML with the bean description:
<bean id="dataManagerFactory"
class="com.mypackage.DataManagerFactory">
<constructor-arg ref="xmlFileDataManager"/>
</bean>
<bean id="xmlFileDataManager"
class="com.mypackage.datamanagers.xmlfiledatamanager.XMLFileDataManager">
</bean>
II. Change every class that is using the data manager so it takes it through the constructor and store it as a class variable. Make Spring bean definitions only for the "root" classes from where the chain of creation starts.
III. Same as II. but for every class that is using the data manager create a Spring bean definition and instantiate every such class by using the Spring Ioc container.
As I'm new to the DI concept, I will appreciate every advice what will be the correct and "best practice" solution.
Many thanks in advance.
Use option 3.
The first option keeps your code untestable. You won't be able to easily mock the static factory method so that it returns a mock DataManager.
The second option will force you to have the root classes know all the dependencies of all the non-root classes in order to make the code testable.
The third option really uses dependency injection, where each bean only know about its direct dependencies, and is injected by the DI container.
Well... why did you write the factory in the first place? Spring is not intended to make you change how you write code (not just to suit Spring that is), so keeping the factory is correct as it uses well-known pattern. Injecting the dependency into the factory will retain that behaviour.
Option 3 is the correct route to take. By using such a configuration you can usefully take components of your configuration and use them in new configurations, and everything will work as expected.
As a rule of thumb, I would expect one call to Spring to instantiate the application context and get the top-level bean. I wouldn't expect to make repeated calls to the Spring framework to get multiple beans. Everything should be injected at the correct level to reflect responsibilities etc.
Beware (since you're new to this) that you don't plumb in your data manager into every class available! This is quite a common mistake to make, and if you've not abstracted out and centralised responsibilities sufficiently, you'll find you're configuring classes with lots of managers. When you see you're doing this it's a good time to step back and look at your abstractions and componentisation.

How Can I create Spring Bean outside of Spring Application Context

I'm developing some kind of plugin which should be called by external java app.
my Plugin is using Spring and of cause I tried to simplify my as I can:
Let's consider that this is 3d party app and it's calling my plugin in its main function.
public class ThirdPartyClass {
public static void main(String[] args) {
GeneralPlugin plugin = new MyPlugin();
plugin.init();
//calling ext. plugin functionality.
plugin.method1();
}
}
Now this is my plugin
package com.vanilla.spring;
#Component
public class MyPlugin implements GeneralPlugin{
#Autowired
Dao mydao;
public void init(){
//some initiation logic goes here...
}
public void method1(){
dao.delete();
}
}
Now my Dao
package com.vanilla.spring;
Component(value="dao")
public class MyDao {
public void delete(){
//SOME DATABASE LOGIC GOES HERE!!!
}
}
now my XML:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
<context:annotation-config />
<context:component-scan base-package="com.vanilla.spring"></context:component-scan>
</beans>
My problem is that my dao is null and I'm getting NullPointerException when accessing dao object.
I
m believe it happens because I'm initiation bean out of Application context and as the result my Autowiring is not working.
Is there any other way to make autowiring work?
"Spring beans" are just that: Java beans. They have no intrinsic abilities other than those given to them by inheritance or object instantiation.
The Spring Application Context is responsible for creating the bean and "wiring" it, which is the process of creating other beans in the context and calling the bean's setters (and constructors) with the results to configure them. To do this is uses the XML configuration file and annotations to decide what to create and where to put it.
If you aren't going to use an actual Application Context, then you have to do all of that work yourself, manually. That is, create the DAO with the proper data source, create the plugin bean, and set the DAO on the plugin bean.
In this specific example, since the 3rd party application controls the instantiation of your plugin bean, you will likely have to either a) create the DAO in the plugin constructor (which is what you're using Spring to avoid in the first place), or b) create an Application Context in the plugin constructor and reference the beans the plugin needs by querying the context. This isn't quite as useful as letting the context do everything, but at least you don't have to configure the rest of the beans your application uses manually (with user names, connection URLs, etc).
If you go the second route you would then need the Spring configuration file somewhere in the classpath or somehow otherwise able to be referenced by the plugin bean.

Aspectj doesn't catch all events in spring framework?

My project is based on spring framework 2.5.4. And I try to add aspects for some controllers (I use aspectj 1.5.3).
I've enabled auto-proxy in application-servlet.xml, just pasted these lines to the end of the xml file:
<aop:aspectj-autoproxy />
<bean id="auditLogProcessor" class="com.example.bg.web.utils.AuditLogProcessor" />
Created aspect:
package com.example.bg.web.utils;
import org.apache.log4j.Logger;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
#Aspect
public class AuditLogProcessor
{
private final static Logger log = Logger.getLogger(AuditLogProcessor.class);
#After("execution(* com.example.bg.web.controllers.assets.AssetThumbnailRebuildController.rebuildThumbnail(..))")
public void afterHandleRequest() {
log.info("test111");
}
#After("execution(* com.example.bg.web.controllers.assets.AssetThumbnailRebuildController.rebuildThumbnail(..))")
public void afterRebuildThumbnail() {
log.info("test222");
}
}
My controllers:
class AssetAddController implements Controller
class AssetThumbnailRebuildController extends MultiActionController
When I set brake points in aspect advisors and invoke controllers I catch only afterHandleRequest() but not afterRebildThumbnail()
What did I do wrong?
NOTE
I'm asking this question on behalf of my friend who doesn't have access to SO beta, and I don't have a clue what it's all about.
EDIT
There were indeed some misspellings, thanks Cheekysoft. But the problem still persists.
Your breakpoints aren't being hit because you are using Spring's AOP Proxies. See understanding-aop-proxies for a description of how AOP Proxies are special.
Basically, the MVC framework is going to call the handleRequest method on your controller's proxy (which for example the MultiActionController you're using as a base class implements), this method will then make an "internal" call to its rebuildThumbnail method, but this won't go through the proxy and thus won't pick up any aspects. (This has nothing to do with the methods being final.)
To achieve what you want, investigate using "real" AOP via load time weaving (which Spring supports very nicely).
AspectJ doesn't work well with classes in the Spring Web MVC framework. Read the bottom of the "Open for extension..." box on the right side of the page
Instead, take a look at the HandlerInterceptor interface.
The new Spring MVC Annotations may work as well since then the Controller classes are all POJOs, but I haven't tried it myself.
The basic setup looks ok.
The syntax can be simplified slightly by not defining an in-place pointcut and just specifying the method to which the after-advice should be applied. (The named pointcuts for methods are automatically created for you.)
e.g.
#After( "com.example.bg.web.controllers.assets.AssetAddController.handleRequest()" )
public void afterHandleRequest() {
log.info( "test111" );
}
#After( "com.example.bg.web.controllers.assets.AssetThumbnailRebuildController.rebuildThumbnail()" )
public void afterRebuildThumbnail() {
log.info( "test222" );
}
As long as the rebuildThumbnail method is not final, and the method name and class are correct. I don't see why this won't work.
see http://static.springframework.org/spring/docs/2.0.x/reference/aop.html
Is this as simple as spelling? or are there just typos in the question?
Sometimes you write rebuildThumbnail and sometimes you write rebildThumbnail
The methods you are trying to override with advice are not final methods in the MVC framework, so whilst bpapas answer is useful, my understanding is that this is not the problem in this case. However, do make sure that the rebuildThumbnail controller action is not final
#bpapas: please correct me if I'm wrong. The programmer's own controller action is what he is trying to override. Looking at the MultiActionController source (and its parents') the only finalized method potentially in the stack is MultiActionController.invokeNamedMethod, although I'm not 100% sure if this would be in the stack at that time or not. Would having a finalized method higher up the stack cause a problem adding AOP advice to a method further down?

Categories