org.quartz-scheduler nullify the reference of repository in the executeInternal(JobExecutionContext executionContext) why? - quartz-scheduler

Its an observation and would like to share the information to know why executeInternal() nullify the reference of customerRepository? I was developing Spring + Quartz + Spring Data JPA example. In this example I was looking to run the multiple jobs at the same time by providing implementation of JobDetailFactoryBean. In jobA.java class I experience an issue....
JobA.java
#Service
public class JobA extends QuartzJobBean {
private CustomerRepository customerRepository = null;
#Autowired
public JobA(CustomerRepository customerRepository) {
this.customerRepository = customerRepository;
}
public JobA() { }
#Override
protected void executeInternal(JobExecutionContext executionContext) throws JobExecutionException {
System.out.println("~~~~~~~ Job A is runing ~~~~~~~~");
Trigger trigger = executionContext.getTrigger();
System.out.println(trigger.getPreviousFireTime());
System.out.println(trigger.getNextFireTime());
getCustomerList();
}
private List<Customer> getCustomerList(){
List<Customer> customers = customerRepository.findAll();
for (Customer customer : customers) {
System.out.println("------------------------------");
System.out.println("ID : "+customer.getId());
System.out.println("NAME : "+customer.getName());
System.out.println("STATUS : "+customer.getStatus());
}
return customers;
}
}
I can't use the customerRepository instance in the executeInternal() why ? If I getCustomerList() from public JobA(CustomerRepository customerRepository) { it works fine there, but if I use from executeInternal(), it nullify the reference of customerRepository why ?
Spring-Quartz.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xmlns:repository="http://www.springframework.org/schema/data/repository"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
http://www.springframework.org/schema/data/repository http://www.springframework.org/schema/data/repository/spring-repository.xsd">
<import resource="classpath:dataSourceContext.xml"/>
<jpa:repositories base-package="com.mkyong.repository" />
<context:component-scan base-package="com.mkyong.*" />
<context:annotation-config />
<bean id="jobA" class="com.mkyong.job.JobA" />
<bean id="jobB" class="com.mkyong.job.JobB" />
<bean id="jobC" class="com.mkyong.job.JobC" />
<!-- ~~~~~~~~~ Quartz Job ~~~~~~~~~~ -->
<bean name="JobA" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<property name="jobClass" value="com.mkyong.job.JobA" />
</bean>
<bean name="JobB" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<property name="jobClass" value="com.mkyong.job.JobB" />
</bean>
<bean name="JobC" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<property name="jobClass" value="com.mkyong.job.JobC" />
</bean>
<!-- ~~~~~~~~~~~ Cron Trigger, run every 5 seconds ~~~~~~~~~~~~~ -->
<bean id="cronTriggerJobA" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" ref="JobA" />
<property name="cronExpression" value="0/5 * * * * ?" />
</bean>
<bean id="cronTriggerJobB" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" ref="JobB" />
<property name="cronExpression" value="0/5 * * * * ?" />
</bean>
<bean id="cronTriggerJobC" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" ref="JobC" />
<property name="cronExpression" value="0/5 * * * * ?" />
</bean>
<!-- ~~~~~~~~~~~~~~~~ Scheduler bean Factory ~~~~~~~~~~~~~~~~ -->
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="cronTriggerJobA" />
<!-- <ref bean="cronTriggerJobB" />
<ref bean="cronTriggerJobC" /> -->
</list>
</property>
</bean>
</beans>
dataSourceContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd">
<context:property-placeholder location="classpath:database.properties"/>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"/>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${mysql.driver.class.name}" />
<property name="url" value="${mysql.url}" />
<property name="username" value="${mysql.username}" />
<property name="password" value="${mysql.password}" />
</bean>
<bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true"/>
<property name="generateDdl" value="true"/>
<property name="database" value="${database.vendor}"/>
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="jpaVendorAdapter" ref="jpaVendorAdapter"/>
<!-- spring based scanning for entity classes-->
<property name="packagesToScan" value="com.mkyong.*"/>
</bean>
</beans>
App.java
public class App {
public static void main(String[] args) throws Exception {
ApplicationContext context = new ClassPathXmlApplicationContext("Spring-Quartz.xml");
}
}

Where are you define the customerRepository bean? you should define it in the xml file, or add #Repository annonation in the class.

Related

How to run spring batch job through CommandLineRunner, if i am using xml based configuration?

