In-memory Job-Explorer definition in Spring batch - spring-batch

I was trying to share My in-memory jobRepository to the jobExplorer. But it throws an error as,
Nested exception is
org.springframework.beans.ConversionNotSupportedException:
Failed to convert property value of type '$Proxy1 implementing
org.springframework.batch.core.repository.JobRepository,org.
springframework.aop.SpringProxy,org.springframework.aop.framework.Advised'
to required type
Even i tried putting '&' sign before jobRepository when passing to jobExplorer for sharing.But attempt end in vain.
I am using Spring Batch 2.2.1
Is the dependency for jobExplorer is only database not in-memory?
Definition is,
<bean id="jobRepository"
class="com.test.repository.BatchRepositoryFactoryBean">
<property name="cache" ref="cache" />
<property name="transactionManager" ref="transactionManager" />
</bean>
<bean id="jobOperator" class="test.batch.LauncherTest.TestBatchOperator">
<property name="jobExplorer" ref="jobExplorer" />
<property name="jobRepository" ref="jobRepository" />
<property name="jobRegistry" ref="jobRegistry" />
<property name="jobLauncher" ref="jobLauncher" />
</bean>
<bean id="jobExplorer" class="test.batch.LauncherTest.TestBatchExplorerFactoryBean">
<property name="repositoryFactory" ref="&jobRepository" />
</bean>
<bean id="transactionManager"
class="org.springframework.batch.support.transaction.ResourcelessTransactionManager" />
<bean id="jobLauncher" class="com.scb.smartbatch.core.BatchLauncher">
<property name="jobRepository" ref="jobRepository" />
</bean>
<!-- To store Batch details -->
<bean id="jobRegistry" class="com.scb.smartbatch.repository.SmartBatchRegistry" />
<bean id="jobRegistryBeanPostProcessor"
class="org.springframework.batch.core.configuration.support.JobRegistryBeanPostProcessor">
<property name="jobRegistry" ref="jobRegistry" />
</bean>
<!--Runtime cache of batch executions -->
<bean id="cache" class="com.scb.cache.TCRuntimeCache" />

thanks for your valuable inputs.
But I used '&' before the job repository reference, which allowed me to use it for my job explorer as a shared resource.
problem solved.
kudos.

Usually you have to wire interface instead of implementation.
Else, probably, you have to add <aop:config proxy-target-class="true"> to create CGLIB-based proxy instead of standard Java-based proxy.
Read Spring official documentation about that

Related

Mapping JPA entity to more than one entityManagers with SpringBatch program

I have developed SpringBatch application and deployed as Web Application in Websphere Liberty profile container. The batch program is designed to read records from a table and invokes HTTP service. Based on the service response a column named status is updated as RECORD_SENT/COMPLETE/ERROR type.
Objective is to reuse the same program for multiple datasources. The data source is passed in job parameter using client type. The datasources are in different schemas but having same datamodel.
Question: How does the transaction manager can be applied at run time inside Job Step or Tasklet?. Seeking help in this regard.
Configuration:
<bean id="entityManagerFactory1"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource1" />
<property name="persistenceUnitName" value="user" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="false" />
</bean>
</property>
<property name="jpaDialect">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
</property>
</bean>
<bean id="entityManagerFactory2"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource2" />
<property name="persistenceUnitName" value="user" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="false" />
</bean>
</property>
<property name="jpaDialect">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
</property>
</bean>
<bean id="entityManagerSelector" class="*com.spring.jpa.test.EntitymanagerSelector">
<property name="entityManagerFactory1" ref="entityManagerFactory1"></property>
<property name="entityManagerFactory2" ref="entityManagerFactory2"></property>
</bean>
job.xml snippet
<bean id="itemReader" class="org.springframework.batch.item.database.JpaPagingItemReader" scope="step">
<property name="entityManagerFactory" value="#{entityManagerSelector.getEntitymanagerForClient({jobParameters['client']})}" />
<property name="queryString" value="select u from User u where u.age > #{jobParameters['age']}" />
</bean>
Setting the job parameters during runtime to identify the client
JobParameters param = new JobParametersBuilder()
.addString("age", "20").addString("client", "client2")
.toJobParameters();
JobExecution execution = jobLauncher.run(job, param);
It will not be possible for you to set the transaction-manager of the Step/tasklet during runtime. You will be better off creating a separate Job's for each client and using their own transaction manager in the tasklet.
<bean id="transactionManager1" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory1" />
</bean>
<bean id="transactionManager2" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory2" />
</bean>
Now use these transaction manager when creating the batch job's
<job id="testJob1" xmlns="http://www.springframework.org/schema/batch">
<step id="client1step1">
<tasklet transaction-manager="transactionManager1">
<chunk reader="itemReader" writer="itemWriter" commit-interval="1" />
</tasklet>
</step>
</job>
<job id="testJob2" xmlns="http://www.springframework.org/schema/batch">
<step id="client2step2">
<tasklet transaction-manager="transactionManager2">
<chunk reader="itemReader" writer="itemWriter" commit-interval="1" />
</tasklet>
</step>
</job>
Let me know if this works out.

