Recent Posts
Archives

Posts Tagged ‘Spring’

PostHeaderIcon Get a field of a bean in Spring

Case

I have to instanciate an object of type FooDao. The only constructor available is FooDao(Connection connection).

On another hand, I have a bean of type BasicDataSource. From this BasicDataSource, I can get a Connection, through the call of BasicDataSource.getConnection().

Question: how to instanciate a bean of type FooDao in Spring?

Solution

The idea, to retrieve a field member of a bean, is to use the attributes factory-bean and factory-method, from which we will get a new bean.

Use the following Spring context file:

[xml]

<bean id="myBasicDataSource" class="org.apache.commons.dbcp.BasicDataSource">
<!– complete … –>
</bean>

<bean id="connection" factory-bean="myBasicDataSource" factory-method="getConnection"
scope="singleton"/>

<bean id="myFooDao" class="com.my.company.FooDao">
<constructor-arg ref="connection"/>
</bean>
[/xml]

Many thanks to David Chau from SFEIR for his help in this issue!

PostHeaderIcon EhCache integration within Spring

Case

You have to use a EhCache in a couple of beans, instancied via Spring.

Fix

In your main Spring configuration file, declare the following block:

[xml]
<bean id="customCache" class="org.springframework.cache.ehcache.EhCacheFactoryBean">
<property name="shared" value="false" />
<property name="cacheManager">
<bean class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation" value="classpath*:ehcache.xml" />
</bean>
</property>
<property name="cacheName" value="SampleConfigOne" />
</bean>
[/xml]

Then, in any of your beans, declare the following property:

[xml]<property name="cache" value="customCache"/>[/xml]

PostHeaderIcon Could not initialize class net.sf.cglib.proxy.Enhancer

Error

Compiling with Maven 2, you have:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory' defined in class path resource [businessApplicationContext.xml]: Invocation of init method failed; nested exception is java.lang.NoClassDefFoundError: Could not initialize class net.sf.cglib.proxy.Enhancer
Caused by: java.lang.NoClassDefFoundError: Could not initialize class net.sf.cglib.proxy.Enhancer

Turning Spring logging level to DEBUG, you find:
DEBUG main org.springframework.beans.factory.xml.DefaultNamespaceHandlerResolver - Ignoring handler [org.springframework.scripting.config.LangNamespaceHandler]: problem with class file or dependent class
java.lang.NoClassDefFoundError: org/codehaus/groovy/control/CompilationFailedException

Fix

Add dependencies to Groovy, BSH and JRuby in your pom.xml:

[xml]
<dependency>
<groupId>groovy</groupId>
<artifactId>groovy</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>org.beanshell</groupId>
<artifactId>bsh</artifactId>
<version>2.0b4</version>
</dependency>
<dependency>
<groupId>org.jruby</groupId>
<artifactId>jruby</artifactId>
<version>0.9.8</version>
</dependency>
[/xml]

Try of Explanation

Spring depends on the three jars above. But Maven does not link your project to them.

PostHeaderIcon javax.naming.ConfigurationException / java.net.MalformedURLException

Context

I have to send JMS messages on queues on clustered servers: t3://firstServer:1234 and t3://secondServer:5678.

The destination queues are retrieved in Spring, thanks to a property like:
[xml]&lt;property name=&quot;providerURL&quot; value=&quot;t3://firstServer:1234,t3://secondServer:5678&quot;/&gt;[/xml]

Error:

I receive the following error:

