I get ClassNotFound exception, here is code:
Server:
<bean id="metaFactoryRmiServiceExporter"
class="org.springframework.remoting.rmi.RmiServiceExporter">
<property name="serviceName" value="metaFactoryService"/>
<property name="service" ref="metaFactoryServiceImpl"/>
<property name="serviceInterface" value="IMetaFactoryService"/>
<property name="registryPort" value="1098"/>
</bean>
Client:
if (System.getSecurityManager() == null) {
System.setSecurityManager(new RMISecurityManager());
}
try {
Registry registry = LocateRegistry.getRegistry("127.0.0.1",1098);
registry.lookup("metaFactoryService");
for (String s:registry.list()) {
System.out.println(s);
}
} catch (Exception e) {
e.printStackTrace();
}
I can get the registry.list() but lookup throws exception. why ?
I've configured security.policy.
Related
I have the below configuration in application context xml file
<bean id="methodMapWithDefaultTxAttributeSource" class="org.springframework.transaction.interceptor.MatchAlwaysTransactionAttributeSource">
<property name="transactionAttribute" value="PROPAGATION_REQUIRES_NEW,timeout_60"/>
</bean>
<bean id="methodMapTxInterceptor"
class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager" ref="txManager"/>
<property name="transactionAttributeSource" ref="methodMapWithDefaultTxAttributeSource"/>
</bean>
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="interceptorNames">
<list>
<idref bean="retryAdvice"/>
<idref bean="methodMapTxInterceptor"/>
</list>
</property>
<property name="beanNames">
<value>service</value>
</property>
</bean>
<bean id="txProxyTemplate"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
abstract="true">
<property name="transactionManager" ref="txManager" />
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRES_NEW,timeout_60</prop>
</props>
</property>
</bean>
<bean id="manager1" class="package2.Manager1">
<constructor-arg ref="dataSource"/>
</bean>
<bean id="manager2" class="package2.Manager2">
<constructor-arg ref="dataSource"/>
</bean>
<bean id="manager1TxProxy" parent="txProxyTemplate">
<property name="proxyTargetClass" value="true" />
<property name="target" ref="manager1" />
</bean>
<bean id="manager2TxProxy" parent="txProxyTemplate">
<property name="proxyTargetClass" value="true" />
<property name="target" ref="manager2"/>
</bean>
<bean id="retryPolicy" class="org.springframework.retry.policy.SimpleRetryPolicy">
<constructor-arg name="maxAttempts" value="3"/>
</bean>
<bean id="retryTemplate" class="org.springframework.retry.support.RetryTemplate">
<property name="retryPolicy" ref="retryPolicy"/>
</bean>
<bean id="rollbackClassifier" class="org.springframework.classify.BinaryExceptionClassifier">
<constructor-arg name="typeMap">
<util:map map-class="java.util.HashMap" key-type="java.lang.Class" value-type="java.lang.Boolean">
<entry key="java.lang.NullPointerException" value="false"/>
</util:map>
</constructor-arg>
<constructor-arg name="defaultValue" value="true"/>
<constructor-arg name="traverseCauses" value="true"/>
</bean>
<bean id="retryAdvice" class="org.springframework.retry.interceptor.StatefulRetryOperationsInterceptor">
<property name="retryOperations" ref="retryTemplate"/>
<property name="rollbackClassifier" ref="rollbackClassifier"/>
<property name="label" value="label"/>
</bean>
<bean id="service" class="package2.Service">
<property name="manager1" ref="manager1"/>
<property name="manager2" ref="manager2TxProxy"/>
</bean>
As you can see i have wrapped a interceptor chain around Service class method. The goal is add retry and transaction facility to all Service class method. I have modified the Service class below method to throw exception whenever it is called
public void executeWithException() {
manager1.execute();
throw new NullPointerException();
//manager2.execute();
}
Now in the first try, the interceptor chain has StatefulRetryOperationsInterceptor and TransactionInterceptor and before calling the Service class method transaction is created. The Service class method throws exception and it will retry.
Now in the second retry, the interceptor chain will have only StatefulRetryOperationsInterceptor and not TransactionInterceptor. I feel this is wrong. Even for second retry a new transaction has to be created. The javadoc says that. But is not happening here. The TransactionInterceptor is skipped.
Am i missing some configuration here.
Please help me out.
Screenshot of call stacktrace on first retry
Screenshot of call stacktrace on second retry
Hi Gary, I tried your example. I created my own transaction manager as shown below
public class MyTransactionManager extends AbstractPlatformTransactionManager {
private int i = 0;
#Override
protected Object doGetTransaction() throws TransactionException {
return new Object();
}
#Override
protected void doBegin(Object transaction, TransactionDefinition definition) throws TransactionException {
System.out.println("Transaction" + i);
i = i + 1;
}
#Override
protected void doCommit(DefaultTransactionStatus status) throws TransactionException {
}
#Override
protected void doRollback(DefaultTransactionStatus status) throws TransactionException {
}
}
Used it in the xml file
<bean id="txManager" class="package2.MyTransactionManager"/>
Below is the console output
Transaction0
Manager1 Execute
Manager1 Execute
Manager1 Execute
Exception in thread "main"
As you see transaction doBegin method is called once printing "Transaction0". This shows new transactions are not created for every retry.
Below is the main method
public class Example2 {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("example2.xml");
Service service1 = (Service)context.getBean("service");
service1.executeWithException();
}
}
When I debugged the code, TransactionInterceptor is in the chain but it is skipped on subsequent retry.
It makes no sense that the interceptor would change between calls; you must be mistaken.
It works fine for me with similar configuration as yours:
#SpringBootApplication
#ImportResource("so70609332-context.xml")
public class So70609332Application {
public static void main(String[] args) {
SpringApplication.run(So70609332Application.class, args);
}
#Bean
TransactionInterceptor txInterceptor(TransactionManager tm) {
return new TransactionInterceptor(tm, new MatchAlwaysTransactionAttributeSource());
}
#Bean
ApplicationRunner runner(Service service, MyTransactionManager tm) {
return args -> {
while (true) {
try {
callIt(service);
}
catch (IllegalStateException e) {
}
catch (Exception e) {
System.out.println(tm.begins);
break;
}
}
};
}
private void callIt(Service nt) {
try {
nt.foo();
}
catch (IllegalStateException e) {
throw e;
}
}
}
class Service {
void foo() {
System.out.println("called: " + TransactionSynchronizationManager.isActualTransactionActive());
throw new IllegalStateException();
}
}
#Component
class MyTransactionManager extends AbstractPlatformTransactionManager {
int begins;
#Override
protected Object doGetTransaction() throws TransactionException {
return new Object();
}
#Override
protected void doBegin(Object transaction, TransactionDefinition definition) throws TransactionException {
this.begins++;
}
#Override
protected void doCommit(DefaultTransactionStatus status) throws TransactionException {
}
#Override
protected void doRollback(DefaultTransactionStatus status) throws TransactionException {
}
}
<?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 https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean
class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="interceptorNames">
<list>
<idref bean="retryAdvice" />
<idref bean="txInterceptor" />
</list>
</property>
<property name="beanNames">
<value>service</value>
</property>
</bean>
<bean id="retryTemplate"
class="org.springframework.retry.support.RetryTemplate">
</bean>
<bean id="retryAdvice"
class="org.springframework.retry.interceptor.StatefulRetryOperationsInterceptor">
<property name="retryOperations" ref="retryTemplate" />
<property name="label" value="label" />
</bean>
<bean id="service" class="com.example.demo.Service" />
</beans>
called: true
called: true
called: true
3
i implemented spring application which is running based on schedulers in weblogic 10. server.
while i am deploying it. i am getting above exception.
here is my stack trace
java.lang.SecurityException: [Security:090398]Invalid Subject: principals=[bpm_weblogic, AdminChannelUsers, Administrators, AppTesters, CrossDomainConnectors, Deployers, Monitors, Operators, OracleSystemGroup]
at weblogic.security.service.SecurityServiceManager.seal(SecurityServiceManager.java:833)
at weblogic.security.service.IdentityUtility.authenticatedSubjectToIdentity(IdentityUtility.java:30)
at weblogic.security.service.RoleManager.getRoles(RoleManager.java:183)
at weblogic.security.service.AuthorizationManager.isAccessAllowed(AuthorizationManager.java:375)
at weblogic.jndi.internal.ServerNamingNode.checkPermission(ServerNamingNode.java:442)
at weblogic.jndi.internal.ServerNamingNode.checkLookup(ServerNamingNode.java:423)
at weblogic.jndi.internal.ServerNamingNode.lookupHere(ServerNamingNode.java:180)
at weblogic.jndi.internal.BasicNamingNode.unbind(BasicNamingNode.java:565)
at weblogic.jndi.internal.WLEventContextImpl.unbind(WLEventContextImpl.java:173)
at javax.naming.InitialContext.unbind(InitialContext.java:435)
at com.tcs.controller.BpmController.run(BpmController.java:94)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:64)
at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:53)
at org.springframework.scheduling.concurrent.ReschedulingRunnable.run(ReschedulingRunnable.java:81)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
at java.util.concurrent.FutureTask.run(FutureTask.java:262)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:178)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:292)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:744)
my spring application is running in one weblogic environment and i am calling bpm which is running in another weblogic environment.
here if don't call bpm i am not getting exception and if i user dataSource instead of jndi it is working fine.
but the problme is i have to call the bpm and i can't user dataSource configuration in production.
here is my controller class
public String executeBpm(User user) {
IBPMContext context = null;
String status = null;
if (logger.isDebugEnabled()) {
logger.debug("executeBpm method starts");
}
try {
if (user.getUserId() != null && !("").equals(user.getUserId())) {
context = ITBABPMContext.getIBPMContextUsingName(user.getUserId());
}
HashMap<String, Object> elements = (HashMap<String, Object>) user.getMap();
UpdateTaskDetails updates = new UpdateTaskDetails();
if (user.getTaskId() != null && !("").equals(user.getTaskId())) {
updates.setTaskID(user.getTaskId());
}
if (user.getTaskId() != null && !("").equals(user.getTaskId())) {
updates.setTaskOutcome(user.getTaskOutcome());
}
if (user.getUserComment() != null && !("").equals(user.getUserComment())) {
updates.setUserComment(user.getUserComment());
}
if (!elements.isEmpty() && elements.size() > 0) {
updates.setElementList(elements);
}
if (logger.isDebugEnabled()) {
logger.debug("executeBpm method ends");
}
status = ITBAACMUtil.updateTaskOutcome(updates, context);
if (status.equalsIgnoreCase("success")) {
bpmProcessorService.write(user.getUserId(), user.getSeqNo());
}
} catch (ITBABPMRuntimeException e) {
e.printStackTrace();
} catch (BPMServiceClientException e) {
e.printStackTrace();
} catch (BPMException e) {
e.printStackTrace();
}
catch (Exception e) {
e.printStackTrace();
}
return status;
}
my dao class
public void write(String userId,Long seqNo){
try{
String query=messageSource.getMessage(BPMConstants.FAILED_QUERY,new Object[]{Long.toString(seqNo)},Locale.US);
jdbcTemplate.update(query);
}catch(Exception e){
logger.error("exception at updating the status to failed ..");
logger.error(e.getStackTrace());
}
}
here one thing is cross domain mapping is are already there and other applications are running just fine. so i don't think this is the issue with cross domain mapping.
here is my configuration file.
<context:component-scan base-package="com.app" />
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="MCDataSource"/>
</bean>
<bean id="txManager" class="org.springframework.transaction.jta.WebLogicJtaTransactionManager" />
<bean id="transactionManager" class="org.springframework.transaction.jta.WebLogicJtaTransactionManager">
<property name="transactionManagerName" value="javax.transaction.TransactionManager"/>
</bean>
<!-- <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:#172.19.8.159:1521/OIM.itba.gov.in" />
<property name="username" value="AppDB"></property>
<property name="password" value="AppDB"></property>
<property name="initialSize" value="2" />
<property name="maxActive" value="5" />
</bean> -->
<bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename">
<value>messages</value>
</property>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="runScheduler" class="com.app.controller.BpmController" />
<task:scheduled-tasks>
<task:scheduled ref="runScheduler" method="run" cron="0 0/5 * * * ?" />
</task:scheduled-tasks>
Hey it seems your problem is you are not switching the context correctly. Once you open up the IBPM context then you are coming back and trying to lookup on your local jndi tree but you have IBPM context credentials which do not authenticate on your local weblogic. You need to open a new context before you perform a jndi lookup operation to your datasource.
Here is some sample code:
jndiTemplate(org.springframework.jndi.JndiTemplate) { bean ->
bean.scope = "prototype"
environment = [
"java.naming.factory.initial":"weblogic.jndi.WLInitialContextFactory",
"java.naming.security.principal" : "username",
"java.naming.security.credentials": "password"
]
}
dataSource(org.springframework.jndi.JndiObjectFactoryBean){
jndiTemplate = ref(jndiTemplate)
jndiName = "name"
exposeAccessContext=true
}
Then when you want to lookup the jndi you can something like.
Inject the jndiTemplate and:
jndiTemplate.context.getProperties()
Or
InitialContext initialContext = new InitialContext(jndiTemplate.getEnvironment());
You can then close it.
Hi all i ave an application with two different databases.
The first db is for our business app, the second belong to a framework we are using.
I have a manager in witch i need to access both dbs to perform some operations.
I configured my app with two entityManagerFactory, one for each datasource, and two transaction managers, one for each entityManagerFactory...
Here my configuration
my persistence.xml
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="ENPIM_BD_PU" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<non-jta-data-source>jdbc/businessDataSource</non-jta-data-source>
<class>it.aicof.projects.enpim.persistence.entities.AccountingRecords</class>
.....
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="hibernate.show_sql" value="false"/>
</properties>
</persistence-unit>
<persistence-unit name="ENPIM_SERV_PU" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>it.aicof.projects.enpim.persistence.entities.Authusers</class>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="hibernate.show_sql" value="false"/>
</properties>
</persistence-unit>
</persistence>
my app-context.xml
<context:annotation-config/>
<context:component-scan base-package="it.aicof.projects.*"/>
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>
<bean id="dataSourceBusiness" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<property name="driverClass" value="${profile.database.driverClassName}" />
<property name="jdbcUrl" value="jdbc:postgresql://${profile.database.hostname}:${profile.database.port}/${profile.database.business}" />
<property name="user" value="${profile.database.username}" />
<property name="password" value="${profile.database.password}" />
<!-- these are C3P0 properties -->
<property name="acquireIncrement" value="${c3p0.acquireIncrement}" />
<property name="initialPoolSize" value="${c3p0.initialPoolSize}" />
<property name="minPoolSize" value="${c3p0.minPoolSize}" />
<property name="maxPoolSize" value="${c3p0.maxPoolSize}" />
<property name="maxIdleTime" value="${c3p0.maxIdleTime}" />
</bean>
<bean id="dataSourceServ" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<property name="driverClass" value="${profile.database.driverClassName}" />
<property name="jdbcUrl" value="jdbc:postgresql://${profile.database.hostname}:${profile.database.port}/${profile.database.serv}" />
<property name="user" value="${profile.database.username}" />
<property name="password" value="${profile.database.password}" />
<!-- these are C3P0 properties -->
<property name="acquireIncrement" value="${c3p0.acquireIncrement}" />
<property name="initialPoolSize" value="${c3p0.initialPoolSize}" />
<property name="minPoolSize" value="${c3p0.minPoolSize}" />
<property name="maxPoolSize" value="${c3p0.maxPoolSize}" />
<property name="maxIdleTime" value="${c3p0.maxIdleTime}" />
</bean>
<bean id="transactionManagerBusiness" class="org.springframework.orm.jpa.JpaTransactionManager"
p:entityManagerFactory-ref="entityManagerFactory">
<qualifier value="business" />
</bean>
<bean id="transactionManagerServ" class="org.springframework.orm.jpa.JpaTransactionManager"
p:entityManagerFactory-ref="entityManagerFactoryServ">
<qualifier value="serv" />
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
p:dataSource-ref="dataSourceBusiness"
p:jpaVendorAdapter-ref="jpaAdapter">
<property name="loadTimeWeaver">
<bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/>
</property>
<property name="persistenceUnitName" value="ENPIM_BD_PU"></property>
</bean>
<bean id="entityManagerFactoryServ"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
p:dataSource-ref="dataSourceServ"
p:jpaVendorAdapter-ref="jpaAdapter">
<property name="loadTimeWeaver">
<bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/>
</property>
<property name="persistenceUnitName" value="ENPIM_SERV_PU"></property>
</bean>
<bean id="jpaAdapter"
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"
p:database="POSTGRESQL" p:showSql="false"/>
Here is the code i'm using
my dao
#PersistenceContext(unitName = "ENPIM_BD_PU")
protected EntityManager em;
#PersistenceContext(unitName = "ENPIM_SERV_PU")
protected EntityManager emServ;
....
public void edit(AddressBook addressBook) throws NonexistentEntityException, Exception {
try {
addressBook = em.merge(addressBook);
} catch (Exception ex) {
Logger.getLogger(this.getClass().getName()).error("edit", ex);
String msg = ex.getLocalizedMessage();
if (msg == null || msg.length() == 0) {
Integer id = addressBook.getId();
if (findAddressBook(id) == null) {
throw new NonexistentEntityException("The addressBook with id " + id + " no longer exists.");
}
}
throw ex;
}
}
public void createBeneficiaryLoginAccount(String username, String password) throws Exception{
try {
Query q = emServ.createNativeQuery("INSERT INTO authusers(username, passwd, registrationdate, lastaccess, lastpasswordchange, active)" +
" VALUES (?, ?, ?, ?, ?, ?)");
q.setParameter(1, username);
q.setParameter(2, password);
q.setParameter(3, new Date());
q.setParameter(4, new Date());
q.setParameter(5, new Date());
q.setParameter(6, 1);
q.executeUpdate();
}catch (Exception ex) {
Logger.getLogger(this.getClass().getName()).error("createBeneficiaryAccount", ex);
throw ex;
}
}
my manager
#Override
public void createBeneficiaryAccount(AddressBook addressBook, String password) {
String username = addressBook.getUsername();
try {
AddressBook ab = this.addressBookJpaDAO.findAddressBook(addressBook.getId());
ab.setUsername(username);
//creo l'utente sul db serv e gli assegno il ruolo di beneficiario
this.createBeneficiaryLoginAccount(username, password);
this.createBeneficiaryUsername(ab, password);
} catch (Throwable t) {
Logger.getLogger(this.getClass().getName()).error("", t);
}
}
#Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = Exception.class, value = "serv")
private void createBeneficiaryLoginAccount(String username, String password) throws Throwable {
try {
//creo l'utente sul db serv e gli assegno il ruolo di beneficiario
this.addressBookJpaDAO.createBeneficiaryLoginAccount(username, password);
} catch (Throwable t) {
Logger.getLogger(this.getClass().getName()).error("createLoginAccount", t);
throw t;
}
}
#Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = Exception.class, value = "business")
private void createBeneficiaryUsername(AddressBook addressBook, String password) throws Throwable {
try {
this.addressBookJpaDAO.edit(addressBook);
} catch (Throwable t) {
Logger.getLogger(this.getClass().getName()).error("createBeneficiaryUsername", t);
throw t;
}
}
when the method that uses the second entityManager is called i get the exception
2014-11-26 11:10:35,844 ERROR controllers.AddressBookJpaController - createBeneficiaryAccount
javax.persistence.TransactionRequiredException: Executing an update/delete query
at org.hibernate.jpa.spi.AbstractQueryImpl.executeUpdate(AbstractQueryImpl.java:71)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
.....
and debugging the application i found that when we try to use the second entityManager we have this error
Exception occurred in target VM: Not allowed to create transaction on shared EntityManager - use Spring transactions or EJB CMT instead
java.lang.IllegalStateException: Not allowed to create transaction on shared EntityManager - use Spring transactions or EJB CMT instead
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:198)
at com.sun.proxy.$Proxy145.getTransaction(Unknown Source)
at it.aicof.projects.enpim.persistence.controllers.AddressBookJpaController.createBeneficiaryLoginAccount(AddressBookJpaController.java:854)
i take a look on the web for some example but all have the same configuration as mine.
So.. why it's not working?
what's wrong?
thanks in advance
andrea
You're annotating #Transactional at a private method. That doesn't work with the Spring Aop Proxy Beans.
The quickest way is to set both methods to public
#Transactional("serv")
public void createBeneficiaryLoginAccount(String username, String password) throws Throwable {
try {
//creo l'utente sul db serv e gli assegno il ruolo di beneficiario
this.addressBookJpaDAO.createBeneficiaryLoginAccount(username, password);
} catch (Throwable t) {
Logger.getLogger(this.getClass().getName()).error("createLoginAccount", t);
throw t;
}
}
#Transactional("business")
public void createBeneficiaryUsername(AddressBook addressBook, String password) throws Throwable {
try {
this.addressBookJpaDAO.edit(addressBook);
} catch (Throwable t) {
Logger.getLogger(this.getClass().getName()).error("createBeneficiaryUsername", t);
throw t;
}
}
Or you might want to use AspectJ mode for AOP, but that is another layer of headaches IMHO.
See: Does Spring #Transactional attribute work on a private method?
Ideally after one queue completes its execution, another queue should start.
I am using Spring JMS. But at a time more than one queue able to execute by which data mismatch occurs.
So can anyone please tell how to restrict concurrent queue or unless first queue ends the 2nd queue cannot be started or all other queues are in waiting.
public class MyQueueListener implements MessageListener {
public void onMessage(Message message) {
try {
if (message instanceof ObjectMessage) {
ObjectMessage objectMessage = (ObjectMessage) message;
MyQueueObject obj= (MyQueueObject)objectMessage.getObject();
String productId = obj.getProductId();
IMyService myService;
myService.updateAllCustomerDetails(productId);
}
} catch (JMSException j) {
j.printStackTrace();
} catch(Exception e) {
e.printStackTrace();
}
}
}
<bean id="mySenderService" class="MySenderService">
<property name="jmsTemplate" ref="myjmsTemplate" />
<property name="queue" ref="myQueueDestination" />
</bean>
<bean id="myQueueDestination" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>queue/myQueue</value>
</property>
<property name="resourceRef">
<value>true</value>
</property>
</bean>
<bean id="myQueueListener" class="MyQueueListener" ></bean>
<bean id="jmsImportContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory" />
<property name="destination" ref="myQueueDestination" />
<property name="messageListener" ref="myQueueListener" />
</bean>
mySenderService.sendMessages();
I have an application which uses spring-jms, websphere mq, websphere application server 7.
On a user interaction, I am putting a message in a Queue A. I have a Listener-A(using DefaultMessageListenerContainer in springframework) which picks up the message. That listener-A is supposed to process it and send a response to Queue A-Response. In that process, I am trying to put another message on a different Queue B for which I have a different Listener-B defined. But for some reason, after the message is put on Queue B, the Listener-B is not picking it up.
When I try to put the message manually on the Queue B, Listener-B picks the message and processes it, but when I try the above mentioned scenario, it doesn't work. Also, when I comment out the code that puts a message on Queue B in the Listener-A, then the Listener-A processes the message and sends a response back to Queue A-Response.
Any help is greatly appreciated. Thanks
Edit: Added code
Here is the spring configuration that I have
<bean id="jmsListener-Parent" abstract="true"
class="MyJmsServiceExporter">
<property name="messageTimeToLive" value="60000" />
</bean>
<bean id="transactionManager" class="org.springframework.transaction.jta.WebSphereUowTransactionManager" />
<bean id="taskExecutor" class="org.springframework.scheduling.commonj.WorkManagerTaskExecutor">
<property name="workManagerName" value="wm/default" />
</bean>
<bean name="jmsListenerContainer-Parent"
abstract="true"
class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory"/>
<property name="concurrentConsumers" value="1"/>
<property name="transactionManager" ref="transactionManager" />
<property name="taskExecutor" ref="taskExecutor" />
</bean>
<bean id="FirstService-Listener" parent="jmsListener-Parent">
<property name="serviceInterface" value="FirstService" />
<property name="service" ref="FirstServiceImpl" />
<property name="messageConverter" ref="MyMessageConverter" />
</bean>
<bean id="SecondService-Listener" parent="jmsListener-Parent">
<property name="serviceInterface" value="SecondService" />
<property name="service" ref="SecondServiceImpl" />
<property name="messageConverter" ref="MyMessageConverter" />
</bean>
<bean name="FirstService-ListenerContainer"
parent="jmsListenerContainer-Parent">
<property name="destination" ref="FirstQueue-Request" />
<property name="messageListener" ref="FirstService-Listener" />
</bean>
<bean name="SecondService-ListenerContainer"
parent="jmsListenerContainer-Parent">
<property name="destination" ref="SecondQueue-Request" />
<property name="messageListener" ref="SecondService-Listener" />
</bean>
<bean id="FirstService-Client"
class="MyJmsServiceInvoker">
<property name="connectionFactory" ref="connectionFactory" />
<property name="serviceInterface" value="FirstService" />
<property name="messageConverter" ref="MyMessageConverter" />
<property name="queue" ref="FirstQueue-Request" />
<property name="responseQueue" ref="FirstQueue-Response" />
<property name="timeToLive" value="60000" />
<property name="receiveTimeout" value="60000" />
</bean>
<bean id="SecondService-Client"
class="MyJmsServiceInvoker">
<property name="connectionFactory" ref="connectionFactory" />
<property name="serviceInterface" value="SecondService" />
<property name="messageConverter" ref="MyMessageConverter" />
<property name="queue" ref="SecondQueue-Request" />
<property name="responseQueue" ref="SecondQueue-Response" />
<property name="timeToLive" value="60000" />
<property name="receiveTimeout" value="60000" />
</bean>
MyJmsServiceInvoker(extends JmsInvokerProxyFactoryBean) methods:
protected Message doExecuteRequest(
Session session,
Queue queue,
Message requestMessage)
throws JMSException {
MessageProducer producer = null;
MessageConsumer consumer = null;
Message responseMessage = null;
String correlationId = null;
String responseSelector = null;
try {
LOG.info("CmsJmsServiceInvoker::doExecuteRequest");
requestMessage.setJMSType("TEXT");
requestMessage.setJMSReplyTo(responseQueue);
requestMessage.setJMSExpiration(this.getTimeToLive());
producer = session.createProducer(queue);
if (isPersistentMessage()) {
producer.setDeliveryMode(DeliveryMode.PERSISTENT);
} else {
producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
}
producer.setTimeToLive(getTimeToLive());
LOG.info("Sending requestMessage.");
producer.send(requestMessage);
correlationId = requestMessage.getJMSMessageID();
responseSelector =
"JMSCorrelationID=\'" + correlationId + "\'";
consumer = session.createConsumer(responseQueue, responseSelector);
long timeout = getReceiveTimeout();
LOG.info("Awaiting response.");
if (timeout > 0) {
responseMessage = consumer.receive(timeout);
} else {
responseMessage = consumer.receive();
}
if (responseMessage == null) {
LOG.info("Timeout encountered.");
throw new RuntimeException("Timeout");
}
} catch (JMSSecurityException jse) {
LOG.error("SecurityException encountered.", jse);
throw new RuntimeException("JMS SecurityException, jse");
} finally {
JmsUtils.closeMessageConsumer(consumer);
JmsUtils.closeMessageProducer(producer);
}
LOG.info("Returning response Message.");
return responseMessage;
}
MyJmsServiceExporter(extends JmsInvokerServiceExporter) methods:
protected void writeRemoteInvocationResult(Message requestMessage,
Session session,
RemoteInvocationResult result)
throws JMSException {
MessageProducer producer = null;
Message response = null;
if (requestMessage.getJMSReplyTo() == null) {
LOG.debug("Async: This request will not have a "
+ "response since there is no reply queue in the "
+ "JMS header.");
return;
}
producer = session.createProducer(requestMessage.getJMSReplyTo());
try {
response = createResponseMessage(requestMessage, session,
result);
producer.setTimeToLive(getMessageTimeToLive());
producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
if (persistentMessage) {
producer.setDeliveryMode(DeliveryMode.PERSISTENT);
}
producer.send(response);
if (LOG.isDebugEnabled()) {
LOG.debug("Sending response message.");
LOG.debug(response);
}
} finally {
if (producer != null) {
JmsUtils.closeMessageProducer(producer);
}
}
}
protected Message createResponseMessage(
Message request,
Session session,
RemoteInvocationResult result)
throws JMSException {
Message response = null;
String correlation = null;
correlation = request.getJMSCorrelationID();
response = super.createResponseMessage(request, session, result);
if (correlation == null) {
correlation = request.getJMSMessageID();
}
response.setJMSCorrelationID(correlation);
response.setJMSExpiration(getMessageTimeToLive());
return response;
}
public void onMessage(Message requestMessage, Session session)
throws JMSException {
RemoteInvocationResult result = null;
try {
RemoteInvocation invocation = readRemoteInvocation(requestMessage);
if (invocation != null) {
result =
invokeAndCreateResult(invocation, getProxyForService());
}
} catch (Throwable throwable) {
if (result == null) {
result = new RemoteInvocationResult(throwable);
}
throwable.printStackTrace();
} finally {
writeRemoteInvocationResult(requestMessage, session, result);
// JmsUtils.commitIfNecessary(session);
}
}
FirstServiceImpl class has a saveText method which is invoked when a message is put in FirstQueue-Request. In that method, I am trying to call SecondService method: validateText(textmessage). This message is put on SecondQueue-Request but never read.
You didn't commit session after message send.
It seems to me that you are trying to implement request-reply-by-correlationid logic while at same time working with transacted resources and manual session handling; all within same method (doExecuteRequest() or writeRemoteInvocationResult()). That's a lot of stuff for 20 lines of code. This kind of code is usually used with temporary queues..
Do you really need to write code on session level? Is there a reason why you couldn't just use jmsTemplate to send message, and messageListenerContainer to receive reply?