Where and how ROLES are defined when using LDAP and Spring security - security

I am using Spring Security and authenticating from an LDAP database. The authentication works fine, but I am not able to utilize roles!
In spring-security.xml there is this tag:
<security:intercept-url pattern="/app/main/admin" access="hasRole('ROLE_USER')"/>
My question is, where is "ROLE_USER" defined? How is a user made to belong to a particular role? Does this happen in the LDAP database? If yes, then how do I do that? I know little about LDAP. Is it another configuration file where I define roles?
Thank you for your help.

I know of two ways we can assign a role to a user after LDAP authentication.
We can divide users in different groups according to their roles in the LDAP database and map those groups to different roles.
See here : How to Map AD Groups to User Role Spring Security LDAP
We can authenticate the user using LDAP authentication and authorize using our local database.
Configuration:
<beans:bean id="ldapAuthProvider" class="org.springframework.security.ldap.authentication.LdapAuthenticationProvider">
<beans:constructor-arg name="authenticator">
<beans:bean
class="org.springframework.security.ldap.authentication.BindAuthenticator">
<beans:constructor-arg ref="contextSource" />
<beans:property name="userSearch">
<beans:bean
class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">
<beans:constructor-arg name="searchBase"
value="ou=example,dc=springframework,dc=org" />
<beans:constructor-arg name="searchFilter"
value="(uid={0})" />
<beans:constructor-arg name="contextSource"
ref="contextSource" />
</beans:bean>
</beans:property>
</beans:bean>
</beans:constructor-arg>
<beans:constructor-arg name="authoritiesPopulator"
ref="myLDAPAuthPopulator" />
</beans:bean>
<authentication-manager alias="authenticationManager">
<authentication-provider ref="ldapAuthProvider" />
</authentication-manager>
Implementation of myLDAPAuthPopulator:
#Component("myLDAPAuthPopulator")
public class MyLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator {
#Autowired
private UserDao userDao;
#Override
public Collection<? extends GrantedAuthority> getGrantedAuthorities(
DirContextOperations userData, String username) {
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
List<String> roleList = userDao.getRoles(username);
if (!roleList.isEmpty()) {
for (String role : roleList) {
System.out.println(role);
authorities.add(new SimpleGrantedAuthority(role));
}
}
else
{
//We know that user is authenticated. So you can add a role here and save it in the database.
}
return authorities;
}

Related

SAP Hybris E-commerce : Send Email in CronJob

I have created a CronJob that works perfectly.
But I want to generate the sending of an email within this Cronjob. I followed a tutorial on the internet.
I start with the creation itemType of ProductsApprovedEmailProcess.
then I created productsApprovedEmailProcess to define the steps be executed by the Process Engine as follow
Then I have added an EmailContext to holds the data to be passed to the email template as follow
public class ProductsApprovedEmailContext extends CustomerEmailContext
{
private String message;
#Override
public void init(final StoreFrontCustomerProcessModel processModel, final EmailPageModel emailPageModel)
{
super.init(processModel, emailPageModel);
if (processModel instanceof ProductsApprovedEmailProcessModel)
{
setMessage(((ProductsApprovedEmailProcessModel) processModel).getMessage());
}
}
public String getMessage()
{
return message;
}
public void setMessage(final String message)
{
this.message = message;
}
}
And I had register ProductsApprovedEmailContext as a bean in Spring as follow
<bean id="productsApprovedEmailContext" class="com.hybris.training.facades.process.email.context.ProductsApprovedEmailContext"
parent="abstractEmailContext"
scope="prototype" >
</bean>
Then I created 2 Velocity templates, one for the email Subject and the other for the Body email-productsapproved-subject.vm and email-productsapproved-body.vm
And the following impex allows you to create RendererTemplates for the Subject and the Body, and attach them to an EmailPageTemplate as follow
$contentCatalog=electronicsContentCatalog
$contentCV=catalogVersion(CatalogVersion.catalog(Catalog.id[default=$contentCatalog]),CatalogVersion.version[default=Online])[default=$contentCatalog:Online]
UPDATE GenericItem[processor=de.hybris.platform.commerceservices.impex.impl.ConfigPropertyImportProcessor];pk[unique=true]
$emailResource=$config-emailResourceValue
$emailPackageName=$config-emailContextPackageName
$lang=en
INSERT_UPDATE RendererTemplate ;code[unique=true] ;contextClass ;templateScript[lang=en,translator=de.hybris.platform.commerceservices.impex.impl.FileLoaderValueTranslator];rendererType(code)[default='velocity']
;email-productsapproved-body ;$emailPackageName.ProductsApprovedEmailContext ;$emailResource/email-productsapproved-body.vm
;email-productsapproved-subject ;$emailPackageName.ProductsApprovedEmailContext ;$emailResource/email-productsapproved-subject.vm
INSERT_UPDATE EmailPage ;$contentCV[unique=true];uid[unique=true] ;masterTemplate(uid,$contentCV) ;approvalStatus(code)[default='approved']
; ;ProductApprovedEmail ;ProductApprovedEmailTemplate ;
And in the Cronjob I added this code !
final ProductsApprovedEmailProcessModel productsApprovedEmailProcessModel = (ProductsApprovedEmailProcessModel) businessProcessService
.createProcess("productsApprovedEmailProcess" + "-" + System.currentTimeMillis(), "productsApprovedEmailProcess");
productsApprovedEmailProcessModel.setMessage("Products approved in csv file");
productsApprovedEmailProcessModel.setSite(baseSiteService.getBaseSiteForUID("electronics"));
productsApprovedEmailProcessModel.setLanguage(CommerceCommonI18NService.getCurrentLanguage());
modelService.save(productsApprovedEmailProcessModel);
businessProcessService.startProcess(productsApprovedEmailProcessModel);
But a acheive this error when I'm strating CronJob using HMC Interface :
Error executing ActionNode with ID [generateProductsApprovedEmail]: HtmlTemplate associated with MasterTemplate of EmailPageModel cannot be null
UPDATE :
Here is my business process :
<process xmlns="http://www.hybris.de/xsd/processdefinition"
start="generateProductsApprovedEmail"
name="productsApprovedEmailProcess"
processClass="com.hybris.training.core.model.process.ProductsApprovedEmailProcessModel"
onError="error">
<action id="generateProductsApprovedEmail" bean="generateProductsApprovedEmail">
<transition name="OK" to="sendEmail"/>
<transition name="NOK" to="error"/>
</action>
<action id="sendEmail" bean="sendEmail">
<transition name="OK" to="removeSentEmail"/>
<transition name="NOK" to="failed"/>
</action>
<action id="removeSentEmail" bean="removeSentEmail">
<transition name="OK" to="success"/>
<transition name="NOK" to="error"/>
</action>
<end id="error" state="ERROR">Something went wrong.</end>
<end id="failed" state="FAILED">Could not send products approved in csv File email.</end>
<end id="success" state="SUCCEEDED">Sent file in email.</end>
After declaring ProductApprovedEmailTemplate (EmailPageTemplate) i got this warn and the mail is not generated :
WARN [TaskExecutor-master-264-ProcessTask [8796715713462]] [GenerateEmailAction] Could not retrieve email page model for ProductApprovedEmail and Electronics Content Catalog:Online, cannot generate email content
Look like, the blog you have followed, it has mentioned each step correctly, but you might be missed something.
Make sure you have followed the below steps correctly.
e.g.
frontendTemplateName should be matched with EmailPageTemplate one
<bean id="generateProductApprovedEmail" parent="abstractGenerateEmailAction">
<property name="frontendTemplateName" value="ProductApprovedEmail"/>
</bean>
Create Email page Template
INSERT_UPDATE EmailPageTemplate ;$contentCV[unique=true];uid[unique=true] ;active ;frontendTemplateName ;subject(code) ;htmlTemplate(code) ;restrictedPageTypes(code)
; ;ProductApprovedEmailTemplate ;true ;ProductApprovedEmail ;email-productsapproved-subject ;email-productsapproved-body ;EmailPage
Create Email Page
INSERT_UPDATE EmailPage ;$contentCV[unique=true];uid[unique=true] ;masterTemplate(uid,$contentCV);approvalStatus(code)[default='approved']
; ;ProductApprovedEmail ;ProductApprovedEmailTemplate ;

Reuse of service-activator for several gateway methods with Splitter

does somebody happen to know if it is valid to reuse a service activator and so also the output-channel using several methods (inbound) especially with a splitter and aggregator.
--> Always with result on the gateway.
In several tests it seems to work fine. As soon I added a splitter with an aggregator I get wrongs result routed to the gateway which then fails with a conversion exception (here in my case it cannot convert boolean to integer).
Thanks,
Paul
Flow
Spring Integration Config
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:int="http://www.springframework.org/schema/integration"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd">
<int:gateway service-interface="activity.BulbMessageGateway">
<int:method name="sendToBulb" request-channel="bulbMessages" reply-channel="bulbSendResult"></int:method>
<int:method name="updateHomeLightStatus" request-channel="homeBulbEntity" reply-channel="homeBulbEntityResult">
</int:method>
<int:method name="updateLightStatus" request-channel="bulbEntities" reply-channel="bulbSendResult">
<int:header name="homeId" expression="#args[0].homeId"/>
<int:header name="bulbId" expression="#args[0].strongId"/>
</int:method>
</int:gateway>
<int:channel id="bulbMessages" />
<int:channel id="bulbSendResult" />
<int:channel id="bulbEntities" />
<int:channel id="homeBulbEntity" />
<int:channel id="homeBulbEntityResult" />
<int:chain input-channel="homeBulbEntity" output-channel="bulbEntities">
<int:splitter expression="payload.bulbs" />
<int:header-enricher>
<int:header name="bulbId" expression="payload.strongId"/>
<int:header name="homeId" expression="payload.homeId"/>
</int:header-enricher>
</int:chain>
<int:transformer method="bulbToLightStatus" input-channel="bulbEntities" output-channel="bulbMessages">
<bean class="util.BulbTransformer"></bean>
</int:transformer>
<int:aggregator input-channel="bulbSendResult" output-channel="homeBulbEntityResult" method="aggregate">
<bean class="util.BooleanAggregator" />
</int:aggregator>
<int:service-activator input-channel="bulbMessages" output-channel="bulbSendResult" method="send">
<bean class="activity.BulbWebsocketMessageSenderBA" />
</int:service-activator>
</beans>
Unit test
#Test
public void sendMessageNoReceiver() {
assertFalse(gateway.sendToBulb(new HomeId("1"), new BulbId("1"), BulbMessageBuilder.restart("foo")));
}
#Test
public void sendMessageWithReceiver() {
MockSession<BulbId, BulbBE> bulbSession = new MockSession<BulbId, BulbBE>(new BulbBE(HomeId.of("1"), BulbId.of("1"), "bulb", "pass"));
registry.addBulbSession(bulbSession);
assertTrue(gateway.sendToBulb(new HomeId("1"), new BulbId("1"), BulbMessageBuilder.restart("foo")));
assertEquals(1, bulbSession.receivedMessages());
}
#Test
public void updateBulbStatus() {
final MockSession<BulbId, BulbBE> bulbSession1 = new MockSession<BulbId, BulbBE>(new BulbBE(HomeId.of("1"), BulbId.of("1"), "bulb", "pass"));
assertFalse(gateway.updateLightStatus(bulbSession1.getIdentity()));
registry.addBulbSession(bulbSession1);
assertTrue(gateway.updateLightStatus(bulbSession1.getIdentity()));
assertEquals(1, bulbSession1.receivedMessages());
final MockSession<BulbId, BulbBE> bulbSession2 = new MockSession<BulbId, BulbBE>(new BulbBE(HomeId.of("1"), BulbId.of("2"), "bulb", "pass"));
assertFalse(gateway.updateLightStatus(bulbSession2.getIdentity()));
registry.addBulbSession(bulbSession2);
assertTrue(gateway.updateLightStatus(bulbSession2.getIdentity()));
assertTrue(gateway.updateLightStatus(bulbSession2.getIdentity()));
assertEquals(2, bulbSession2.receivedMessages());
assertEquals(1, bulbSession1.receivedMessages());
}
#Test
public void updateHomeBulbStatus() {
final HomeBE home = new HomeBE();
home.setId(new ObjectId());
final MockSession<BulbId, BulbBE> bulbSession1 = new MockSession<BulbId, BulbBE>(new BulbBE(home.getStrongId(), BulbId.of("1"), "bulb", "pass"));
registry.addBulbSession(bulbSession1);
final MockSession<BulbId, BulbBE> bulbSession2 = new MockSession<BulbId, BulbBE>(new BulbBE(home.getStrongId(), BulbId.of("2"), "bulb", "pass"));
registry.addBulbSession(bulbSession2);
home.addBulb(bulbSession1.getIdentity());
assertEquals(1, gateway.updateHomeLightStatus(home));
assertEquals(1, bulbSession1.receivedMessages());
assertEquals(0, bulbSession2.receivedMessages());
home.addBulb(bulbSession2.getIdentity());
assertEquals(2, gateway.updateHomeLightStatus(home));
assertEquals(2, bulbSession1.receivedMessages());
assertEquals(1, bulbSession2.receivedMessages());
}
The last test fails if it is executed together with the other tests. It passes if it is executed alone.
The error is that the last method (using the splitter) receives now a boolean, which seems to be a result of the other two methods registered. The result of these methods is a boolean.
Please, share config on the matter.
And according your graph it would be better if you'd minimize the config as much as possible to isolate the problem.
From other side, please, be more specific: your question is fully unclear.
That is your own service. How can we be sure that it is safe to be used in different places? Only you, as an author, can determine that.
UPDATE
Sorry for the delay. Was busy with the release.
And thank for sharing the config for your use-case.
Now I see the problem.
You use everywhere on the gateway's methods a reply-channel. See the documentation on the matter when you need that:
Typically you don’t have to specify the default-reply-channel, since a Gateway will auto-create a temporary, anonymous reply channel, where it will listen for the reply. However, there are some cases which may prompt you to define a default-reply-channel (or reply-channel with adapter gateways such as HTTP, JMS, etc.).
Since you use the same bulbSendResult in different places the behavior is really unpredictable. Moreoever that channel is DirectChannel, so the round-robin balancer are on the scene.
You should get rid of those reply-channel's at all and just rely from your downstream components on the replyChannel header. Therefore you should remove those output-channels in the components which are intended to return replies to your gateway.
For example the last service-activator should be just like this:
<int:service-activator input-channel="bulbMessages" method="send">
<bean class="activity.BulbWebsocketMessageSenderBA"/>
</int:service-activator>
Since you general question how to reuse this service-activator, I'm answering to the question having the config from you:
<int:chain input-channel="homeBulbEntity">
<int:splitter expression="payload.bulbs"/>
<int:header-enricher>
<int:header name="bulbId" expression="payload.strongId"/>
<int:header name="homeId" expression="payload.homeId"/>
</int:header-enricher>
<int:transformer method="bulbToLightStatus">
<bean class="util.BulbTransformer"/>
</int:transformer>
<int:gateway request-channel="bulbMessages"/>
<int:aggregator method="aggregate">
<bean class="util.BooleanAggregator"/>
</int:aggregator>
</int:chain>
Pay attention to the absent output-channel for the <chain>. Therefore it sends reply directly to the replyChannel from headers and as a return to your updateHomeLightStatus gateway's method.
Another trick is that <int:gateway request-channel="bulbMessages"/> which sends messages in the middle of the <chain> flow to your <service-activator> and wait for the reply from there exactly the same way as a top-level gateway - via replyChannel header. For the <service-activator> without an output-channel it is a black-box where to send the reply. It uses just replyChannel from headers!
After receiving the reply gateway in the <chain> push the message to the <aggregator>.
When aggregator will do its logic, the result will be send to the top-level gateway as an output from the <chain>.
That's all.
Let me know what else isn't clear here.

Spring Integration - Scheduling Job from configuration file

I'm using Spring Integration to parse XML file and i will need to create a thread (and each one have a different rate) for each tag.
Right now (with the help of many users here :)) i'm able to split XML by tag and then route it to the appropiate service-activator.
This works great but i'm not able to redirect to a channel that create "a thread" and then execute the operations. Right now i have the following configuration and in my mind (that i dont know if it is correct...)
Split tag -> Route to the appropiate channel -> Start a thread(from tag configuration) -> Execute the operation
This is my actual configuration that split tag and redirect to the channel.
The router should redirect not toward a channel directly, but schedule them.
In first instance will be enought to redirect it in a pool with fixed rate and later i will use XPATH to get the attribute and then replace this "fixed" rate with the correct value.
I've tried many solutions to create this flow but each one fails or do not compile :(
<context:component-scan base-package="it.mypkg" />
<si:channel id="rootChannel" />
<si-xml:xpath-splitter id="mySplitter" input-channel="rootChannel" output-channel="routerChannel" create-documents="true">
<si-xml:xpath-expression expression="//service" />
</si-xml:xpath-splitter>
<si-xml:xpath-router id="router" input-channel="routerChannel" evaluate-as-string="true">
<si-xml:xpath-expression expression="concat(name(./node()), 'Channel')" />
</si-xml:xpath-router>
<si:service-activator input-channel="serviceChannel" output-channel="endChannel">
<bean class="it.mypkg.Service" />
</si:service-activator>
UPDATE:
Using this configuration for the service this should run a task every 10 seconds (the id=service1) and every 5 seconds the other (the id=service2). In the same way i can have another tag that is handle by another class (because this will have another behaviour)
<root>
<service id="service1" interval="10000" />
<service id="service2" interval="5000" />
<activity id="activity1" interval="50000" />
<root>
I will have a classe (Service) that is general to handle Service tag and this complete some operation and then "return me" the value so i can redirect to another channel.
public class Service {
public int execute() {
// Execute the task and return the value to continue the "chain"
}
}
It's not at all clear what you mean; you split a tag; route it but want to "schedule" it at a rate in the XML. It's not clear what you mean by "schedule" here - normally each message is processed once not multiple times on a schedule.
As I said, I don't understand what you need to do, but a smart poller might be suitable.
Another possibility is the delayer where the amount of the delay can be derived from the message.
EDIT
Since your "services" don't seem to take any input data, it looks like you simply need to configure/start an <inbound-channel-adapter/> for each service, and then start it, based on the arguments in the XML.
<int:inbound-channel-adapter id="service1" channel="foo"
auto-startup="false"
ref="service1Bean" method="execute">
<poller fixed-delay="1000" />
</int:inbound-channel-adapter/>
Note auto-startup="false".
Now, in the code that receives the split
#Autowired
SourcePollingChannelAdapter service1;
...
public void startService1(Node node) {
...
service1.setTrigger(new PeridicTrigger(...));
service1.start();
...
}
I dont know if this is the right way to implement the flow, but i've write the follow code:
applicationContext.xml
<context:component-scan base-package="it.mypkg" />
<!-- Expression to extract interval from XML tag -->
<si-xml:xpath-expression id="selectIntervalXpath" expression="//*/#interval" />
<si:channel id="rootChannel" />
<!-- Split each tag to redirect on router -->
<si-xml:xpath-splitter id="mySplitter" input-channel="rootChannel" output-channel="routerChannel" create-documents="true">
<si-xml:xpath-expression expression="//service|//activity" />
</si-xml:xpath-splitter>
<!-- Route each tag to the appropiate channel -->
<si-xml:xpath-router id="router" input-channel="routerChannel" evaluate-as-string="true">
<si-xml:xpath-expression expression="concat(name(./node()), 'Channel')" />
</si-xml:xpath-router>
<!-- Activator for Service Tag -->
<si:service-activator input-channel="serviceChannel" method="schedule">
<bean class="it.mypkg.Service" />
</si:service-activator>
<!-- Activator for Activity Tag -->
<si:service-activator input-channel="activityChannel" method="schedule">
<bean class="it.mypkg.Activity" />
</si:service-activator>
<!-- Task scheduler -->
<task:scheduler id="taskScheduler" pool-size="10"/>
Each tag will extend an Operation class (to avoid code duplication on bean injection)
Operation.java
public abstract class Operation {
protected TaskScheduler taskScheduler;
protected XPathExpression selectIntervalXpath;
abstract public void schedule(Node document);
#Autowired
public void setTaskScheduler(TaskScheduler taskScheduler) {
this.taskScheduler= taskScheduler;
}
public TaskScheduler getTaskScheduler() {
return this.taskScheduler;
}
#Autowired
public void setSelectIntervalXpath(XPathExpression selectIntervalXpath) {
this.selectIntervalXpath = selectIntervalXpath;
}
public XPathExpression getSelectIntervalXPath() {
return this.selectIntervalXpath;
}
}
And an example of Service class (that handle all tags service provided on .xml)
public class Service extends Operation {
private static final Logger log = Logger.getLogger(Service.class);
#Override
public void schedule(Node document) {
log.debug("Scheduling Service");
long interval = Long.parseLong(this.selectIntervalXpath.evaluateAsString(document));
this.taskScheduler.scheduleAtFixedRate(new ServiceRunner(), interval);
}
private class ServiceRunner implements Runnable {
public void run() {
log.debug("Running...");
}
}
}
Now to continue my flow i will need to find a way to redirect the output of each job to Spring Integration (applicationContext.xml).

