What am I trying to achieve is schedule a query to my database every 30 minutes, this query will bring me many records with many new task to schedule, these new task will perform new CRUD operations to my database and some other operations.
First, I'm using @EnableScheduling to schedule a "SELECT" query
@Service
@EnableScheduling
public class ScheduleUpdatesTransaction {
final static Logger logger = Logger.getLogger(ScheduleUpdatesTransaction.class);
@Scheduled(fixedDelay = 10000)
public void executeTransaction() {
ScheduledExecutorService executor = Executors.newScheduledThreadPool(10);
List<Object[]> programUpdatesList = playerDAO.getUpdatesByTimeIterval(myCustomDateTime);//Ok, it access database an retrieve data
for(Object[] element: programUpdatesList){
Long seconds = Long.parseLong(element[0].toString());
Long myKey = Long.parseLong(element[1].toString());
executor.schedule(new ScheduleThreadTransaction(myKey), seconds , TimeUnit.SECONDS);//Ok, it triggers the task
}
executor.shutdown();
}
}
This is the ScheduleThreadTransaction class:
@Component
public class ScheduleThreadTransaction implements Runnable{
@Autowired
private PlayerTaskDAO playerTaskDAO;
private Long myIdentificator;
public ScheduleThreadTransaction() {
super();
}
public ScheduleThreadTransaction(Long identificator) {
myIdentificator = identificator;
}
public void run() {
try{
PlayerTask playerTask = playerTaskDAO.findOne(myIdentificator);// not working, java.lang.NullPointerException
//More CRUD operations here
}catch(Exception e){
e.printStackTrace();
}
}
public Long getMyIdentificator() {
return myIdentificator;
}
public void setMyIdentificator(Long myIdentificator) {
this.myIdentificator = myIdentificator;
}
}
The problem is when calling findOne, I get NullPointerException. Any suggestion? I'm using Spring 4 and JPA 2.1.
EDIT:
I made some changues in the configuration, this is my XML configuration:
<context:component-scan base-package="com.myproject"/>
<mvc:annotation-driven>
<mvc:message-converters>
<bean id="jsonMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper">
<bean class="com.fasterxml.jackson.databind.ObjectMapper">
<property name="serializationInclusion" value="NON_NULL"/>
</bean>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
<mvc:resources mapping="/images/*" location="/images/" />
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceXmlLocation" value="classpath:META-INF/persistence.xml" />
<property name="persistenceUnitName" value="myProjectPersistence" />
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
<property name="jpaDialect" ref="jpaDialect" />
</bean>
<bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="database" value="HSQL" />
<property name="databasePlatform" value="org.hibernate.dialect.HSQLDialect" />
</bean>
<bean id="jpaDialect" class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
<property name="dataSource" ref="dataSource" />
<property name="jpaDialect" ref="jpaDialect" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://127.0.0.1:3306/myConection" />
<property name="username" value="123456" />
<property name="password" value="654321" />
</bean>
<bean id="velocityEngine" class="org.springframework.ui.velocity.VelocityEngineFactoryBean">
<property name="resourceLoaderPath" value="/WEB-INF/velocity/"/>
</bean>
<bean id="statusUpdateService" class="com.myproject.StatusUpdateService" />
<bean id="scheduledExecutorFactoryBean" class="org.springframework.scheduling.concurrent.ScheduledExecutorFactoryBean" />
<bean id="scheduleThreadTransactionService" class="com.myproject.ScheduleThreadTransactionService" />
This is the ScheduleUpdatesTransaction class:
@Service
@EnableScheduling
public class ScheduleUpdatesTransaction {
final static Logger logger = Logger.getLogger(ScheduleUpdatesTransaction.class);
@Autowired
private PlayerCoreUpdateDAO playerCoreUpdateDAO;
@Autowired
StatusUpdateService statusUpdateService;
@Scheduled(fixedDelay = 100000)
public void executeTransaction() {
Util util = new Util();
List<Object[]> programUpdatesList = playerCoreUpdateDAO.getWeaponUpdatesByTimeIterval(new Date());
for(Object[] element: programUpdatesList){
Long seconds = Long.parseLong(element[2].toString());
String finishDate =element[3].toString();
Long myUpdateKey = Long.parseLong(element[0].toString());
System.out.println("UPGRADETIME " + seconds + " FINISHUPGRADETIME " + myUpdateKey);
statusUpdateService.executeTransaction(seconds, myUpdateKey);
}
}
}
The StatusUpdateService class:
@Service
public class StatusUpdateService {
final static Logger logger = Logger.getLogger(StatusUpdateService.class);
@Autowired
private ScheduledExecutorFactoryBean scheduledExecutorFactoryBean;
@Autowired
private Provider<ScheduleThreadTransactionService> runnableFactory;
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void executeTransaction(Long seconds, Long myUpdateKey){
try{
ScheduledExecutorService executor = scheduledExecutorFactoryBean.getObject();
ScheduleThreadTransactionService runnable = runnableFactory.get();
runnable.setElementKey(myUpdateKey);
executor.schedule(runnable, seconds, TimeUnit.SECONDS);
}catch(Exception e){
logger.error(e);
}
}
}
And finally the ScheduleThreadTransactionService class:
@Service
public class ScheduleThreadTransactionService implements Runnable{
final static Logger logger = Logger.getLogger(ScheduleThreadTransactionService.class);
private Long elementKey;
public ScheduleThreadTransactionService() {
}
public ScheduleThreadTransactionService(Long elementKey) {
this.elementKey = elementKey;
}
@Autowired
private PlayerCoreUpdateDAO playerCoreUpdateDAO;
//Adding @transactional throws an error
public void run() {
try{
PlayerCoreUpdate playerCoreUpdate = playerCoreUpdateDAO.findOne(elementKey);//It works!
playerCoreUpdateDAO.update(playerCoreUpdate);//Didn't work, need @transactional
}catch(Exception e){
logger.error(e);
}
}
public Long getElementKey() {
return elementKey;
}
public void setElementKey(Long elementKey) {
this.elementKey = elementKey;
}
public PlayerCoreUpdateDAO getPlayerCoreUpdateDAO() {
return playerCoreUpdateDAO;
}
public void setPlayerCoreUpdateDAO(PlayerCoreUpdateDAO playerCoreUpdateDAO) {
this.playerCoreUpdateDAO = playerCoreUpdateDAO;
}
}
Adding @Transactional give me this error:
2015-09-28 12:33:32,840 scheduledExecutorFactoryBean-1 ERROR service.StatusUpdateService - org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.myproject.ScheduleThreadTransactionService] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
Is there a short fix to get this thing running?
Regards.