AffinityKeyMapped not working with Ignite 2.4/2.5/2.6 and Scala - scala

Using Scala 2.11.7/Java 1.8.0_161/RHEL7.
We have two caches whose elements share the same affinity key. The affinity key is defined as follows:
case class IgniteTradePayloadKey(
#(AffinityKeyMapped#field)
tradeKey: TradeKey,
... other fields
) extends Serializable
case class IgniteDealPayloadKey(
#(AffinityKeyMapped#field)
tradeKey: TradeKey,
child: Int,
... other fields
) extends Serializable
Those are used as key to two ignite caches (Trades and Deals). We want instances of Trades and Deals to be collocated, as we perform computations using both. Think of them as having a parent/child relationship, and we would like to keep the parent and its children in the same node because our calculations require both. Parents are uniquely identified by TradeKey, so we use that in both caches to control affinity. Note that they are also used as part of the Ignite key itself. They are not part of the value.
This worked beautifully with Ignite 1.7; we then tried to upgrade to a more recent version of Ignite (we tried 2.4, 2.5 and 2.6), and without any code change whatsoever, there are children that are no longer collocated with their parents. Reverted back to 1.7 to be sure, and collocation works. We tried to override the affinity function with something simple (just a hash on the TradeKey), and again, it works with 1.7, but not with any of the 2.X versions listed above.
What are we missing?
Configuration as requested (apologies for the massive file). We tried with and without defining our own affinity function, with the same results.
<beans xmlns="http://www.springframework.org/schema/beans"
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_FALLBACK"/>
<property name="searchSystemEnvironment" value="true"/>
</bean>
<bean id="CLIENT_MODE" class="java.lang.String">
<constructor-arg value="${IGNITE_CLIENT_MODE:false}" />
</bean>
<!-- Ignite common configuration -->
<bean abstract="true" id="common.cfg" class="org.apache.ignite.configuration.IgniteConfiguration">
<property name="gridName" value="MTS Trades Cache Grid" />
<property name="failureDetectionTimeout" value="60000"/>
<property name="clientFailureDetectionTimeout" value="60000"/>
<property name="peerClassLoadingEnabled" value="true"/>
<property name="clientMode" ref="CLIENT_MODE"/>
<property name="rebalanceThreadPoolSize" value="4"/>
<property name="deploymentMode" value="CONTINUOUS"/>
<property name="discoverySpi">
<bean class="org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi">
<property name="localPort" value="47700"/>
<property name="localPortRange" value="20"/>
<!-- Setting up IP finder for this cluster -->
<property name="ipFinder">
<bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder">
<property name="addresses">
<list>
<value>127.0.0.1:47700..47720</value>
</list>
</property>
</bean>
</property>
</bean>
</property>
<property name="communicationSpi">
<bean class="org.apache.ignite.spi.communication.tcp.TcpCommunicationSpi">
<property name="localPort" value="49100"/>
<property name="sharedMemoryPort" value="-1" />
<property name="messageQueueLimit" value="1024"/>
</bean>
</property>
<!-- Cache configuration -->
<property name="cacheConfiguration">
<list>
<!-- deals -->
<bean class="org.apache.ignite.configuration.CacheConfiguration">
<property name="name" value="dealPayloads" />
<property name="cacheMode" value="PARTITIONED" />
<property name="backups" value="0" />
<property name="OnheapCacheEnabled" value="true"/>
<property name="queryEntities">
<list>
<bean class="org.apache.ignite.cache.QueryEntity">
<!-- setting indexed type's key class -->
<property name="keyType" value="com.company.ignite.IgniteDealPayloadKey" />
<!-- setting indexed type's value class -->
<property name="valueType" value="com.company.ignite.IgniteDealPayload" />
</bean>
</list>
</property>
<property name="affinity">
<bean class="com.company.ignite.affinity.IgniteAffinityFunction">
<property name="partitions" value="1024"/>
</bean>
</property>
<property name="atomicityMode" value="ATOMIC" />
<property name="rebalanceMode" value="ASYNC" />
<property name="copyOnRead" value="false" />
<!-- Set rebalance batch size to 8 MB. -->
<property name="rebalanceBatchSize" value="#{8 * 1024 * 1024}"/>
<!-- Explicitly disable rebalance throttling. -->
<property name="rebalanceThrottle" value="0"/>
<!-- Set 4 threads for rebalancing. -->
<property name="rebalanceThreadPoolSize" value="4"/>
</bean>
<!-- trade versions -->
<bean class="org.apache.ignite.configuration.CacheConfiguration">
<property name="name" value="tradePayloads" />
<property name="cacheMode" value="PARTITIONED" />
<property name="backups" value="0" />
<property name="OnheapCacheEnabled" value="true"/>
<property name="queryEntities">
<list>
<bean class="org.apache.ignite.cache.QueryEntity">
<!-- setting indexed type's key class -->
<property name="keyType" value="com.company.ignite.IgniteTradePayloadKey" />
<!-- setting indexed type's value class -->
<property name="valueType" value="com.company.ignite.IgniteTradePayload" />
</bean>
</list>
</property>
<property name="affinity">
<bean class="com.company.ignite.affinity.IgniteAffinityFunction">
<property name="partitions" value="1024"/>
</bean>
</property>
<property name="atomicityMode" value="ATOMIC" />
<property name="rebalanceMode" value="ASYNC" />
<property name="copyOnRead" value="false" />
<!-- Set rebalance batch size to 8 MB. -->
<property name="rebalanceBatchSize" value="#{8 * 1024 * 1024}"/>
<!-- Explicitly disable rebalance throttling. -->
<property name="rebalanceThrottle" value="0"/>
<!-- Set 4 threads for rebalancing. -->
<property name="rebalanceThreadPoolSize" value="4"/>
</bean>
</list>
</property>
</bean>
</beans>
In addition, this is the relevant exception:
[22:28:24,418][INFO][grid-timeout-worker-#23%MTS Trades Cache Grid%][IgniteKernal%MTS Trades Cache Grid] FreeList [name=MTS Trades Cache Grid, buckets=256, dataPages=9658, reusePages=0]
[22:28:57,335][INFO][pub-#314%MTS Trades Cache Grid%][GridDeploymentLocalStore] Class locally deployed: class com.company.pt.tradesrouter.routing.ComputeJob
[22:28:57,705][SEVERE][pub-#314%MTS Trades Cache Grid%][GridJobWorker] Failed to execute job [jobId=48df049c461-b3ba568d-6a39-4296-b03f-0c046e7cf3f7, ses=GridJobSessionImpl [ses=GridTaskSessionImpl [taskName=com.company.pt.tradesrouter.routing.ComputeJob, dep=GridDeployment [ts=1532382444003, depMode=CONTINUOUS, clsLdr=sun.misc.Launcher$AppClassLoader#764c12b6, clsLdrId=a717c19c461-e5241c47-40d4-4085-a7fa-4f1916275b2e, userVer=0, loc=true, sampleClsName=o.a.i.i.processors.cache.distributed.dht.preloader.GridDhtPartitionFullMap, pendingUndeploy=false, undeployed=false, usage=2], taskClsName=com.company.pt.tradesrouter.routing.ComputeJob, sesId=38df049c461-b3ba568d-6a39-4296-b03f-0c046e7cf3f7, startTime=1532384937062, endTime=1532388537300, taskNodeId=b3ba568d-6a39-4296-b03f-0c046e7cf3f7, clsLdr=sun.misc.Launcher$AppClassLoader#764c12b6, closed=false, cpSpi=null, failSpi=null, loadSpi=null, usage=1, fullSup=false, internal=false, topPred=null, subjId=b3ba568d-6a39-4296-b03f-0c046e7cf3f7, mapFut=IgniteFuture [orig=GridFutureAdapter [ignoreInterrupts=false, state=INIT, res=null, hash=1635946755]], execName=null], jobId=48df049c461-b3ba568d-6a39-4296-b03f-0c046e7cf3f7]]
class org.apache.ignite.IgniteException: null
at org.apache.ignite.internal.processors.closure.GridClosureProcessor$C2.execute(GridClosureProcessor.java:1858)
at org.apache.ignite.internal.processors.job.GridJobWorker$2.call(GridJobWorker.java:566)
at org.apache.ignite.internal.util.IgniteUtils.wrapThreadLoader(IgniteUtils.java:6623)
at org.apache.ignite.internal.processors.job.GridJobWorker.execute0(GridJobWorker.java:560)
at org.apache.ignite.internal.processors.job.GridJobWorker.body(GridJobWorker.java:489)
at org.apache.ignite.internal.util.worker.GridWorker.run(GridWorker.java:110)
at org.apache.ignite.internal.processors.job.GridJobProcessor.processJobExecuteRequest(GridJobProcessor.java:1189)
at org.apache.ignite.internal.processors.job.GridJobProcessor$JobExecutionListener.onMessage(GridJobProcessor.java:1921)
at org.apache.ignite.internal.managers.communication.GridIoManager.invokeListener(GridIoManager.java:1555)
at org.apache.ignite.internal.managers.communication.GridIoManager.processRegularMessage0(GridIoManager.java:1183)
at org.apache.ignite.internal.managers.communication.GridIoManager.access$4200(GridIoManager.java:126)
at org.apache.ignite.internal.managers.communication.GridIoManager$9.run(GridIoManager.java:1090)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.NullPointerException
at com.company.pt.tradesrouter.routing.ComputeJob$$anonfun$1$$anonfun$2.apply(ComputeJob.scala:49)
at com.company.pt.tradesrouter.routing.ComputeJob$$anonfun$1$$anonfun$2.apply(ComputeJob.scala:47)
at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:245)
at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:245)
at scala.collection.immutable.Set$Set1.foreach(Set.scala:79)
at scala.collection.TraversableLike$class.map(TraversableLike.scala:245)
at scala.collection.AbstractSet.scala$collection$SetLike$$super$map(Set.scala:47)
at scala.collection.SetLike$class.map(SetLike.scala:92)
at scala.collection.AbstractSet.map(Set.scala:47)
at com.company.pt.tradesrouter.routing.ComputeJob$$anonfun$1.apply(ComputeJob.scala:47)
at com.company.pt.tradesrouter.routing.ComputeJob$$anonfun$1.apply(ComputeJob.scala:44)
at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:245)
at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:245)
at scala.collection.immutable.HashMap$HashMap1.foreach(HashMap.scala:221)
at scala.collection.immutable.HashMap$HashTrieMap.foreach(HashMap.scala:428)
at scala.collection.immutable.HashMap$HashTrieMap.foreach(HashMap.scala:428)
at scala.collection.TraversableLike$class.map(TraversableLike.scala:245)
at scala.collection.AbstractTraversable.map(Traversable.scala:104)
at com.company.pt.tradesrouter.routing.ComputeJob.call(ComputeJob.scala:44)
at com.company.pt.tradesrouter.routing.ComputeJob.call(ComputeJob.scala:21)
at org.apache.ignite.internal.processors.closure.GridClosureProcessor$C2.execute(GridClosureProcessor.java:1855)
... 14 more