I am reading txt file and writing csv file with itemprocessor
Below my xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:batch="http://www.springframework.org/schema/batch" `xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/batch http://www.springframework.org/schema/batch/spring-batch-3.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
<!-- JobRepository and JobLauncher are configuration/setup classes -->
<bean id="jobRepository" class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean" />
<bean id="jobLauncher" class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
<property name="jobRepository" ref="jobRepository" />
</bean>
<!-- ItemReader reads a complete line one by one from input file -->
<bean id="flatFileItemReader" class="org.springframework.batch.item.file.FlatFileItemReader" scope="step">
<property name="resource" value="classpath:Test.txt" />
<property name="lineMapper">
<bean class="org.springframework.batch.item.file.mapping.DefaultLineMapper">
<property name="fieldSetMapper">
<!-- Mapper which maps each individual items in a record to properties in POJO -->
<bean class="com.chaman.springbatch.ResultFieldSetMapper" />
</property>
<property name="lineTokenizer">
<!-- A tokenizer class to be used when items in input record are separated by specific characters -->
<bean class="org.springframework.batch.item.file.transform.DelimitedLineTokenizer">
<!-- <property name="delimiter" value="|" /> -->
</bean>
</property>
</bean>
</property>
</bean>
<bean id="flatFileItemWriter" class="org.springframework.batch.item.file.FlatFileItemWriter" scope="step">`
`
<property name="resource" value="file:csv/Result.csv" />
<property name="lineAggregator">
<!-- An Aggregator which converts an object into delimited list of strings -->
<bean class="org.springframework.batch.item.file.transform.DelimitedLineAggregator">
<!-- <property name="delimiter" value="|" /> -->
<property name="fieldExtractor">
<!-- Extractor which returns the value of beans property through reflection -->
<bean class="org.springframework.batch.item.file.transform.BeanWrapperFieldExtractor">
<property name="names" value="number" />
</bean>
</property>
</bean>
</property>
</bean>
<!-- XML ItemWriter which writes the data in XML format -->
<!-- <bean id="xmlItemWriter" class="org.springframework.batch.item.xml.StaxEventItemWriter">
<property name="resource" value="file:xml/examResult.xml" />
<property name="rootTagName" value="UniversityExamResultList" />
<property name="marshaller">
<bean class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="classesToBeBound">
<list>
<value>com.websystique.springbatch.model.ExamResult</value>
</list>
</property>
</bean>
</property>
</bean> -->
<!-- Optional ItemProcessor to perform business logic/filtering on the input records -->
<bean id="itemProcessor" class="com.chaman.springbatch.ResultItemProcessor" />
<!-- Optional JobExecutionListener to perform business logic before and after the job -->
<bean id="jobListener" class="com.chaman.springbatch.ResultJobListener" />
<!-- Step will need a transaction manager -->
<bean id="transactionManager" class="org.springframework.batch.support.transaction.ResourcelessTransactionManager" />
<!-- Actual Job -->
<batch:job id="ResultJob">
<batch:step id="step1">
<batch:tasklet transaction-manager="transactionManager">
<batch:chunk reader="flatFileItemReader" writer="flatFileItemWriter" processor="itemProcessor" commit-interval="10" />
</batch:tasklet>
</batch:step>
<batch:listeners>
<batch:listener ref="jobListener" />
</batch:listeners>
</batch:job>
How to run spring batch job through CommandLineRunner, if i am using xml based configuration?
This is explained in the documentation, see Running Jobs from the Command Line. Here is an example:
java CommandLineJobRunner myJob-configuration.xml myJob param=value
package com.paul.testspringbatch;
import java.util.Date;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.boot.CommandLineRunner;
public class MyCommandLineRunner implements CommandLineRunner {
private JobLauncher jobLauncher;
private Job resultJob;
#Override
public void run(String... args) throws Exception {
JobParameters jobParameters = new JobParametersBuilder().addDate("start-date", new Date()).toJobParameters();
this.jobLauncher.run(resultJob, jobParameters);
}
public void setJobLauncher(JobLauncher jobLauncher) {
this.jobLauncher = jobLauncher;
}
public void setResultJob(Job resultJob) {
this.resultJob = resultJob;
}
}
add the bean to your xml:
<bean id="jobLauncher" class="com.paul.testspringbatch.MyCommandLineRunner">
<property name="jobLauncher" ref="jobLauncher" />
<property name="resultJob" ref="ResultJob" />
</bean>
when the application starts up, the job will be excuted.

Spring batch: how to configure xa transactions

This is my situation:
a Postgres database where I have only Spring Batch tables
an Oracle database where I have business data to read, write and update
I have tried to configure an XA enviroment with Atomikos and it seems to work but honestly I haven't understand what is exactly happening.
Can you check my configuration, please? I'm totally noob in these things...
If I set "hibernate.transaction.jta.platform" to "com.atomikos.icatch.jta.hibernate4.AtomikosPlatform" instead of my class "SpringJtaPlatformAdapter" it seems that the batch doesn't commit on my Postgres DB. Why?
For testing I was using Spring "JpaPagingItemReader". With this reader I get always the exception "java.lang.IllegalStateException: A JTA EntityManager cannot use getTransaction()" so I copied this solution: solution
Why I need to do this? Is there another JpaReader for XA?
Thanks a lot for your help.
Here my configuration:
spring-batch-core 3.0.7.RELEASE
spring-jdbc and spring-orm 4.0.5.RELEASE
hibernate-entitymanager 5.0.7.Final
Atomikos transactions-jta, transactions-jdbc, transactions-hibernate4 4.0.6
database.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
<bean id="oracleDataSource" class="com.atomikos.jdbc.AtomikosDataSourceBean"
init-method="init" destroy-method="close">
<property name="xaDataSourceClassName" value="oracle.jdbc.xa.client.OracleXADataSource" />
<property name="uniqueResourceName" value="oracleDS" />
<property name="minPoolSize" value="1" />
<property name="maxPoolSize" value="3"/>
<property name="testQuery" value="select * from dual" />
<property name="xaProperties">
<props>
<prop key="URL">${database.oracle.url}</prop>
<prop key="user">${database.oracle.username}</prop>
<prop key="password">${database.oracle.password}</prop>
</props>
</property>
</bean>
<bean id="postgresDataSource" class="com.atomikos.jdbc.AtomikosDataSourceBean"
init-method="init" destroy-method="close">
<property name="xaDataSourceClassName" value="org.postgresql.xa.PGXADataSource" />
<property name="uniqueResourceName" value="postgresDS" />
<property name="minPoolSize" value="1" />
<property name="maxPoolSize" value="3"/>
<property name="testQuery" value="select * from batch_job_execution" />
<property name="xaProperties">
<props>
<prop key="serverName">localhost</prop>
<prop key="databaseName">postgres</prop>
<prop key="user">${database.postgresql.username}</prop>
<prop key="password">${database.postgresql.password}</prop>
</props>
</property>
</bean>
<bean id="atomikosTransactionService" class="com.atomikos.icatch.config.UserTransactionServiceImp"
init-method="init" destroy-method="shutdownForce">
<constructor-arg>
<props>
<prop key="com.atomikos.icatch.service">com.atomikos.icatch.standalone.UserTransactionServiceFactory</prop>
<prop key="com.atomikos.icatch.tm_unique_name">coriTransactionManager</prop>
</props>
</constructor-arg>
</bean>
<bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp" depends-on="atomikosTransactionService">
<property name="transactionTimeout" value="300" />
</bean>
<bean id="atomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager"
init-method="init" depends-on="atomikosTransactionService" destroy-method="close">
<property name="forceShutdown" value="true" />
<property name="startupTransactionService" value="false" />
</bean>
<bean id="mainTransactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManager" ref="atomikosTransactionManager" />
<property name="userTransaction" ref="atomikosUserTransaction" />
</bean>
<alias name="mainTransactionManager" alias="transactionManager" />
<!-- inject the Atomikos transaction manager into a Spring Hibernate adapter for JTA Platform -->
<bean id="springJtaPlatformAdapter" class="com.mydomain.jta.SpringJtaPlatformAdapter">
<property name="jtaTransactionManager" ref="mainTransactionManager" />
</bean>
<bean id="entityManagerFactoryOracle" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
depends-on="mainTransactionManager,springJtaPlatformAdapter">
<property name="persistenceXmlLocation" value="classpath:persistence.xml" />
<property name="persistenceUnitName" value="oraclePersistenceUnit" />
<property name="jpaVendorAdapter" ref="jpaVendorAdapterOracle"/>
<property name="dataSource" ref="oracleDataSource" />
<property name="jpaPropertyMap" ref="jpaPropertyMapOracle"></property>
</bean>
<bean id="jpaVendorAdapterOracle" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="generateDdl" value="false"/>
<property name="showSql" value="true" />
<property name="databasePlatform" value="org.hibernate.dialect.Oracle10gDialect" />
</bean>
<util:map id="jpaPropertyMapOracle">
<entry key="hibernate.transaction.jta.platform" value="com.mydomain.jta.SpringJtaPlatformAdapter" />
<!-- <entry key="hibernate.transaction.jta.platform" value="com.atomikos.icatch.jta.hibernate4.AtomikosPlatform"/> -->
</util:map>
</beans>
context.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/jdbc
http://www.springframework.org/schema/jdbc/spring-jdbc.xsd">
<bean id="jobRepository" class="org.springframework.batch.core.repository.support.JobRepositoryFactoryBean">
<property name="dataSource" ref="postgresDataSource" />
<property name="transactionManager" ref="transactionManager" />
<property name="databaseType" value="POSTGRES" />
<property name="isolationLevelForCreate" value="ISOLATION_DEFAULT"/>
</bean>
<bean id="jobLauncher" class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
<property name="jobRepository" ref="jobRepository" />
</bean>
</beans>
SpringJtaPlatformAdapter
public class SpringJtaPlatformAdapter extends AbstractJtaPlatform {
private static final long serialVersionUID = 1L;
private static TransactionManager sTransactionManager;
private static UserTransaction sUserTransaction;
#Override
protected TransactionManager locateTransactionManager() {
return sTransactionManager;
}
#Override
protected UserTransaction locateUserTransaction() {
return sUserTransaction;
}
public void setJtaTransactionManager(JtaTransactionManager jtaTransactionManager) {
sTransactionManager = jtaTransactionManager.getTransactionManager();
sUserTransaction = jtaTransactionManager.getUserTransaction();
}
}

Can i intercept the jobExecution.getExecutionContext() method using spring-aop?

i have to intercept the jobExecution.getExecutionContext() method of org.springframework.batch.core.JobExecution.java class of Spring-Batch.
Here is the sample code.
Spring-Customer.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:batch="http://www.springframework.org/schema/batch"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/jdbc
http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
http://www.springframework.org/schema/batch
http://www.springframework.org/schema/batch/spring-batch.xsd">
<bean id="jobExecution" class="org.springframework.batch.core.JobExecution" >
</bean>
<property name="target" ref="jobExecution" />
<property name="interceptorNames">
<list>
<value>customerAdvisor</value>
</list>
</property>
</bean>
<bean id="customerAdvisor"
class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<property name="mappedName" value="getExecutionContext" />
<property name="advice" ref="hijackAroundMethodBeanAdvice" />
</bean>
<!--<bean id="customerAdvisor"
class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="patterns">
<list>
<value>.*getExecutionContext.*</value>
</list>
</property>
<property name="advice" ref="hijackAroundMethodBeanAdvice" />
</bean>
--><bean id="jobRepository"
class="org.springframework.batch.core.repository.support.JobRepositoryFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="transactionManager" ref="transactionManager" />
<property name="databaseType" value="mysql" />
</bean>
<bean id="transactionManager"
class="org.springframework.batch.support.transaction.ResourcelessTransactionManager" />
<bean id="jobLauncher"
class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
<property name="jobRepository" ref="jobRepository" />
</bean>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/test" />
<property name="username" value="root" />
<property name="password" value="root" />
</bean>
<!-- create job-meta tables automatically -->
<jdbc:initialize-database data-source="dataSource">
<jdbc:script location="org/springframework/batch/core/schema-drop-mysql.sql" />
<jdbc:script location="org/springframework/batch/core/schema-mysql.sql" />
</jdbc:initialize-database>
<bean id="report" class="com.mkyong.model.Report" scope="prototype" />
<bean id="itemProcessor" class="com.mkyong.CustomItemProcessor" />
<batch:job id="helloWorldJob">
<batch:step id="step1">
<batch:tasklet>
<batch:chunk reader="cvsFileItemReader" writer="xmlItemWriter" processor="itemProcessor"
commit-interval="10">
</batch:chunk>
</batch:tasklet>
</batch:step>
</batch:job>
<bean id="cvsFileItemReader" class="org.springframework.batch.item.file.FlatFileItemReader">
<property name="resource" value="classpath:cvs/input/report.csv" />
<property name="lineMapper">
<bean class="org.springframework.batch.item.file.mapping.DefaultLineMapper">
<property name="lineTokenizer">
<bean
class="org.springframework.batch.item.file.transform.DelimitedLineTokenizer">
<property name="names" value="id,sales,qty,staffName,date" />
</bean>
</property>
<property name="fieldSetMapper">
<bean class="com.mkyong.ReportFieldSetMapper" />
<!-- if no data type conversion, use BeanWrapperFieldSetMapper to map by name
<bean
class="org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper">
<property name="prototypeBeanName" value="report" />
</bean>
-->
</property>
</bean>
</property>
</bean>
<bean id="xmlItemWriter" class="org.springframework.batch.item.xml.StaxEventItemWriter">
<property name="resource" value="file:xml/outputs/report.xml" />
<property name="marshaller" ref="reportMarshaller" />
<property name="rootTagName" value="report" />
</bean>
<bean id="reportMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="classesToBeBound">
<list>
<value>com.mkyong.model.Report</value>
</list>
</property>
</bean>
HijackAroundMethod.java
package com.mkyong.aop;
import java.util.Arrays;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
public class HijackAroundMethod implements MethodInterceptor
{
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
System.out.println("Method name : "
+ methodInvocation.getMethod().getName());
System.out.println("Method arguments : "
+ Arrays.toString(methodInvocation.getArguments()));
//same with MethodBeforeAdvice
System.out.println("HijackAroundMethod : Before method hijacked!");
try{
//proceed to original method call
Object result = methodInvocation.proceed();
//same with AfterReturningAdvice
System.out.println("HijackAroundMethod : Before after hijacked!");
return result;
}catch(IllegalArgumentException e){
//same with ThrowsAdvice
System.out.println("HijackAroundMethod : Throw exception hijacked!");
throw e;
}
}
}
App.java
package com.mkyong;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App {
public static void main(String[] args) {
String[] springConfig =
{
"Spring-Customer.xml"
};
ApplicationContext context =
new ClassPathXmlApplicationContext(springConfig);
JobLauncher jobLauncher = (JobLauncher) context.getBean("jobLauncher");
Job job = (Job) context.getBean("helloWorldJob");
try {
JobExecution execution = jobLauncher.run(job, new JobParameters());
ExecutionContext executionContext = execution.getExecutionContext();
executionContext.put("Test", "Test String");
System.out.println("Exit Status : " + execution.getStatus());
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("Done");
}
}
So when the execution.getExecutionContext() method is called then it must call the invoke method in HijackAroundMethod class, but somehow it doesn't work like that.

Velocity email is not working

I use Velocity and Java mail sender but I get a NullPointerException and I don't know why. And I tried a lot but can't solve the problem, to be honest I don't have any idea about what the problem can depends on.
Here are the sample codes I use.
Thanks full for any help.
SEVERE: Servlet.service() for servlet [mvc-dispatcher] in context with path [/guard_weblayer] threw exception [Request processing failed; nested exception is java.lang.NullPointerException] with root cause
java.lang.NullPointerException
at se.guards.mail.VelocityEmailService.sendLostPasswordEmail(VelocityEmailService.java:49)
at se.guards.lostpassword.LostPasswordController.processSubmit(LostPasswordController.java:71)
public interface VelocityMailRepository
{
public void sendLostPasswordEmail(final User user, final String action);
}
public class VelocityEmailService implements VelocityMailRepository
{
private static final Logger logger= LoggerFactory.getLogger(VelocityEmailService.class);
#Autowired
private VelocityEngine velocity;
#Autowired
private JavaMailSenderImpl javaMailSenderImpl;
#Autowired
private JavaMailSender sender;
public void sendLostPasswordEmail(final User user, final String action)
{
logger.debug("Sending lost password email to: {}", user.getUsername());
MimeMessagePreparator preparator = new MimeMessagePreparator() {
public void prepare(MimeMessage mimeMessage) throws Exception {
MimeMessageHelper message = new MimeMessageHelper(mimeMessage);
message.setTo(user.getEmail());
message.setFrom("no-reply#sziebert.net");
message.setSubject("Your Password");
Map<String, Object> model = new HashMap<String, Object>();
model.put("user", user);
model.put("url", action);
String text = mergeTemplateIntoString(velocity, "email/lost-password.vm","password", model);
message.setText(text, true);
}
};
this.sender.send(preparator);
}
public class LostPasswordFormValidator implements Validator {
private static final Logger logger = LoggerFactory.getLogger(LostPasswordFormValidator.class);
public boolean supports(Class clazz) {
return LostPasswordForm.class.equals(clazz);
}
public void validate(Object obj, Errors errors) {
logger.debug("Validating lost password form.");
LostPasswordForm form = (LostPasswordForm) obj;
// Insure that a value with specified.
rejectIfEmptyOrWhitespace(errors, "username", "error.username.empty");
// Insure the inputs don't contain any illegal characters.
if (!isAlphanumeric(form.getUsername()))
errors.rejectValue("username", "error.username.illegal.chars");
if (isNotBlank(form.getUsername()) && form.getUsername().length() < 4)
errors.rejectValue("username", "error.username.too.short");
}
}
#Controller
public class LostPasswordController
{
private static final Logger logger = LoggerFactory.getLogger(LostPasswordController.class);
VelocityEmailService sender= new VelocityEmailService();
UserService service= new UserService();
#InitBinder
public void initBinder(WebDataBinder binder)
{
binder.setAllowedFields(new String[] { "captcha", "username" });
}
#ModelAttribute("form")
public LostPasswordForm populateForm()
{
return new LostPasswordForm();
}
#RequestMapping(value = "/lostPassword", method = RequestMethod.GET)
public String lostPassword()
{
logger.debug("Rendering lost password form.");
return "lostPassword";
}
#RequestMapping(value = "/lostPassword", method = RequestMethod.POST)
public String processSubmit(#ModelAttribute("form") LostPasswordForm form,HttpServletResponse response, BindingResult result)
{
logger.debug("Processing lost password form.");
new LostPasswordFormValidator().validate(form, result);
if (!result.hasErrors())
{
User user = service.findUserByUsername(form.getUsername());
System.out.println(user);
if (user != null)
{
String frob = BCrypt.hashpw(user.getUsername() + "3m4il", BCrypt.gensalt());
String link = createLostPasswordLink(user, frob);
sender.sendLostPasswordEmail(user, link);
response.addCookie(persistFrob(frob));
return "lost-password-success";
}
result.rejectValue("username", "error.username.invalid");
}
return "lostPassword";
}
private String createLostPasswordLink(final User user, final String frob)
{
StringBuilder link = new StringBuilder();
link.append("http://localhost:8080/password/reset.do?frob=");
link.append(frob);
link.append("&username=");
link.append(user.getUsername());
return link.toString();
}
private Cookie persistFrob(final String frob)
{
Cookie cookie = new Cookie("frob", frob);
cookie.setMaxAge(60 * 60); // 1 hour
return cookie;
}
}
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd">
<context:component-scan base-package=".........weblayer" />
<mvc:annotation-driven />
<context:annotation-config />
<mvc:resources mapping="/resources/**" location="/resources/" />
<context:property-placeholder location="classpath*:*.properties" />
<bean id="messageTemplate" class="org.springframework.mail.SimpleMailMessage"
scope="prototype">
<property name="from" value="myemailaddress" />
</bean>
<!-- - This bean resolves specific types of exceptions to corresponding
logical - view names for error views. The default behaviour of DispatcherServlet
- is to propagate all exceptions to the servlet container: this will happen
- here with all other types of exceptions. -->
<bean
class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<prop key="org.springframework.web.servlet.PageNotFound">pageNotFound</prop>
<prop key="org.springframework.dao.DataAccessException">dataAccessFailure</prop>
<prop key="org.springframework.transaction.TransactionException">dataAccessFailure</prop>
</props>
</property>
</bean>
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/users/" />
<property name="suffix" value=".jsp" />
</bean>
<bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basenames" value="mymessages"></property>
</bean>
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- max upload size in bytes -->
<property name="maxUploadSize" value="50242880" />
<!-- max size of file in memory (in bytes) -->
<property name="maxInMemorySize" value="1048576" /> <!-- 1MB -->
</bean>
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" />
</beans>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
<property name="host" value="${mail.host}" />
<property name="username" value="${mail.username}" />
<property name="password" value="${mail.password}" />
<property name="port" value="${mail.port}" />
<property name="protocol" value="smtp" />
<property name="javaMailProperties">
<props>
<prop key="mail.smtp.auth">${mail.smtp.auth}</prop>
<prop key="mail.smtp.connectiontimeout">5000</prop>
<prop key="mail.smtp.sendpartial">${mail.smtp.sendpartial}</prop>
<prop key="mail.smtp.userset">${mail.smtp.userset}</prop>
<prop key="mail.mime.charset">UTF-8</prop>
<prop key="mail.smtp.isSecure">${mail.smtp.isSecure}</prop>
<prop key="mail.smtp.requiresAuthentication">${mail.smtp.requiresAuthentication}</prop>
<prop key="mail.smtps.auth">${mail.smtps.auth}</prop>
<prop key="mail.smtp.port">${mail.port}</prop>
<prop key="mail.smtp.socketFactory.class">javax.net.ssl.SSLSocketFactory</prop>
<prop key="mail.smtp.socketFactory.fallback">${mail.smtp.socketFactory.fallback}</prop>
<prop key="mail.smtp.starttls.enable">${mail.smtp.starttls.enable}</prop>
<prop key="mail.debug">${mail.debug}</prop>
</props>
</property>
</bean>
<bean id="messageTemplate" class="org.springframework.mail.SimpleMailMessage"
scope="prototype">
<property name="from" value="${mail.username}" />
</bean>
<!-- Mail sender configured for using Gmail -->
<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl"
p:host="smtp.gmail.com" p:username="${mail.username}" p:password="${mail.password}">
<property name="javaMailProperties">
<props>
<prop key="mail.smtp.auth">true</prop>
<prop key="mail.smtp.starttls.enable">true</prop>
</props>
</property>
</bean>
<bean id="velocityEngine"
class="org.springframework.ui.velocity.VelocityEngineFactoryBean">
<property name="velocityProperties">
<props>
<prop key="resource.loader">class</prop>
<prop key="class.resource.loader.class">org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader
</prop>
</props>
</property>
</bean>
</beans>
Solved
Just change
VelocityEmailService sender= new VelocityEmailService();
UserService service= new UserService();
to
VelocityEmailService sender;
UserService service;
There is no any need of initiation.
And the emailConfig.xml :
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
<property name="host" value="${mail.host}" />
<property name="port" value="${mail.port}" />
<property name="username" value="${mail.username}" />
<property name="password" value="${mail.password}" />
<property name="javaMailProperties">
<props>
<prop key="mail.smtp.auth">true</prop>
<prop key="mail.smtp.starttls.enable">true</prop>
<prop key="mail.smtp.debug">true</prop>
</props>
</property>
</bean>
<bean id="velocityEngine" class="org.springframework.ui.velocity.VelocityEngineFactoryBean">
<property name="resourceLoaderPath" value="/WEB-INF/velocity/"/>
</bean>
</beans>

EntityManager.merge() is not updating the database

I am trying to update the user_info table with the new password using EntityManager.merge(), but it is not getting committed. Below is my code:
app-cofig.xml:
<!-- Application Message Bundle -->
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="/WEB-INF/messages" />
<property name="cacheSeconds" value="300" />
</bean>
<bean id="loginValidator" class="com.sbi.llms.validator.LoginValidator"/>
<bean id="loginProcessor" class="com.sbi.llms.processor.LoginProcessor">
<property name="userDao" ref="userDao"/>
</bean>
<!-- Resolves view names to protected .jsp resources within the /WEB-INF/views directory -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
<bean id="forgetProcessor" class="com.test.ForgetPasswordProcessor">
<property name="forgetDao" ref="forgetDao"/>
</bean>
<bean name="/popup_forgot_password.html" class="com.test.ForgetPasswordController">
<property name="processor" ref="forgetProcessor"/>
<property name="commandClass" value="com.test.ForgetPasswordDTO"/>
<property name="commandName" value="btn_reset"/>
<property name="formView" value="popup_forgot_password"/>
<property name="successView" value="popup_forgot_password"/>
<property name="validator">
<bean class="com.test.LoginValidator"/>
</property>
</bean>
<bean id="myDataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="oracle.jdbc.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:#10.0.27.105:1521/LLMSDB1"/>
<property name="username" value="llms"/>
<property name="password" value="llms12"/>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager" p:entityManagerFactory-ref="entityManagerFactory" />
<bean id="entityManager" class="org.springframework.orm.jpa.support.SharedEntityManagerBean" p:entityManagerFactory-ref="entityManagerFactory" />
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="myDataSource" />
<property name="persistenceUnitName" value="cccPersistenceUnit" />
<property name="jpaDialect" ref="jpaDialect" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter">
<property name="databasePlatform" value="org.eclipse.persistence.platform.database.OraclePlatform"/>
<property name="showSql" value="true"/>
</bean>
</property>
<property name="loadTimeWeaver">
<bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver" />
</property>
</bean>
<bean id="baseJPADao" class="com.sbi.llms.dao.jpa.BaseJPADAO">
<property name="entityManager" ref="entityManager"/>
</bean>
<bean id="userDao" class="com.sbi.llms.dao.UserDAO">
<property name="entityManager" ref="entityManager"/>
</bean>
<bean id="forgetDao" class="com.test.ForgetPasswordDAO">
<property name="entityManager" ref="entityManager"/>
</bean>
<bean id="jpaDialect" class="org.springframework.orm.jpa.vendor.EclipseLinkJpaDialect" />
persistance.xml
<?xml version="1.0" encoding="UTF-8" ?>
<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_2_0.xsd"
version="2.0" xmlns="http://java.sun.com/xml/ns/persistence">
<persistence-unit name="cccPersistenceUnit" transaction-type="RESOURCE_LOCAL"> <!-- "RESOURCE_LOCAL" -->
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<mapping-file>META-INF/LoginModel.xml</mapping-file>
<mapping-file>META-INF/eclipselink-orm.xml</mapping-file>
<class>com.sbi.llms.model.LoginModel</class>
<class>com.test.ForgetPasswordModel</class>
<properties>
<!-- Configure cache size. -->
<property name="eclipselink.cache.size.default" value="1000" />
<!-- Configure simple SQL logging for demonstration. -->
<property name="eclipselink.logging.level" value="FINE" />
<property name="eclipselink.logging.thread" value="false" />
<property name="eclipselink.logging.session" value="false" />
<property name="eclipselink.logging.exceptions" value="false" />
<property name="eclipselink.logging.timestamp" value="false" />
</properties>
</persistence-unit>
</persistence>
Here is my DAO
public class ForgetPasswordDAO {
private Vector loginResult = null;
private int resultTrue = 1;
private int resultFalse = 0;
protected EntityManager entityManager;
JpaEntityManager jpaEntityManager;
public ForgetPasswordDAO() {
}
public EntityManager getEntityManager() {
return entityManager;
}
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
public Integer fetchUser(ForgetPasswordModel model) throws Exception {
try {
ForgetPasswordDTO DTO ;
if(model == null) {
throw new Exception("102");
}
Integer result = 0;
String userName = model.getUser_id();
String dob = model.getDob();
System.out.println("UserDTO " + model.getUser_id() + " "
+ model.getDob());
ForgetPasswordModel forgetModel = null;
System.out.println(entityManager.isOpen()+">>");
forgetModel = entityManager.find(ForgetPasswordModel.class, model.getUser_id());
entityManager.close();
System.out.println("UserDAO " + forgetModel.getUser_id() + " DOB "
+ forgetModel.getDob()+" EMAIL_ID "+forgetModel.getEmail_id()+" PASSWORD "+forgetModel.getPasswd());
if(model.getDob().equals(forgetModel.getDob())) {
System.out.println("USER VALID , CAN PROCEED WITH PASSWORD RESET");
String passwd = GenerateRandomPassword.generateRandomPassword();
System.out.println("generated password is" +passwd);
entityManager.getTransaction().begin();
forgetModel.setPasswd(passwd);
entityManager.merge(forgetModel);
entityManager.getTransaction().commit();
System.out .println("updated password is "+forgetModel.getPasswd());
String email=forgetModel.getEmail_id();
ForgetPasswordSendMail.SendMail( email, passwd);
result=1;
}
else
{
System.out.println("USER InVALID , Please Provide Valid Data");
}
return result;
} catch (Exception e) {
throw new Exception("103", e);
}
}
}
When I run the above code I get the following error:
java.lang.IllegalStateException: Not allowed to create transaction on shared EntityManager - use Spring transactions or EJB CMT instead
org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:198)
com.sun.proxy.$Proxy6.getTransaction(Unknown Source)
com.test.ForgetPasswordDAO.fetchUser(ForgetPasswordDAO.java:81)
com.test.ForgetPasswordProcessor.execute(ForgetPasswordProcessor.java:52)
com.test.ForgetPasswordController.onSubmit(ForgetPasswordController.java:56)
org.springframework.web.servlet.mvc.SimpleFormController.processFormSubmission(SimpleFormController.java:272)
org.springframework.web.servlet.mvc.AbstractFormController.handleRequestInternal(AbstractFormController.java:268)
org.springframework.web.servlet.mvc.AbstractController.handleRequest(AbstractController.java:153)
org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter.handle(SimpleControllerHandlerAdapter.java:48)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:790)
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:719)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:644)
org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:560)
javax.servlet.http.HttpServlet.service(HttpServlet.java:641)
javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
Since you are using Spring, you need to use Spring transactions, not JPA transactions.
You need to declare the transaction in Spring, or access the EntityManager directly, not through Spring.