Estou com alguns problemas com o uso da JPA no Tomcat e talvez vocês possam me ajudar..
Usando a implementação Toplink, criei um projeto com uma tela inicial de Login.
O que está acontecendo é que quando o site é carregado e o formulário de Login submetido, a autenticação falha, ou seja, o usuário informado do formulário não é encontrado.
Constatei que isso acontece porque o contexo/conexão JPA ainda não está concluída. Isto é, se eu tendo o Login uma vez, duas vezes, na terceira vez ele acontece com sucesso, exatamente no momento em que a conexão JPA está realizada.
Não consigo entender por quê isso acontece, na máquina local não tenho esse problema.
O método de login não deveria aguardar o término da criação do contexto?
Criei um filtro. Quando a action responsável pelo login é invocada, no seu input "vem" um EntityManager com uma transação aberta. Quando a action é encerrada o filtro comita a transação e fecha o EntityManager (close).
Quando a aplicação é inicializada (filtro é instanciado no ApplicationManager - loadActions) acontece a criação do EMF (EntityManagerFactory) do contexto em questão.
O que pode estar errado?
ApplicationManager
Code:
public void loadActions() {
filter(new JPAFilter("PU"));
/* Filtro de autenticação */
addGlobalFilter (new AuthenticationFilter());
addGlobalConsequence(AuthenticationFilter.LOGIN , new Redirect("/index.jsp"));
//Login
ActionConfig ac = new ActionConfig("/Login", LoginAction.class);
ac.addConsequence(LoginAction.SUCCESS, new Redirect ("/index.jsp"));
ac.addConsequence(LoginAction.ERROR, new Forward ("/index.jsp"));
addActionConfig(ac);
ac.addFilter(new RedirectAfterLoginFilter());
ac.addConsequence(RedirectAfterLoginFilter.REDIR, new Redirect());
//Logout
ac = new ActionConfig("/Logout", LogoutAction.class);
ac.addConsequence(LogoutAction.SUCCESS, new Redirect("/index.jsp"));
addActionConfig(ac);
/* Fim do filtro de autenticação */
}
Filtro para o JPA
Code:
public class JPAFilter extends InputWrapper implements AfterConsequenceFilter {
public static final String KEY = "jpa_entityManager";
private String EntityManagerKEY = KEY;
private EntityManagerFactory emf;
private ThreadLocal<EntityManager> emLocal = new ThreadLocal<EntityManager>();
private ThreadLocal<EntityTransaction> transLocal = new ThreadLocal<EntityTransaction>();
/**
* Construtor
*
* @param persistenceUnit
*/
public JPAFilter(String persistenceUnit) {
Factory.setPU(persistenceUnit);
Factory.getInstance();
}
public String filter(InvocationChain chain) throws Exception {
Action action = chain.getAction();
super.setInput(action.getInput());
action.setInput(this);
String result = chain.invoke();
return result;
}
public void afterConsequence(Action action, Consequence c,
boolean conseqExecuted, boolean actionExecuted, String result) {
EntityManager em = emLocal.get();
if (em != null) {
try {
em.getTransaction().commit();
} catch (Exception e) {
Debug.log("Não foi possível efetuar COMMIT da na transação.", "Mensagem: " + e.getMessage());
}
em.close();
emLocal.set(null);
removeValue(EntityManagerKEY);
}
}
public void destroy() {
Factory.close();
}
public Object getValue(String key) {
if (key.equals(EntityManagerKEY)) {
EntityManager em = emLocal.get();
if (em == null) {
try {
em = Factory.getInstance().getEntityManager();
emLocal.set(em);
} catch (Exception e) {
Debug.log("Não foi possível criar EntityManager.", "Mensagem: " + e.getMessage());
}
}
em = emLocal.get();
if (em != null){
try {
em.getTransaction().begin();
setValue(key, em);
} catch (Exception e) {
Debug.log("Não foi possível efetuar start da na transação.", "Mensagem: " + e.getMessage());
}
}
return em;
}
return super.getValue(key);
}
Factory
Code:
public class Factory {
private static Factory instance = null;
private static String PU;
private EntityManagerFactory factory = null;
private EntityManager em = null;
public Factory () {
try {
factory = Persistence.createEntityManagerFactory(PU);
} catch (Exception e) {
Debug.log("Exceção ao criar EntityManagerFactory. ",
"Mensagem: " + e.getMessage());
throw new RuntimeException(e);
}
}
public EntityManager getEntityManager() {
try {
em = factory.createEntityManager();
return em;
} catch (Exception e) {
Debug.log("Exceção ao criar EntityManager. ",
"Mensagem: " + e.getMessage());
throw new RuntimeException(e);
}
}
public static synchronized Factory getInstance() {
if (instance == null) {
instance = new Factory();
}
return instance;
}
public static void setPU(String persistenceUnit) {
PU = persistenceUnit;
}
public static void close() {
if (instance.em != null)
if (instance.em.isOpen())
instance.em.clear();
if (instance.factory != null)
if (instance.factory.isOpen())
instance.factory.close();
}
LoginAction
Code:
public class LoginAction extends BaseLoginAction {
public String execute() throws Exception {
if (!isPost())
return ERROR;
Entidade e = null;
try {
EntityManager manager = (EntityManager) input.getValue(JPAFilter.KEY);
e = (Entidade) JpaDao.recuperarUm(manager, "Entidade.recuperaEntidadePorLogin",
"login", username.toLowerCase());
if (e != null) {
if (!e.getPassword().equalsIgnoreCase(password))
{
addError("resultado", "Senha inválida.");
return ERROR;
}
} else {
Debug.log("Exceção ao tentar efetuar Login (Entidade retornou NULO).", "Username: " + username + " Password: "+ password);
addError("resultado", "Login e/ou senha inválido(s).");
return ERROR;
}
//----
} catch (Exception ex) {
Debug.log("Exceção ao tentar efetuar Login (Entidade retornou NULO).",
"Mensagem: " + ex.getMessage());
return ERROR;
}
try {
setUserSession(e);
} catch (Exception ex ){
Debug.log("Exceção ao setar Usuário da sessão.", "ID Entidade: " + e.getId() + " Username: "+ e.getLogin(), "Mensagem: " + ex.getMessage());
}
return SUCCESS;
}
}
Qualquer ajuda é bem vinda..
Obrigado
Marcos