Spring SimpleThreadScope does not support descruction callbacks - spring

I would like to run parallel selenium tests (using webriver and the Spring JUnit runner). Webdriver is a spring bean with the custom thread scope. But I get a following warning SimpleThreadScope does not support descruction callbacks So the browsers are not closed. Any idea how to close them (more precisely call the quit method)?
spring config
<bean id="threadScope" class="org.springframework.context.support.SimpleThreadScope" />
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
<property name="scopes">
<map>
<entry key="thread" value-ref="threadScope" />
</map>
</property>
</bean>
<bean id="webDriver" class="org.openqa.selenium.remote.RemoteWebDriver" scope="thread" destroy-method="quit">
<constructor-arg name="remoteAddress" value="http://localhost:4444/wd/hub" />
<constructor-arg name="desiredCapabilities" ref="browserAgent" />
</bean>
maven config
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.12</version>
<configuration>
<includes>
<include>**/*Test.class</include>
</includes>
<reportsDirectory>${basedir}/target/surefire-reports</reportsDirectory>
<parallel>classes</parallel>
<threadCount>2</threadCount>
<perCoreThreadCount>false</perCoreThreadCount>
</configuration>
</plugin>
This post http://www.springbyexample.org/examples/custom-thread-scope-module-code-example.html suggests a custom Thread implementations. But where is an extension point type of Runnable using any JUnit runner?
public class ThreadScopeRunnable implements Runnable {
protected Runnable target = null;
/**
* Constructor
*/
public ThreadScopeRunnable(Runnable target) {
this.target = target;
}
/**
* Runs <code>Runnable</code> target and
* then afterword processes thread scope
* destruction callbacks.
*/
public final void run() {
try {
target.run();
} finally {
ThreadScopeContextHolder.currentThreadScopeAttributes().clear();
}
}
}

Here there is a workaround, not perfect solution, because it blocks browsers until the end of all tests.
You have to create a register of thread scope beans which handles their destruction.
public class BeanRegister {
private Set<CustomWebDriver> beans= new HashSet<CustomWebDriver>();
public void register(CustomWebDriver bean) {
beans.add(bean);
}
#PreDestroy
public void clean() {
for (CustomWebDriver bean : beans) {
bean.quit();
}
}
}
Config it as singleton.
<bean class="BeanRegister" />
You have to write a class extending RemoteWebDriver.
public class CustomWebDriver extends RemoteWebDriver {
#Autowired
private BeanRegister beanRegister;
#PreConstruct
public void init() {
beanRegister.register(this);
}
}
That's it.

Related

why have a compile error in dependent jar but still could run project successfully?

When look source code of org.apache.commons.dbcp.BasicDataSource in intellij idea I found this error
Class 'BasicDataSource' must either be declared abstract or implement abstract method 'getParentLogger()' in 'CommonDataSource'
And I use below maven dependency
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
</dependency>
and this configuration
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url"
value="jdbc:mysql://localhost/test?useUnicode=true"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
but my project could run successfully. Then I write a test class to mock this error
public class Foo {
public static void main(String[] args) {
System.out.println("hello world");
}
interface IA{
String getParentLog();
}
class AImpl implements IA{
public void doSomething(){
System.out.println("doSomething");
}
}
}
but this time I cannot run it and have a compile error
Error:(14, 5) java: com.foobar.Foo.AImpl is not abstract and does not override abstract method getParentLog() in com.foobar.Foo.IA
Why is so?
Two things -
First, your part related to DataSources contradicts in the usage. I doubt you might have ended up editing the class BasicDataSource post downloading the sources or used some other dependency that brings in another implementation of DataSource class implemented in the above sample. Please confirm you are not using any other dependency that brings a conflicting class in the classpath.
Note while using the mentioned dependency commons-dbcp:1.4 the class DataSource is imported from the package javax.sql with following syntax :
public interface DataSource extends javax.sql.CommonDataSource,
java.sql.Wrapper { .. }
Second part, the class named AImpl is not abstract in which case it must define the methods of the interface it is implementing as -
class AImpl implements IA{
public void doSomething(){
System.out.println("doSomething");
}
#Override
String getParentLog() {
/** Define how getParentLog is implemented in this class */
return null; // return string here after the above definition
}
}

Spring Data lazyload does not LazyInitializationException

