Solved

abstract spring beans

Posted on 2014-02-12
7
511 Views
Last Modified: 2014-04-01
hi experts

I have created abstract beans in my spring beans xml file and i am trying to provide concrete implimentation to these abstract beans in my Processor but getting some errors.

These are my abstract beans and properties file

 
  <bean id="abstractQueue" class="org.springframework.jndi.JndiObjectFactoryBean" abstract="true">
        <property name="jndiTemplate">
            <ref bean="jndiTemplate" />
        </property>
    </bean>

    <bean id="abstractMessageListner" abstract="true">
    	<property name="system" value="${system}"/>    	 
    </bean>

    <bean id="abstractMessageListenerContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer" abstract="true">        
        <property name="connectionFactory" ref="cachedConnectionFactory" />
        <property name="concurrentConsumers" value="3" />
		<property name="maxConcurrentConsumers" value="10" />
		<property name="receiveTimeout" value="5000" />
		<property name="idleTaskExecutionLimit" value="10" />
		<property name="idleConsumerLimit" value="1" />
		<property name="sessionAcknowledgeModeName" value="AUTO_ACKNOWLEDGE" />
		<property name="sessionTransacted" value="true" />
		<property name="cacheLevelName" value="CACHE_SESSION"/>
		<property name="acceptMessagesWhileStopping" value="true"/>  
    </bean>

    <bean id="processor" class="com.tarmax.util.MessageListenerContainerProcessor">
    	<property name="queueId" value="Queue_name"/>
    	<property name="propertiesLocation" value="classpath:application.properties"/>    	
    </bean>

Open in new window


My application.properties file
Queue_name = CUST_QUEUE_1,CUST_QUEUE_2    # queue names
system = pint
mailserver.host=smtprelay.pint.com

Open in new window


This is my MessageListenerContainerProcessor which impliments  BeanDefinitionRegistryPostProcessor


public class MessageListenerContainerProcessor implements BeanDefinitionRegistryPostProcessor
{
	private static final Logger logger = LoggerFactory.getLogger(MessageListenerContainerProcessor.class);

    private int listenerCounter = 0;
    private String allQueues; 
    private String queueId;
 
	public void setPropertiesLocation(Resource location) throws IOException {
		Properties props = new Properties();
		props.load(location.getInputStream());
		this.allQueues = props.getProperty(getQueueId());
	}

	 public String getQueueId() {
		return queueId;
	}

	public void setQueueId(String queueId) {
		this.queueId = queueId;
	}

	public String[] getQueues() {
	 String[] queues = null;
	 if(allQueues != null){
		 if(allQueues.contains(",")){ //multiple Queues CUST_QUEUE_1,CUST_QUEUE_2
			 queues = allQueues.split(",");
		 }else{//single Queue
			 queues = new String[1];
			 queues[0] = allQueues;
		 }
	 }
	 return queues;
	 }
	
	
	/*
	 * BeanDefinitionRegistryPostProcessor fires before BeanFacoryPostProcessor 
	 * which is responsible for reading proerpties file <context:property-placeholder/>. 
	 * So during the creation of MessageListenerContainerProcessor
	 * reference to properties file will still not be resolved 
	 */
	
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
    	String[] queues  = getQueues();
    	for(String queue : queues){    		 
    		registerListenerBeans(registry, queue, "com.tarmax.util.MessageObservable");
    	}
    }

    private void registerListenerBeans(BeanDefinitionRegistry registry, String queueName, String messageListenerClassName) {
    	listenerCounter++;
        //now provide concrete bean definitions
		
        GenericBeanDefinition queueDefinition = new GenericBeanDefinition(); //for Queue
        GenericBeanDefinition messageListenerDefinition = new GenericBeanDefinition(); //for MessageListener
        GenericBeanDefinition messagelistenerContainerDefinition = new GenericBeanDefinition(); //for MessageListenerContainer

        //Queue definition for abstractQueue
        queueDefinition.setParentName("abstractQueue");
        MutablePropertyValues queuePropertyValues = new MutablePropertyValues();
        queuePropertyValues.add("jndiName", queueName);
        queueDefinition.setPropertyValues(queuePropertyValues);
        registry.registerBeanDefinition("queue"+listenerCounter, queueDefinition);
        logger.info("Queue created with name>>"+queueName);
        
        //MessageListner definition for abstractMessageListner
        messageListenerDefinition.setParentName("abstractMessageListner");
        messageListenerDefinition.setBeanClassName(messageListenerClassName);
        MutablePropertyValues messageListenerPropertyValues = new MutablePropertyValues();
        messageListenerPropertyValues.add("queueName", queueName);
        messageListenerPropertyValues.add("messageListenerContainer", messagelistenerContainerDefinition);
        messageListenerDefinition.setPropertyValues(messageListenerPropertyValues);
        registry.registerBeanDefinition("messageListener"+listenerCounter, messageListenerDefinition);
        logger.info("Message Listener Definition created with name>>"+messageListenerDefinition.getParentName());
        
        //MessageListenerContainer definition for abstractMessageListenerContainer      
        messagelistenerContainerDefinition.setParentName("abstractMessageListenerContainer");
        MutablePropertyValues messagelistenerContainerPropertyValues = new MutablePropertyValues();
        messagelistenerContainerPropertyValues.add("destination", queueDefinition);
        messagelistenerContainerPropertyValues.add("messageListener", messageListenerDefinition);
        messagelistenerContainerDefinition.setPropertyValues(messagelistenerContainerPropertyValues);
        registry.registerBeanDefinition("listenerContainer"+listenerCounter, messagelistenerContainerDefinition);
        logger.info("Message Listener Definition Container created with name>>"+messagelistenerContainerDefinition.getParentName());
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    }
	