Most probably, you hit a bug, that was introduced in Ignite 2.0: https://issues.apache.org/jira/browse/IGNITE-5795
Because of this bug #AffinityKeyMapped annotation is ignored in classes, that are used in query entity configuration. As far as I can see, this is exactly your case.
It's going to be fixed in Ignite 2.7.
There is a workaround for this problem: you can list the problematic classes in BinaryConfiguration#classNames configuration property. Binary configuration should be specified as IgniteConfiguration#binaryConfiguration. This configuration should be the same on all nodes. You may also need to configure CacheConfiguration#keyConfiguration for your cache.

Related

How to integrate Apache Ignite with Cassandra as third party persistence?

I tried out below configurations but I get ClassNotFoundException for org.apache.ignite.cache.store.cassandra.CassandraCacheStoreFactory. I am using docker image of apache ignite to achieve the same and its version is 2.9.1.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="ignite.cfg" class="org.apache.ignite.configuration.IgniteConfiguration">
<property name="cacheConfiguration">
<list>
<!-- Configuring persistence for "cache1" cache -->
<bean class="org.apache.ignite.configuration.CacheConfiguration">
<property name="name" value="cache1"/>
<!-- Tune on Read-Through and Write-Through mode -->
<property name="readThrough" value="true"/>
<property name="writeThrough" value="true"/>
<!-- Specifying CacheStoreFactory -->
<property name="cacheStoreFactory">
<bean class="org.apache.ignite.cache.store.cassandra.CassandraCacheStoreFactory">
<!-- Datasource configuration bean which is responsible for Cassandra connection details -->
<property name="dataSourceBean" value="cassandraDataSource"/>
<!-- Persistent settings bean which is responsible for the details of how objects will be persisted to Cassandra -->
<property name="persistenceSettingsBean" value="primitive_csndra_cache"/>
</bean>
</property>
</bean>
</list>
</property>
</bean>
<bean id="loadBalancingPolicy" class="com.datastax.driver.core.policies.TokenAwarePolicy">
<constructor-arg type="com.datastax.driver.core.policies.LoadBalancingPolicy">
<bean class="com.datastax.driver.core.policies.RoundRobinPolicy"/>
</constructor-arg>
</bean>
<bean id="cassandraAdminDataSource"
class="org.apache.ignite.cache.store.cassandra.datasource.DataSource">
<property name="port" value="9042" />
<property name="contactPoints" value="mycassandra.default.svc.cluster.local" />
<property name="readConsistency" value="ONE" />
<property name="writeConsistency" value="ONE" />
<property name="loadBalancingPolicy" ref="loadBalancingPolicy" />
</bean>
<bean id="primitive_csndra_cache" class="org.apache.ignite.cache.store.cassandra.persistence.KeyValuePersistenceSettings">
<constructor-arg type="java.lang.String">
<value><![CDATA[
<persistence keyspace="hello" table="primitive_xyz">
<keyPersistence class="java.lang.String" strategy="PRIMITIVE" column="key"/>
<valuePersistence class="java.lang.String" strategy="PRIMITIVE" column="value"/>
</persistence>]]>
</value>
</constructor-arg>
</bean>
</beans>
Can anyone help me out on this? Any sort of sample github project or blog reference will also work out for me.
Take a look at these docs: https://ignite.apache.org/docs/latest/extensions-and-integrations/cassandra/configuration
and examples: https://ignite.apache.org/docs/latest/extensions-and-integrations/cassandra/usage-examples
overview: https://ignite.apache.org/docs/latest/extensions-and-integrations/cassandra/overview

In-memory Job-Explorer definition in 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

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>