Using spring cloud namespace and two DataSources

I have a Spring Integration WAR component that I'm updating to run in private PCF. I have two DataSources and a RabbitMQ connection factory defined in the application.
I see an article from Thomas Risberg on using the cloud namespace and handling multiple services of the same time - https://spring.io/blog/2011/11/09/using-cloud-foundry-services-with-spring-part-3-the-cloud-namespace. This is handled by using #Autowired and #Qualifier annotations.
I'm wondering how this can be achieved though when we're not #Autowired and #Qualifier annotations, e.g. wiring a DataSource into a JdbcTemplate. Here we do not have the ability to specify a #Qualifier annotation.
My application is Spring XML config based. I do have ability to use #Autowired and #Qualifier annotations on one of the DataSources, but the other is JPA entity manager. See code snippet.
Any help is much appreciated.
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="persistenceUnitName" value="activity-monitor" />
<property name="jpaVendorAdapter" ref="jpaVendorAdapter"/>
<property name="jpaProperties">
<value>
hibernate.format_sql=true
</value>
</property>
</bean>
<beans profile="cloud">
<cloud:data-source id="dataSource" service-name="actmon-db-service" />
</beans>
Java Build Pack: java_buildpack_offline java-buildpack-offline-v2.4.zip
Spring Auto-reconfiguration version 1.4.0.
UPDATE: This is the full config for both data sources, including PropertySourcesPlaceholderConfigurer with properties loaded from data source using DAO.
<bean id="cic.application.ppc" class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
<property name="properties" ref="cic.application.properties"/>
<property name="locations" ref="cic.application.propertyLocations"/>
</bean>
<bean id="cic.application.properties" class="java.util.Properties">
<constructor-arg value="#{cicPropertiesService.properties}"></constructor-arg>
</bean>
<bean id="cic.properties.propertiesService" name="cicPropertiesService"
class="com.emc.it.eis.properties.service.DefaultPropertiesService">
<constructor-arg index="0"
ref="cic.properties.propertiesDao" />
</bean>
<bean id="cic.properties.propertiesDao" class="com.emc.it.eis.properties.dao.JdbcPropertiesDao">
<constructor-arg ref="cic.properties.dataSource" />
</bean>
<beans profile="default">
<jee:jndi-lookup id="cic.properties.dataSource"
jndi-name="jdbc/intdb" />
</beans>
<beans profile="cloud">
<cloud:data-source id="cic.properties.dataSource" service-name="oracle-cicadm-db-service" />
</beans>
<beans>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="actmonDataSource" />
<property name="persistenceUnitName" value="activity-monitor" />
<property name="jpaVendorAdapter" ref="jpaVendorAdapter"/>
<property name="jpaProperties">
<value>
hibernate.format_sql=true
</value>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
</beans>
<beans profile="default">
<jee:jndi-lookup id="dataSource"
jndi-name="jdbc/actmon" />
</beans>
<beans profile="cloud">
<cloud:data-source id="actmonDataSource" service-name="postgres-actmon-db-service" />
</beans>
<beans profile="default,cloud">
<bean id="jpaVendorAdapter"
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="database" value="POSTGRESQL" />
</bean>
</beans>
Output from CF when I deploy https://gist.github.com/anonymous/3986a1a7cea4f20c096e. Note it is skipping auto re-configuration of javax.sql.DataSources
First of all, the post from Thomas is pretty old, and references a deprecated support library. Instead of the org.cloudfoundry:cloudfoundry-runtime:0.8.1 dependency, you should use Spring Cloud Connectors dependencies instead.
You can then follow the instructions provided for using XML configuration with Spring Cloud Connectors. With multiple services of the same type, you will need to specify the name of the service for each bean. Following your example, and assuming you created two CF database services named inventory-db and customer-db, that might look something like this:
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="inventory-dataSource" />
<property name="persistenceUnitName" value="activity-monitor" />
<property name="jpaVendorAdapter" ref="jpaVendorAdapter"/>
<property name="jpaProperties">
<value>
hibernate.format_sql=true
</value>
</property>
</bean>
<beans profile="cloud">
<cloud:data-source id="inventory-dataSource" service-name="inventory-db">
<cloud:data-source id="customer-dataSource" service-name="customer-db">
</beans>
I've managed to resolve the issue by using the factory bean used by the spring cloud:data-source, CloudDataSourceFactory. Creating an instance of this and wiring up the config including the service-name of the CF service. This avoids the issue of our PropertySourcesPlaceholderConfigurer trying to use the data source before our the bean has even been defined.
<!--
configure cloud data source for using CloudDataSourceFactory; this is what spring cloud:data-source is using;
required to manually wire this data source bean as cloud:data-source bean gets defined in a phase after our
PropertySourcesPlaceholderConfigurer bean.
-->
<bean id="cic.properties.dataSource" class="org.springframework.cloud.service.relational.CloudDataSourceFactory">
<constructor-arg value="oracle-cicadm-db-service" />
<constructor-arg>
<!-- configuring minimal data source as it is used only to bootstrap properties on app start-up -->
<bean class="org.springframework.cloud.service.relational.DataSourceConfig">
<constructor-arg>
<bean class="org.springframework.cloud.service.PooledServiceConnectorConfig.PoolConfig">
<constructor-arg value="0" />
<constructor-arg value="2" />
<constructor-arg value="180" />
</bean>
</constructor-arg>
<!-- ConnectionConfig not required for cic.properties.dataSource so setting to null -->
<constructor-arg value="#{ null }" />
</bean>
</constructor-arg>
</bean>

