How to inject Spring DAO class in QuartzJobBean, using JobDetailFactoryBean Annotated way - quartz-scheduler

How to inject Spring DAO class in QuartzJobBean, I am using JobDetailFactoryBean instantiated at Config class level. I am using Spring4 Quartz 2.2.1 Annotation ways
#Configuration
public class SchedulerConfig {
#Bean
public JobDetailFactoryBean jobDetailFactoryBean() {
JobDetailFactoryBean factory = new JobDetailFactoryBean();
factory.setJobClass(SchedulerService.class);
//Should I inject DAO here?
factory.setGroup("mygroup");
factory.setName("myjob");
return factory;
}
}
QuartzJobBean been extended to execute
#PersistJobDataAfterExecution
#DisallowConcurrentExecution
#Service
public class SchedulerService extends QuartzJobBean {
#Autowire
public SchedulerDAO schDAO;
protected void executeInternal(JobExecutionContext ctx) throws JobExecutionException {
System.out.println("---SchedulerService .executeInternal ----");
try {
init(ctx.getJobDetail().getJobDataMap(),
ctx.getScheduler().getContext());
} catch (SchedulerException e) {
e.printStackTrace();
}
// I want to do DAO methods used here - how to do that?
// Can get access to DAO
schDAO.getSomeMethods();
}
}

Your problem is that Quartz, does not know anything about your configuration class, so it can't autowired an unknown bean.
Go to SchedulerConfig.java and declare your service or DAO as autowired, then use a jobdata and map this object in order to be passed in Quartz. Then you can use it inside executeInternal method of Quartz.
For example
#Configuration
public class mplampla{
#Autowired
private YourDAO dao;
#Bean
public JobDetailFactoryBean jobDetailFactoryBean(){
JobDetailFactoryBean factory = new JobDetailFactoryBean();
Map<String,Object> map = new HashMap<String,Object>();
map.put("YourDAO", dao);
factory.setJobDataAsMap(map);
return factory;
}
}
Then in your YourJob.java
public class YourJob extends QuartzJobBean {
#Override
protected void executeInternal(JobExecutionContext ctx) throws JobExecutionException {
JobDataMap dataMap = ctx.getJobDetail().getJobDataMap();
YourDAO dao = (YourDAO) dataMap.get("YourDAO");
dao.getMethods();
}
}
Be carefull if you are using #Service class and YourDAO class as #Transational, you will get error about undeclared Bean. In this case you have to pass the inteface of your DAO.

Related

How to use different EntityManager based on condition at runtime?