Open in new window

     

This is MessageObservable which is used above
	Public class MessageObservable implements MessageListener{
	@Override
	public void onMessage(Message message){
	   //process message	   
		}
	}

Open in new window


when i put a break point inside this method registerListenerBeans(BeanDefinitionRegistry registry, String queueName, String messageListenerClassName)
i dont see any problems, it reaches the end of the method but at the end throws this error trace on console
      
(2014-02-12 18:09:19,579) INFO  [main] org.springframework.beans.factory.config.PropertyPlaceholderConfigurer - Loading properties file from class path resource [application.properties]
java.lang.StackOverflowError
	at java.lang.StringBuilder.append(StringBuilder.java:132)
	at java.lang.StringBuilder.<init>(StringBuilder.java:110)
	at org.springframework.util.PropertyPlaceholderHelper.parseStringValue(PropertyPlaceholderHelper.java:131)
	at org.springframework.util.PropertyPlaceholderHelper.replacePlaceholders(PropertyPlaceholderHelper.java:125)
	at org.springframework.beans.factory.config.PropertyPlaceholderConfigurer$PlaceholderResolvingStringValueResolver.resolveStringValue(PropertyPlaceholderConfigurer.java:255)
	at org.springframework.beans.factory.config.BeanDefinitionVisitor.resolveStringValue(BeanDefinitionVisitor.java:282)
	at org.springframework.beans.factory.config.BeanDefinitionVisitor.visitParentName(BeanDefinitionVisitor.java:91)
	at org.springframework.beans.factory.config.BeanDefinitionVisitor.visitBeanDefinition(BeanDefinitionVisitor.java:77)
	at org.springframework.beans.factory.config.BeanDefinitionVisitor.resolveValue(BeanDefinitionVisitor.java:169)
	at org.springframework.beans.factory.config.BeanDefinitionVisitor.visitPropertyValues(BeanDefinitionVisitor.java:141)
	at org.springframework.beans.factory.config.BeanDefinitionVisitor.visitBeanDefinition(BeanDefinitionVisitor.java:82)
	at org.springframework.beans.factory.config.BeanDefinitionVisitor.resolveValue(BeanDefinitionVisitor.java:169)
	at org.springframework.beans.factory.config.BeanDefinitionVisitor.visitPropertyValues(BeanDefinitionVisitor.java:141)
	at org.springframework.beans.factory.config.BeanDefinitionVisitor.visitBeanDefinition(BeanDefinitionVisitor.java:82)
	at org.springframework.beans.factory.config.BeanDefinitionVisitor.resolveValue(BeanDefinitionVisitor.java:169)
	at org.springframework.beans.factory.config.BeanDefinitionVisitor.visitPropertyValues(BeanDefinitionVisitor.java:141)	