JPATransactionManager and annotation driven transactions

I've a small spring3/Hibernate JPA application running and I've come a cropper when trying to use Transactional annotations. Basically they are being ignored by the TransactionManager.
I have a save method that I've amended to highlight that the Transactional attribute readOnly is being ignored. Basically I would have figured that the persist call would have resulted in an exception being thrown because the readOnly attribute is set to true however this is not the case and the entity persists happily to an in-memory HSQLDB.
#Transactional(readOnly=true)
public Product save(Product product) throws HibernateException {
getEntityManager().persist(product);
return product;
}
The JPATransaction manager is wired as follows...
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="org.hsqldb.jdbcDriver" />
<property name="url" value="jdbc:hsqldb:mem:testdb;shutdown=false" />
<property name="username" value="sa" />
<property name="password" value="" />
</bean>
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" id="jpaProperties">
<property name="ignoreUnresolvablePlaceholders" value="true" />
<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
<property name="searchSystemEnvironment" value="true" />
<property name="location" value="classpath:landingPage-hibernate.properties"/>
</bean>
<util:properties id="jpaHibernateProperties">
<prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
<prop key="hibernate.cache.provider_class">net.sf.ehcache.hibernate.EhCacheProvider</prop>
<prop key="hibernate.cache.use_query_cache">true</prop>
<prop key="hibernate.cache.use_second_level_cache">true</prop>
</util:properties>
<bean id="hibernateVendor" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="databasePlatform" value="${hibernate.dialect}"/>
<property name="showSql" value="${hibernate.show_sql}" />
<property name="generateDdl" value="${generateDdl}"/>
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="landingPagePersistence"/>
<property name="dataSource" ref="dataSource"/>
<property name="jpaVendorAdapter" ref="hibernateVendor"/>
<property name="jpaPropertyMap" ref="jpaHibernateProperties"/>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
Would anyone have an example of JPATransactionManager working with Transactional attributes or am I misunderstanding the usage of JPA entirely? I can see in the EntityManager constructor that the PersistenceContext is always EXTENDED as opposed to TRANSACTION which appears to have some bearing on whether or not the annotations are taken into consideration. Any help would be greatly appreciated.
Thanks,
Mark.
It's not a bug. It's a documented, expected behavior:
This just serves as a hint for the actual transaction subsystem; it will not necessarily cause failure of write access attempts. A transaction manager which cannot interpret the read-only hint will not throw an exception when asked for a read-only transaction.

