Use entity manager in scheduled service call

Hi,

I’m having trouble getting a service called through the scheduler and have it working.

The service (still work in progress) aims to send out reminders via email on a number of objects that have reached their deadline. Obviously, I want the function to run once a day through the scheduler.

This is my service code (stripped).

/*
 * Copyright (c) 2017, Axxemble
 */
package com.axxemble.base27.service;

import com.axxemble.base27.cm.CmStatus;
import com.axxemble.base27.entity.CounterMeasure;
import com.axxemble.base27.entity.Staff;
import com.haulmont.chile.core.model.MetaClass;
import com.haulmont.cuba.core.EntityManager;
import com.haulmont.cuba.core.Persistence;
import com.haulmont.cuba.core.Query;
import com.haulmont.cuba.core.app.EmailService;
import com.haulmont.cuba.core.entity.Entity;
import com.haulmont.cuba.core.global.*;
import org.springframework.stereotype.Service;

import javax.inject.Inject;
import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service(ReminderService.NAME)
public class ReminderServiceBean implements ReminderService {
    @Inject
    private EmailService emailService;

    @Inject
    private Persistence persistence;

    @Inject
    private GlobalConfig globalConfig;

    @Inject
    private Messages messages;

    public void sendReminders(){
        // Get objects of type that have date set to today, for these send emails to owners
        EntityManager em = persistence.getEntityManager();

        // CMs
        Query query = em.createQuery("select o.id from base$CounterMeasure o where o.status < 4 "+
                                                       // "and @between(o.createTs, now, now+1, day) "+
                                                        "order by o.owner");
        List<Object[]> list = query.getResultList();
        list.forEach((record) -> {
            CounterMeasure cm = em.reload((CounterMeasure) record[0], View.LOCAL);
            sendMail(cm.getTitle(), cm.getOwner());
        });

    }

    private void sendMail(String body, Staff owner) {
        // Get owner's email
        owner = persistence.getEntityManager().reload(owner, View.LOCAL);
        if (owner != null && owner.getEmail() != null) {
            // Build email
            Map<String, Serializable> params = new HashMap<>();
            params.put("body", body);
            params.put("link", globalConfig.getWebAppUrl());

            EmailInfo emailInfo = new EmailInfo(
                    owner.getEmail(), // recipients
                    "Base27: " + messages.getMessage(getClass(), "subjectReminder"), // subject
                    "no-reply@axxemble.com", // the "from" address will be taken from the "cuba.email.fromAddress" app property
                    "com/axxemble/base27/templates/email.txt", // body template
                    params // template parameters
            );
            emailService.sendEmailAsync(emailInfo);
        };

    }
}

When called through the scheduler I get this error:

ERROR c.h.cuba.core.sys.ServiceInterceptor - Exception:
java.lang.IllegalStateException: No active transaction
        at com.haulmont.cuba.core.sys.PersistenceImpl.getEntityManager(PersistenceImpl.java:152) ~[cuba-core-6.4.5.jar:6.4.5]
        at com.haulmont.cuba.core.sys.PersistenceImpl.getEntityManager(PersistenceImpl.java:146) ~[cuba-core-6.4.5.jar:6.4.5]
        at com.axxemble.base27.service.ReminderServiceBean.sendReminders(ReminderServiceBean.java:40) ~[app-core-0.1-SNAPSHOT.jar:na]
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_121]
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_121]
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_121]
        at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_121]

The ‘at com.axxemble.base27.service.ReminderServiceBean.sendReminders(ReminderServiceBean.java:40)’ refers to this line in the service bean:

EntityManager em = persistence.getEntityManager();

Somehow there is no option to work with the entity manager when called through the scheduler?

Any help appreciated.

1 Like

Hi,

First of all, you have to start DB transaction Programmatic Transaction Management - CUBA Platform. Developer’s Manual Persistence.getEntityManager() can be invoked only if there is an active transaction in the current thread.

2 Likes

Thanks Yuriy, worked as expected following the indicated topic.
Regards, Berend