Error : null

Open in new window


Any idea what i am missing if anything ?
Thanks.

PS: This question is related to
http://www.experts-exchange.com/Programming/Languages/Java/Q_28315067.html
0
Comment
Question by:royjayd
  • 4
  • 3
7 Comments
 

Author Comment

by:royjayd
ID: 39854942
I think iknow where the problem is ..in the code we are tryin to read properties file for 'mailserver.host' (mailserver.host=smtprelay.pint.com )
but it fails since the properties file is not loaded.
Similarly there are lot of other proerties which needs to be read when application starts up.

Is ther any way i can load the properties file upfront before it reaches my MessageListenerContainerProcessor ?

thanks.
0
 
LVL 35

Expert Comment

by:mccarl
ID: 39854949
I'm pretty sure that the error that you are getting doesn't have much to do with that part of the code that you posted. From the error message it appears that the problem happens after all this, where the PropertyPlaceholderConfigurer is doing it's bit. Therefore, could you post your full spring beans xml file so that I can see what is going on with that?

Also, just something to try... do you get the same problem if you hard code the value of 'system' in the abstractMessageListener definition in the xml, rather than using ${system}? If this fixes the issue, the reason for the error may be similar to your previous problem, ie. the order that beans get instantiated and when placeholders get resolved, etc. That's not too much of a problem though, because we can fix it similar to how you get the value for 'queues' into the PostProcessor and then into the beans that it creates. But just check that that is the issue first, and if not post the full xml.
0
 

Author Comment

by:royjayd
ID: 39857571
Alright I am investigating a little bit more, will keep you posted.
Thank you.
0
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 
LVL 35

Expert Comment

by:mccarl
ID: 39857973
Sorry, I didn't see your additional comment http:#a39854942 before I posted mine and so I've only just seen it now...

in the code we are tryin to read properties file for 'mailserver.host'
I don't see that in the parts that you've posted. So as I said above, if you can post the full xml that would help.

Is ther any way i can load the properties file upfront before it reaches my MessageListenerContainerProcessor ?
As I said in your other question, there is NO way to do this using the standard PropertyPlaceholderConfigurer as the order of instantiation means that the PropertyPlaceholderConfigurer loads too late to be able to set the property values. Note though, that this is only a problem for your MessageListenerContainerProcessor and from the xml above, you aren't setting any property-based values on that. You can still use the PropertyPlaceholderConfigurer on other beans in your xml file just fine. (With the one possible exception, as I noted above, I'm not sure whether it will work or not on those abstract beans that are used by the PostProcessor)

Alright I am investigating a little bit more, will keep you posted.
Ok, but if you can post the full xml in the meantime, I can look over that too.
0
 

Author Comment