[java]javax.naming.ConfigurationException [Root exception is java.net.MalformedURLException: port expected: t3://firstServer:1234,t3://secondServer:5678][/java]

Explanation and fix:

When you send messages on many queues, you must not repeat the protocol (here: t3://)! Fixing the issue is very simple: you have to remove the second t3:// in Spring property:

[xml]&lt;property name=&quot;providerURL&quot; value=&quot;t3://firstServer:1234,secondServer:5678&quot;/&gt;[/xml]

PostHeaderIcon Spring using multi instances of JndiTemplate

Case

Spring application context file:

[xml]
&lt;bean id=&quot;jmsQueueConnectionFactory&quot;
class=&quot;org.springframework.jndi.JndiObjectFactoryBean&quot;&gt;
&lt;property name=&quot;jndiName&quot; value=&quot;jonathan.jms-connection-factory.external&quot;/&gt;
&lt;property name=&quot;jndiEnvironment&quot;&gt;
&lt;props&gt;
&lt;prop key=&quot;java.naming.factory.initial&quot;&gt;weblogic.jndi.WLInitialContextFactory&lt;/prop&gt;
&lt;prop key=&quot;java.naming.provider.url&quot;&gt;
t3://anOtherServer:8521
&lt;/prop&gt;
&lt;prop key=&quot;java.naming.security.principal&quot;&gt;jonathan&lt;/prop&gt;
&lt;prop key=&quot;java.naming.security.credentials&quot;&gt;jonathan&lt;/prop&gt;
&lt;prop key=&quot;weblogic.jndi.enableDefaultUser&quot;&gt;true&lt;/prop&gt;
&lt;/props&gt;
&lt;/property&gt;
&lt;/bean&gt;
&lt;bean id=&quot;mainJndiTemplate&quot; class=&quot;org.springframework.jndi.JndiTemplate&quot;&gt;
&lt;property name=&quot;environment&quot;&gt;
&lt;props&gt;
&lt;prop key=&quot;java.naming.factory.initial&quot;&gt;weblogic.jndi.WLInitialContextFactory&lt;/prop&gt;
&lt;prop key=&quot;java.naming.provider.url&quot;&gt;t3://mainServer:1234&lt;/prop&gt;
&lt;prop key=&quot;java.naming.security.principal&quot;&gt;myPrincipal&lt;/prop&gt;
&lt;prop key=&quot;java.naming.security.credentials&quot;&gt;myPassword&lt;/prop&gt;
&lt;prop key=&quot;weblogic.jndi.enableDefaultUser&quot;&gt;false&lt;/prop&gt;
&lt;/props&gt;
&lt;/property&gt;
&lt;/bean&gt;
[/xml]

Description

I use two instances of JndiTemplate to send JMS messages on two different queues, on two different Weblogic domains, using two different Ldap directories. When I try to send messages on the second server, it does not work: I get an error because the second server receives credentials that should be sent to the first server.

[Security:090398]Invalid Subject: principals=[...]

Quick fix

Remove the properties weblogic.jndi.enableDefaultUser from within the XML.

PostHeaderIcon java.lang.SecurityException: [Security:090398]Invalid Subject: principals=[myRole]

Short stacktrace:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'myJmsTemplate' (...) Invocation of init method failed; nested exception is java.lang.SecurityException: [Security:090398]Invalid Subject: principals=[myRole]

Complete stacktrace

(copy paste in a text editor if the complete stack is not displayed in your browser):

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'myJmsTemplate' defined in URL [zip:C:/workarea/development/servers/wl_server/servers/XXXX/tmp/_WL_user/XXXXXXXXXXXX-ear/7gtxm8/XXXXXXXX-services-ejb.jar!/com/XXXXX/businessApplicationContext-XXXXXXXX.xml]: Cannot resolve reference to bean 'myJmsQueueConnectionFactory' while setting bean property 'connectionFactory'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'myJmsQueueConnectionFactory' defined in URL [zip:C:/workarea/development/servers/wl_server/servers/ejbtier/tmp/_WL_user/XXXXXX-ear/7gtxm8/XXXXXXXX.jar!/com/bnpparibas/primeweb/businessApplicationContextXXXXXXXXXXXX.xml]: Invocation of init method failed; nested exception is java.lang.SecurityException: [Security:090398]Invalid Subject: principals=[myRole]
 at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:275)
 at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:104)
 at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1245)
 at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1010)
 at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:472)
 at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory$1.run(AbstractAutowireCapableBeanFactory.java:409)
 at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:380)
 at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:264)
 at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:221)
 at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:261)
 at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:185)
 at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:164)
 at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:881)
(...)

The issue appears when I try to deploy an EJB sending JMS messages from my Weblogic server, to another one, in another domain.

Fix:

  • I have not fixed the issue myself, I gave pieces of advice to the teams in charge of solving them. But I assume following guidelines are OK.
  • Indeed there are two issues: one on credentials and another on servers
  • Servers need trust each other. More information is available here. I assume trust is granted thanks to the use of certificates.
  • On another hand, credentials from my server, it is to say here “myRole” must be accepted by distant Ldap juridiction. I assume that distant EJB environment must something like:
    • distantEnvironment.put(InitialContext.SECURITY_PRINCIPAL, "myRole");

Now it should work!

PostHeaderIcon Deploy a JMS destination queue with Spring

Abstract

Case: we have to send JMS messages to a third-party server, using Spring. Of course, we have to discriminate production, UAT and developments environments. We can decide to use one Spring configuration file per environment, but it is complex to maintain.

Here is the way I proceded:

Declare the factory

[xml]<bean id="myJmsQueueConnectionFactory">
<property name="jndiName" value="my.jms.QueueConnectionFactory"/>
<property name="jndiTemplate" ref="myJmsJndiTemplate"/>
</bean>[/xml]

Declare a Jndi Template

[xml]<bean id="myJmsJndiTemplate">
<property name="environment">
<props>
<prop key="java.naming.factory.initial">weblogic.jndi.WLInitialContextFactory</prop>
<prop key="java.naming.provider.url"><strong>${my.jms.host}</strong></prop>
</props>
</property>
</bean>[/xml]
The variable ${my.jms.host} is used to indicate the actual destination host. The value is given in a property file myConfig.properties, for instance:

my.jms.host=t3://127.0.0.1:1234

Obviously, each environnement needs its ad hoc property file!

Declare a JMS Template

It gathers the factory and the queue name.
[xml]<bean id="myJmsTemplate">
<property name="connectionFactory" ref="myJmsQueueConnectionFactory"/>
<property name="defaultDestination" ref="myJmsQueue"/>
</bean>[/xml]

Declare the destination queue

[xml]<bean id="myJmsQueue">
<property name="jndiName" value="my.jms.destination.queue.name"/>
</bean>[/xml]

Ensure the property file is in classpath

[xml]<bean id="conf">
<property name="locations">
<list>
<value>classpath*:myConfig.properties</value>
</list>
</property>
</bean>[/xml]
Restart WebLogic, deploy your EAR. Now it should work!

Notice: in case you’re not sure the distant host is up or not, you may add this attribute to your beans: lazy-init="true"

PostHeaderIcon NoClassDefFoundError: com/sun/corba/se/connection/ORBSocketFactory

Error

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jmsQueueConnectionFactory' defined in class path resource MyResourceApplicationContext.xml]: Invocation of init method failed; nested exception is java.lang.NoClassDefFoundError: com/sun/corba/se/connection/ORBSocketFactory

Fix: In the classpath, replace Weblogic 8.X jars with Weblogic 9.2 jars