Getting Exception when used Spring Integration with Atomikos for transaction(JMS and DB)

I am getting following exception when used atomikos transaction manager with spring integration
14:36:18.182 DEBUG [main][org.springframework.integration.jms.JmsSendingMessageHandler] org.springframework.integration.jms.JmsSendingMessageHandler#0 received message: [Payload=EmployeeRecord{name='Rmex123', address=Phoenix, AZ}][Headers={timestamp=1403732178182, id=95b13ba2-3b22-4724-8d8d-d3d98c39a694}]
14:36:18.241 WARN [main][com.atomikos.jms.ConsumerProducerSupport] atomikos MessageProducer proxy for ActiveMQMessageProducer { value=ID:PHXJ05376352-13260-1403732176990-1:1:2:1 }: The JMS session you are using requires a JTA transaction context for the calling thread and none was found.
Please correct your code to do one of the following:
1. start a JTA transaction if you want your JMS operations to be subject to JTA commit/rollback, or
2. increase the maxPoolSize of the AtomikosConnectionFactoryBean to avoid transaction timeout while waiting for a connection, or
3. create a non-transacted session and do session acknowledgment yourself, or
4. set localTransactionMode to true so connection-level commit/rollback are enabled.
14:36:18.242 WARN [main][com.atomikos.jms.AtomikosTransactionRequiredJMSException] The JMS session you are using requires a JTA transaction context for the calling thread and none was found.
Please correct your code to do one of the following:
1. start a JTA transaction if you want your JMS operations to be subject to JTA commit/rollback, or
2. increase the maxPoolSize of the AtomikosConnectionFactoryBean to avoid transaction timeout while waiting for a connection, or
3. create a non-transacted session and do session acknowledgment yourself, or
4. set localTransactionMode to true so connection-level commit/rollback are enabled.
Exception in thread "main" org.springframework.integration.MessageHandlingException: error occurred in message handler [org.springframework.integration.jms.JmsSendingMessageHandler#0]
at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:79)
Am I missing something here?
Do i need to start a JTA transaction explicitly
Please help to resolve this
<context:component-scan base-package="com.mycompany.poc.sif" />
<int:publish-subscribe-channel id="reqChannel"/>
<int:channel id="jmsChannel" />
<int:service-activator input-channel="inChannel" ref="serviceHandler" output-channel="inUnmarshalChannel" />
<!-- To convert incoming XML to EmployeeRecord -->
<int-xml:unmarshalling-transformer unmarshaller="unMarshaller" input-channel="inUnmarshalChannel" output-channel="reqChannel"/>
<!-- To perform Database insert -->
<jdbc:outbound-channel-adapter channel="reqChannel" query="insert into EMPLOYEERECORD(name,address) values (:payload.name, :payload.address)" data-source="atomikos.dataSource" />
<!-- To perform JMS Queue send -->
<int:object-to-string-transformer input-channel="reqChannel" output-channel="jmsChannel"/>
<jms:outbound-channel-adapter id="jms" jms-template="jmsTemplate" channel="jmsChannel" />
<!-- To perform BG check Service Call -->
<int:transformer ref="bgCheckTransformerBean" input-channel="reqChannel" output-channel="headerChannel"/>
<ws:header-enricher input-channel="headerChannel" output-channel="wsChannel">
<ws:soap-action value="http://www.example.org/wspBackGroundcheckService/backGroundCheck" />
</ws:header-enricher>
<ws:outbound-gateway id="bgcheckGateway" request-channel="wsChannel" reply-channel="outChannel"
marshaller="jaxbMarshaller" unmarshaller="jaxbMarshaller" uri="http://host1:3057/BackGroundcheckService" />
<int:header-filter header-names="ws_soapAction" input-channel="outChannel" output-channel="respChannel" />
<int:transformer ref="responseTransformerBean" input-channel="respChannel" output-channel="endChannel"/>
<!-- Bean definitions -->
<beans:bean id="serviceHandler" class="com.mycompany.poc.sif.service.EmpOnboardService" />
<beans:bean id="jaxbMarshaller"
class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<beans:property name="contextPaths"
value="org.example.backgroundcheckservice" />
<beans:property name="checkForXmlRootElement" value="false" />
</beans:bean>
<beans:bean id="unMarshaller"
class="org.springframework.oxm.castor.CastorMarshaller">
<beans:property name="mappingLocation" value="classpath:mapping.xml" />
</beans:bean>
<beans:bean id="payloadTransformerBean"
class="com.mycompany.poc.sif.transformer.PayloadTransformer" />
<beans:bean id="bgCheckTransformerBean"
class="com.mycompany.poc.sif.transformer.BGCheckTransformer" />
<beans:bean id="responseTransformerBean"
class="com.mycompany.poc.sif.transformer.ResponseTransformer" />
<beans:bean id="db2.datasource" class="com.ibm.db2.jcc.DB2XADataSource">
<beans:property name="serverName" value="hostname" />
<beans:property name="portNumber" value="1234" />
<beans:property name="databaseName" value="ADB" />
<beans:property name="driverType" value="4" />
<beans:property name="user" value="user" />
<beans:property name="password" value="passwd" />
</beans:bean>
<!-- Define JMS template -->
<beans:bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<beans:property name="connectionFactory" ref="atomikos.connectionFactory"></beans:property>
<beans:property name="defaultDestination" ref="requestQueue"></beans:property>
<beans:property name="sessionTransacted" value="true"></beans:property>
</beans:bean>
<beans:bean id="requestQueue" class="org.apache.activemq.command.ActiveMQQueue">
<beans:constructor-arg value="queue.sif"/>
</beans:bean>
<!-- Define Transaction Manager and User Transaction -->
<beans:bean id="jta.transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
<beans:property name="transactionManager" ref="atomikos.transactionManager"/>
<beans:property name="userTransaction" ref="atomikos.userTransaction"/>
</beans:bean>
<!-- javax.transaction.TransactionManager -->
<beans:bean id="atomikos.transactionManager" class="com.atomikos.icatch.jta.UserTransactionManager"
init-method="init" destroy-method="close">
<beans:property name="forceShutdown" value="false"/>
</beans:bean>
<!-- javax.transaction.UserTransaction -->
<beans:bean id="atomikos.userTransaction"
class="com.atomikos.icatch.jta.UserTransactionImp">
<beans:property name="transactionTimeout" value="3000"/>
</beans:bean>
<!--Wrap the JMS here-->
<!-- Atomikos JTA configuration, nothing specific to Spring here -->
<beans:bean id="atomikos.connectionFactory" class="com.atomikos.jms.AtomikosConnectionFactoryBean"
init-method="init" destroy-method="close">
<beans:property name="uniqueResourceName" value="xa.activemq"/>
<beans:property name="xaConnectionFactory" ref="xa.connectionFactory"/>
<beans:property name="localTransactionMode" value="false"/>
<!-- XAConnectionFactory -->
<beans:property name="maxPoolSize" value="10"/>
</beans:bean>
<beans:bean id="xa.connectionFactory" class="org.apache.activemq.ActiveMQXAConnectionFactory">
<beans:property name="brokerURL" value="tcp://localhost:61616"/>
<beans:property name="userName" value="admin"/>
<beans:property name="password" value="admin"/>
</beans:bean>
<!-- Wrap the DB datasources-->
<beans:bean id="atomikos.dataSource" class="com.atomikos.jdbc.AtomikosDataSourceBean">
<beans:property name="uniqueResourceName" value="xa.db2"/>
<beans:property name="xaDataSource" ref="db2.datasource"/>
<!-- XADataSource -->
</beans:bean>
<stream:stdout-channel-adapter id="endChannel" />
Error
:16:14.486 DEBUG [main][org.springframework.integration.channel.DirectChannel] preSend on channel 'inUnmarshalChannel', message: [Payload=Rmex123Phoenix, AZ][Headers={timestamp=1403738174485, id=5cdf38dc-1c45-4392-a7c7-7b2caf586701}]
16:16:14.486 DEBUG [main][org.springframework.integration.transformer.MessageTransformingHandler] org.springframework.integration.transformer.MessageTransformingHandler#0 received message: [Payload=Rmex123Phoenix, AZ][Headers={timestamp=1403738174485, id=5cdf38dc-1c45-4392-a7c7-7b2caf586701}]
16:16:14.496 DEBUG [main][org.springframework.integration.transformer.MessageTransformingHandler] handler 'org.springframework.integration.transformer.MessageTransformingHandler#0' sending reply Message: [Payload=EmployeeRecord{name='Rmex123', address=Phoenix, AZ}][Headers={timestamp=1403738174496, id=93d53947-5564-4bf1-bc7c-a4471c185b88}]
16:16:14.496 DEBUG [main][org.springframework.integration.channel.PublishSubscribeChannel] preSend on channel 'reqChannel', message: [Payload=EmployeeRecord{name='Rmex123', address=Phoenix, AZ}][Headers={timestamp=1403738174496, id=93d53947-5564-4bf1-bc7c-a4471c185b88}]
16:16:14.496 DEBUG [main][org.springframework.integration.jdbc.JdbcMessageHandler] org.springframework.integration.jdbc.JdbcMessageHandler#0 received message: [Payload=EmployeeRecord{name='Rmex123', address=Phoenix, AZ}][Headers={timestamp=1403738174496, id=93d53947-5564-4bf1-bc7c-a4471c185b88}]
16:16:14.517 WARN [main][com.atomikos.jdbc.AbstractDataSourceBean] AtomikosDataSoureBean 'xa.db2': poolSize equals default - this may cause performance problems!
16:16:15.758 DEBUG [main][org.springframework.integration.jdbc.JdbcMessageHandler] Generated keys: [{UPDATED=1}]
16:16:15.758 DEBUG [main][org.springframework.integration.transformer.MessageTransformingHandler] org.springframework.integration.transformer.MessageTransformingHandler#1 received message: [Payload=EmployeeRecord{name='Rmex123', address=Phoenix, AZ}][Headers={timestamp=1403738174496, id=93d53947-5564-4bf1-bc7c-a4471c185b88}]
16:16:15.758 DEBUG [main][org.springframework.integration.transformer.MessageTransformingHandler] handler 'org.springframework.integration.transformer.MessageTransformingHandler#1' sending reply Message: [Payload=EmployeeRecord{name='Rmex123', address=Phoenix, AZ}][Headers={timestamp=1403738175758, id=809a9316-3c1d-474c-879f-eddbbb82fb2f}]
16:16:15.758 DEBUG [main][org.springframework.integration.channel.DirectChannel] preSend on channel 'jmsChannel', message: [Payload=EmployeeRecord{name='Rmex123', address=Phoenix, AZ}][Headers={timestamp=1403738175758, id=809a9316-3c1d-474c-879f-eddbbb82fb2f}]
16:16:15.758 DEBUG [main][org.springframework.integration.jms.JmsSendingMessageHandler] org.springframework.integration.jms.JmsSendingMessageHandler#0 received message: [Payload=EmployeeRecord{name='Rmex123', address=Phoenix, AZ}][Headers={timestamp=1403738175758, id=809a9316-3c1d-474c-879f-eddbbb82fb2f}]
16:16:15.809 WARN [main][com.atomikos.jms.ConsumerProducerSupport] atomikos MessageProducer proxy for ActiveMQMessageProducer { value=ID:PHXJ05376352-15248-1403738173579-1:1:2:1 }: The JMS session you are using requires a JTA transaction context for the calling thread and none was found.
Please correct your code to do one of the following:
1. start a JTA transaction if you want your JMS operations to be subject to JTA commit/rollback, or
2. increase the maxPoolSize of the AtomikosConnectionFactoryBean to avoid transaction timeout while waiting for a connection, or
3. create a non-transacted session and do session acknowledgment yourself, or
4. set localTransactionMode to true so connection-level commit/rollback are enabled.
16:16:15.809 WARN [main][com.atomikos.jms.AtomikosTransactionRequiredJMSException] The JMS session you are using requires a JTA transaction context for the calling thread and none was found.
Please correct your code to do one of the following:
1. start a JTA transaction if you want your JMS operations to be subject to JTA commit/rollback, or
2. increase the maxPoolSize of the AtomikosConnectionFactoryBean to avoid transaction timeout while waiting for a connection, or
3. create a non-transacted session and do session acknowledgment yourself, or
4. set localTransactionMode to true so connection-level commit/rollback are enabled.
Exception in thread "main" org.springframework.integration.MessageHandlingException: error occurred in message handler [org.springframework.integration.jms.JmsSendingMessageHandler#0]
at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:79)
at org.springframework.integration.dispatcher.UnicastingDispatcher.doDispatch(UnicastingDispatcher.java:115)
at org.springframework.integration.dispatcher.UnicastingDispatcher.dispatch(UnicastingDispatcher.java:102)
at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:77)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:157)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:128)
at org.springframework.integration.core.MessagingTemplate.doSend(MessagingTemplate.java:288)
at org.springframework.integration.core.MessagingTemplate.send(MessagingTemplate.java:149)
at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.sendMessage(AbstractReplyProducingMessageHandler.java:216)
at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.sendReplyMessage(AbstractReplyProducingMessageHandler.java:200)
at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.produceReply(AbstractReplyProducingMessageHandler.java:165)
at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.handleResult(AbstractReplyProducingMessageHandler.java:159)
at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.handleMessageInternal(AbstractReplyProducingMessageHandler.java:141)
at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:73)
at org.springframework.integration.dispatcher.BroadcastingDispatcher.invokeHandler(BroadcastingDispatcher.java:121)
at org.springframework.integration.dispatcher.BroadcastingDispatcher.dispatch(BroadcastingDispatcher.java:112)
at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:77)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:157)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:128)
at org.springframework.integration.core.MessagingTemplate.doSend(MessagingTemplate.java:288)
at org.springframework.integration.core.MessagingTemplate.send(MessagingTemplate.java:149)
at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.sendMessage(AbstractReplyProducingMessageHandler.java:216)
at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.sendReplyMessage(AbstractReplyProducingMessageHandler.java:200)
at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.produceReply(AbstractReplyProducingMessageHandler.java:165)
at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.handleResult(AbstractReplyProducingMessageHandler.java:159)
at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.handleMessageInternal(AbstractReplyProducingMessageHandler.java:141)
at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:73)
at org.springframework.integration.dispatcher.UnicastingDispatcher.doDispatch(UnicastingDispatcher.java:115)
at org.springframework.integration.dispatcher.UnicastingDispatcher.dispatch(UnicastingDispatcher.java:102)
at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:77)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:157)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:128)
at org.springframework.integration.core.MessagingTemplate.doSend(MessagingTemplate.java:288)
at org.springframework.integration.core.MessagingTemplate.send(MessagingTemplate.java:149)
at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.sendMessage(AbstractReplyProducingMessageHandler.java:216)
at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.sendReplyMessage(AbstractReplyProducingMessageHandler.java:200)
at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.produceReply(AbstractReplyProducingMessageHandler.java:165)
at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.handleResult(AbstractReplyProducingMessageHandler.java:159)
at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.handleMessageInternal(AbstractReplyProducingMessageHandler.java:141)
at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:73)
at org.springframework.integration.dispatcher.UnicastingDispatcher.doDispatch(UnicastingDispatcher.java:115)
at org.springframework.integration.dispatcher.UnicastingDispatcher.dispatch(UnicastingDispatcher.java:102)
at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:77)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:157)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:128)
at com.amex.poc.sif.main.TransactionTestApp.main(TransactionTestApp.java:29)
Caused by: org.springframework.jms.UncategorizedJmsException: Uncategorized exception occured during JMS processing; nested exception is com.atomikos.jms.AtomikosTransactionRequiredJMSException: The JMS session you are using requires a JTA transaction context for the calling thread and none was found.
Please correct your code to do one of the following:
1. start a JTA transaction if you want your JMS operations to be subject to JTA commit/rollback, or
2. increase the maxPoolSize of the AtomikosConnectionFactoryBean to avoid transaction timeout while waiting for a connection, or
3. create a non-transacted session and do session acknowledgment yourself, or
4. set localTransactionMode to true so connection-level commit/rollback are enabled.
at org.springframework.jms.support.JmsUtils.convertJmsAccessException(JmsUtils.java:316)
at org.springframework.jms.support.JmsAccessor.convertJmsAccessException(JmsAccessor.java:169)
at org.springframework.jms.core.JmsTemplate.execute(JmsTemplate.java:494)
at org.springframework.jms.core.JmsTemplate.send(JmsTemplate.java:566)
at org.springframework.jms.core.JmsTemplate.convertAndSend(JmsTemplate.java:689)
at org.springframework.jms.core.JmsTemplate.convertAndSend(JmsTemplate.java:677)
at org.springframework.integration.jms.JmsSendingMessageHandler.send(JmsSendingMessageHandler.java:145)
at org.springframework.integration.jms.JmsSendingMessageHandler.handleMessageInternal(JmsSendingMessageHandler.java:112)
at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:73)
... 45 more
Caused by: com.atomikos.jms.AtomikosTransactionRequiredJMSException: The JMS session you are using requires a JTA transaction context for the calling thread and none was found.
Please correct your code to do one of the following:
1. start a JTA transaction if you want your JMS operations to be subject to JTA commit/rollback, or
2. increase the maxPoolSize of the AtomikosConnectionFactoryBean to avoid transaction timeout while waiting for a connection, or
3. create a non-transacted session and do session acknowledgment yourself, or
4. set localTransactionMode to true so connection-level commit/rollback are enabled.
at com.atomikos.jms.AtomikosTransactionRequiredJMSException.throwAtomikosTransactionRequiredJMSException(AtomikosTransactionRequiredJMSException.java:40)
at com.atomikos.jms.ConsumerProducerSupport.enlist(ConsumerProducerSupport.java:112)
at com.atomikos.jms.AtomikosJmsMessageProducerProxy.send(AtomikosJmsMessageProducerProxy.java:52)
at com.atomikos.jms.AtomikosJmsMessageProducerProxy.send(AtomikosJmsMessageProducerProxy.java:133)
at org.springframework.jms.core.JmsTemplate.doSend(JmsTemplate.java:633)
at org.springframework.jms.core.JmsTemplate.doSend(JmsTemplate.java:604)
at org.springframework.jms.core.JmsTemplate$3.doInJms(JmsTemplate.java:569)
at org.springframework.jms.core.JmsTemplate.execute(JmsTemplate.java:491)
... 51 more
This is my main Method from which i pass the message to channel
************************************************************
public static void main(String[] args) {
final String[] configFiles = {"/META-INF/spring/integration/spring-integration-context-standalone.xml"
};
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext(configFiles,TransactionTestApp.class);
BeanFactoryChannelResolver channelResolver = new BeanFactoryChannelResolver(context);
// Compose the XML message according to the server's schema
String requestXml =
""
+"Rat123"
+"Phoenix, AZ"
+"";
// Create the Message object
//org.springframework.integration.Message message =MessageBuilder.withPayload(requestXml).build();
org.springframework.integration.Message message = MessageBuilder.withPayload(requestXml).build();
// Send the Message to the handler's input channel
org.springframework.integration.MessageChannel channel = channelResolver.resolveChannelName("inChannel");
channel.send((org.springframework.integration.Message) message);
}
You need to start the transaction.
Instead of simply sending the message to inChannel, consider using a Messaging Gateway; annotate it as #Transactional and the framework will start the transaction.
If you must send to the channel, do it within a TransactionTemplate.execute() method.
EDIT:
If the flow starts with a polled inbound adapter, mark the poller with <transactional/>.
If the flow starts with a non-transactional message-driven adapter (e.g., WS, HTTP) you need to insert a transactional gateway to scope the transaction...
public interface TxGate {
#Transactional
Message<?> exchange(Message<?> message);
}
<int-ws:inbound-gateway ... requestChannel="startTx" ... />
<int:service-activator input-channel="startTx" ref="txGate" />
<int:gateway id="txGate" request-channel="onward" service=interface="foo.TxGate" />
Error when tried to do the above
*************************************\
15:09:03.664 INFO [main][org.springframework.integration.gateway.GatewayProxyFactoryBean$MethodInvocationGateway] started onboardService
15:09:03.664 INFO [main][org.springframework.integration.gateway.GatewayProxyFactoryBean] started onboardService
15:09:03.695 DEBUG [main][org.springframework.integration.util.MessagingMethodInvokerHelper] Method [public final void com.sun.proxy.$Proxy21.addAdvice(int,org.aopalliance.aop.Advice) throws org.springframework.aop.framework.AopConfigException] is not eligible for Message handling.
java.lang.IllegalArgumentException: Found more than one parameter type candidate: [int] and [org.aopalliance.aop.Advice]
at org.springframework.util.Assert.isNull(Assert.java:89)
at org.springframework.integration.util.MessagingMethodInvokerHelper$HandlerMethod.setExclusiveTargetParameterType(MessagingMethodInvokerHelper.java:624)
at org.springframework.integration.util.MessagingMethodInvokerHelper$HandlerMethod.generateExpression(MessagingMethodInvokerHelper.java:558)
at org.springframework.integration.util.MessagingMethodInvokerHelper$HandlerMethod.(MessagingMethodInvokerHelper.java:440)
at org.springframework.integration.util.MessagingMethodInvokerHelper$1.doWith(MessagingMethodInvokerHelper.java:302)
at org.springframework.util.ReflectionUtils.doWithMethods(ReflectionUtils.java:480)
at org.springframework.integration.util.MessagingMethodInvokerHelper.findHandlerMethodsForTarget(MessagingMethodInvokerHelper.java:276)
at org.springframework.integration.util.MessagingMethodInvokerHelper.(MessagingMethodInvokerHelper.java:169)
at org.springframework.integration.util.MessagingMethodInvokerHelper.(MessagingMethodInvokerHelper.java:121)
at org.springframework.integration.util.MessagingMethodInvokerHelper.(MessagingMethodInvokerHelper.java:116)
at org.springframework.integration.handler.MethodInvokingMessageProcessor.(MethodInvokingMessageProcessor.java:56)
at org.springframework.integration.handler.ServiceActivatingHandler.(ServiceActivatingHandler.java:35)
at org.springframework.integration.config.ServiceActivatorFactoryBean.createMethodInvokingHandler(ServiceActivatorFactoryBean.java:48)
at org.springframework.integration.config.AbstractStandardMessageHandlerFactoryBean.createHandler(AbstractStandardMessageHandlerFactoryBean.java:72)
at org.springframework.integration.config.AbstractSimpleMessageHandlerFactoryBean.createHandlerInternal(AbstractSimpleMessageHandlerFactoryBean.java:99)
at org.springframework.integration.config.AbstractSimpleMessageHandlerFactoryBean.getObject(AbstractSimpleMessageHandlerFactoryBean.java:81)
Adding method="exchange" to the service activator should solve this.