by:royjayd
ID: 39859895
After some more investigation i was able to narrow down.
I am loading up 7 xml files on start up(each with different configurations like
datasource.xml contains database inormation
mqconfig.xml contains MQ config info
tibcoConfig.xml contains tibco config info, and so on
The xmls are huge so i really cannot post here.But i have tried to explain the problem situation below along with the problem code


Here is my main xml : application.xml

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans"
		xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:task="http://www.springframework.org/schema/task" 
       xmlns:drools="http://drools.org/schema/drools-spring"
       xmlns:aop="http://www.springframework.org/schema/aop"       
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:jms="http://www.springframework.org/schema/jms"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
       http://www.springframework.org/schema/beans/spring-beans-3.1.xsd 
       http://www.springframework.org/schema/context 
       http://www.springframework.org/schema/context/spring-context.xsd
 	   http://www.springframework.org/schema/tx 
	   http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
	   http://www.springframework.org/schema/aop 
	   http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
	   http://drools.org/schema/drools-spring 
	   http://drools.org/schema/drools-spring.xsd
	   http://www.springframework.org/schema/task
       http://www.springframework.org/schema/task/spring-task-3.0.xsd
	   http://www.springframework.org/schema/jms
	   http://www.springframework.org/schema/jms/spring-jms-3.0.xsd">
	   
<context:component-scan base-package="com.tarmax.util" />
	<context:spring-configured />
	<tx:annotation-driven transaction-manager="transactionManager" />
	
	<import resource="datasource.xml" />
	<import resource="mqconfig.xml" />
	<import resource="tibcoConfig.xml" />
	<import resource="customBeans.xml" />
	
	<bean id="placeholderConfigurer"
		class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
		<property name="locations">
			<list>				 
				<value>classpath:application.properties</value>
			</list>
		</property>
	</bean>
	
  <bean id="abstractQueue" class="org.springframework.jndi.JndiObjectFactoryBean" abstract="true">
        <property name="jndiTemplate">
            <ref bean="jndiTemplate" />
        </property>
    </bean>

    <bean id="abstractMessageListner" abstract="true">
    	<property name="system" value="${system}"/>    	 
    </bean>

    <bean id="abstractMessageListenerContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer" abstract="true">        
        <property name="connectionFactory" ref="cachedConnectionFactory" />
        <property name="concurrentConsumers" value="3" />
		<property name="maxConcurrentConsumers" value="10" />
		<property name="receiveTimeout" value="5000" />
		<property name="idleTaskExecutionLimit" value="10" />
		<property name="idleConsumerLimit" value="1" />
		<property name="sessionAcknowledgeModeName" value="AUTO_ACKNOWLEDGE" />
		<property name="sessionTransacted" value="true" />
		<property name="cacheLevelName" value="CACHE_SESSION"/>
		<property name="acceptMessagesWhileStopping" value="true"/>  
    </bean>

    <bean id="processor" class="com.tarmax.util.MessageListenerContainerProcessor">
    	<property name="queueId" value="Queue_name"/>
    	<property name="propertiesLocation" value="classpath:application.properties"/>    	
    </bean>

	<bean id="client" class="com.tarmax.util.Client" init-method="initialize">
	<property name="system" value="TARMAX"/>	
	<property name="observer" ref="obsvr"/>	
	</bean>
	
	<bean id="obsvr" class="com.tarmax.util.Listener">
		<property name="processor" ref="customProcessor"/>	
		<property name="goDownTime" value="60000"/>					
	</bean> 
	
<bean id="customProcessor" class="com.tarmax.util.CustomProcessor">
</bean>

</beans>

Open in new window

     

datasource.xml contains
<beans>
		<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
		<property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver" />
		<property name="url" value="${url.value}" />
		<property name="username" value="${user.value}" />
		<property name="password" value="${pass.value}" />		 
	</bean>

Open in new window

     

similarly mqconfig.xml contains

<bean id="cachedConnectionFactory" class="org.springframework.jms.connection.CachedConnectionFactory">
    		<property name="reconnectOnException" value="true"/>
    		<property name="sessionCacheSize" value="200"/>
    </bean>
	
	<bean id="errorQ" class="org.springframework.jndi.JndiObjectFactoryBean">
		<property name="jndiTemplate" ref="jndiTemplate"/>
		<property name="jndiName" value="${error.queue}"/>
	</bean> 
	and so on ..
	

Open in new window

     

Client and CustomProcessor classes

	
public Class Client{
public static void main(String[] args) {
String springXml = System.getProperty(application.xml);
ApplicationContext appCtx = new ClassPathXmlApplicationContext(springXml);
}
}

public class CustomProcessor {
	
 @Autowired	
private DefaultMessageListenerContainer abstractMessageListenerContainer;
	
public void processMerchandise(Object message) throws JMSException {
	
try{
analyzeObjectValidateAndStore(message);
}cathc(Exception e){
abstractMessageListenerContainer.stop();	
}

Open in new window


      
Flow is Client.main() method starts up and loads all the xmls (under application.xml)
As we start getting messages
 com.tarmax.util.MessageObservable.onMessage() method gets invoked which invokes
 CustomProcessor.processMerchandise() method.
processMerchandise() method validates and stores messages in database.

Regarding the problem posted in original question:
As i guessed earlier the problem is with loading the value from properties file.
In all the above xmls(under appliaction.xml) i hard coded the values without reading from properties file
Example
before: <property name="username" value="${user.value}" />
after: <property name="username" value="tarmax" />  and so on.

Then i had to comment out this peice of code
<bean id="placeholderConfigurer"	class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>				 
<value>classpath:application.properties</value>
</list>
</property>
</bean>

Open in new window

     
      
Now it does not give me that Null pointer exception related to reading properties file. However i get another exception::
java.lang.NoClassDefFoundError: Could not initialize class org.springframework.beans.factory.BeanCreationException
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:529)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:458)
	at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:295)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:292)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:626)
	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932)
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479)
	at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
	at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:93)
	at com.tarmax.util.Client.main(Client.java:180)
