I'm new to WebSphere and am trying to host a simple website that I can log into using an Oracle database.
I can get to my website, but when I try and log in I get the following warning and am not able to log in:
[WARNING ] Detected JSESSIONID with invalid length; expected length of 23, found 28, setting: 99D3CCB2FF585D3B3E80293BFA1C to null.
[WARNING ] HHH000183: no persistent classes found for query class: select a FROM com.model.User a where username = 'user'
No entity found for query
The warning no persistent classes found for query class: is being thrown when I try and create the query to log in inside of my CommonServiceImple.java:
Query query = getEntityManager().createQuery("select a FROM " + className + " a where username = '" + username + "'");
The No entity found for query is caused in the next line trying to run the query. This is because the query object is null because of the previous warning: Object obj = query.getSingleResult();.
server.xml
<dataSource id="jdbc/test" jndiName="jdbc/test" type="javax.sql.DataSource">
<jdbcDriver id="oracle-driver" libraryRef="oracle-lib">
<library></library>
</jdbcDriver>
<connectionManager id="ConnectionManager" minPoolSize="1" numConnectionsPerThreadLocal="10"/>
<properties.oracle URL="jdbc:oracle:thin:#crappie.ddvc.local:1521:STILOG" password="password" user="user"/>
</dataSource>
<library id="oracle-lib">
<fileset dir="C:/Users/user/workspace/WebAdmin/WebContent/WEB-INF/lib/" includes="ojdbc6.jar"/>
</library>
web.xml
<resource-ref>
<description>DataSource</description>
<res-ref-name>jdbc/test</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
<res-sharing-scope>Shareable</res-sharing-scope>
<mapped-name>jdbc/test</mapped-name>
</resource-ref>
ibm-web-bnd.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-bnd
xmlns="http://websphere.ibm.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://websphere.ibm.com/xml/ns/javaee http://websphere.ibm.com/xml/ns/javaee/ibm-web-bnd_1_0.xsd"
version="1.0">
<virtual-host name="default_host" />
<resource-ref name="jdbc/test" binding-name="jdbc/test"/>
</web-bnd>
persistence.xml
<persistence 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"
version="1.0">
<persistence-unit name="pu1">
</persistence-unit>
</persistence>
applicationContext.xml
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.0.xsd">
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
<bean id="commonService" class="com.service.CommonServiceImpl"/>
<bean id="mainMenuService" class="com.service.MainMenuServiceImpl"/>
<bean id="storeFilterService" class="com.service.StoreFilterServiceImpl"/>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="database" value="ORACLE" />
<property name="showSql" value="true" />
</bean>
</property>
<property name="persistenceUnitManager" ref="pum"/>
<property name="persistenceUnitName" value="pu1" />
<property name="jpaProperties">
<props>
<prop key="org.hibernate.envers.store_data_at_delete">true</prop>
</props>
</property>
</bean>
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>jdbc/test</value>
</property>
<property name="cache"
value="true"/>
<property name="lookupOnStartup"
value="true"/>
<property name="resourceRef"
value="true"/>
</bean>
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
<bean id="pum"
class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager">
<property name="persistenceXmlLocations">
<list>
<value>classpath:META-INF/persistence.xml</value>
</list>
</property>
<property name="defaultDataSource" ref="dataSource"></property>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="loginAction" scope="prototype" class="com.action.LoginAction">
<constructor-arg ref="commonService" />
</bean>
<bean id="userAction" scope="prototype" class="com.action.UserAction">
<constructor-arg ref="commonService" />
</bean>
</beans>
Nothing interesting in User.java
#Entity
#Table(name="WEB_PAGE_USERS")
public class User {
#Id
#GeneratedValue(strategy=GenerationType.AUTO, generator="seq")
#SequenceGenerator(name="seq", sequenceName="WEB_PAGE_USERS_ID_SEQ")
private Integer id;
private String username;
private String password;
private String name;
//...
}
Or the ComonServiceImpl.java
#Transactional
public class CommonServiceImpl implements CommonService{
private EntityManager em;
#PersistenceContext(unitName="pu1")
public void setEntityManager(EntityManager em) {
this.em = em;
}
// MTD added for explicit order by
#SuppressWarnings("unchecked")
public List<Object> findAll(String name) {
getEntityManager().clear();
String sql = "select a FROM " + name + " a";
Query query = getEntityManager().createQuery(sql);
return query.getResultList();
}
//...(other sql selects, updates, inserts)
}
LoginAction.java
public class LoginAction extends ActionSupport {
private static final long serialVersionUID = 1L;
private CommonService service;
private String username;
private String password;
private String environment;
public LoginAction(CommonService service) {
this.service = service;
}
public String execute() throws Exception {
return Action.SUCCESS;
}
#SuppressWarnings({ "unchecked", "static-access" })
public String login() throws Exception {
//Encrypt input password
CEncrypt cEncrypt = new CEncrypt();
String encryptedPwd = cEncrypt.encryptString(password);
//Get user by Username
User user = (User) service.findUser(username, User.class.getName());
//Check if input password is the same as the password in the database & login
if (user!=null && user.getPassword().equals(encryptedPwd)) {
#SuppressWarnings("rawtypes")
Map session = ActionContext.getContext().getSession();
session.put("logged-in","true");
session.put("loggedIn", "true");
session.put("WebAdminUserID", user.getUsername());
session.put("WebAdminUsername", user.getName());
session.put("WebAdminID", user.getRole_id());
return Action.SUCCESS;
} else {
return Action.ERROR;
}
}
//...
}
UPDATE
I was able to test my connection to the datasource by manually calling the lookup. But since my website is built on the persistence unit I would like to fix that error instead of re-writing the project to call the connection directly like this:
public String getEnvironment() {
try
{
Context initCtx = new InitialContext();
Context envCtx = (Context) initCtx.lookup("java:comp/env");
DataSource test = (DataSource)envCtx.lookup("jdbc/test");
Connection con = test.getConnection();
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("select * from WEB_PAGE_USERS where username = 'user'");
while(rs.next()){
System.out.println("username="+rs.getString("username")+", password="+rs.getString("password")+", role id="+rs.getString("role_id"));
}
// environment = "[" + (String)envCtx.lookup("Environment") + "]";
} catch (Exception e)
{
System.out.println("Environment Exception: " + e.getMessage());
}
return environment;
}
Which does return the correct data username=user, password=password, role id=1
To fix my answer I had to add every model class I had with the #Entity annotation to my persistence.xml file. It seems that even though I am using an entityManager I still needed to specify all of the #Entity classes (normally in Tomcat the entityManager would automatically find all of the classes).
Also I was getting that [WARNING ] Detected JSESSIONID with invalid length; expected length of 23, found 28, setting: 99D3CCB2FF585D3B3E80293BFA1C to null. warning which was causing my session to be cleared each time a page loaded (makes it hard to stay logged in). So I increased the length to 28 in the server.xml on WebSphere.
server.xml
<server description="new server">
<!-- Enable features -->
<featureManager>
<feature>jsp-2.2</feature>
<feature>jndi-1.0</feature>
<feature>jdbc-4.0</feature>
<feature>localConnector-1.0</feature>
<feature>servlet-3.0</feature>
<feature>jaxrs-1.1</feature>
</featureManager>
<!-- To access this server from a remote client add a host attribute to the following element, e.g. host="*" -->
<httpEndpoint host="localhost" httpPort="9080" httpsPort="9443" id="defaultHttpEndpoint"/>
<dataSource id="jdbc/test" jndiName="jdbc/test" type="javax.sql.DataSource">
<jdbcDriver id="oracle-driver" libraryRef="oracle-lib"/>
<connectionManager id="ConnectionManager" minPoolSize="1" numConnectionsPerThreadLocal="10"/>
<properties.oracle URL="jdbc:oracle:thin:#crappie.local:1521:STILOG" password="password" user="user"/>
</dataSource>
<library id="oracle-lib">
<fileset dir="C:/Users/user/workspace/WebAdmin/WebContent/WEB-INF/lib/" includes="ojdbc6.jar"/>
</library>
<applicationMonitor updateTrigger="mbean"/>
<webApplication id="WebAdmin" location="WebAdmin.war" name="WebAdmin"/>
<httpSession idLength="28"></httpSession>
</server>
persistence.xml
<persistence 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"
version="1.0">
<persistence-unit name="pu1">
<class>com.model.App</class>
<class>com.model.AudioType</class>
<class>com.model.AuditRevisionEntity</class>
<class>com.model.ClosedGroup</class>
<class>com.model.ClosedSchedule</class>
<class>com.model.ClosedScheduleGroup</class>
<class>com.model.Department</class>
<class>com.model.Dnis</class>
<class>com.model.DnisVoiceTalent</class>
<class>com.model.GlobalXferGroupTemplate</class>
<class>com.model.Language</class>
<class>com.model.Location</class>
<class>com.model.MainMenu</class>
<class>com.model.NameValue</class>
<class>com.model.NameValueFunction</class>
<class>com.model.NameValueType</class>
<class>com.model.Peg</class>
<class>com.model.PegType</class>
<class>com.model.PharmacyConfig</class>
<class>com.model.Promo</class>
<class>com.model.PromoMessage</class>
<class>com.model.PromoSchedule</class>
<class>com.model.PromoType</class>
<class>com.model.Role</class>
<class>com.model.Schedule</class>
<class>com.model.ScheduleHours</class>
<class>com.model.ScheduleRecording</class>
<class>com.model.ScheduleType</class>
<class>com.model.Server</class>
<class>com.model.SpecialSchedule</class>
<class>com.model.SpecialScheduleRecording</class>
<class>com.model.Store</class>
<class>com.model.StoreAudio</class>
<class>com.model.StoreClosedGroup</class>
<class>com.model.StoreDepartment</class>
<class>com.model.StorePromo</class>
<class>com.model.StoreSchedule</class>
<class>com.model.StoreSpcSchedule</class>
<class>com.model.StoreType</class>
<class>com.model.StoreXferGroup</class>
<class>com.model.SystemMaintenance</class>
<class>com.model.TargetSystem</class>
<class>com.model.Timezone</class>
<class>com.model.Title</class>
<class>com.model.User</class>
<class>com.model.UserWebPage</class>
<class>com.model.UserWebPageAccess</class>
<class>com.model.UserWebPageClassType</class>
<class>com.model.VoiceTalent</class>
</persistence-unit>
</persistence>
I'm working on a project using Struts, Spring and Hibernate. After clicking on a button, the Struts action leads me through a DS and DAO, in which I try to call a native query to update the DB. Here is the error trace:
javax.persistence.TransactionRequiredException: Executing an update/delete query
at org.hibernate.ejb.QueryImpl.executeUpdate(QueryImpl.java:48)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:79)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:618)
at org.springframework.orm.jpa.SharedEntityManagerCreator$DeferredQueryInvocationHandler.invoke(SharedEntityManagerCreator.java:310)
at $Proxy496.executeUpdate(Unknown Source)
at com.my.project.MyDAO.unsubscribe(MyDAO.java:307)
at com.my.project.MyDS.unsubscribe(MyDS.java:507)
at com.my.project.MyDS.updateValue(MyDS.java:784)
at com.my.project.MyAction.handleUpdate(MyAction.java:235)
MyDAO :
public class MyDAO extends
AbstractDAOGenericImpl<MyEntity> {
/** Entity Manager */
#PersistenceContext(unitName = "myPersistenceUnit")
private EntityManager entityManager;
#Transactional(readOnly = false, isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED, rollbackFor = {Exception.class})
public int unsubscribe(String entityId) throws JrafDaoException {
StringBuilder strQuery = new StringBuilder();
strQuery.append("update MYENTITY set SUBSCRIBE=:subscribe where ENTITY_ID=:entity_id");
final Query myQuery = getEntityManager().createNativeQuery(strQuery.toString(), MyEntity.class);
myQuery.setParameter("subscribe", "N");
myQuery.setParameter("entity_id", entityId);
try {
return myQuery.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
}
return 0;
}
}
In MyDS :
#Autowired
#Qualifier("MyDAO")
private MyDAO myDao;
#Transactional(readOnly = false, isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED, rollbackFor = {Exception.class})
public int unsubscribe(String entityId) throws JrafDomainException {
return myDao.unsubscribe(entityId);
}
MyAction :
public class MyAction extends DispatchAction {
private MyDS myDS;
// ...
private ActionForward handleUpdate(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
MyForm myForm = (MyForm) form;
myDS.unsubscribe(myForm.getEntityId());
}
}
And application-context-spring.xml :
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.5.xsd">
<!-- Enterprise layer's dependencies -->
<bean id="springLocator"
class="com.jraf.bootstrap.locator.SpringLocator">
</bean>
<!-- To precise the persistence configuration name file -->
<bean id="persistenceUnitManager"
class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager">
<property name="persistenceXmlLocations">
<list>
<value>/META-INF/persistence-web.xml</value>
</list>
</property>
</bean>
<!-- EntityManagerFactory definition : JPA one -->
<bean id="myEmf"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitManager"
ref="persistenceUnitManager" />
<property name="persistenceUnitName" value="myPersistenceUnit" />
</bean>
<!-- TransactionManager JPA one -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="myEmf" />
</bean>
<!-- EntityManagerFactory definition : JPA one -->
<bean id="myEmf2" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitManager" ref="persistenceUnitManager" />
<property name="persistenceUnitName" value="myPersistenceUnit2" />
</bean>
<!-- Transaction Manager definition : JPA one-->
<bean id="myTxManager2" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="myEmf2" />
</bean>
<!-- Enable annotation usage for transaction -->
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="corePoolSize" value="1" />
<property name="maxPoolSize" value="1" />
<property name="queueCapacity" value="1" />
</bean>
<bean id="myDS" class="com.my.internal.MyDS">
<property name="myDao" ref="MyDAO"/>
</bean>
<!-- Enable the annotation usage (bean injection for instance) -->
<context:annotation-config />
</beans>
I'm working on an existing project which is why the unsubscribe function already exists and uses a native query instead of a HQL one. But maybe I should use it instead...?
Thanks for your help.
I also faced the similar issue.
Adding
tx:annotation-driven transaction-manager="transactionManager"
to your spring context xml will resolve the issue.
I have configured CAS 4 / Spring Security / Active Directory and able to authenticate successfully.
But I have difficulty in to retrieve roles and later use that for authorisation.
I have the roles available after the authentication in CAS but I want to pass this to the service (web app) so that it can be used to check the authorisation (for eg. hasRole('ROLE_EDITOR') )
I think I am making some configuration mistake in the below beans which I investigating further. I have shown these configuration fragments.
bean 'casAuthenticationProvider' and the property 'authenticationUserDetailsService'
bean 'ldapAuthenticationHandler' -- 'principalAttributeMap' property
bean 'attributeRepository'
Server logs
2014-09-25 16:59:45,516 DEBUG [org.jasig.cas.authentication.LdapAuthenticationHandler] - <Found principal attribute: [displayName[James TAYLOR]]>
2014-09-25 16:59:45,516 DEBUG [org.jasig.cas.authentication.LdapAuthenticationHandler] - <Found principal attribute: [memberOf[CN=USERTOKEN,OU=GROUPS,OU=EGATE,DC=EGATE-T,DC=LOCAL, CN=ROLE_APP_NOTIFICA
TION,OU=GROUPS,OU=EGATE,DC=EGATE-T,DC=LOCAL, CN=ROLE_CIR_AUTHORISER,OU=GROUPS,OU=EGATE,DC=EGATE-T,DC=LOCAL, CN=ROLE_APP_SANCTIONS_DB,OU=GROUPS,OU=EGATE,DC=EGATE-T,DC=LOCAL, CN=ROLE_APP_COLLEGES,OU=GRO
UPS,OU=EGATE,DC=EGATE-T,DC=LOCAL, CN=ROLE_APP_CIR,OU=GROUPS,OU=EGATE,DC=EGATE-T,DC=LOCAL, CN=ROLE_CIR_EDITOR,OU=GROUPS,OU=EGATE,DC=EGATE-T,DC=LOCAL]]>
2014-09-25 16:59:45,519 INFO [org.jasig.cas.authentication.PolicyBasedAuthenticationManager] - <LdapAuthenticationHandler successfully authenticated taylorj+password>
2014-09-25 16:59:45,519 DEBUG [org.jasig.cas.authentication.principal.PersonDirectoryPrincipalResolver] - <Attempting to resolve a principal...>
2014-09-25 16:59:45,521 DEBUG [org.jasig.cas.authentication.principal.PersonDirectoryPrincipalResolver] - <Creating SimplePrincipal for [taylorj]>
2014-09-25 16:59:45,522 DEBUG [org.jasig.cas.persondir.LdapPersonAttributeDao] - <Created seed map='{username=[taylorj]}' for uid='taylorj'>
2014-09-25 16:59:45,522 DEBUG [org.jasig.cas.persondir.LdapPersonAttributeDao] - <Adding attribute 'uid' with value '[taylorj]' to query builder 'null'>
2014-09-25 16:59:45,522 DEBUG [org.jasig.cas.persondir.LdapPersonAttributeDao] - <Constructed LDAP search query [sAMAccountName=taylorj]>
2014-09-25 16:59:45,524 DEBUG [org.jasig.cas.persondir.LdapPersonAttributeDao] - <Generated query builder '[org.ldaptive.SearchFilter#-1419023406::filter=sAMAccountName={0}, parameters={0=taylorj}]' f
rom query Map {username=[taylorj]}.>
2014-09-25 16:59:45,527 DEBUG [org.ldaptive.SearchOperation] - <execute request=[org.ldaptive.SearchRequest#1241774557::baseDn=dc=egate-t,dc=local, searchFilter=[org.ldaptive.SearchFilter#-1419023406:
:filter=sAMAccountName={0}, parameters={0=taylorj}], returnAttributes=[], searchScope=null, timeLimit=0, sizeLimit=10, derefAliases=null, typesOnly=false, binaryAttributes=null, sortBehavior=UNORDERED
, searchEntryHandlers=null, searchReferenceHandlers=null, controls=null, followReferrals=false, intermediateResponseHandlers=null] with connection=[org.ldaptive.DefaultConnectionFactory$DefaultConnect
ion#511019109::config=[org.ldaptive.ConnectionConfig#1652971138::ldapUrl=ldap://eb2ts-app14, connectTimeout=3000, responseTimeout=-1, sslConfig=[org.ldaptive.ssl.SslConfig#1637458774::credentialConfig
=[org.ldaptive.ssl.X509CredentialConfig#-421683437::trustCertificates=classpath:root_CA_base64.cer, authenticationCertificate=null, authenticationKey=null], trustManagers=null, enabledCipherSuites=nul
l, enabledProtocols=null, handshakeCompletedListeners=null], useSSL=false, useStartTLS=false, connectionInitializer=null], providerConnectionFactory=[org.ldaptive.provider.jndi.JndiConnectionFactory#3
99139047::connectionCount=1, environment={java.naming.factory.initial=com.sun.jndi.ldap.LdapCtxFactory, com.sun.jndi.ldap.connect.timeout=3000, java.naming.ldap.version=3}, providerConfig=[org.ldaptiv
e.provider.jndi.JndiProviderConfig#1738533348::operationExceptionResultCodes=[PROTOCOL_ERROR, SERVER_DOWN], properties={}, connectionStrategy=DEFAULT, environment=null, tracePackets=null, removeDnUrls
=true, searchIgnoreResultCodes=[TIME_LIMIT_EXCEEDED, SIZE_LIMIT_EXCEEDED, PARTIAL_RESULTS], sslSocketFactory=null, hostnameVerifier=null, controlProcessor=org.ldaptive.provider.ControlProcessor#33b4ac
e2]], providerConnection=org.ldaptive.provider.jndi.JndiConnection#1ac243f3]>
2014-09-25 16:59:45,540 DEBUG [org.ldaptive.SearchOperation] - <execute response=[org.ldaptive.Response#370759675::result=[[]], resultCode=SUCCESS, message=null, matchedDn=null, responseControls=null,
referralURLs=[ldap://ForestDnsZones.EGATE-T.LOCAL/DC=ForestDnsZones,DC=EGATE-T,DC=LOCAL??base], messageId=-1] for request=[org.ldaptive.SearchRequest#1241774557::baseDn=dc=egate-t,dc=local, searchFil
ter=[org.ldaptive.SearchFilter#-1419023406::filter=sAMAccountName={0}, parameters={0=taylorj}], returnAttributes=[], searchScope=null, timeLimit=0, sizeLimit=10, derefAliases=null, typesOnly=false, bi
naryAttributes=null, sortBehavior=UNORDERED, searchEntryHandlers=null, searchReferenceHandlers=null, controls=null, followReferrals=false, intermediateResponseHandlers=null] with connection=[org.ldapt
ive.DefaultConnectionFactory$DefaultConnection#511019109::config=[org.ldaptive.ConnectionConfig#1652971138::ldapUrl=ldap://eb2ts-app14, connectTimeout=3000, responseTimeout=-1, sslConfig=[org.ldaptive
.ssl.SslConfig#1637458774::credentialConfig=[org.ldaptive.ssl.X509CredentialConfig#-421683437::trustCertificates=classpath:root_CA_base64.cer, authenticationCertificate=null, authenticationKey=null],
trustManagers=null, enabledCipherSuites=null, enabledProtocols=null, handshakeCompletedListeners=null], useSSL=false, useStartTLS=false, connectionInitializer=null], providerConnectionFactory=[org.lda
ptive.provider.jndi.JndiConnectionFactory#399139047::connectionCount=1, environment={java.naming.factory.initial=com.sun.jndi.ldap.LdapCtxFactory, com.sun.jndi.ldap.connect.timeout=3000, java.naming.l
dap.version=3}, providerConfig=[org.ldaptive.provider.jndi.JndiProviderConfig#1738533348::operationExceptionResultCodes=[PROTOCOL_ERROR, SERVER_DOWN], properties={}, connectionStrategy=DEFAULT, enviro
nment=null, tracePackets=null, removeDnUrls=true, searchIgnoreResultCodes=[TIME_LIMIT_EXCEEDED, SIZE_LIMIT_EXCEEDED, PARTIAL_RESULTS], sslSocketFactory=null, hostnameVerifier=null, controlProcessor=or
g.ldaptive.provider.ControlProcessor#33b4ace2]], providerConnection=org.ldaptive.provider.jndi.JndiConnection#1ac243f3]>
2014-09-25 16:59:45,546 DEBUG [org.jasig.cas.authentication.PolicyBasedAuthenticationManager] - <org.jasig.cas.authentication.principal.PersonDirectoryPrincipalResolver#bf07ee0 resolved taylorj from t
aylorj+password>
2014-09-25 16:59:45,548 INFO [org.jasig.cas.authentication.PolicyBasedAuthenticationManager] - <Authenticated taylorj with credentials [taylorj+password].>
2014-09-25 16:59:45,549 DEBUG [org.jasig.cas.authentication.PolicyBasedAuthenticationManager] - <Attribute map for taylorj: {}>
2014-09-25 16:59:45,549 INFO [org.perf4j.TimingLogger] - <start[1411660785397] time[151] tag[AUTHENTICATE]>
2014-09-25 16:59:45,556 INFO [com.github.inspektr.audit.support.Slf4jLoggingAuditTrailManager] - <Audit trail record BEGIN
Spring Security config
<beans:bean id="casAuthenticationProvider"
class="org.springframework.security.cas.authentication.CasAuthenticationProvider">
<beans:property name="serviceProperties" ref="serviceProperties" />
<beans:property name="ticketValidator" ref="ticketValidator" />
<beans:property name="authenticationUserDetailsService" ref="ldapUserDetailsService" />
<beans:property name="key" value="cas_auth_provider_ldap" />
</beans:bean>
<beans:bean id="ldapUserDetailsService"
class="org.springframework.security.cas.userdetails.GrantedAuthorityFromAssertionAttributesUserDetailsService" >
<beans:constructor-arg >
<beans:list>
<beans:value>authorities</beans:value>
</beans:list>
</beans:constructor-arg>
</beans:bean>
CAS deployerConfigContext.xml
<bean id="authenticationManager" class="org.jasig.cas.authentication.PolicyBasedAuthenticationManager">
<constructor-arg>
<map>
<entry key-ref="ldapAuthenticationHandler" value-ref="primaryPrincipalResolver" />
</map>
</constructor-arg>
<property name="authenticationPolicy">
<bean class="org.jasig.cas.authentication.AnyAuthenticationPolicy" />
</property>
</bean>
<bean id="ldapAuthenticationHandler"
class="org.jasig.cas.authentication.LdapAuthenticationHandler"
p:principalIdAttribute="sAMAccountName"
c:authenticator-ref="authenticator">
<property name="principalAttributeMap">
<map>
<entry key="displayName" value="displayName" />
<entry key="mail" value="mail" />
<entry key="memberOf" value="memberOf" />
</map>
</property>
</bean>
<bean id="primaryPrincipalResolver"
class="org.jasig.cas.authentication.principal.PersonDirectoryPrincipalResolver" >
<property name="attributeRepository" ref="attributeRepository" />
</bean>
<bean id="attributeRepository"
class="org.jasig.cas.persondir.LdapPersonAttributeDao"
p:connectionFactory-ref="pooledLdapConnectionFactory"
p:baseDN="${ldap.baseDn}" p:searchControls-ref="searchControls" p:searchFilter="sAMAccountName={0}">
<property name="queryAttributeMapping">
<map>
<entry key="username" value="uid" />
</map>
</property>
<property name="resultAttributeMapping">
<map>
<entry key="uid" value="username" />
<entry key="givenname" value="first_name" />
<entry key="sn" value="last_name" />
<entry key="mail" value="email" />
</map>
</property>
</bean>
<bean id="searchControls"
class="javax.naming.directory.SearchControls"
p:searchScope="2"
p:countLimit="10" />
After spending too much time to use the CAS feature to retrieve the roles and it did nt work...
So I decided to retrieve the needed LDAP attributes myself after successful login.
In my case I used Java, Spring framework, etc...
I have my class MyCasAuthenticationUserDetailsService that would looks like below and extends org.springframework.security.core.userdetails.AuthenticationUserDetailsService
And in initialiseAdditionalUserDetails() method I retrieve the needed attributes and set in my own CasUser class which extends org.springframework.security.core.userdetails.User
public class MyCasAuthenticationUserDetailsService implements AuthenticationUserDetailsService<Authentication> {
#Override
public UserDetails loadUserDetails(Authentication token) throws UsernameNotFoundException {
sAMAccountName = token.getName();
init();
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
for (String role : getRoles()) {
authorities.add(new SimpleGrantedAuthority(role));
}
CasUser user = new CasUser(sAMAccountName, NON_EXISTENT_PASSWORD_VALUE, authorities);
// Sets additional user details
user = initialiseAdditionalUserDetails(sAMAccountName, user);
return user;
}
/**
* Retrieves the user roles from LDAP
*
* #return
*/
private List<String> getRoles() {
List<String> result = new ArrayList<String>();
try {
SearchResult searchResult = searchExecutor.search(connectionFactory, "(sAMAccountname=" + sAMAccountName + ")", "memberOf").getResult();
LdapEntry entry = searchResult.getEntry();
if (entry != null) {
Collection<String> roles = entry.getAttribute().getStringValues();
StringBuffer rolesCSV = new StringBuffer();
for (String role : roles) {
int start = role.indexOf("=");
int end = role.indexOf(",");
rolesCSV.append(role.substring(start + 1, end));
rolesCSV.append(",");
}
String role = rolesCSV.deleteCharAt(rolesCSV.length() - 1).toString();
String rolesArr[] = role.split(",");
result = Arrays.asList(rolesArr);
}
} catch (LdapException e) {
LOG.error(e);
}
return result;
}
/**
* Initialise additional user details like country, ISO country code, email,
* etc
*
*/
private CasUser initialiseAdditionalUserDetails(String sAMAccountName, CasUser user) {
try {
SearchResult searchResult = searchExecutor.search(connectionFactory, "(sAMAccountname=" + sAMAccountName + ")", "c", "co", "mail",
"givenName", "sn", "displayName").getResult();
LdapEntry entry = searchResult.getEntry();
if (entry != null) {
if (entry.getAttribute("givenName") != null) {
String firstName = entry.getAttribute("givenName").getStringValue();
user.setFirstName(firstName);
}
if (entry.getAttribute("sn") != null) {
String lastName = entry.getAttribute("sn").getStringValue();
user.setLastName(lastName);
}
if (entry.getAttribute("displayName") != null) {
String fullName = entry.getAttribute("displayName").getStringValue();
user.setFullName(fullName);
}
if (entry.getAttribute("c") != null) {
String isoCountryCode = entry.getAttribute("c").getStringValue();
user.setIsoCountryCode(isoCountryCode);
}
if (entry.getAttribute("co") != null) {
String country = entry.getAttribute("co").getStringValue();
user.setCountry(country);
}
if (entry.getAttribute("mail") != null) {
String email = entry.getAttribute("mail").getStringValue();
user.setEmail(email);
}
}
} catch (LdapException e) {
LOG.error(e);
}
return user;
}
}
And finally on the CAS Java clients .... I configure myCasAuthenticationUserDetailsService as below.....
<beans:bean id="casAuthenticationProvider"
class="org.springframework.security.cas.authentication.CasAuthenticationProvider">
<beans:property name="serviceProperties" ref="serviceProperties" />
<beans:property name="ticketValidator" ref="ticketValidator" />
<beans:property name="authenticationUserDetailsService"
ref="myCasAuthenticationUserDetailsService" />
<beans:property name="key" value="notification" />
</beans:bean>
<beans:bean id="myCasAuthenticationUserDetailsService"
class="com.jai.cas.MyCasAuthenticationUserDetailsService">
<beans:property name="ldapUrl" value="${ldapUrl}" />
<beans:property name="ldapAdminDn" value="${ldapAdminDn}" />
<beans:property name="ldapAdminPwd" value="${ldapAdminPwd}" />
<beans:property name="ldapUserBaseDn" value="${ldapUserBaseDn}" />
</beans:bean>
This would retrieve all the needed attributes....
I have a single-context Spring-WS application (that is, there is only one file in my project that contains definitions), something-servlet.xml. When I call persist through my DAOs, no entries are getting created in my database. I'm also not getting any exceptions thrown.
If there is any more information I've left out that'd be helpful in determining the issue, please let me know. Thanks.
something-servlet.xml:
<?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:context="http://www.springframework.org/schema/context"
xmlns:sws="http://www.springframework.org/schema/web-services"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/web-services http://www.springframework.org/schema/web-services/web-services-2.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:component-scan base-package="com.abc.direct.mailserver" />
<context:property-placeholder location="classpath:manager.properties" />
<sws:annotation-driven />
<sws:dynamic-wsdl id="manager" portTypeName="AbcDirect"
locationUri="/mailerManagerService/" targetNamespace="http://ecsdfsds.com/direct/definitions">
<sws:xsd location="/WEB-INF/mailManagerRequest.xsd" />
</sws:dynamic-wsdl>
<bean id="mailServerPersistenceManager"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="directMailDataSource" />
<property name="packagesToScan" value="com.abc.direct.mailserver.dao"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
</bean>
<bean id="directMailDataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${database.driverClassName}" />
<property name="url" value="${database.url}" />
<property name="username" value="${database.username}" />
<property name="password" value="${database.password}" />
</bean>
</beans>
Dao Classes:
#Entity
#Table(name="virtualusertable")
public class VirtualUser {
#Id
#Column(name="user")
private String user;
// private String domain;
// private String targetAddress;
public VirtualUser(String username) {
this.user = username;
}
public String getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
}
#Component
public class VirtualUsers {
#PersistenceContext
EntityManager entityManager;
public void save(VirtualUser user) {
this.entityManager.persist(user);
}
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
}
Endpoint:
#Endpoint
public class MailManagerEndpoint {
private static final String NAMESPACE_URI = "http://asfsdfs.com/direct/schemas";
static final Namespace NAMESPACE = Namespace.getNamespace(NAMESPACE_URI);
private MailManagerService service;
#Autowired
private VirtualUsers virtualUsers;
#Autowired
public MailManagerEndpoint(MailManagerService mailManagerService) {
this.service = mailManagerService;
}
#PayloadRoot(namespace = NAMESPACE_URI, localPart = "MailManagerRequest")
public #ResponsePayload Element handleRequest(#RequestPayload Element element) throws JDOMException, IOException {
VirtualUser user = new VirtualUser("newuser");
virtualUsers.save(user);
return new Element("success");
}
}
Startup logs: http://pastebin.com/9Z6MWRSG
Transaction logs: http://pastebin.com/ZFEC0EMJ
In the startup logs, I"m really curious as to why this block repeats itself like 7 times:
2014-04-25 10:34:03,634 DEBUG EntityLoader:146 - Static select for entity com.abc.direct.mailserver.dao.VirtualUser [READ]: select virtualuse0_.user as user1_0_0_ from virtualusertable virtualuse0_ where virtualuse0_.user=?
2014-04-25 10:34:03,635 DEBUG QuerySpacesImpl:177 - Adding QuerySpace : uid = <gen:0> -> org.hibernate.loader.plan.build.internal.spaces.EntityQuerySpaceImpl#e58a68d]
2014-04-25 10:34:03,635 DEBUG FetchStyleLoadPlanBuildingAssociationVisitationStrategy:94 - Building LoadPlan...
2014-04-25 10:34:03,635 DEBUG LoadQueryJoinAndFetchProcessor:111 - processing queryspace <gen:0>
2014-04-25 10:34:03,636 DEBUG LoadPlanTreePrinter:72 - LoadPlan(entity=com.abc.direct.mailserver.dao.VirtualUser)
- Returns
- EntityReturnImpl(entity=com.abc.direct.mailserver.dao.VirtualUser, querySpaceUid=<gen:0>, path=com.abc.direct.mailserver.dao.VirtualUser)
- QuerySpaces
- EntityQuerySpaceImpl(uid=<gen:0>, entity=com.abc.direct.mailserver.dao.VirtualUser)
- SQL table alias mapping - virtualuse0_
- alias suffix - 0_
- suffixed key columns - {user1_0_0_}
UPDATE:
persist() output after adding #Transactional and :
2014-04-25 11:24:47,517 DEBUG SharedEntityManagerCreator$SharedEntityManagerInvocationHandler:253 - Creating new EntityManager for shared EntityManager invocation
2014-04-25 11:24:47,950 DEBUG AbstractSaveEventListener:130 - Generated identifier: newuser, using strategy: org.hibernate.id.Assigned
2014-04-25 11:24:48,011 DEBUG EntityManagerFactoryUtils:435 - Closing JPA EntityManager
If you want to insert data to DB, you need a transaction. In order for Spring to provide a transaction, you need to put <tx:annotation-driven /> to your Spring context file, and put #Transactional annotation on the method that you insert data to DB. This way, Spring initiates a transaction for you as the method execution starts, and commits it when the method execution comes to an end (or rolls it back if an exception is thrown).
So, I try to use Spring for transaction management. Finally my application had worked, but deleting do not commits. Before using Spring I managed transactions in DAO, and I thought that after I can remove this code. But now deleting do not commit to DB.
My DAO:
protected Session getSession() {
Session session = sessionFactory.openSession();
ThreadLocalSessionContext.bind(session);
return session;
}
public void delete(T t) {
Session session = getSession();
// **this approach I used before**
// session.beginTransaction();
// try {
// session.delete(t);
// session.getTransaction().commit();
// } catch (Exception e) {
// session.getTransaction().rollback();
// }
session.delete(t);
}
My applicationContext:
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation=" http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url"
value="jdbc:mysql://ngs-java-srv.synapse.com:3306/mybase" />
<property name="username" value="user" />
<property name="password" value="password" />
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<!-- <property name="configLocation" value="hibernate.cfg.xml" /> -->
<property name="packagesToScan" value="todolist.entity" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.cache.provider_class">org.hibernate.cache.internal.NoCacheProvider</prop>
<prop key="hibernate.show_sql">false</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
</bean>
<!-- dao beans -->
<bean id="userDao"
class="todolist.dao.hibernate.UserDaoImpl">
<constructor-arg>
<value>todolist.entity.User</value>
</constructor-arg>
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="itemDao"
class="todolist.dao.hibernate.ItemDaoImpl">
<constructor-arg>
<value>todolist.entity.Item</value>
</constructor-arg>
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<!-- service bean -->
<bean id="userService" class="todolist.service.UserServiceImpl">
<property name="userDao" ref="userDao" />
<property name="itemDao" ref="itemDao" />
</bean>
<!-- transaction manager -->
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" mode="aspectj"/>
<!-- <tx:annotation-driven/> -->
<!-- <aop:config>
<aop:pointcut id="serviceMethods"
expression="execution(* todolist.service.UserService.*(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="serviceMethods" />
</aop:config>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" propagation="REQUIRES_NEW" />
<tx:method name="deleteItem" no-rollback-for="Exception" />
</tx:attributes>
</tx:advice> -->
<!-- backbeans -->
<bean id="userLogin" class="todolist.jsf.UserLogin"
scope="request">
<property name="userService" ref="userService" />
</bean>
<bean id="userLogged" class="todolist.jsf.UserLogged"
scope="session">
<aop:scoped-proxy />
</bean>
<bean id="userRegister" class="todolist.jsf.UserRegister"
scope="request">
<property name="userService" ref="userService" />
</bean>
<bean id="createItem" class="todolist.jsf.CreateItem"
scope="request">
<property name="userService" ref="userService" />
</bean>
<bean id="todoList" class="todolist.jsf.TodoList"
scope="request">
<property name="userService" ref="userService" />
</bean>
</beans>
UserServiceImpl class
package todolist.service;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.apache.log4j.Logger;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import todolist.exception.AuthorizationError;
import todolist.exception.DuplicateLoginsException;
import todolist.service.StringToHashTool;
import todolist.dao.ItemDao;
import todolist.dao.UserDao;
import todolist.entity.Item;
import todolist.entity.User;
public class UserServiceImpl implements UserService {
//private static final Logger log = Logger.getLogger(UserServiceImpl.class);
private UserDao userDao;
private ItemDao itemDao;
public void setItemDao(ItemDao itemDao) {
this.itemDao = itemDao;
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
#Override
#Transactional(propagation = Propagation.REQUIRES_NEW)
public boolean isUserExists(String login) {
return (userDao.getUserByLogin(login) != null);
}
#Override
#Transactional(propagation = Propagation.REQUIRES_NEW)
public boolean isPasswordCorrect(String login, String password) {
if (isUserExists(login)) {
return userDao.getUserByLogin(login).getPassword()
.equals(StringToHashTool.getHash(password));
} else {
return false;
}
}
#Override
#Transactional(propagation = Propagation.REQUIRES_NEW)
public User login(String login, String password) {
if (isPasswordCorrect(login, password)) {
return userDao.getUserByLogin(login);
} else {
throw new AuthorizationError("Incorrect password");
}
}
#Override
#Transactional(propagation = Propagation.REQUIRES_NEW)
public boolean register(String login, String password) {
if (isUserExists(login)) {
throw new DuplicateLoginsException("Login " + login + " is already used.");
} else {
User user = new User();
user.setLogin(login);
user.setPassword(StringToHashTool.getHash(password));
userDao.save(user);
return true;
}
}
#Override
#Transactional(propagation = Propagation.REQUIRES_NEW)
public void logout() {
}
#Override
#Transactional(propagation = Propagation.REQUIRES_NEW)
public Item createItem(Long creator_id, Long performer_id,
String description, Date dueDate) {
Item item = new Item();
User user = userDao.getById(creator_id);
item.setCreator(user);
user = userDao.getById(performer_id);
item.setPerformer(user);
item.setDescription(description);
item.setStartDate(new Date());
item.setDueDate(dueDate);
itemDao.save(item);
return item;
}
#Override
#Transactional(propagation = Propagation.REQUIRES_NEW)
public void deleteItem(Long item_id) {
Item item = itemDao.getById(item_id);
itemDao.delete(item);
}
#Override
#Transactional(propagation = Propagation.REQUIRES_NEW)
public List<Item> getUserItems(String login) {
User user = userDao.getUserByLogin(login);
return itemDao.getItemsByPerformer(user.getId());
}
#Override
#Transactional(propagation = Propagation.REQUIRES_NEW)
public List<User> getUsers() {
return userDao.getUsers();
}
}
<aop:pointcut
id="serviceMethods"
expression="execution(*todolist.service.UserService.*(..))"
/>
First Step:
Change this to:
<aop:pointcut
id="serviceMethods"
expression="todolist.service.UserServiceImpl.delete()"
/>
See if delete's start committing. I just want to make sure you flush out any typos and what have you. If this explicit config fails then there must be something wrong with the config.
I have had success using the Spring HibernateTransactionManager object and annotation driven configuration. In my application-context, I simply declare the following two beans:
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="session_factory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
Then in my service layer, your UserServiceImpl for example:
public class UserServiceImpl implements UserService {
private final UserDao userDao;
private final ItemDao itemDao;
public UserServiceImpl(UserDao userDao, ItemDao itemDao) {
this.userDao = userDao;
this.itemDao = itemDao;
}
#Override
#Transactional(propagation = Propagation.REQUIRES_NEW)
public boolean isUserExists(String login) {
return (userDao.getUserByLogin(login) != null);
}
...
It's important to move you transaction annotations as close to the view (in MVC) as possible. The reason is 1) performance and 2) atomic transactions. If the call calling the UserService calls the isUserExists, isPasswordCorrect and login methods in a single function call, you would want those to execute in a single transaction. To do so, remove the #Transactional annotation from the UserServiceImpl and move it to the calling class. This ensures that a single transaction is used for all three method calls. For atomic execution, this also works. Think of the classic bank money transfer example. If you had two separate transactions on the UserService, the first two method call can succeed and the last one fail. The firt two transactions would be committed because they are in separate transaction blocks which would leave you database in an inconsistent state. Of course, atomic transactions are mostly relevant for transactions that write data.
Also, don't add the transactional annotations to the interfaces, keep them on the implementations.
Then in my DAO, I simply do a sessionFactory.getCurrentSession() and go from there. getCurrentSession() is thread safe but keep it private to your DAOs.
Use getCurrentSession instead of openSession in your DAO, so that the getSession method looks like:
protected Session getSession() {
return sessionFactory.getCurrentSession();
}
You're creating a new session that uses a different database connection so the transaction set up for the service doesn't apply.
Also as you have them configured the DAOs will have a default scope of singleton; passing an entity as a constructor-argument doesn't make sense. A singleton shouldn't have instance state specific to some individual transaction.