Problems with Spring WS Streaming Attachments with Security Interceptor

I'm having problems getting Spring WS to receive a request which has a file attached and use streaming. The problem is I get the following exception whenever I try to use a security interceptor:
2011-01-11 15:10:05,132 DEBUG [org.springframework.ws.soap.server.SoapMessageDispatcher] -
java.lang.IllegalArgumentException: Error in converting SOAP Envelope to Document
at org.springframework.ws.soap.axiom.support.AxiomUtils.toDocument(AxiomUtils.java:135)
at org.springframework.ws.soap.security.wss4j.Wss4jSecurityInterceptor.toDocument(Wss4jSecurityInterceptor.java:621)
at org.springframework.ws.soap.security.wss4j.Wss4jSecurityInterceptor.validateMessage(Wss4jSecurityInterceptor.java:492)
at org.springframework.ws.soap.security.AbstractWsSecurityInterceptor.handleRequest(AbstractWsSecurityInterceptor.java:104)
at org.springframework.ws.server.MessageDispatcher.dispatch(MessageDispatcher.java:213)
at org.springframework.ws.server.MessageDispatcher.receive(MessageDispatcher.java:168)
at org.springframework.ws.transport.support.WebServiceMessageReceiverObjectSupport.handleConnection(WebServiceMessageReceiverObjectSupport.java:88)
at org.springframework.ws.transport.http.WebServiceMessageReceiverHandlerAdapter.handle(WebServiceMessageReceiverHandlerAdapter.java:57)
at org.springframework.ws.transport.http.MessageDispatcherServlet.doService(MessageDispatcherServlet.java:230)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:571)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:511)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:530)
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:426)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:119)
at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:457)
at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:229)
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:931)
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:361)
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:186)
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:867)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:117)
at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:245)
at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:126)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:113)
at org.eclipse.jetty.server.Server.handle(Server.java:337)
at org.eclipse.jetty.server.HttpConnection.handleRequest(HttpConnection.java:581)
at org.eclipse.jetty.server.HttpConnection$RequestHandler.content(HttpConnection.java:1020)
at org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:775)
at org.eclipse.jetty.http.HttpParser.parseAvailable(HttpParser.java:228)
at org.eclipse.jetty.server.HttpConnection.handle(HttpConnection.java:417)
at org.eclipse.jetty.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:474)
at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:437)
at java.lang.Thread.run(Thread.java:595)
Caused by: org.apache.axiom.om.OMException: java.util.NoSuchElementException
at org.apache.axiom.om.impl.builder.StAXOMBuilder.next(StAXOMBuilder.java:249)
at org.apache.axiom.om.impl.llom.OMNodeImpl.build(OMNodeImpl.java:327)
at org.apache.axiom.om.impl.llom.OMElementImpl.build(OMElementImpl.java:706)
at org.springframework.ws.soap.axiom.support.AxiomUtils.toDocument(AxiomUtils.java:125)
... 34 more
Caused by: java.util.NoSuchElementException
at com.ctc.wstx.sr.BasicStreamReader.next(BasicStreamReader.java:1083)
at org.apache.axiom.om.impl.builder.StAXOMBuilder.parserNext(StAXOMBuilder.java:506)
at org.apache.axiom.om.impl.builder.StAXOMBuilder.next(StAXOMBuilder.java:161)
... 37 more
I am using the Axiom Message Factory:
<bean id="messageFactory" class="org.springframework.ws.soap.axiom.AxiomSoapMessageFactory">
<property name="payloadCaching" value="false"/>
<property name="attachmentCaching" value="true"/>
<property name="attachmentCacheThreshold" value="1024" />
</bean>
My endpoint mapping uses the wss4jSecurityInterceptor:
<bean class="org.springframework.ws.server.endpoint.mapping.PayloadRootQNameEndpointMapping">
<property name="mappings">
<props>
<prop key="{http://www.aquilauk.co.uk/hribulkupload}BulkHRRequest">hriBulkUploadEndpoint</prop>
</props>
</property>
<property name="interceptors">
<list>
<!-- <bean class="org.springframework.ws.server.endpoint.interceptor.PayloadLoggingInterceptor"/> -->
<ref bean="wss4jSecurityInterceptor"/>
</list>
</property>
</bean>
and my security interceptor has been set up to ensure it does not make use of the Payload:
<bean id="wss4jSecurityInterceptor" class="org.springframework.ws.soap.security.wss4j.Wss4jSecurityInterceptor">
<property name="validationActions" value="UsernameToken" />
<property name="validationCallbackHandler" ref="springWSS4JHandler"/>
<property name="secureResponse" value="false"/>
<property name="secureRequest" value="false" />
</bean>
<bean id="acegiWSS4JHandler"
class="org.springframework.ws.soap.security.wss4j.callback.SpringPlainTextPasswordValidationCallbackHandler">
<property name="authenticationManager" ref="authenticationManager"/>
</bean>
Regard,
Craig
I believe that the security interceptor you have defined still consumes the payload. It just doesn't perform any security validation on it. The AxiomSoapMessageFactory.createWebServiceMesssage() method should be being called in order to create the MessageContext that is provided to the security interceptor. The security interceptor then ignores it as per the secureRequest flag.
I Found the solutions to this problem through trial and error:
The problem is the setup of the wss4jSecurityInterceptor, the lines:
<property name="secureResponse" value="false"/>
<property name="secureRequest" value="false" />
should have been:
<property name="validateRequest" value="false" />
<property name="validateResponse" value="false" />