Error : Could not initialize class org.springframework.beans.factory.BeanCreationException

Open in new window




Thanks for your help.
0
 
LVL 35

Accepted Solution

by:
mccarl earned 500 total points
ID: 39863696
Ok, a few things goin on here...

Now it does not give me that Null pointer exception
It wasn't actually a NullPointerException, but a StackOverflowError (The "null" printed at the end of that trace was just saying that there was no (null) error message)

However i get another exception
This one is more interesting... There are two problems in one with this error. First that fact that it is "trying" to throw a BeanCreationException means that there is something wrong with your xml definitions, more on this in a bit.

Second, is that Java is having an issue even just creating the BeanCreationException object so that it can throw it. This one is more severe because it indicates an environment wide sort of issue. It is a little bit strange but my initial guess is that maybe you have mismatched or multiple versions of the Spring jars in your classpath, and probably we are talking specifically about spring-core and spring-beans. Make sure that they are from the same Spring version and that you don't have other versions as well in your classpath.

The fact that you are getting this issue, means that it is more than possible that if it is jar version problems, than this may be the cause of some of your other issues as well.


But back to why a BeanCreationException... My guess for that might be what you are trying to do with @AutoWiring the abstractMessageListenerContainer into your CustomProcessor class. The real question is though... what are you trying to achieve by calling .stop() on the DMLC when your code raises any exception in your "analyzeObjectValidateAndStore" method? That seems like quite an odd thing to do, but maybe if you can explain what your aim is with this I can help with an alternative.


As i guessed earlier the problem is with loading the value from properties file.
I think you might be right but I don't think you should need to remove ALL the ${  } uses in your xml files, just possibly that one ${system} as defined on your "abstractMessageListner" bean definition. You may need to move that one to being read directly from the properties file in the same way that you read the queue names.



Just as an aside, in your code for your BeanDefinitionRegistryPostProcessor where you do this...
		 if(allQueues.contains(",")){ //multiple Queues CUST_QUEUE_1,CUST_QUEUE_2
			 queues = allQueues.split(",");
		 }else{//single Queue
			 queues = new String[1];
			 queues[0] = allQueues;
		 }

Open in new window

... it can be reduced simply to this...
		 queues = allQueues.split(",");

Open in new window

... and the case where there is only one queue name will be handled correctly, the same as if there are multiple queue names.
0
 

Author Comment

by:royjayd
ID: 39865741
>>>That seems like quite an odd thing to do
:)

Well our plan is to stop the container after the first exception is thrown so that other messages are not processed , so we go back and investigate why it failed and then restart the container to process further messages. Feel free to recommend any better approaches, would appreciate it.

Regarding spring jars, I think they are fine since our app works without any issues with the original code( the one which doesn't use abstract beans), not sure what is going on.let me go through everything once more, will keep you posted.

Thanks.
0

Featured Post

Highfive + Dolby Voice = No More Audio Complaints!

Poor audio quality is one of the top reasons people don’t use video conferencing. Get the crispest, clearest audio powered by Dolby Voice in every meeting. Highfive and Dolby Voice deliver the best video conferencing and audio experience for every meeting and every room.

Join & Write a Comment

Introduction This article is the last of three articles that explain why and how the Experts Exchange QA Team does test automation for our web site. This article covers our test design approach and then goes through a simple test case example, how …
In this post we will learn how to connect and configure Android Device (Smartphone etc.) with Android Studio. After that we will run a simple Hello World Program.
Viewers learn about the “for” loop and how it works in Java. By comparing it to the while loop learned before, viewers can make the transition easily. You will learn about the formatting of the for loop as we write a program that prints even numbers…
Video by: Michael
Viewers learn about how to reduce the potential repetitiveness of coding in main by developing methods to perform specific tasks for their program. Additionally, objects are introduced for the purpose of learning how to call methods in Java. Define …

708 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now