I have a hard time to understand why a seam-managed persistence context (SMPC)
@PersistenceContext behaves differently from a non-managed persistence context
@PersistenceContext.
I know I have to use @In to use the SMPC entitymanger - but it looks like Seam also
changes the behaviour for @PersistenceContext when SMPC is enabled.
Example - non-managed (expected behaviour):
| @Stateful
| @Name("authenticatorService")
| @Scope(ScopeType.SESSION)
| public class AuthenticatorBean implements AuthenticatorLocal {
| private static final String CONTEXT_PARAMETER_MAX_ATTEMPTS =
"sine.login.max.attempts";
| private static final String CONTEXT_PARAMETER_TIME_LOCK =
"sine.login.time.lock";
|
| @Logger
| private Log log;
|
| @PersistenceContext
| private EntityManager em;
|
| @In
| FacesMessages facesMessages;
|
| @EJB
| private UserLocal userService;
|
| @In(create = false, required = false)
| @Out(required = false)
| private User userDomain;
|
| @Out(required = false)
| private User loggedInUserDomain;
|
| private boolean authenticateError;
| private HashMap<String, Integer>loginAttempts = new HashMap<String,
Integer>();
|
| public boolean authenticate() {
| authenticateError = false;
|
| userDomain =
userService.getUserByUsername(Identity.instance().getUsername());
| if (userDomain != null) {
| if (userDomain.isTimeLocked()) {
| if (System.currentTimeMillis() - userDomain.getTimeLock().getTime()
| >
(Long.parseLong(Util.getContextParameter(CONTEXT_PARAMETER_TIME_LOCK)) * 60000)) {
| loginAttempts.put(userDomain.getUsername(), 0);
| userDomain.setTimeLock(null);
| } else {
| facesMessages.addToControlFromResourceBundle("username",
FacesMessage.SEVERITY_ERROR,
| "loginTimeLocked");
|
| authenticateError = true;
| return false;
| }
| }
|
| if (userDomain.getPassword()
|
.equals(Password.encodePasswordMD5(Identity.instance().getPassword(),
userDomain.getId()))) {
| if (!userDomain.isLocked()) {
| for (Role role : userDomain.getRoles()) {
| Identity.instance().addRole(role.getName());
| }
|
| loginAttempts.put(userDomain.getUsername(), 0);
| loggedInUserDomain = userDomain; // Store userDomain in Session
|
| return true;
| }
| }
| } else {
| log.info("Login error - user don't exist: {0}",
Identity.instance().getUsername());
| }
|
| facesMessages.addToControlFromResourceBundle("username",
FacesMessage.SEVERITY_ERROR, "loginError");
|
| authenticateError = true;
| return false;
| }
|
| @Observer(value = Identity.EVENT_LOGIN_FAILED, create = false)
| public void failedLoginEvent() {
| if ((userDomain != null) && !userDomain.isTimeLocked()) {
| int attempts = loginAttempts.containsKey(userDomain.getUsername())
| ? loginAttempts.get(userDomain.getUsername()) : 0;
|
| if (++attempts >=
Integer.parseInt(Util.getContextParameter(CONTEXT_PARAMETER_MAX_ATTEMPTS))) {
| userDomain.setTimeLock(new Date());
| em.merge(userDomain); // I need to merge because entity is detached
*************************** ATTENTION ***********
| em.flush();
| log.info("Time lock on user: {0}",
userDomain.getUsername());
| } else {
| loginAttempts.put(userDomain.getUsername(), attempts);
| }
| }
| }
|
| public boolean isAuthenticateError() {
| return authenticateError;
| }
|
| @Remove // Seam needs this one for stateful beans
| public void destroy() {
| }
| }
|
Above example works fine and the database is updated correctly.
Example - SMPC (I don't need the merge anymore - looks like @PersistenceContext is
extended, but why?):
| @Stateful
| @Name("authenticatorService")
| @Scope(ScopeType.SESSION)
| public class AuthenticatorBean implements AuthenticatorLocal {
| private static final String CONTEXT_PARAMETER_MAX_ATTEMPTS =
"sine.login.max.attempts";
| private static final String CONTEXT_PARAMETER_TIME_LOCK =
"sine.login.time.lock";
|
| @Logger
| private Log log;
|
| @PersistenceContext
| private EntityManager em;
|
| @In
| FacesMessages facesMessages;
|
| @EJB
| private UserLocal userService;
|
| @In(create = false, required = false)
| @Out(required = false)
| private User userDomain;
|
| @Out(required = false)
| private User loggedInUserDomain;
|
| private boolean authenticateError;
| private HashMap<String, Integer>loginAttempts = new HashMap<String,
Integer>();
|
| public boolean authenticate() {
| authenticateError = false;
|
| userDomain =
userService.getUserByUsername(Identity.instance().getUsername());
| if (userDomain != null) {
| if (userDomain.isTimeLocked()) {
| if (System.currentTimeMillis() - userDomain.getTimeLock().getTime()
| >
(Long.parseLong(Util.getContextParameter(CONTEXT_PARAMETER_TIME_LOCK)) * 60000)) {
| loginAttempts.put(userDomain.getUsername(), 0);
| userDomain.setTimeLock(null);
| } else {
| facesMessages.addToControlFromResourceBundle("username",
FacesMessage.SEVERITY_ERROR,
| "loginTimeLocked");
|
| authenticateError = true;
| return false;
| }
| }
|
| if (userDomain.getPassword()
|
.equals(Password.encodePasswordMD5(Identity.instance().getPassword(),
userDomain.getId()))) {
| if (!userDomain.isLocked()) {
| for (Role role : userDomain.getRoles()) {
| Identity.instance().addRole(role.getName());
| }
|
| loginAttempts.put(userDomain.getUsername(), 0);
| loggedInUserDomain = userDomain; // Store userDomain in Session
|
| return true;
| }
| }
| } else {
| log.info("Login error - user don't exist: {0}",
Identity.instance().getUsername());
| }
|
| facesMessages.addToControlFromResourceBundle("username",
FacesMessage.SEVERITY_ERROR, "loginError");
|
| authenticateError = true;
| return false;
| }
|
| @Observer(value = Identity.EVENT_LOGIN_FAILED, create = false)
| public void failedLoginEvent() {
| if ((userDomain != null) && !userDomain.isTimeLocked()) {
| int attempts = loginAttempts.containsKey(userDomain.getUsername())
| ? loginAttempts.get(userDomain.getUsername()) : 0;
|
| if (++attempts >=
Integer.parseInt(Util.getContextParameter(CONTEXT_PARAMETER_MAX_ATTEMPTS))) {
| userDomain.setTimeLock(new Date());
| em.flush();
| log.info("Time lock on user: {0}",
userDomain.getUsername());
| } else {
| loginAttempts.put(userDomain.getUsername(), attempts);
| }
| }
| }
|
| public boolean isAuthenticateError() {
| return authenticateError;
| }
|
| @Remove // Seam needs this one for stateful beans
| public void destroy() {
| }
| }
|
Above example works fine and the database is updated correctly, but I don't need to
merge anymore - looks like @PersistenceContext is extended when running under SMPC.
Could someone explain why @PersistenceContext behaves differently under a SMPC?
Thanks.
View the original post :
http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4125702#...
Reply to the post :
http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&a...