I'm trying to use a Facade class, which extends an abstract facade, to persist an entity with JPA. The database classes involved are:
src/net/bounceme/dur/selenium/jpa/
├── AbstractFacade.java
├── Feed.java
├── FeedJpaController.java
├── LinkFacade.java
├── Link.java
├── LinkJpaController.java
├── PageFacade.java
├── Page.java
└── PageJpaController.java
While AbstractFacade
reports success in persisting a Page
:
run:
[java] [EL Info]: 2014-11-17 14:56:29.301--ServerSession(23999191)--EclipseLink, version: Eclipse Persistence Services - 2.5.2.v20140319-9ad6abd
[java] [EL Info]: connection: 2014-11-17 14:56:30.276--ServerSession(23999191)--file:/home/thufir/NetBeansProjects/SeleniumIterator/build/classes/_SeleniumIteratorPU login successful
[java] Nov 17, 2014 2:56:55 PM net.bounceme.dur.selenium.jpa.AbstractFacade create
[java] INFO: ..persisted!
[java] Nov 17, 2014 2:57:19 PM net.bounceme.dur.selenium.jpa.AbstractFacade create
[java] INFO: ..persisted!
^Cthufir@dur:~/NetBeansProjects/SeleniumIterator$
That success isn't reflected in the database:
mysql>
mysql> select * from pages;
Empty set (0.00 sec)
mysql>
mysql> describe pages;
+---------+-----------+------+-----+-------------------+-----------------------------+
| Field | Type | Null | Key | Default | Extra |
+---------+-----------+------+-----+-------------------+-----------------------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| created | timestamp | NO | | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
| page | text | NO | | NULL | |
| link_id | int(11) | NO | | 0 | |
| status | int(11) | NO | | 0 | |
+---------+-----------+------+-----+-------------------+-----------------------------+
5 rows in set (0.05 sec)
mysql>
The SeleniumWebPageIterator
class iterates links correctly:
package selenium;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
import net.bounceme.dur.selenium.jpa.Link;
import net.bounceme.dur.selenium.jpa.LinkFacade;
import net.bounceme.dur.selenium.jpa.Page;
import net.bounceme.dur.selenium.jpa.PageFacade;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
public class SeleniumWebPageIterator {
private final static Logger log = Logger.getLogger(SeleniumWebPageIterator.class.getName());
private final PageFacade pageFacade = new PageFacade();
private final LinkFacade linkFacade = new LinkFacade();
public SeleniumWebPageIterator() {
}
public void processLinks() {
List<Link> links = linkFacade.findAll();
for (Link l : links) {
processLink(l);
}
}
private void processLink(Link l) {
log.fine(l.toString());
WebDriver driver = new FirefoxDriver(); //don't display
driver.get(l.getLink());
driver.manage().timeouts().implicitlyWait(9, TimeUnit.SECONDS);
String s = driver.getPageSource();
createPage(l, s);
driver.close();
}
private void createPage(Link l, String s) {
Page p = new Page();
p.setCreated(new Date());
p.setLinkId(l.getId());
p.setPage(s);
pageFacade.create(p); //page has no id..
}
}
There are links (URL's) in the database, and the webpages are visited by Selenium. The source HTML for the page isn't persisted, however.
The PageFacade
is simple:
package net.bounceme.dur.selenium.jpa;
import java.util.logging.Logger;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
public class PageFacade extends AbstractFacade {
private final static Logger log = Logger.getLogger(PageFacade.class.getName());
private final EntityManagerFactory emf = Persistence.createEntityManagerFactory("SeleniumIteratorPU");
// @PersistenceContext(unitName = "SeleniumReaderPU")
public PageFacade() {
super(Page.class);
}
@Override
protected EntityManager getEntityManager() {
return emf.createEntityManager();
}
}
and extends, of course, AbstractFacade
:
package net.bounceme.dur.selenium.jpa;
import java.util.List;
import java.util.logging.Logger;
import javax.persistence.EntityManager;
public abstract class AbstractFacade<T> {
private final static Logger log = Logger.getLogger(AbstractFacade.class.getName());
private Class<T> entityClass;
public AbstractFacade(Class<T> entityClass) {
this.entityClass = entityClass;
}
protected abstract EntityManager getEntityManager();
public void create(T entity) {
getEntityManager().persist(entity);
log.info("..persisted!");
}
public void edit(T entity) {
getEntityManager().merge(entity);
}
public void remove(T entity) {
getEntityManager().remove(getEntityManager().merge(entity));
}
public T find(Object id) {
return getEntityManager().find(entityClass, id);
}
public List<T> findAll() {
javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
cq.select(cq.from(entityClass));
return getEntityManager().createQuery(cq).getResultList();
}
public List<T> findRange(int[] range) {
javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
cq.select(cq.from(entityClass));
javax.persistence.Query q = getEntityManager().createQuery(cq);
q.setMaxResults(range[1] - range[0] + 1);
q.setFirstResult(range[0]);
return q.getResultList();
}
public int count() {
javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
javax.persistence.criteria.Root<T> rt = cq.from(entityClass);
cq.select(getEntityManager().getCriteriaBuilder().count(rt));
javax.persistence.Query q = getEntityManager().createQuery(cq);
return ((Long) q.getSingleResult()).intValue();
}
}
which uses PageJpaController
to actually persist to the database:
package net.bounceme.dur.selenium.jpa;
import java.io.Serializable;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Query;
import javax.persistence.EntityNotFoundException;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import net.bounceme.dur.selenium.jpa.exceptions.NonexistentEntityException;
public class PageJpaController implements Serializable {
public PageJpaController(EntityManagerFactory emf) {
this.emf = emf;
}
private EntityManagerFactory emf = null;
public EntityManager getEntityManager() {
return emf.createEntityManager();
}
public void create(Page page) {
EntityManager em = null;
try {
em = getEntityManager();
em.getTransaction().begin();
em.persist(page);
em.getTransaction().commit();
} finally {
if (em != null) {
em.close();
}
}
}
public void edit(Page page) throws NonexistentEntityException, Exception {
EntityManager em = null;
try {
em = getEntityManager();
em.getTransaction().begin();
page = em.merge(page);
em.getTransaction().commit();
} catch (Exception ex) {
String msg = ex.getLocalizedMessage();
if (msg == null || msg.length() == 0) {
Integer id = page.getId();
if (findPage(id) == null) {
throw new NonexistentEntityException("The page with id " + id + " no longer exists.");
}
}
throw ex;
} finally {
if (em != null) {
em.close();
}
}
}
public void destroy(Integer id) throws NonexistentEntityException {
EntityManager em = null;
try {
em = getEntityManager();
em.getTransaction().begin();
Page page;
try {
page = em.getReference(Page.class, id);
page.getId();
} catch (EntityNotFoundException enfe) {
throw new NonexistentEntityException("The page with id " + id + " no longer exists.", enfe);
}
em.remove(page);
em.getTransaction().commit();
} finally {
if (em != null) {
em.close();
}
}
}
public List<Page> findPageEntities() {
return findPageEntities(true, -1, -1);
}
public List<Page> findPageEntities(int maxResults, int firstResult) {
return findPageEntities(false, maxResults, firstResult);
}
private List<Page> findPageEntities(boolean all, int maxResults, int firstResult) {
EntityManager em = getEntityManager();
try {
CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
cq.select(cq.from(Page.class));
Query q = em.createQuery(cq);
if (!all) {
q.setMaxResults(maxResults);
q.setFirstResult(firstResult);
}
return q.getResultList();
} finally {
em.close();
}
}
public Page findPage(Integer id) {
EntityManager em = getEntityManager();
try {
return em.find(Page.class, id);
} finally {
em.close();
}
}
public int getPageCount() {
EntityManager em = getEntityManager();
try {
CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
Root<Page> rt = cq.from(Page.class);
cq.select(em.getCriteriaBuilder().count(rt));
Query q = em.createQuery(cq);
return ((Long) q.getSingleResult()).intValue();
} finally {
em.close();
}
}
}
The code for the <class>JpaController
works fine in another project. In fact, these database operations should probably be in their own project as a library, but I don't believe there's a problem with the underlying Page
, which was created with "Entity Classes from Database...", nor the similarly created JpaController. I added the facade, as per a similar scenario.
How do I troubleshoot where the persistence goes wrong?
I've checked that the PageJpaController
receives a Page
, and that the object has fields. yet, for some reason, the database table for Page
remains unaffected. I'm not sure how to troubleshoot further.
According to the log you are calling:
This means:
However this does not mean that the entity is written to the database. If a new transaction begins the persistence context becomes synchronized with the transaction. In order to synchronize the persistence context (managed entities) with the database you would need to invoke
flush
orcommit
. It looks likePageJpaController.create
does this properly but is it invoked? I guess it's not.