Threading issues with Hibernate

I'm experiencing a strange behaviour with Hibernate. I've been banging my head against the wall for a while now, and will award any answer which leads to a solution with a +100 bounty.
I have a JAX-RS (Jersey) REST server, with a filter that associates one Hibernate-session per request.
In one request a client POSTs some data which is stored in the database using one session (and one transaction). In a subsequent call, the client tries to GET this entity, but Hibernate can't find it.
Some observations:
I can only reproduce this if I run multiple simultaneous clients. I've never managed to reproduce it by running one client at a time.)
I can see the entity ID in the database, and if I restart the server, the entity is found by Hibernate as it should.
The error does not occur if I use a thread pool of size 1 (regardless of how many clients I run simultaneously).
Here's the code, with some logging:
chargeables.setId(new SecureRandom().nextLong());
System.out.printf("%s, session: %s [%s]%n",
Thread.currentThread(),
System.identityHashCode(session),
"session.beginTransaction()");
session.beginTransaction();
System.out.printf("%s, session: %s [%s]%n",
Thread.currentThread(),
System.identityHashCode(session),
"session.save(id = "+chargeables.getId()+")");
session.save(chargeables);
System.out.printf("%s, session: %s [%s]%n",
Thread.currentThread(),
System.identityHashCode(session),
"session.getTransaction().commit()");
session.getTransaction().commit();
The code for getting the entity:
System.out.printf("%s, session: %s [%s]%n",
Thread.currentThread(),
System.identityHashCode(session),
"session.get("+id+")");
Chargeables entity = (Chargeables) session.get(Chargeables.class, id);
if (entity == null)
System.out.printf("%s, session: %s [%s]%n",
Thread.currentThread(),
System.identityHashCode(session),
"ENTITY NOT FOUND!");
Now here is an excerpt of the resulting log (with some additional open/close session output):
Thread[Grizzly(5),5,main], session: 2041842357 [factory.openSession()]
Thread[Grizzly(5),5,main], session: 2041842357 [session.beginTransaction()]
Thread[Grizzly(5),5,main], session: 2041842357 [session.save(id = 7939229356942262438)]
Thread[Grizzly(5),5,main], session: 2041842357 [session.getTransaction().commit()]
Thread[Grizzly(5),5,main], session: 2041842357 [session.close()]
[...]
Thread[Grizzly(7),5,main], session: 1717445911 [factory.openSession()]
Thread[Grizzly(7),5,main], session: 1717445911 [session.get(7939229356942262438)]
Thread[Grizzly(7),5,main], session: 1717445911 [ENTITY NOT FOUND!]
Thread[Grizzly(7),5,main], session: 1717445911 [session.close()]
Why on earth do I reach ENTITY NOT FOUND!?
Hibernate version: 4.1.9.Final
MySQL verison: 14.14 Distrib 5.5.29
Mapping file for Chargeables:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping
default-cascade="all"
package="se.package.common.chargeables"
default-lazy="false">
<class name="Chargeables">
<id name="id" type="long">
<generator class="assigned"/>
</id>
<property name="startTimeStamp" />
<property name="endTimeStamp" />
<list name="chargeables">
<key column="chargeableId" />
<list-index column="pos" />
<many-to-many class="Chargeable"/>
</list>
</class>
<class name="Chargeable">
<id column="id" type="long">
<generator class="native"/>
</id>
<discriminator />
<property name="timestamp" />
</class>
<subclass name="DataTransfer" extends="Chargeable">
<property name="bytesSent" />
<property name="bytesReceived" />
</subclass>
<subclass name="TelephonyChargeable" extends="Chargeable">
<many-to-one name="num" />
</subclass>
<subclass name="Call" extends="TelephonyChargeable">
<property name="duration" />
</subclass>
<subclass name="OutgoingCall" extends="Call" />
<subclass name="IncomingCall" extends="Call" />
<subclass name="Message" extends="TelephonyChargeable" />
<subclass name="Sms" extends="Message" />
<subclass name="IncomingSms" extends="Sms" />
<subclass name="OutgoingSms" extends="Sms" />
<subclass name="Mms" extends="Message" />
<subclass name="IncomingMms" extends="Mms" />
<subclass name="OutgoingMms" extends="Mms" />
</hibernate-mapping>
IMHO it's an isolation problem. Your second session start before the transaction of the 1st one is commited. As default hibernate isolation level is read_commited, the 2nd session can't so retrieve the entity. How are you passing id between the 2 threads ?
If you can see the commit in the database, it cannot be an isolation issue at the MySQL level: console operations are also client operations, you don't get special powers when running them, so they conform to the isolation policy you selected.
Looking out for solution, I discovered that Hibernate provide some facilities to cache DB results: there are actually 2 levels of cache implemented there. Perhaps your hibernate installation comes bundled with a cache mechanism?
The first level works on a per session basis, which is consistent with the behaviour you observe when running the code on one thread, and seemingly happens to be activated by default. I am not Hibernate proficient, I can't say that for sure, but my opinion is that your setup has this first level of cache set in read-only mode, while you would like it to be in read-write mode.

Resources