My congfiguration is like below:
The abstract class:
public abstract class AbstractFacade<T> {
private Class<T> entityClass;
public AbstractFacade(Class<T> entityClass) {
this.entityClass = entityClass;
}
protected abstract EntityManager getEntityManager();
public T find(Object id) {
return getEntityManager().find(entityClass, id);
}
// other methods create(T), edit(T), ...
The Ejb that extends the abstract class (i have many others EJBs and about 12 different persistence units):
#Stateless
public class FilesDao extends AbstractFacade<Files> {
#PersistenceContext(unitName = "myfirstPU")
private EntityManager firstEm;
#PersistenceContext(unitName = "mysecondPU")
private EntityManager secondEm;
// i have more than two persistenceUnit ...
#Override
protected EntityManager getEntityManager() {
return firstEm; // or secondEm based on condition
}
public FilesDao() {
super(Files.class);
}
public Files findByFileref(String inFileRef) {
try {
Query q = firstEm.createNamedQuery("Files.findByFileref"); // or secondEm based on condition
q.setParameter("fileref", inFileRef);
Files file = (Files) q.getSingleResult();
return file;
} catch (NoResultException e) {
return null;
}
}
I want to use FilesDao like this :
#Stateless
#LocalBean
public class FileBusiness {
#EJB
FilesDao fileDao;
public void myMethod(){
if(condition1){
//use the FileDao with the EnityManager **firstEm**
}
else if(condition2){
//use the FileDao with the EnityManager **secondtEm**
}
...
}
Is there a way to achieve that ?
I read about using CDI with produces method.
CDI-Producers are not that hard, see the following example.
The following classes are CDI-Qualifier annotations, which are used to distinguish implementations.
#Retention(RetentionPolicy.RUNTIME)
#Target({ TYPE, METHOD, FIELD, PARAMETER, CONSTRUCTOR })
#Qualifier
public #interface MyfirstPUQualifier { }
#Retention(RetentionPolicy.RUNTIME)
#Target({ TYPE, METHOD, FIELD, PARAMETER, CONSTRUCTOR })
#Qualifier
public #interface MysecondPUQualifier { }
The following is a CDI-Bean which injects the different EntityManagers and implements producer methods, making the two EntityManagers available to CDI, distinguished via CDI-Qualifiers
#ApplicationScoped
class MYProducer {
#PersistenceContext(unitName = "myfirstPU")
private EntityManager firstEm;
#PersistenceContext(unitName = "mysecondPU")
private EntityManager secondEm;
#Produces
#RequestScoped
#MyfirstPUQualifier
public EntityManager produceMyfirstPU(){
return firstEm;
}
#Produces
#RequestScoped
#MysecondPUQualifier
public EntityManager produceMysecondPU(){
return secondEm;
}
}
The following shows a CDI-Bean injecting both EntityManagers. This could be extracted to an abstract base class, because maybe needed by other DAOs as well.
#Stateless
public class FileDao {
#Inject
#MyfirstPUQualifier
private EntityManager emFirst;
#Inject
#MysecondPUQualifier
private EntityManager emSecond;
public void myDaoMEthod(){
final EntityManager em = getEntityManager();
...
}
private EntityManager getEntityManager(){
if(condition1){
return emFirst;
}
else if(condition2){
return emSecond;
}
}
}
No can use the FileDao bean without taking care what EntityManager to use, because shouldn't be decided in this bean anyway
#Stateless
#LocalBean
public class FileBusiness {
#EJB
FilesDao fileDao;
public void myMethod(){
// FileDao will decide what entity manager to use
fileDao.doStruff();
}
}

Spring 4, Mockito 2, Junit 4 in Eclipse Oxygen - DAO not mocked

I have an annotated Junit 4 test using JDK 1.8 running in Eclipse. I'm using Mockito to mock the DAO in the service class under test. The runner in the abstract class extends SpringJUnit4ClassRunner. When I run the test, the unimplemented method in the concrete DAO class is called, instead of the mocked method. I've searched and searched, and can't seem to find a solution. What am I doing wrong?
SOLVED - I changed the #InjectMocks #Autowired IOrganizationsService organizationsService; to remove the interface and autowiring, #InjectMocks OrganizationsService organizationsService; fixed below, and the DAO gets mocked. Now the question, why wasn't the DAO in the declaration using the interface mocked?
#ContextConfiguration(classes = { AppXmlConfigTest.class, AppConfig.class }, inheritLocations = false)
#WebAppConfiguration
public class MockOrganizationsServiceTest extends AbstractCoreJunit4Test {
public MockOrganizationsServiceTest() {
super();
}
#InjectMocks
OrganizationsService organizationsService;
#Mock
IOrganizationsDao organizationsDao;
#Before
public void setupMock() {
MockitoAnnotations.initMocks(this);
}
#Test
public void testGetOrganizations() {
LocalDate localDate = LocalDate.now();
List<OrganizationTypeEnum> organizationTypes = new ArrayList<OrganizationTypeEnum>();
organizationTypes.add(OrganizationTypeEnum.All);
List<AllocationStatusEnum> allocationStatuses = new ArrayList<AllocationStatusEnum>();
allocationStatuses.add(AllocationStatusEnum.ALL);
List<IOrganization> organizations = new ArrayList<IOrganization>();
IOrganization organization = new Organization();
organization.setOrganizationId(1);
organizations.add(organization);
Mockito.when(organizationsDao.getOrganizations(isA(LocalDate.class), isA(List.class), isA(List.class))).thenReturn(organizations);
List<IOrganization> orgs = organizationsService.getOrganizations(localDate, organizationTypes, allocationStatuses);
assertNotNull(orgs);
}
}
The service class is this,
public class OrganizationsService extends AbstractService implements IOrganizationsService {
#Autowired
IOrganizationsDao organizationsDao;
/**
* #param organizationsDao the organizationsDao to set
*/
public void setOrganizationsDao(IOrganizationsDao organizationsDao) {
this.organizationsDao = organizationsDao;
}
#Override
public List<IOrganization> getOrganizations(LocalDate effectiveDate, List<OrganizationTypeEnum> organizationTypes, List<AllocationStatusEnum> allocationStatuses) {
return organizationsDao.getOrganizations(effectiveDate, organizationTypes, allocationStatuses);
}
and the DAO is this,
public class OrganizationsDao extends AbstractDao implements IOrganizationsDao {
#Override
public List<IOrganization> getPendingOrganizations(LocalDate effectiveDate) {
// TODO Auto-generated method stub
return null;
}
#Override
public List<IOrganization> getOrganizations(LocalDate effectiveDate, List<OrganizationTypeEnum> organizationTypeEnums,
List<AllocationStatusEnum> allocationStatuses) {
// TODO Auto-generated method stub
return null;
}
I think the issue here is that while mocking the method call you are using isA for parameters. As per my understanding, isA method is used for the verification not for passing the parameters. Try any method instead:
Mockito.when(organizationsDao.getOrganizations(any(LocalDate.class), any(List.class), any(List.class))).thenReturn(organizations);

How to change my DAO Bean from EJB to pure CDI?

I want to reuse my AbstractDAO in a new project, except this time I don't want to use EJB annotations - just CDI ones.
So far, I've been using it like this:
public abstract class AbstractDAO<T> {
#PersistenceContext(unitName = "myUnit")
private EntityManager entityManager;
private Class<T> entityClass;
public AbstractDAO(Class<T> entityClass) {
this.entityClass = entityClass;
}
protected EntityManager getEntityManager() {
return entityManager;
}
public void save(T entity) {
entityManager.persist(entity);
}
public void update(T entity) {
entityManager.merge(entity);
}
public void remove(T entity) {
entityManager.remove(entityManager.merge(entity));
}
public T findById(Object id) {
return entityManager.find(entityClass, id);
}
public List<T> findBy(String attrName, Object attrValue) {
// Impl here
}
// [...] Many more search methods
}
And I've been creating a DAO for each Entity, like this for example:
#Stateless
public class UserDAO extends AbstractDAO<User> {
public UserDAO() {
super(User.class);
}
public User findByUsername(String username) {
if (username != null) {
return super.findOneBy("username", username.toLowerCase());
}
return null;
}
}
Now I would like to get rid of the #Stateless annotation. But simply replacing it with a #RequestScoped one won't work because of the non-private constructor with no parameters requirement of JSR-346
How can I refactor my DAO to a pure CDI one ?
Two issues here: CDI beans are not transaction aware by default -unlike EJBs, so you will have to use #Transactional qualifier if you want to do saves/updates...
Second, your no-arg constructor: you only need to pass the entity class to your abstract class even though you also specify it as a generic argument. You can infer the actual class like this:
public class AbstractDAO<T> {
private transient Class<T> entityClass;
#SuppressWarnings("unchecked")
public AbstractDAO() {
Type generSuperCls = getClass().getGenericSuperclass();
if (generSuperCls instanceof Class) {
generSuperCls = ((Class<?>) generSuperCls).getGenericSuperclass();
}
ParameterizedType parameterizedType = (ParameterizedType) generSuperCls;
Type type = parameterizedType.getActualTypeArguments()[0];
if (type instanceof Class) {
this.entityClass = (Class<T>) type;
} else if (type instanceof ParameterizedType) {
this.entityClass = (Class<T>) ((ParameterizedType) type).getRawType();
}
}
#PersistenceContext
private EntityManager em;
public T getById(Object id) throws ServiceException {
return getEm().find(entityClass, id);
}
// other methods follow
}
As a side note, why do you want to get rid of EJBs? Benchmarks show you get better performance using pooled slsb than cdi and they together very well(every EJB beans is also a CDI bean in jee container).

How to run update query in Spring JPA for quartz job

I have a quartz job in spring 4 and I am using JPA hibernate to update database value through quartz job but I am getting javax.persistence.TransactionRequiredException: Executing an update/delete query
I don't understand what kind of configuration is missing in quartz job. I referred to SpringBeanAutowiringSupport example still update is failing but select is working fine.
Below is my code
#Configuration
#ComponentScan("com.stock")
public class QuartzConfiguration {
#Autowired
private ApplicationContext applicationContext;
#Bean
public JobDetailFactoryBean jobDetailBalanceCarryForward(){
JobDetailFactoryBean factory = new JobDetailFactoryBean();
factory.setJobClass(BillingCroneSvcImpl.class);
Map<String,Object> map = new HashMap<String,Object>();
map.put("task", "balanceCarryForward");
factory.setJobDataAsMap(map);
factory.setGroup("BalanceCarryForwardJob");
factory.setName("balance carry forward");
return factory;
}
#Bean
public CronTriggerFactoryBean cronTriggerBalanceCarryForward(){
CronTriggerFactoryBean stFactory = new CronTriggerFactoryBean();
stFactory.setJobDetail(jobDetailBalanceCarryForward().getObject());
stFactory.setStartDelay(3000);
stFactory.setName("balancCarryForwardTrigger");
stFactory.setGroup("balanceCarryForwardgroup");
stFactory.setCronExpression("0 0/1 * 1/1 * ? *");
return stFactory;
}
#Bean
public SpringBeanJobFactory springBeanJobFactory() {
AutoWiringSpringBeanJobFactory jobFactory = new AutoWiringSpringBeanJobFactory();
jobFactory.setApplicationContext(applicationContext);
return jobFactory;
}
#Bean
public SchedulerFactoryBean schedulerFactoryBean() {
SchedulerFactoryBean schedulerFactory = new SchedulerFactoryBean();
schedulerFactory.setJobFactory(springBeanJobFactory());
schedulerFactory.setTriggers(cronTriggerBalanceCarryForward().getObject());
return schedulerFactory;
}
}
Below class where quartz executeInternal method is written
#Service
#PersistJobDataAfterExecution
#DisallowConcurrentExecution
#Autowired
private BillingCroneRepo billingCroneRepo;
public class BillingCroneSvcImpl extends QuartzJobBean implements BillingCroneSvc {
#Override
#Transactional
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(context);
billingCroneRepo.updateBalance();
// this method throws exception javax.persistence.TransactionRequiredException: Executing an update/delete query
}
}
App config class
#EnableWebMvc
#EnableTransactionManagement
#Configuration
#ComponentScan({ "com.stock.*" })
#Import({ SecurityConfig.class })
#PropertySource("classpath:jdbc.properties")
public class AppConfig extends WebMvcConfigurerAdapter {
private static final String PROPERTY_NAME_DATABASE_DRIVER = "db.driver";
private static final String PROPERTY_NAME_DATABASE_PASSWORD = "db.password";
private static final String PROPERTY_NAME_DATABASE_URL = "db.url";
private static final String PROPERTY_NAME_DATABASE_USERNAME = "db.username";
private static final String PROPERTY_NAME_HIBERNATE_DIALECT = "hibernate.dialect";
private static final String PROPERTY_NAME_HIBERNATE_SHOW_SQL = "hibernate.show_sql";
private static final String PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN = "entitymanager.packages.to.scan";
#Resource
private Environment env;
#Bean(name = "dataSource")
public DriverManagerDataSource dataSource() {
DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource();
driverManagerDataSource.setDriverClassName(env.getRequiredProperty(PROPERTY_NAME_DATABASE_DRIVER));
driverManagerDataSource.setUrl(env.getRequiredProperty(PROPERTY_NAME_DATABASE_URL));
driverManagerDataSource.setUsername(env.getRequiredProperty(PROPERTY_NAME_DATABASE_USERNAME));
driverManagerDataSource.setPassword(env.getRequiredProperty(PROPERTY_NAME_DATABASE_PASSWORD));
return driverManagerDataSource;
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(dataSource());
entityManagerFactoryBean.setPersistenceProviderClass(HibernatePersistence.class);
entityManagerFactoryBean.setPackagesToScan(env.getRequiredProperty(PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN));
entityManagerFactoryBean.setJpaProperties(hibProperties());
return entityManagerFactoryBean;
}
private Properties hibProperties() {
Properties properties = new Properties();
properties.put(PROPERTY_NAME_HIBERNATE_DIALECT,env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_DIALECT));
properties.put(PROPERTY_NAME_HIBERNATE_SHOW_SQL,env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_SHOW_SQL));
return properties;
}
#Bean
public PlatformTransactionManager transactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
return transactionManager;
}
#Bean
public ReloadableResourceBundleMessageSource messageSource(){
ReloadableResourceBundleMessageSource messageSource=new ReloadableResourceBundleMessageSource();
String[] resources= {"classpath:messages"};
messageSource.setBasenames(resources);
return messageSource;
}
#Bean
public LocaleResolver localeResolver() {
final CookieLocaleResolver ret = new CookieLocaleResolver();
ret.setDefaultLocale(new Locale("en_IN"));
return ret;
}
#Bean
public LocaleChangeInterceptor localeChangeInterceptor(){
LocaleChangeInterceptor localeChangeInterceptor=new LocaleChangeInterceptor();
localeChangeInterceptor.setParamName("language");
return localeChangeInterceptor;
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/Angular/**").addResourceLocations("/Angular/");
registry.addResourceHandler("/css/**").addResourceLocations("/css/");
registry.addResourceHandler("/email_templates/**").addResourceLocations("/email_templates/");
registry.addResourceHandler("/fonts/**").addResourceLocations("/fonts/");
registry.addResourceHandler("/img/**").addResourceLocations("/img/");
registry.addResourceHandler("/js/**").addResourceLocations("/js/");
registry.addResourceHandler("/Landing_page/**").addResourceLocations("/Landing_page/");
}
#Bean
public static PropertySourcesPlaceholderConfigurer properties() {
PropertySourcesPlaceholderConfigurer pspc = new PropertySourcesPlaceholderConfigurer();
org.springframework.core.io.Resource[] resources = new ClassPathResource[] { new ClassPathResource("application.properties") };
pspc.setLocations(resources);
pspc.setIgnoreUnresolvablePlaceholders(true);
return pspc;
}
#Bean
public InternalResourceViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setViewClass(JstlView.class);
viewResolver.setPrefix("/WEB-INF/pages/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
// through below code we directly read properties file in jsp file
#Bean(name = "propertyConfigurer")
public PropertiesFactoryBean mapper() {
PropertiesFactoryBean bean = new PropertiesFactoryBean();
bean.setLocation(new ClassPathResource("application.properties"));
return bean;
}
}
Can anybody please assist me how to resolve transational issue in spring JPA with quartz
Thanks you all for your help. Finally I autowired EntityManagerFactory instead of persitance EntityManager and it is working fine. I tried all scenario but nothing worked to inject spring transactional in quartz so finally autoriwed entitymanagerfactory
Below is my repo class code.
#Repository
public class BillingCroneRepoImpl implements BillingCroneRepo {
/*#PersistenceContext
private EntityManager entityManager;*/
#Autowired
EntityManagerFactory entityManagerFactory;
public boolean updateTable(){
EntityManager entityManager = entityManagerFactory.createEntityManager();
EntityTransaction entityTransaction = entityManager.getTransaction();
entityTransaction.begin(); // this will go in try catch
Query query = entityManager.createQuery(updateSql);
// update table code goes here
entityTransaction.commit(); // this will go in try catch
}
}
I'm not the Spring specialist, but I think new ... doesn't work with #Transactional
#Service
#PersistJobDataAfterExecution
#DisallowConcurrentExecution
public class BillingCroneSvcImpl extends QuartzJobBean implements BillingCroneSvc {
#Autowired
BillingCroneRepo billingCroneRepo;
#Override
#Transactional
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(context);
billingCroneRepo.updateBalance();
}
}
It's because quartz is using the bean instead of the proxy generated for #Transactional.
Use either MethodInvokingJobDetailFactoryBean (instead of inheriting QuartzJob) or use a dedicated wrapper quarz bean (inheriting from QuartzJob) that call the spring bean (not inheriting from QuartzJob) having the #Transactionnal annotation.
EDIT : this is in fact not the problem
The problem is here :
JobDetailFactoryBean factory = new JobDetailFactoryBean();
factory.setJobClass(BillingCroneSvcImpl.class);
By passing the class, I presume that Quartz will instantiate it itself, so Spring won't create it and won't wrap the bean in a Proxy that handle the #Transactionnal behaviour.
Instead you must use something along the line :
#Bean(name = "billingCroneSvc")
public BillingCroneSvc getSvc(){
return new BillingCroneSvcImpl();
}
#Bean
public JobDetailFactoryBean jobDetailBalanceCarryForward(){
JobDetailFactoryBean factory = new JobDetailFactoryBean();
getSvc();// just make sure the bean is instantiated
factory.setBeanName("billingCroneSvc");
...
}

Can I do setter injection using #Inject annotation

In my GWTP application I need to Inject HttpServletRequest, HttpSession as instance variable of ActionHandler.
My ActionHandler is initialized through Spring.
I can't get current Request object through Spring as it instantiates just POJO.
I am thinking about mixing GIN and Spring.
Would I be able inject HttpServletRequest using GIN in my ActionHandler which is instantiated through Spring?????
Is it possible to do following way??
#Configuration
#Import(DefaultModule.class)
public class ServerModule extends HandlerModule
{
#Bean
public UserVerficationActionHandler getUserVerificationActionActionHandler()
{
return new UserVerficationActionHandler();
}
}
public class UserVerficationActionHandler implements ActionHandler<UserVerficationAction, UserVerficationActionResult>
{
#Autowired
private UserService userService;
private Provider<HttpServletRequest> requestProvider;
#Inject
public UserVerficationActionHandler()
{
}
public UserVerficationActionResult execute(UserVerficationAction action, ExecutionContext context) throws ActionException
{
....
}
#Inject
public Provider<HttpServletRequest> setRequestProvider()
{
return requestProvider;
}
}
-------ActionHandler Ends--------
Can somebody let me know Is it possible to do SetterInjection this way?
Second thing, if above is possible then will I be getting current request object using this method?
Thanks in advance.
Bhavesh.