Habe mal eine Frage, da man sowas natürlich nicht im Studium beigebracht bekommt.
Ich möchte bald meine erste "echte" Webapplikation veröffentlichen, leider bin ich mir extrem unsicher ob man das alles so machen kann. Im Studium habe ich zwar schon mit EclipseLink und Tomcat gearbeitet, leider wurde das große Thema Thread Safe nie wirklich behandelt.
Meine GenericDao sieht so aus, etwas von Hibernate Tutorial abgeguckt:
Habe mich für viele DAOs entschieden, daher sieht eine DAO so aus:
Die Facaden steuern meine Transaktion, da die nicht JTA sind, sonder Resource-Local.
Eine passende Facade sieht so aus:
Ablauf:
Eine JSF Seite arbeitet mit eine ManagedBean, wobei in der ManagedBean eine Entity erstellt wird.
Wenn diese fertig ausgefüllt ist wird eine Aktion ausgeführt. In dieser Aktion-Methode wird dann eine Facade erstellt und das Objekt der Facade übergeben. Die Facade startet eine Transaktion und versucht das Objekt in der Datenbank zu speichern. Alleine klappt das natürlich auch alles wunderbar. Habe aber gelesen, das der EntityManager nicht ThreadSafe ist. Wie testen man sowas, also wie testen man eine Webanwendung auf Thread Safe? VIelen Dank für eure Hilfe.
Ich möchte bald meine erste "echte" Webapplikation veröffentlichen, leider bin ich mir extrem unsicher ob man das alles so machen kann. Im Studium habe ich zwar schon mit EclipseLink und Tomcat gearbeitet, leider wurde das große Thema Thread Safe nie wirklich behandelt.
Meine GenericDao sieht so aus, etwas von Hibernate Tutorial abgeguckt:
Java:
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package de.dao;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.NoResultException;
import javax.persistence.Persistence;
import javax.persistence.Query;
import javax.persistence.criteria.CriteriaQuery;
public abstract class GenericDAO<T> implements Serializable {
private static final long serialVersionUID = 1L;
private static final EntityManagerFactory emf = Persistence.createEntityManagerFactory("WebApplication4PU");
private EntityManager em;
private Class<T> entityClass;
public void beginTransaction() {
em = emf.createEntityManager();
em.getTransaction().begin();
}
public void commit() {
em.getTransaction().commit();
}
public void rollback() {
em.getTransaction().rollback();
}
public void closeTransaction() {
em.close();
}
public void commitAndCloseTransaction() {
commit();
closeTransaction();
}
public boolean isEntityManagerNull() {
return (em == null);
}
public boolean isTransactionActive() {
return em.getTransaction().isActive();
}
public void flush() {
em.flush();
}
public void joinTransaction() {
em = emf.createEntityManager();
em.joinTransaction();
}
public GenericDAO(Class<T> entityClass) {
this.entityClass = entityClass;
}
public void save(T entity) {
em.persist(entity);
}
public void delete(T entity) {
T entityToBeRemoved = em.merge(entity);
em.remove(entityToBeRemoved);
}
public T update(T entity) {
return em.merge(entity);
}
public T find(long entityID) {
return em.find(entityClass, entityID);
}
public T findReferenceOnly(int entityID) {
return em.getReference(entityClass, entityID);
}
@SuppressWarnings({"unchecked", "rawtypes"})
public List<T> findAll() {
CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
cq.select(cq.from(entityClass));
return em.createQuery(cq).getResultList();
}
protected Collection<T> findResult(String namedQuery, Map<String, Object> parameters) {
Collection<T> result = null;
try {
Query query = em.createNamedQuery(namedQuery);
if (parameters != null && !parameters.isEmpty()) {
populateQueryParameters(query, parameters);
}
result = query.getResultList();
} catch (NoResultException e) {
System.out.println("No result found for named query: " + namedQuery);
} catch (Exception e) {
System.out.println("Error while running query: " + e.getMessage());
e.printStackTrace();
}
return result;
}
@SuppressWarnings("unchecked")
protected T findOneResult(String namedQuery, Map<String, Object> parameters) {
T result = null;
try {
Query query = em.createNamedQuery(namedQuery);
if (parameters != null && !parameters.isEmpty()) {
populateQueryParameters(query, parameters);
}
result = (T) query.getSingleResult();
} catch (NoResultException e) {
System.out.println("No result found for named query: " + namedQuery);
} catch (Exception e) {
System.out.println("Error while running query: " + e.getMessage());
e.printStackTrace();
}
return result;
}
private void populateQueryParameters(Query query, Map<String, Object> parameters) {
for (Entry<String, Object> entry : parameters.entrySet()) {
query.setParameter(entry.getKey(), entry.getValue());
}
}
}
Habe mich für viele DAOs entschieden, daher sieht eine DAO so aus:
Java:
public class AccountDAO extends GenericDAO<Account> {
private static final long serialVersionUID = 1L;
public AccountDAO() {
super(Account.class);
}
public void accountHinzufuegen(Account account) {
save(account);
}
public Account findAccountByKundennummer(String kundennummer) {
Map<String, Object> parameters = new HashMap<String, Object>();
parameters.put("kundennummer", kundennummer);
return findOneResult(Account.FIND_BY_KUNDENNUMMER, parameters);
}
}
Die Facaden steuern meine Transaktion, da die nicht JTA sind, sonder Resource-Local.
Eine passende Facade sieht so aus:
Java:
public class AccountFacade implements Serializable {
private AccountDAO accountDAO = new AccountDAO();
private static final Logger LOG = FileLogger.getLogger(AccountFacade.class.getName());
public void accountHinzufuegen(Account account) {
try {
accountDAO.beginTransaction();
accountDAO.accountHinzufuegen(account);
accountDAO.commitAndCloseTransaction();
} catch (RollbackException re) {
LOG.log(Level.SEVERE,
"Commit schlug fehl", re);
} catch (PersistenceException pe) {
LOG.log(Level.SEVERE,
"Entity-Manager meldet einen Fehler", pe);
accountDAO.rollback();
} catch (Throwable th) {
LOG.log(Level.SEVERE,
"Unerwarteter Fehler", th);
if (!accountDAO.isEntityManagerNull() && accountDAO.isTransactionActive()) {
accountDAO.rollback();
}
}
}
}
Ablauf:
Eine JSF Seite arbeitet mit eine ManagedBean, wobei in der ManagedBean eine Entity erstellt wird.
Wenn diese fertig ausgefüllt ist wird eine Aktion ausgeführt. In dieser Aktion-Methode wird dann eine Facade erstellt und das Objekt der Facade übergeben. Die Facade startet eine Transaktion und versucht das Objekt in der Datenbank zu speichern. Alleine klappt das natürlich auch alles wunderbar. Habe aber gelesen, das der EntityManager nicht ThreadSafe ist. Wie testen man sowas, also wie testen man eine Webanwendung auf Thread Safe? VIelen Dank für eure Hilfe.