How to initialize ConnectionFactory for remote JMS queue when remote machine is not running?

Using JBoss 4.0.5, JBossMQ, and Spring 2.0.8, I am trying to configure Spring to instantiate beans which depend on a remote JMS Queue resource. All of the examples I've come across depend on using JNDI to do lookup for things like the remote ConnectionFactory object.
My problem is when trying to bring up a machine which would put messages into the remote queue, if the remote machine is not up, JNDI lookup simply fails, causing deployment to fail. Is there a way to get Spring to keep trying to lookup this object in the background while not blocking the remainder of deployment?
Iit's difficult to be sure without seeing your spring config, but assuming you're using Spring's JndiObjectFactoryBean to do the JNDI lookup, then you can set the lookupOnStartup property to false, which allows the context to start up even if the JNDI target isn't there. The JNDI resolution will be done the first time the ConnectionFactory is used.
However, this just shifts the problem further up the chain, because if some other component tries to get a JMS Connection on startup, then you're back where you started. You can use the lazy-init="true" attribute on your other beans to prevent this from happening on deployment, but it's easy to accidentally put something in your config which forces everything to initialize.
You're absolutely right. I tried setting lookupOnStartup to false and lazy-init=true . This just defers the problem to the first time that the Queue is attempted to be used. Then an exception as follows is thrown:
[org.jboss.mq.il.uil2.SocketManager] Failed to handle: org.jboss.mq.il.uil2.msgs.CloseMsg29702787[msgType: m_connectionClosing, msgID: -2147483606, error: null]
java.io.IOException: Client is not connected
Moreover, it looks like the lookup is never attempted again. When the machine with the remote queue is brought back up, no messages are ever processed subsequently. This really does seem like it should be well within the envelope of use cases for J2EE nonsense, and yet I'm not having much luck... It feels like it should even maybe be a solved problem.
For completion's sake, the following is the pertinent portion of my Spring configuration.
<bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate">
<property name="environment">
<props>
<prop key="java.naming.provider.url">localhost:1099</prop>
<prop key="java.naming.factory.url.pkgs">org.jnp.interfaces:org.jboss.naming</prop>
<prop key="java.naming.factory.initial">org.jnp.interfaces.NamingContextFactory</prop>
</props>
</property>
</bean>
<bean id="connectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiTemplate">
<ref bean="jndiTemplate"/>
</property>
<property name="jndiName">
<value>ConnectionFactory</value>
</property>
</bean>
<bean id="remoteJndiTemplate" class="org.springframework.jndi.JndiTemplate" lazy-init="true">
<property name="environment">
<props>
<prop key="java.naming.provider.url">jnp://10.0.100.232:1099</prop>
<prop key="java.naming.factory.url.pkgs">org.jnp.interfaces:org.jboss.naming</prop>
<prop key="java.naming.factory.initial">org.jnp.interfaces.NamingContextFactory</prop>
</props>
</property>
</bean>
<bean id="remoteConnectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean" lazy-init="true">
<property name="jndiTemplate" ref="remoteJndiTemplate"/>
<property name="jndiName" value="ConnectionFactory" />
<property name="lookupOnStartup" value="false" />
<property name="proxyInterface" value="javax.jms.ConnectionFactory" />
</bean>
<bean id="destinationResolver" class="com.foo.jms.FooDestinationResolver" />
<bean id="localVoicemailTranscodingDestination" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiTemplate" ref="jndiTemplate"/>
<property name="jndiName" value="queue/voicemailTranscoding" />
</bean>
<bean id="globalVoicemailTranscodingDestination" class="org.springframework.jndi.JndiObjectFactoryBean" lazy-init="true" >
<property name="jndiTemplate" ref="remoteJndiTemplate" />
<property name="jndiName" value="queue/globalVoicemailTranscoding" />
</bean>
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate" >
<property name="connectionFactory" ref="connectionFactory"/>
<property name="defaultDestination" ref="localVoicemailTranscodingDestination" />
</bean>
<bean id="remoteJmsTemplate" class="org.springframework.jms.core.JmsTemplate" lazy-init="true">
<property name="connectionFactory" ref="remoteConnectionFactory"/>
<property name="destinationResolver" ref="destinationResolver"/>
</bean>
<bean id="globalQueueStatus" class="com.foo.bar.recording.GlobalQueueStatus" />
<!-- Do not deploy this bean for machines other than transcoding machine -->
<condbean:cond test="${transcoding.server}">
<bean id="voicemailMDPListener"
class="org.springframework.jms.listener.adapter.MessageListenerAdapter" lazy-init="true">
<constructor-arg>
<bean class="com.foo.bar.recording.mdp.VoicemailMDP" lazy-init="true">
<property name="manager" ref="vmMgr" />
</bean>
</constructor-arg>
</bean>
</condbean:cond>
<bean id="voicemailForwardingMDPListener"
class="org.springframework.jms.listener.adapter.MessageListenerAdapter" lazy-init="true">
<constructor-arg>
<bean class="com.foo.bar.recording.mdp.QueueForwardingMDP" lazy-init="true">
<property name="queueStatus" ref="globalQueueStatus" />
<property name="template" ref="remoteJmsTemplate" />
<property name="remoteDestination" ref="globalVoicemailTranscodingDestination" />
</bean>
</constructor-arg>
</bean>
<bean id="prototypeListenerContainer"
class="org.springframework.jms.listener.DefaultMessageListenerContainer"
abstract="true"
lazy-init="true">
<property name="concurrentConsumers" value="5" />
<property name="connectionFactory" ref="connectionFactory" />
<!-- 2 is CLIENT_ACKNOWLEDGE: http://java.sun.com/j2ee/1.4/docs/api/constant-values.html#javax.jms.Session.CLIENT_ACKNOWLEDGE -->
<!-- 1 is autoacknowldge -->
<property name="sessionAcknowledgeMode" value="1" />
<property name="sessionTransacted" value="true" />
</bean>
<!-- Do not deploy this bean for machines other than transcoding machine -->
<condbean:cond test="${transcoding.server}">
<bean id="voicemailMDPContainer" parent="prototypeListenerContainer" lazy-init="true">
<property name="destination" ref="globalVoicemailTranscodingDestination" />
<property name="messageListener" ref="voicemailMDPListener" />
</bean>
</condbean:cond>
<bean id="voicemailForwardMDPContainer" parent="prototypeListenerContainer" lazy-init="true">
<property name="destination" ref="localVoicemailTranscodingDestination" />
<property name="messageListener" ref="voicemailForwardingMDPListener" />
</bean>