I want to run some process just after the deployment of Glassfish. Process will run every hour and it contains fetching data from DB table via stateless bean CarService with findAll() below:
#PersistenceContext
private EntityManager em;
public List<Cars> findAll() {
javax.persistence.criteria.CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
cq.select(cq.from(Cars.class));
return em.createQuery(cq).getResultList();
}
Then i am using ScheduledExecutorService with starts process after deployment.
#ManagedBean(eager=true)
#ApplicationScoped
public class ApplicationStateChange {
private ScheduledExecutorService scheduler;
#PostConstruct
public void init() {
System.out.println("ejb init method called");
scheduler = Executors.newScheduledThreadPool(2);
scheduler.scheduleAtFixedRate(new ScheduleTask();, 15, 30, TimeUnit.SECONDS);
}
#PreDestroy
public void destroy() {
/* Shutdown stuff here */
System.out.println("ejb destroy method called");
scheduler.shutdownNow();
}
above ScheduleTask() contains the process including business logic e.g:
public class ScheduleTask implements Runnable {
#Inject
CarService carService;
private volatile ScheduledExecutorService scheduler = null;
#Override
public void run() {
System.out.println("scheduletask is called");
List<Car> carList = new ArrayList<>();
carList = carService.findAll();
if (carList != null) {
for (Car car : carList) {
System.out.println(car);
}
}
}
i am unable to get the findALL() method by injecting into above runnable class. scheduler works fine but it fails when it reaches to carList = carService.findAll(); infact its failing at javax.persistence.criteria.CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
I suspect persistence context is not loaded properly at the time of its calling.
I have followed following questionsSpawning threads in a JSF managed bean for scheduled tasks using a timer
scheduledExecutorService, timerService and Stateless EJB on scheduled jobs
As clearly exposed in the answer for the first question you have linked, simply use #Schedule into a #Singleton SessionBean annotated with #Startup in order to ensure it runs when the server starts or the application is deployed.
As you correctly mentioned, EntityManager and PersistenceContext cannot be injected into a non container-mananged class (and Singleton SessionBean is a managed class).
Linked Answer:
Spawning threads in a JSF managed bean for scheduled tasks using a timer
Related
I'm having an issue with JPA in multithreads application. I'm using JPA proxy authentication to access the database. Everything runs fine in session beans but when in java thread run() method, I cannot use #EJB so I use Initialcontext to look up the bean. When the program executes, I'm getting invalid username/password; logon denied.
#Stateless
public class MyDAO{
#PersistenceContext(name="myPU")
private EntityManager em;
public MyEntity getData(String id){
return em.find(MyEntity.class, id);
}
#AroundInvoke
public Object setSessionUser(InvocationContext ctx){
if(ctx.getTarget() instanceof MyDAO){
Map properties = new HasMap();
properties.put("eclipselink.oracle.proxy-type", OracleConnection.PROXYTYPE_USER_NAME);
properties.put(OracleConnection.PROXY_USER_NAME, "myusername");
properties.put("eclipselink.jdbc.exclusive-connection.mode", "Always");
properties.put("eclipselink.jdbc.exclusive-connection.is-lazy", "false");
((org.eclipse.persistence.internal.jpa.EntityManagerImpl)em.getDelegate()).setProperties(properties);
}
return ctx.proceed();
}
}
inside run();
#Override
public void run(){
...
MyDAO dao = (MyDAO) new InitialContext().lookup("java:module/...");
EntityObject obj = dao.getData("123456");
...
}
I have an application scoped bean
#ManagedBean(name = "myController")
#ApplicationScoped
public class MyController implements Serializable{
...
public void allOn(){...}
And i want to call the allOn() method from a quartz-job
import org.quartz.Job;
public class CronJobAllOn implements Job{
#Override
public void execute(..){
//call allOn();}
}
I tried to pass the FacesContext to the Job-Class via the JobDataMap
JobDataMap jobDataMap = new JobDataMap();
jobDataMap.put("facesContext", FacesContext.getCurrentInstance());
JobDetail job = newJob(CronJobAllOn.class)
.usingJobData(jobDataMap)
.withIdentity("job1", "group1")
.build();
But it only throws an IllegalStateException when i try to call it in the CronJobAllOn Class
public void execute(JobExecutionContext context) throws JobExecutionException {
FacesContext fc= (FacesContext) context.getMergedJobDataMap().get("facesContext");
MyController test = (MyController)fc.getExternalContext().getApplicationMap().get("MyController");
test.allOn();}
How can i call the allOn() method in MyController from a quartz-job?
I got the solution for my Problem, the short comment from BalusC put me on the right path.
I switched to TomEE, to get CDI.
To use the CDI-Bean injection in my jobs, i had to create my own JobFactory Class:
public class CdiJobFactory implements JobFactory {
#Inject
#Any
private Instance<Job> jobs;
#Override
public Job newJob(TriggerFiredBundle triggerFiredBundle, Scheduler scheduler) throws SchedulerException {
final JobDetail jobDetail = triggerFiredBundle.getJobDetail();
final Class<? extends Job> jobClass = jobDetail.getJobClass();
for (Job job : jobs) {
if (job.getClass().isAssignableFrom(jobClass)) {
return job;
}
}
throw new RuntimeException("Cannot create a Job of type " + jobClass);
}
create the Factory
Scheduler scheduler = new StdSchedulerFactory().getScheduler();
scheduler.setJobFactory(cdiJobFactory);
after that i was able to inject myController:
public class CronJobAllOn implements Job{
#Inject
private MyController mc;
#Override
public void execute(JobExecutionContext context) throws JobExecutionException {
mc.allOn();
}
I have Stateless bean that calls asynchronous operation. I would like to inject to this bean my another bean, which stores (or rather should store) running process status. Here is my code:
Processor:
#Stateless
public class Processor {
#Asynchronous
public void runLongOperation() {
System.out.println("Operation started");
try {
for (int i = 1; i <= 10; i++) {
//Status update goes here...
Thread.sleep(1000);
}
} catch (InterruptedException e) {
}
System.out.println("Operation finished");
}
}
ProcessorHandler:
#ManagedBean(eager = true, name="ph")
#ApplicationScoped
public class ProcessorHandler implements RemoteInterface {
public String status;
#EJB
private Processor processor;
#PostConstruct
public void init(){
status = "Initialized";
}
#Override
public void process() {
processor.runLongOperation();
}
public String getStatus() {
return status;
}
}
Process method of ProcessHandler is bound to a button.
I would like to modify status of ProcessHandler bean from inside of Processor, so I can display updated status to user.
I tried to use #Inject, #ManagedProperty and #EJB annotations, but without success.
I'm testing my soulution on Websphere v8.5 developed using Eclipse EE.
When added inject to Processor class...
#Inject
public ProcessorHandler ph;
I got error:
The #Inject java.lang.reflect.Field.ph reference of type ProcessorHandler for the <null> component in the Processor.war module of the ProcessorEAR application cannot be resolved.
You should never have any client-specific artifacts (JSF, JAX-RS, JSP/Servlet, etc) in your service layer (EJB). It makes the service layer unreusable across different clients/front-ends.
Simply move private String status field into the EJB as it's actually the one responsible for managing it.
#ManagedBean(eager = true, name="ph")
#ApplicationScoped
public class ProcessorHandler implements RemoteInterface {
#EJB
private Processor processor;
#Override
public void process() {
processor.runLongOperation();
}
public String getStatus() {
return processor.getStatus();
}
}
Note that this won't work on a #Stateless, but on #Singleton or Stateful only for the obvious reasons.
I've the below managed bean
#ManagedBean
#RequestScoped
public class customerBean {
private Customer customer;
private CustomerJpaController customerJpa;
#PostConstruct
public void init() {
customer = new Customer();
}
public String addCustomer() throws Exception {
customerJpa.create(customer);
return "customer";
}
// getter and setter
}
The CustomerJpaController looks like below:
public class CustomerJpaController implements Serializable {
#PersistenceContext(unitName = "JFSCustomerPU")
private EntityManagerFactory emf = null;
private UserTransaction utx = null;
public CustomerJpaController(UserTransaction utx, EntityManagerFactory emf) {
this.utx = utx;
this.emf = emf;
}
// ...
}
When addCustomer() is invoked from the view, it throws java.lang.NullPointerException at line customerJpa.create(customer);. How is this caused and how can I solve it?
In your code sample, your CustomerJpaController is never instantiated. So, you get a null pointer exception.
I advise you to switch to CDI and rely on its injection method to have your entity manager (factory?) properly instantiated and injected in your controller when this last is instantiated. And, so, to use #Named instead of #ManagedBean.
So, you would have :
#Named
#RequestScoped
public class CustomerJpaController implements Serializable {
...
}
(or whichever scope better fits your need)
It seems to me that you should use an EntityManager (EM) rather than an EntityManagerFactory (EMF) in your controller.
If your EMF is container managed and you have only one persistence unit, you can use the standard JPA #PersistenceContext annotation :
#PersistenceContext
private EntityManager entityManager;
If your EMF is not managed, you can leverage the power of deltaspike JPA module (remember : deltaspike is good for you :-) ) and inject an EntityManager in your controller :
#Named
#RequestScoped
public class CustomerJpaController implements Serializable {
#Inject
private EntityManager em;
}
This requires the implementation of an EntityManagerProducer class, which can have any name but must have one method annotated #Produces #RequestScoped returning an EntityManager and another one taking an EntityManager parameter annotated with #Disposes. Ex :
public class MyEntityManagerProducer {
#Inject
#PersistenceUnitName("myPU")
private EntityManagerFactory emf;
#Produces
#RequestScoped
public EntityManager createEntityManager() {
return emf.createEntityManager();
}
public void disposeEntityManager(#Disposes em) {
if (em.isOpen()) {
em.close();
}
}
Note the usage of #PersistenceUnitName("myPU"), the deltaspike annotation that will handle the instanciation of the EMF.
If you have multiple persistence units, as it is often the case in the real world, you can set them apart with qualifiers. To declare a qualifier, declare an #interface with the following annotations :
#Target({ FIELD, METHOD, PARAMETER, TYPE })
#Retention(RUNTIME)
#Documented
#Qualifier
public #interface MyQualifier {
}
Then, add this qualifier to all #Produces, #Disposes and #Inject, to allow CDI to decide which persistence unit / entity manager you are willing to use :
public class MyEntityManagerProducer {
#Inject
#PersistenceUnitName("myPU")
private EntityManagerFactory emf;
#Produces
#MyQualifier
#RequestScoped
public EntityManager createEntityManager() {
return emf.createEntityManager();
}
public void disposeEntityManager(#Disposes #MyQualifier em) {
if (em.isOpen()) {
em.close();
}
}
and in your controller :
#Named
#RequestScoped
public class CustomerJpaController implements Serializable {
#Inject
#MyQualifier
private EntityManager em;
}
All this requires CDI. Configuring CDI is way beyond a short answer to your question. I use OpenWebBeans in all my projects. Weld is also very popular.
This is my understanding of things (it might not be 100% correct but it will give you a general idea) :
Where in your bean is your Service instantiated ? Nowhere. In other words customerJpa is null.
Starting a connection to a db weights a lot on resources. So instead of you instantiating different services by yourself and opening-closing connections, the container has a pool of services and give the free ones to whoever needs it (in your case your bean needs one). How do you ask the container to give you a service :
Annotate #EJB above your service:
#EJB
private CustomerJpaController customerJpa;
and I think you are missing #Stateless as well
#Stateless
public class CustomerJpaController...
It's advised to switch to #Named and #RequestScoped (the other package) instead of #ManagedBean. Then you can use #Inject to inject your service instead of #EJB.here you can read further on the subject.
I'm trying to inject a bean in a stateless EJB. But i would like that bean be different when EJB is called from a ManagedBean or from a EJB Timer.
Here is my EJB in which i inject a User bean:
MyEjb.java
#Stateless
class MyEjb{
#Inject
#CurrentContext
private User user;
public void foo(){
System.out.println(user);
}
}
Here is a EJB Timer that use the EJB:
TimerTest.java
#Singleton
#Startup
class TimerTest {
#EJB
private MyEjb myEjb;
#Timeout
public void doIt(Timer timer) {
myEjb.foo();
}
#Produces
#CurrentContext
public User produceCurrentUserInEjbTimer(){
return new User("system");
}
}
Finally, the ManagedBean using MyEjb :
MyManagedBean.java
#ManagedBean
#SessionScoped
class MyManagedBean {
#EJB
private MyEjb myEjb;
public void bar() {
myEjb.foo();
}
#Produces
#CurrentContext
#RequestScoped
public User produceCurrentUserInManagedBean(){
return new User(FacesContext.getCurrentInstance().getExternalContext().getRemoteUser());
}
}
When the timeout is reach, i would like that foo method of MyEbj use the system User created by the method produceCurrentUserInEjbTimer.
And when the bar method of the ManagedBean is invoked, i would like that foo method of MyEbj use the remote User of the FaceContext (created by the method produceCurrentUserInManagedBean).
I would rather have only one producer that checks if FacesContext.getCurrentInstance() != null then call the apropriate code:
public User produceCurrentUser(){
if(FacesContext.getCurrentInstance() != null){
return new User(FacesContext.getCurrentInstance().getExternalContext().getRemoteUser());
}
else{
return new User("system");
}
}
You can also inject you User directly on the timer or the ManagedBean and then use InjectionPoint object to know to which class your User is injected:
public User produceCurrentUser(InjectionPoint injectionPoint){
System.out.println(injectionPoint.getBean());
}
You should also use #Named and #javax.enterprise.context.SessionScoped as you have CDI on your application instead of #ManagedBean.
UPDATE
I'm not sure that there is a direct method to get the context of the injection, it wil be possible throw CDI extension but I've never try it.
What about obtaining a contextual instance by programmatic lookup:
#Stateless
class MyEjb{
#Inject #Any Instance<User> userSource;
public void foo(String context) // you should define contexts your self as jms, jsf ...
{
// Every expected context will have a qualifier
Annotation qualifier = context.equals("jsf") ?
new JSFQualifier() : new JMSQualifier();
User p = userSource.select(qualifier).get();
System.out.println(user);
}
}
This was you can inject your EJB and pass the context param to foo:
#Named
#SessionScoped
class MyManagedBean {
#EJB
private MyEjb myEjb;
public void bar() {
myEjb.foo("jsf");
}
}