In a servelt, I try to call the session bean method to insert data to database via JPA. The insert process is written in the session bean.
I tried another example, which I select data from DB. The "select" works good. But I have no idea that why insert does not work.
The error information is:
HTTP Status 500
description: The server encountered an internal error () that prevented it from fulfilling this request.
exception: javax.ejb.EJBException
note: The full stack traces of the exception and its root causes are available in the GlassFish Server Open Source Edition 3.0.1 logs.
I think there is something wrong with "tx.commit()", when I comment it then there is no error. But I do not know what the exactly problem.
Here is the bean class
#Stateless
#LocalBean
public class testSession {
public testSession() {
// TODO Auto-generated constructor stub
}
public void insertData(){
EntityManagerFactory emf;
EntityManager em;
//the Entity Class-Category
Category cat=new Category();
//set value
cat.setId(5);
cat.setName("test cat");
//the "test" is the persist unit in persistence.xml
emf=Persistence.createEntityManagerFactory("test");
em=emf.createEntityManager();
EntityTransaction tx=em.getTransaction();
tx.begin();
em.persist(cat);
tx.commit();
em.close();
emf.close();
}
}
In the servlet
#WebServlet("/testServlet")
public class testServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
#EJB
testSession ts;
public testServlet() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
PrintWriter out=response.getWriter();
out.print("<html><body>");
//call the method in the session bean to insert data
ts.insertData();
out.print("</body></html>");
}
}
you need Injection via #PersistenceContext
The EntityManager itself is created by the container using the information in the persistence.xml, so to use it at runtime, we simply need to request it be injected into one of our components. We do this via #PersistenceContext
The #PersistenceContext annotation can be used on any CDI bean, EJB, Servlet, Servlet Listener, Servlet Filter, or JSF ManagedBean. If you don't use an EJB you will need to use a UserTransaction begin and commit transactions manually. A transaction is required for any of the create, update or delete methods of the EntityManager to work.
Example:
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
#Stateless
#LocalBean
public class testSession {
#PersistenceContext(unitName = "MyUNIT_PERSIS_IMPORTANT_View_THE_persistence.XML")
private EntityManager entityManager;
public testSession() {
// TODO Auto-generated constructor stub
}
public void insertData(){
//the Entity Class-Category
Category cat=new Category();
//set value
cat.setId(5);
cat.setName("test cat");
entityManager.persist(cat);
}
}
Reference
http://tomee.apache.org/examples-trunk/injection-of-entitymanager/
I have used maven to this demo
Demo
https://mega.co.nz/#!AxtRVQzB!MdwwOXA1e_VayWgwIdxGdREhd69QDb6la0yT0mLMaKA
to url to of servlet this
http://<HOST>/use-session-bean-to-insert-data-with-jpa/testServlet
SQL create
CREATE TABLE category (
id INT NOT NULL AUTO_INCREMENT,
`name` VARCHAR(200),
PRIMARY KEY (id));
Persistence.xml
...
<persistence-unit name="test" transaction-type="JTA">
..
Java Servlet
import com.mycompany.ejb.testSession;
import java.io.IOException;
import java.io.PrintWriter;
import javax.ejb.EJB;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
*
* #author I2B Boris
*/
#WebServlet(name = "testServlet", urlPatterns = {"/testServlet"})
public class testServlet extends HttpServlet {
#EJB
testSession ts;
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
PrintWriter out = response.getWriter();
out.print("<html><body>");
//call the method in the session bean to insert data
ts.insertData();
out.print("</body></html>");
}
}
Java EJB
package com.mycompany.ejb;
import com.mycompany.entities.Category;
import javax.ejb.Stateless;
import javax.ejb.LocalBean;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
/**
*
* #author I2B Boris
*/
#Stateless
#LocalBean
public class testSession {
#PersistenceContext(unitName = "test")
private EntityManager entityManager;
public void insertData() {
//the Entity Class-Category
Category cat = new Category();
//set value
cat.setId(5);
cat.setName("test cat");
entityManager.persist(cat);
}
}
Entity
package com.mycompany.entities;
import java.io.Serializable;
import javax.persistence.*;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import javax.xml.bind.annotation.XmlRootElement;
/**
*
* #author I2B Boris
*/
#Entity
#Table(name = "category")
#XmlRootElement
#NamedQueries({
#NamedQuery(name = "Category.findAll", query = "SELECT c FROM Category c"),
#NamedQuery(name = "Category.findById", query = "SELECT c FROM Category c WHERE c.id = :id"),
#NamedQuery(name = "Category.findByName", query = "SELECT c FROM Category c WHERE c.name = :name")})
public class Category implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#NotNull
#Column(name = "id")
private Integer id;
#Size(max = 200)
#Column(name = "name")
private String name;
public Category() {
}
public Category(Integer id) {
this.id = id;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public int hashCode() {
int hash = 0;
hash += (id != null ? id.hashCode() : 0);
return hash;
}
#Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof Category)) {
return false;
}
Category other = (Category) object;
if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
return false;
}
return true;
}
#Override
public String toString() {
return "com.mycompany.entities.Category[ id=" + id + " ]";
}
}
Related
I am trying to add a row to the database using hibernate and sessions/sessionfactory. However when I did the following code, it only added to the database once with values of "1, null". I think the problem is within ProductAdd.java (below), but I am not sure.
package com.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import com.product.Product;
import com.utility.HibernateUtility;
#WebServlet("/ProductAdd")
public class ProductAdd extends HttpServlet {
private static final long serialVersionUID = 1L;
#Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("inside servlet");
Product product= new Product(request.getParameter("prodId"),request.getParameter("prodName"));
try {
Product p = new Product();
p.setName(product.getName());
p.setId(product.getName());
Session session = HibernateUtility.getSessionFactory().openSession();
org.hibernate.Transaction transaction = null;
try {
transaction = session.beginTransaction();
String sql = "INSERT INTO Product VALUES (:idVal, :nameVal)";
Query query = session.createSQLQuery(sql);
query.setParameter("idVal", product.getId());
query.setParameter("nameVal", product.getName());
query.executeUpdate();
session.getTransaction().commit();
} catch (HibernateException e) {
transaction.rollback();
e.printStackTrace();
} finally {
session.close();
}
System.out.println(("Product is added."));
} catch (Exception e) {
// TODO: handle exception
}
HttpSession session= request.getSession();
session.setAttribute("sesname", request.getParameter("prodId"));
response.sendRedirect("addsuccess.jsp");
}
}
Here is my Product.java if needed also:
package com.product;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
#Entity
public class Product implements Serializable{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private String id;
private String name;
public Product(String string, String string2) {
super();
// TODO Auto-generated constructor stub
}
public Product() {
// TODO Auto-generated constructor stub
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
I also have my HibernateUtility class:
package com.utility;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;
public class HibernateUtility {
private static final SessionFactory sessionFactory = createSessionFactory();
public static SessionFactory createSessionFactory() {
try {
return new AnnotationConfiguration().configure().buildSessionFactory();
} catch (Exception ex) {
System.err.println("SessionFactory creation failed");
throw new ExceptionInInitializerError(ex);
}
}
/**
* #return the sessionfactory
*/
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
}
Along with hibernate.cfg.xml.
You are not actually using the request parameters because your product constructor looks like this:
public Product(String string, String string2) {
super();
// TODO Auto-generated constructor stub
}
So this line doesn't do what you expect:
Product product= new Product(request.getParameter("prodId"),request.getParameter("prodName"));
And neither do these:
Product p = new Product();
p.setName(product.getName());
p.setId(product.getName());
or these:
query.setParameter("idVal", product.getId());
query.setParameter("nameVal", product.getName());
(by the way, not sure what is the use of p if you still use product to set the query params).
So you end up with null for the product name, and 1 for the id because of the GenerationType.AUTO, otherwise that would have been null too, I think.
You need to change your constructor to use the parameters:
public Product(String string, String string2) {
this.id = string;
this.name = string2;
}
This way, you will later have something to send to your database query.
I have a legacy app using JEE5 , I add a class "People" and add "by hand" in the database a lot of records (people only has peopleid and a string peopledesc)
If I use the method getAllPeople() I get the list correctly populated, every data is there
But when I try to persist a new record by code using persistPeople(People pep) It just does nothing
The system.out.println shows the description added to the object so the new created object is passed to the method, but it is not persisted in the database :(
No error is shown in the console output.
People.java
#Entity
public class People implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int idpeople;
private String desc;
persistence.xml
<persistence-unit name="PersistenceUnit" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>entities.People</class>
......
PeopleDAOImPL.JAVA
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceUnit;
import residencias.dominio.Renovacion;
#Stateless
public class PeopleDAOImpl implements PeopleDAO {
//EntityManagerFactory emf = Persistence.createEntityManagerFactory("PersistenceUnit");
#PersistenceUnit(unitName="PersistenceUnit")
private EntityManagerFactory emf;
#Override
public void persistPeople(People pep) {
EntityManager em = emf.createEntityManager();
System.out.println("description is :"+pep.getDesc());
em.persist(pep);
}
#Override
public List<People> getAllPeople() {
EntityManager em = emf.createEntityManager();
List<People> results = new ArrayList();
Query queryPrincipal;
try {
queryPrincipal = em.createQuery("SELECT p FROM People p");
results = queryPrincipal.getResultList();
return results;
} catch (Exception e) {
System.out.println(results.size());
return results;
} finally {
if (em != null) {
emf.close();
em.close();
}
}
}
While during the invocation of a query, you are not obliged to be running within a transaction, when you try to persist / update state of an entity you must be running that particular action within a transaction boundary.
In your case you could use following configuration:
#Stateless
#TransactionManagement(TransactionManagementType.CONTAINER)
public class PeopleDAOImpl implements PeopleDAO {
#PersistenceUnit(unitName="PersistenceUnit")
private EntityManagerFactory emf;
#Override
#TransactionAttribute(TransactionAttributeType.REQUIRED)
public void persistPeople(People pep) {
EntityManager em = emf.createEntityManager();
System.out.println("description is :"+pep.getDesc());
em.persist(pep);
}
I am currently learning JPA. And in the doc, it noted that only when entity is detached to be remotely by other JVM, that it need to be Serializable.
However, for testing purpose, I created my Entity as an Inner Private Class of my persistence Class (a CDI).
And when I attempt to persist the Entity using EntityManager. I get an exception as follow:
Caused by: Exception [EclipseLink-7155] (Eclipse Persistence Services - 2.5.0.v20130507-3faac2b): org.eclipse.persistence.exceptions.ValidationException
Exception Description: The type [class minh.ea.common.Ultilities.DatabaseLogger] for the attribute [this$0] on the entity class [class minh.ea.common.Ultilities.DatabaseLogger$LogRecord] is not a valid type for a serialized mapping. The attribute type must implement the Serializable interface.
This exception as I understood, meaning my entity Attribute need to be Serializable as well as the Class. So what is the reason, where is it being passed to?
All of these are running under GlassFish 4.0 Container. JPA using EclipseLink 2.1
My implementation of the persistence and the inner Entity is as follow:
package minh.ea.common.Ultilities;
import java.util.Date;
import javax.enterprise.context.ApplicationScoped;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.PersistenceContext;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.transaction.Transactional;
/**
*
* #author Minh
*/
#ApplicationScoped
#minh.ea.common.Ultilities.qualifiers.Database
public class DatabaseLogger implements Logger {
#PersistenceContext
private EntityManager em;
private final long MAX_SIZE=2097152;
public DatabaseLogger(){
}
#Override
#Transactional
public void info(Object obj) {
em.persist(new RecordEntry("INFO", new Date(), obj.toString()));
}
#Override
#Transactional
public void warn(Object obj) {
em.persist(new RecordEntry("WARN", new Date(), obj.toString()));
}
#Override
#Transactional
public void error(Object obj) {
em.persist(new RecordEntry("ERROR", new Date(), obj.toString()));
}
#Override
#Transactional
public void fatal(Object obj) {
em.persist(new RecordEntry("FATAL", new Date(), obj.toString()));
}
#Entity
public class LogRecord{
#Id #GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String type;
#Temporal(TemporalType.TIMESTAMP)
private Date time;
private String message;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public Date getTime() {
return time;
}
public void setTime(Date time) {
this.time = time;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public LogRecord() {
}
public LogRecord(String type, Date time, String message) {
this.type = type;
this.time = time;
this.message = message;
}
}
}
Best regards,
As per this reference, valid Entity classes must be top-level classes, meaning that your inner class won't work.
Try pulling it out into a Entity class of its own, as it would be in a proper system, and persist again.
I use this tutorrial and I created this
table (id ,username) prints;
and now I want to insert data to it using the restful web service
what should I put in the content text box to do that ?
this is my paints class
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package entities;
import java.io.Serializable;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import javax.xml.bind.annotation.XmlRootElement;
/**
*
* #author subhi
*/
#Entity
#Table(name = "prints")
#XmlRootElement(name = "prints")
#NamedQueries({
#NamedQuery(name = "Prints.findAll", query = "SELECT p FROM Prints p"),
#NamedQuery(name = "Prints.findById", query = "SELECT p FROM Prints p WHERE p.id = :id"),
#NamedQuery(name = "Prints.findByUsername", query = "SELECT p FROM Prints p WHERE p.username = :username")})
public class Prints implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Basic(optional = false)
#NotNull
#Column(name = "id")
private Integer id;
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 30)
#Column(name = "username")
private String username;
public Prints() {
}
public Prints(Integer id) {
this.id = id;
}
public Prints(Integer id, String username) {
this.id = id;
this.username = username;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
#Override
public int hashCode() {
int hash = 0;
hash += (id != null ? id.hashCode() : 0);
return hash;
}
#Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof Prints)) {
return false;
}
Prints other = (Prints) object;
if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
return false;
}
return true;
}
#Override
public String toString() {
return "entities.Prints[ id=" + id + " ]";
}
}
I tried use put method but I got this error
and why I didn't have post method in combobox?
controller code java EE 6
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package service;
import entities.Prints;
import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import org.netbeans.saas.RestResponse;
import org.netbeans.saas.google.GoogleMapService;
/**
*
* #author subhi
*/
#Stateless
#Path("entities.prints")
public class PrintsFacadeREST extends AbstractFacade<Prints> {
#PersistenceContext(unitName = "test3PU")
private EntityManager em;
public PrintsFacadeREST() {
super(Prints.class);
}
#POST
#Override
#Consumes({"application/xml", "application/json"})
public void create(Prints entity) {
super.create(entity);
}
#PUT
#Override
#Consumes({"application/xml", "application/json"})
public void edit(Prints entity) {
super.edit(entity);
}
#DELETE
#Path("{id}")
public void remove(#PathParam("id") Integer id) {
super.remove(super.find(id));
}
#GET
#Path("{id}")
#Produces({"application/xml", "application/json"})
public Prints find(#PathParam("id") Integer id) {
return super.find(id);
}
#GET
#Override
#Produces({"application/xml", "application/json"})
public List<Prints> findAll() {
return super.findAll();
}
#GET
#Path("{from}/{to}")
#Produces({"application/xml", "application/json"})
public List<Prints> findRange(#PathParam("from") Integer from, #PathParam("to") Integer to) {
return super.findRange(new int[]{from, to});
}
#GET
#Path("count")
#Produces("text/plain")
public String countREST() {
return String.valueOf(super.count());
}
#Override
protected EntityManager getEntityManager() {
return em;
}
#GET
#Produces("text/html")
public String getGoogleMap() {
// Drag and drop the getGoogleMap operation here
try {
String address = "16 Network Circle, Menlo Park";
java.lang.Integer zoom = 15;
String iframe = "false";
RestResponse result = GoogleMapService.getGoogleMap(address, zoom, iframe);
return result.getDataAsString();
} catch (Exception ex) {
ex.printStackTrace();
}
return "";
}
}
Put the request body part there.If you going to update some entity then you should pass the dto with data which should be updated.I didn't go through your link.this part can be in Json or XML.(like below)
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<prints>
<id>1</id>
<username>test</username>
</prints>
you have to annotate your dto lets say printsDTO as below
#XmlRootElement(name = "prints")
public class PrintsDTO {
private int id;
private String username;
// have getters and setteres for above
}
I used code to insert data to my restful web service using restful client application as follow
NewJerseyClient client = new NewJerseyClient();
Prints p = new Prints();
p.setId(235);
p.setUsername("subhi");
client.create_XML(p);
and this is sufficient for my case
First here is my entire EJB file:
package enkia.pulse.indexing.beans;
import enkia.pulse.core.Category;
import enkia.pulse.core.Product;
import enkia.pulse.core.Review;
import enkia.pulse.core.Twitter;
import enkia.utils.HarvestingConstants;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.Resource;
import javax.ejb.SessionContext;
import javax.ejb.Stateless;
import javax.ejb.TimedObject;
import javax.ejb.Timer;
import javax.ejb.TimerService;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.transaction.UserTransaction;
import twitter4j.FilterQuery;
import twitter4j.Status;
import twitter4j.StatusDeletionNotice;
import twitter4j.StatusListener;
import twitter4j.TwitterException;
import twitter4j.TwitterStream;
import twitter4j.TwitterStreamFactory;
import twitter4j.auth.AccessToken;
/**
*
* #author joshua
*/
#Stateless
public class TwitterBean implements TwitterBeanLocal,
TimedObject {
List<String> _twitterTopics;
Map<String,Integer> _tagCatRel;
TimerService _timerService;
Timer _timer;
/** The session context needed to create the timer */
#Resource
private SessionContext _sc;
#PersistenceContext(unitName=HarvestingConstants.PERSISTENCE_UNIT)
EntityManager _entityManager;
/** A logging object for formatted output to the server log. */
private Logger _logger;
private int errors;
/**
* Constructs the logger
*/
public TwitterBean(){
_logger = Logger.getLogger(this.getClass().getName());
_logger.log(Level.INFO,"Instantiating Twitter Bean");
}
/**
* Attempts to retrieve the configuration object. Creates the harvester
* with the configuration and then sets a timer to run the harvester
* periodically
*/
public void initialize() {
_logger.log(Level.INFO,"Initializing Twitter bean.");
_twitterTopics = new LinkedList<String>();
_tagCatRel = new HashMap<String,Integer>();
_timerService = _sc.getTimerService();
_timer = _timerService.createTimer(0,1000*60*60,null); //restart every hour
_logger.log(Level.INFO,"Starting Twitter timer");
}
public void ejbTimeout(Timer timer) {
_logger.log(Level.INFO,"Running Twitter timer");
findTopics();
try {
setupStream();
} catch (TwitterException ex) {
Logger.getLogger(TwitterBean.class.getName()).log(Level.SEVERE, null, ex);
}
}
private void setupStream() throws TwitterException{
StatusListener listener = new StatusListener(){
#Override
public void onStatus(Status status) {
insertStatus(status);
}
#Override
public void onDeletionNotice(StatusDeletionNotice statusDeletionNotice) {
//DO nothing
}
#Override
public void onTrackLimitationNotice(int numberOfLimitedStatuses) {
_logger.log(Level.INFO,"Track limitation notice: "+numberOfLimitedStatuses);
}
#Override
public void onScrubGeo(long l, long l1) {
_logger.log(Level.INFO,"Scrub GEO");
}
#Override
public void onException(Exception ex) {
ex.printStackTrace();
}
};
TwitterStream twitterStream = new TwitterStreamFactory().getInstance();
twitterStream.setOAuthConsumer("secret", "secret");
twitterStream.setOAuthAccessToken(new AccessToken("secret","secret"));
FilterQuery query = new FilterQuery();
query = query.track(_twitterTopics.toArray(new String[_twitterTopics.size()]));
twitterStream.addListener(listener);
twitterStream.filter(query);
}
public void insertStatus(Status status){
String foundTag="";
for(String tag : _tagCatRel.keySet()){
if(status.getText().toLowerCase().contains(tag.toLowerCase())){
//found
foundTag=tag;
break;
}
}
if(foundTag.equals("")){
return;
}
Integer category = _tagCatRel.get(foundTag);
Query q=_entityManager.createNamedQuery("Category.findByCategoryId");
q.setParameter("categoryId",category);
Category c = (Category) q.getSingleResult();
Product p = new Product(c);
_entityManager.persist(p);
_entityManager.merge(p);
Review r = new Review();
r.setReview(status.getText());
r.setUrl("http://www.twitter.com/"+status.getUser().getScreenName()+"/statuses/"+status.getId());
r.setProcessed(0);
r.setDateCreated(status.getCreatedAt().getTime());
p.getPartNumber();
r.setProductId(p.getProductId());
_entityManager.persist(r);
_logger.log(Level.INFO,"Added tweet:" + r.getReview());
}
private void findTopics() {
_twitterTopics = new LinkedList<String>();
Query twitterQuery=_entityManager.createNamedQuery("Twitter.findAll");
String all="";
for(Object t: twitterQuery.getResultList()){
Twitter twitter=(Twitter) t;
for(String tag : twitter.getTags().split(" ")){
_twitterTopics.add(tag);
all+=tag+", ";
Integer test = twitter.getCategoryId();
_tagCatRel.put(tag,twitter.getCategoryId());
}
}
_logger.log(Level.INFO,"Tracking: "+all);
}
}
And my persistence.xml:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" 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">
<persistence-unit name="PulsePU" transaction-type="JTA">
<jta-data-source>pulseEJB</jta-data-source>
<class>enkia.pulse.core.Category</class>
<class>enkia.pulse.core.Department</class>
<class>enkia.pulse.core.Feature</class>
<class>enkia.pulse.core.Product</class>
<class>enkia.pulse.core.Review</class>
<class>enkia.pulse.core.ReviewSnippet</class>
<class>enkia.pulse.core.Sentiment</class>
<class>enkia.pulse.core.SentimentReview</class>
<class>enkia.pulse.core.Twitter</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties/>
</persistence-unit>
</persistence>
Lastly is my sun-resource.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE resources PUBLIC "-//Sun Microsystems, Inc.//DTD Application Server 9.0 Resource Definitions //EN" "http://www.sun.com/software/appserver/dtds/sun-resources_1_3.dtd">
<resources>
<jdbc-resource enabled="true" jndi-name="pulseEJB" object-type="user" pool-name="mysqlPool"/>
<jdbc-connection-pool allow-non-component-callers="false" associate-with-thread="false" connection-creation-retry-attempts="0" connection-creation-retry-interval-in-seconds="10" connection-leak-reclaim="false" connection-leak-timeout-in-seconds="0" connection-validation-method="auto-commit" datasource-classname="com.mysql.jdbc.jdbc2.optional.MysqlDataSource" fail-all-connections="false" idle-timeout-in-seconds="300" is-connection-validation-required="false" is-isolation-level-guaranteed="true" lazy-connection-association="false" lazy-connection-enlistment="false" match-connections="false" max-connection-usage-count="0" max-pool-size="32" max-wait-time-in-millis="60000" name="mysqlPool" non-transactional-connections="false" pool-resize-quantity="2" res-type="javax.sql.DataSource" statement-timeout-in-seconds="-1" steady-pool-size="8" validate-atmost-once-period-in-seconds="0" wrap-jdbc-objects="false">
<property name="serverName" value="endpoint"/>
<property name="portNumber" value="3306"/>
<property name="databaseName" value="pulse"/>
<property name="User" value="user"/>
<property name="Password" value="password"/>
<property name="URL" value="jdbc:mysql://endpoint/pulse"/>
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
I'm using Netbeans.
I instantiate my EJB in a webproject. I have another EJB setup the same that I instantiate there that works fine with container managed transaction. I also tried just saying "screw it" and used UserTransaction but that had problems with the merge and ended up with numerous unexpected problems, NPE on p right after "_entityManager.persist(p); _entityManager.merge(p);"
Any suggestions on where to look for differences between the two EJBs is appreciated as I'm out of ideas.
I also noticed netbeans is generating sources for two of my entity classes in the problematic EJB labeled "ap-source-output" but doesn't in the working EJB.
Generated Code I don't understand why being generated below:
package enkia.pulse.core;
import javax.annotation.Generated;
import javax.persistence.metamodel.SingularAttribute;
import javax.persistence.metamodel.StaticMetamodel;
#Generated(value="EclipseLink-2.2.0.v20110202-r8913", date="2012-08-08T23:09:05")
#StaticMetamodel(Twitter.class)
public class Twitter_ {
public static volatile SingularAttribute<Twitter, Integer> id;
public static volatile SingularAttribute<Twitter, String> tags;
public static volatile SingularAttribute<Twitter, Integer> categoryId;
public static volatile SingularAttribute<Twitter, Long> lastStatus;
}
And
package enkia.pulse.core;
import enkia.pulse.core.Category;
import javax.annotation.Generated;
import javax.persistence.metamodel.SingularAttribute;
import javax.persistence.metamodel.StaticMetamodel;
#Generated(value="EclipseLink-2.2.0.v20110202-r8913", date="2012-08-08T23:41:31")
#StaticMetamodel(Product.class)
public class Product_ {
public static volatile SingularAttribute<Product, String> productBrand;
public static volatile SingularAttribute<Product, Category> category;
public static volatile SingularAttribute<Product, String> model;
public static volatile SingularAttribute<Product, byte[]> image;
public static volatile SingularAttribute<Product, String> productName;
public static volatile SingularAttribute<Product, String> imageURL;
public static volatile SingularAttribute<Product, String> specifications;
public static volatile SingularAttribute<Product, Integer> productId;
public static volatile SingularAttribute<Product, String> partNumber;
}
While I'm at it I'll show the entity file too:
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package enkia.pulse.core;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
/**
*
* #author fbarrow
*/
#Entity
#Table(name = "twitter")
#NamedQueries({
#NamedQuery(name = "Twitter.findAll", query = "SELECT t FROM Twitter t"),
#NamedQuery(name = "Twitter.findById", query = "SELECT t FROM Twitter t WHERE t.id = :id"),
#NamedQuery(name = "Twitter.findByCategoryId", query = "SELECT t FROM Twitter t WHERE t.categoryId = :categoryId"),
#NamedQuery(name = "Twitter.findByTags", query = "SELECT t FROM Twitter t WHERE t.tags = :tags"),
#NamedQuery(name = "Twitter.findByLastStatus", query = "SELECT t FROM Twitter t WHERE t.lastStatus = :lastStatus")})
public class Twitter implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Integer id;
#Column(name = "categoryId")
private Integer categoryId;
#Column(name = "tags")
private String tags;
#Column(name = "lastStatus")
private Long lastStatus;
public Twitter() {
}
public Twitter(Integer id) {
this.id = id;
}
public Twitter(Integer id, Integer categoryId, String tags, Long lastStatus) {
this.id = id;
this.categoryId = categoryId;
this.tags = tags;
this.lastStatus = lastStatus;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getCategoryId() {
return categoryId;
}
public void setCategoryId(Integer categoryId) {
this.categoryId = categoryId;
}
public String getTags() {
return tags;
}
public void setTags(String tags) {
this.tags = tags;
}
public Long getLastStatus() {
return lastStatus;
}
public void setLastStatus(Long lastStatus) {
this.lastStatus = lastStatus;
}
#Override
public int hashCode() {
Integer hash = 0;
hash += (id != null ? id.hashCode() : 0);
return hash;
}
#Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof Twitter)) {
return false;
}
Twitter other = (Twitter) object;
if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
return false;
}
return true;
}
#Override
public String toString() {
return "enkia.pulse.core.Twitter[ id=" + id + " ]";
}
}
Error:
SEVERE: javax.persistence.TransactionRequiredException
at com.sun.enterprise.container.common.impl.EntityManagerWrapper.doTxRequiredCheck(EntityManagerWrapper.java:163)
at com.sun.enterprise.container.common.impl.EntityManagerWrapper.doTransactionScopedTxCheck(EntityManagerWrapper.java:145)
at com.sun.enterprise.container.common.impl.EntityManagerWrapper.persist(EntityManagerWrapper.java:263)
at enkia.pulse.indexing.beans.TwitterBean.insertStatus(TwitterBean.java:154)
at enkia.pulse.indexing.beans.TwitterBean$1.onStatus(TwitterBean.java:99)
at twitter4j.StatusStreamImpl.onStatus(StatusStreamImpl.java:78)
at twitter4j.AbstractStreamImplementation$1.run(AbstractStreamImplementation.java:107)
at twitter4j.internal.async.ExecuteThread.run(DispatcherImpl.java:114)
Use of Timer to create TwitterStream, running an independent thread?
The timer calls setupStream, which creates a listener, and binds that listener to twitterStream, created via the TwitterStreamFactory. That code isn't shown, however from the context it would appear that the TwitterStream is running code asynchronously:
twitter4j.internal.async.ExecuteThread
is in your stack-trace, below the exception. My bet is you're managing your own threads, which is not running within the container's context - all bets are off for accessing container resources and interacting with the container in this model (which is why Java EE so strongly suggests that you do NOT run your own threading model).
Specifically, that code is NOT running within a container managed transaction.
You might explore having the the Timer Service launch the background task via an MDB, which will run asynchronously from your EJB, in a proper container.