Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to put(bind) object to jndi in spring declaratively?

We have a plain standalone spring application and we need to put jdbc datasource in jndi. (we use jboss treecache and it need datasource to be in the jndi).

Some googling found most of all jndi-lookup examples with spring, where an object is already put in jndi (by tomcat or application server etc), but we need otherwise: I have a plain datasource Spring bean, which I inject to other services, but I can't inject it to TreeCache, because it needs it only from jndi.

Found org.springframework.jndi.JndiTemplate, which can be declared as bean, e.g.:

<bean id="fsJndiTemplate" class="org.springframework.jndi.JndiTemplate">
    <property name="environment">
        <props>
            <prop key="java.naming.factory.initial">com.sun.jndi.fscontext.RefFSContextFactory</prop>
            <prop key="java.naming.provider.url">file:///c:\windows\temp</prop>
        </props>
    </property>
</bean>

but not found how to bind with it other than in java code: fsJndiTemplate.bind(name, obj) from init-method of some other bean. Is there any way to do it declaratively?

like image 699
yetanothercoder Avatar asked May 12 '11 07:05

yetanothercoder


2 Answers

I realize this is an old question, but there's a way to do this without custom code. It's fairly verbose, but 100% declarative.

<!-- inside container, use JndiTemplate -->
<bean id="jndiBinder" class="org.springframework.jndi.JndiTemplate"/>
<!-- outside container (e.g. for tests), use SimpleNamingContextBuilder -->
<!-- <bean id="jndiBinder" class="org.springframework.mock.jndi.SimpleNamingContextBuilder" factory-method="emptyActivatedContextBuilder"/> -->

<!-- use MethodInvokingFactoryBean to call 'bind' on 'jndiBinder' -->
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
    <property name="targetObject" ref="jndiBinder"/>
    <property name="targetMethod" value="bind"/>
    <property name="arguments">
        <array>
            <value type="java.lang.String">java:comp/UserTransaction</value>
            <ref bean="atomikosUserTransaction"/>
        </array>
    </property>
</bean>

<!-- define as many bindings as you need -->
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
    <property name="targetObject" ref="jndiBinder"/>
    <property name="targetMethod" value="bind"/>
    <property name="arguments">
        <array>
            <value type="java.lang.String">another/jndi/name</value>
            <value>literal_value</value>
        </array>
    </property>
</bean>

The MethodInvokingFactoryBean can also be used to set System properties (which comes in handy when using Atomikos), as long as the bean that reads the System properties depends-on that MethodInvokingFactoryBean.

<bean id="atomikosSystemProps" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
    <property name="targetObject">
        <bean class="java.lang.System" factory-method="getProperties"/>
    </property>
    <property name="targetMethod" value="putAll"/>
    <property name="arguments" ref="atomikosJtaProps"/>
</bean>
<bean id="atomikosJtaProps" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
    <property name="properties">
        <props>
            <prop key="com.atomikos.icatch.no_file">true</prop>
            <prop key="com.atomikos.icatch.hide_init_file_path">true</prop>
            <prop key="com.atomikos.icatch.service">com.atomikos.icatch.standalone.UserTransactionServiceFactory</prop>
            <prop key="com.atomikos.icatch.log_base_dir">/opt/txlogs</prop>
        </props>
    </property>
</bean>
<bean id="atomikosUserTransactionService" class="com.atomikos.icatch.config.UserTransactionServiceImp" init-method="init" destroy-method="shutdownForce" depends-on="atomikosSystemProps"/>
like image 154
superEb Avatar answered Oct 19 '22 11:10

superEb


Thanks for the questions. I wrote a variant of Treydone's solution and thought it might be useful to have actual code here (as it's pretty short):

public class JndiExporter implements InitializingBean {

    private final JndiTemplate template = new JndiTemplate();

    private Map<String, Object> jndiMapping = null;

    @Override
    public void afterPropertiesSet() throws Exception {
            for(Entry<String, Object> addToJndi: jndiMapping.entrySet()){
                    template.bind(addToJndi.getKey(), addToJndi.getValue());
            }
    }

    public void setJndiMapping(Map<String, Object> jndiMapping) {
            this.jndiMapping = jndiMapping;
    }

}

Note that I implemented InitializingBean instead of BeanFactoryAware. This allows a configuration (with references) like this:

<bean id="jndiExporter" class="com.ra.web.util.JndiExporter">
    <property name="jndiMapping">
        <map>
            <entry key="bean1" value-ref="other_spring_bean_id" />
            <entry key="bean2" value="literal_value" />
        </map>
    </property>
</bean>
like image 20
Spina Avatar answered Oct 19 '22 09:10

Spina