#Component
#Transactional
public class TestClass extends AbstractClass
{
#Autowire
ClassARepo classARepo;
#Override
public void test() {
ClassA classA = classARepo.findOne(1);
List<ClassB> list = classA.getClassBs();
list.size();
}
}
ClassB is mapped as onetomany and lazily loaded.
In the above code
classARepo.findOne(1);
Executes correctly. but
List<ClassB> list = classA.getClassBs();
list.size();
Fails with LazyInitializationException.
public interface ClassARepo extends CrudRepository<ClassA, Integer> {
}
Instance for TestA is created like the one below
#PersistJobDataAfterExecution
#DisallowConcurrentExecution
#Transactional
#Component
public class TestClassJOB extends AbstractJob
{
#Autowired
TestClass indexer;
}
Context:
<!-- JPA mapping configuration -->
<bean id="persistenceXmlLocation" class="java.lang.String">
<constructor-arg value="classpath:/persistence.xml"></constructor-arg>
</bean>
<!-- entity manager -->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
p:dataSource-ref="dataSource" p:persistenceUnitName="jpaData"
p:persistenceXmlLocation-ref="persistenceXmlLocation">
<property name="packagesToScan" value="com..persist.entity" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
</bean>
<!-- transaction manager -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"
p:entityManagerFactory-ref="entityManagerFactory" lazy-init="true" p:dataSource-ref="dataSource" />
<!-- JPA repositories -->
<jpa:repositories base-package="com..persist.repo"
entity-manager-factory-ref="entityManagerFactory" transaction-manager-ref="transactionManager" />
I tried many resources and could not solve the issue. The following error message is displayed "could not initialize proxy - no Session".
What could be the cause of the issue?
When the session is available while classARepo.findOne(1) is called, why is not available during lazy fetch(list.size())?
The issue was the instance for TestClassJOB was created by Quartz. So the transnational proxy was not applied to the class which was the reason for the issue.
I fixed the issue by declaring a transaction template
#Autowired
TransactionTemplate transactionTemplate;
and then wrapping the code within
transactionTemplate.execute(new TransactionCallbackWithoutResult()
{
#Override
protected void doInTransactionWithoutResult(TransactionStatus status)
{
<code here>
}
}

How to execute SQL script only once at startup in Spring?

I have a web application based on Spring JDBC and Jersey RESTful web service. I'm using the following Spring JDBC template class to initiate the dataSource and execute an SQL script (update_condition_table.sql):
public class CustomerJDBCTemplate implements CustomerDAO {
private DataSource dataSource;
private JdbcTemplate jdbcTemplateObject;
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
this.jdbcTemplateObject = new JdbcTemplate(dataSource);
Resource rc = new ClassPathResource("update_condition_table.sql");
JdbcTestUtils.executeSqlScript(jdbcTemplateObject, rc, false);
}
// ......other methods
}
The bean configuration file is beans.xml:
<!-- Initialization for data source -->
<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/customer" />
<property name="username" value="root" />
<property name="password" value="mypassword" />
</bean>
<!-- Definition for customerJDBCTemplate bean -->
<bean id="customerJDBCTemplate" class="com.example.db.CustomerJDBCTemplate">
<property name="dataSource" ref="dataSource" />
</bean>
The Jersey controller class contains the instantiation of class CustomerJDBCTemplate and serves as the REST web service:
#Path("/customer")
public class CustomerService {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
CustomerJDBCTemplate dbController = (CustomerJDBCTemplate) context.getBean("customerJDBCTemplate");
// ... some GET/POST methods
}
When I launched my web app by entering the index URL in the browser, the SQL script gets executed by the customerJDBCTemplate bean. However, when I clicked to navigate to other pages, it crashed and reported that the SQL script cannot be executed again. So obviously the SQL script was executed again after initialization of dataSource and initial launch of the index web page. How to avoid this by just running the SQL script only once upon initial startup of the web app?
Looks like I need to move the bean instantiate code out of CustomerService class, but where should I put that code?
I figured it out that I should set the bean application context to be static within CustomerService class and do it in the static initialization block as follows:
#Path("/customer")
public class CustomerService {
private static ApplicationContext context;
private static CustomerJDBCTemplate dbController;
static {
context = new ClassPathXmlApplicationContext("beans.xml");
dbController = (CustomerJDBCTemplate) context.getBean("customerJDBCTemplate");
}
//... other methods
}
I guess the reason is Jersey creates a different instance of CustomerService for each HTTP session (correct me if I'm wrong). So if I set the bean context as instance variable, it will do the initialization for every HTTP request.
Have your CustomerJDBCTemplate implement InitializingBean. afterPropertiesSet will get called once, right after all properties have been set by Spring's BeanFactory.
For example:
public class CustomerJDBCTemplate implements CustomerDAO, InitializingBean {
...
// ......other methods
public void afterPropertiesSet() throws Exception {
//do your initializing, or call your initializing methods
}
}

Spring Instantiation using a none-static factory method

I have got a situation where I would like to create bean2 in Spring config:
beans.xml:
<bean id="bean1" class="...">
<property name="..." ref="..." />
</bean>
bean2 = bean1.foo()
Would appreciate any help,
Thanks,
Behzad
You can use instance factory method. See corresponding chapter in Spring documentation.
<bean id="bean2" factory-bean="bean1" factory-method="foo"/>
If you are using annotations you can use:
#Configuration
public class AppConfig {
#Bean
#Lazy
public Bean1 getBean1(){
return Bean1.getInstance();
}
#Bean
public Bean2 getBean2() {
return this.getBean1().newBean2(); //in your example is this.getBean1().foo();
}
}

How to use #Autowired in a Quartz Job?

i am using quartz with spring
and i want to inject/use another class in the job class
and i don't know how to do it correctly
the xml:
<beans xmlns="http://www.springframework.org/schema/beans"
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-2.5.xsd">
<!-- Scheduler task -->
<bean name="schedulerTask" class="com.mkyong.quartz.SchedulerTask" />
<!-- Scheduler job -->
<bean name="schedulerJob"
class="org.springframework.scheduling.quartz.JobDetailBean">
<property name="jobClass" value="com.mkyong.quartz.SchedulerJob" />
<property name="jobDataAsMap">
<map>
<entry key="schedulerTask" value-ref="schedulerTask" />
</map>
</property>
</bean>
<!-- Cron Trigger -->
<bean id="cronTrigger"
class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail" ref="schedulerJob" />
<property name="cronExpression" value="0/10 * * * * ?" />
</bean>
<!-- Scheduler -->
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="jobDetails">
<list>
<ref bean="schedulerJob" />
</list>
</property>
<property name="triggers">
<list>
<ref bean="cronTrigger" />
</list>
</property>
</bean>
</beans>
the quartz job:
package com.mkyong.quartz;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.scheduling.quartz.QuartzJobBean;
public class SchedulerJob extends QuartzJobBean
{
private SchedulerTask schedulerTask;
public void setSchedulerTask(SchedulerTask schedulerTask) {
this.schedulerTask = schedulerTask;
}
protected void executeInternal(JobExecutionContext context)
throws JobExecutionException {
schedulerTask.printSchedulerMessage();
}
}
the task to be executed:
package com.mkyong.quartz;
public class SchedulerTask {
public void printSchedulerMessage() {
System.out.println("Struts 2 + Spring + Quartz ......");
}
}
i want to inject another DTO class that deals with Database in the task class
to do some database work in the task, how to do that ?
In your solution you are using the spring #Autowired annotation in a class that is not instantiated by Spring. Your solution will still work if you remove the #Autowired annotation because Quartz is setting the property, not Spring.
Quartz will try to set every key within the JobDataMap as a property. E.g. since you have a key "myDao" Quartz will look for a method called "setMyDao" and pass the key's value into that method.
If you want Spring to inject spring beans into your jobs, create a SpringBeanJobFactory and set this into your SchedulerFactoryBean with the jobFactory property within your spring context.
SpringBeanJobFactory javadoc:
Applies scheduler context, job data map and trigger data map entries
as bean property values
Not sure if this is what you want, but you can pass some configuration values to the Quartz job. I believe in your case you could take advantage of the jobDataAsMap property you already set up, e.g.:
<property name="jobDataAsMap">
<map>
<entry key="schedulerTask" value-ref="schedulerTask" />
<entry key="param1" value="com.custom.package.ClassName"/>
</map>
</property>
Then you should be able to access it in your actual Java code in manual way:
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
schedulerTask.printSchedulerMessage();
System.out.println(context.getJobDetail().getJobDataMap().getString("param1"));
}
Or using the magic Spring approach - have the param1 property defined with getter/setter. You could try defining it with java.lang.Class type then and have the done automatically (Spring would do it for you):
private Class<?> param1;
// getter & setter
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
schedulerTask.printSchedulerMessage();
System.out.println("Class injected" + getParam1().getName());
}
I haven't tested it though.
ApplicationContext springContext =
WebApplicationContextUtils.getWebApplicationContext(
ContextLoaderListener.getCurrentWebApplicationContext().getServletContext()
);
Bean bean = (Bean) springContext.getBean("beanName");
bean.method();
As mentioned in inject bean reference into a Quartz job in Spring? you can use spring SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
#Named
public class SampleJob implements Job {
#Inject
private AService aService;
#Override
public void execute(JobExecutionContext context)
throws JobExecutionException {
//Do injection with spring
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
aService.doIt();
}
}
As mentioned it may not wotk on some spring version but I have tested it on 4.2.1.RELEASE which worked fine.
this is my solution:
public class MySpringBeanJobFactory extends
org.springframework.scheduling.quartz.SpringBeanJobFactory implements
ApplicationContextAware {
private ApplicationContext ctx;
#Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
this.ctx = applicationContext;
}
#Override
protected Object createJobInstance(TriggerFiredBundle bundle)
throws Exception {
Object jobInstance = super.createJobInstance(bundle);
ctx.getAutowireCapableBeanFactory().autowireBean(jobInstance);
return jobInstance;
}
}
then config the class of MySpringBeanJobFactory in the xml:
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="jobFactory">
<bean class="com.xxxx.MySpringBeanJobFactory" />
</property>
<property name="configLocation" value="classpath:quartz.properties" />
<property name="triggers">
<list>
<ref bean="cronTrigger"/>
</list>
</property>
</bean>
Good luck ! :)

Resources