Fix av schedulering av workerthreads

git-svn-id: svn://svn.dsv.su.se/scipro/scipro/trunk@520 73ecded7-942e-4092-bab0-0e58ef0ee984
This commit is contained in:
mpeters 2011-03-29 10:53:40 +00:00
parent e266ff3aed
commit e2816711ed
10 changed files with 164 additions and 72 deletions

@ -8,8 +8,11 @@ import org.apache.wicket.ResourceReference;
import org.apache.wicket.Response;
import org.apache.wicket.Session;
import org.apache.wicket.authorization.strategies.CompoundAuthorizationStrategy;
import org.apache.wicket.injection.web.InjectorHolder;
import org.apache.wicket.protocol.http.WebApplication;
import org.odlabs.wiquery.ui.themes.IThemableApplication;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import se.su.dsv.scipro.basepages.DemoPage;
import se.su.dsv.scipro.basepages.SystemSettingsPage;
@ -17,6 +20,7 @@ import se.su.dsv.scipro.knol.resource.page.ResourcePage;
import se.su.dsv.scipro.loginlogout.pages.LoginPage;
import se.su.dsv.scipro.loginlogout.pages.LogoutPage;
import se.su.dsv.scipro.message.pages.MessagePage;
import se.su.dsv.scipro.peer.pages.PeerReviewTemplatePage;
import se.su.dsv.scipro.peer.pages.PeerTestPage;
import se.su.dsv.scipro.project.pages.ProjectFilePage;
import se.su.dsv.scipro.project.pages.ProjectStartPage;
@ -50,7 +54,7 @@ public class SciProApplication extends RepositoryApplication implements IThemabl
private final String jaasPath = "/WEB-INF/classes/jaas.conf";
private final String krb5Path = "/WEB-INF/classes/kerb5.conf";
private Scheduler scheduler = null;
//private Scheduler scheduler = null;
/*
* A string setable in the sys-admin settings page that displays for example a system takedown notice
@ -81,12 +85,13 @@ public class SciProApplication extends RepositoryApplication implements IThemabl
mountBookmarkablePage("logout", LogoutPage.class);
mountBookmarkablePage("project", ProjectStartPage.class);
mountBookmarkablePage("project/files", ProjectFilePage.class);
mountBookmarkablePage("admin/settings/", SystemSettingsPage.class);
mountBookmarkablePage("project/schedule", SchedulePlannerPage.class);
mountBookmarkablePage("admin/settings", SystemSettingsPage.class);
mountBookmarkablePage("peer", PeerTestPage.class);
mountBookmarkablePage("peer/templates", PeerReviewTemplatePage.class);
mountBookmarkablePage("mess", MessagePage.class);
mountBookmarkablePage("r", ResourcePage.class);
mountBookmarkablePage("demo", DemoPage.class);
mountBookmarkablePage("project/schedule", SchedulePlannerPage.class);
mountBookmarkablePage("demo", DemoPage.class);
mountBookmarkablePage("project/schedule/event", EventPage.class);
mountBookmarkablePage("templates/details", ScheduleTemplateDetailsPage.class);
mountBookmarkablePage("admin/templates", ScheduleTemplatesAdminPage.class);
@ -103,7 +108,11 @@ public class SciProApplication extends RepositoryApplication implements IThemabl
//getResourceSettings().addStringResourceLoader(new JpaStringResourceLoader());
getSecuritySettings().setUnauthorizedComponentInstantiationListener(new ComponentSecurityLogger());
scheduler = new Scheduler();
/*
* Passing the applicationContext on to workerthreads-scheduler via SchedulerServletContextListener defined in web.xml
*/
WebApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
getServletContext().setAttribute("org.springframework.web.context.WebApplicationContext", ctx);
}
@SuppressWarnings("unchecked")
@ -126,7 +135,7 @@ public class SciProApplication extends RepositoryApplication implements IThemabl
@Override
protected void onDestroy() {
scheduler.stopWorking();
//scheduler.stopWorking();
super.onDestroy();
}

@ -5,7 +5,7 @@ import java.util.concurrent.atomic.AtomicInteger;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import org.apache.wicket.spring.injection.annot.SpringBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.jpa.EntityManagerHolder;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.transaction.TransactionStatus;
@ -15,7 +15,7 @@ import org.springframework.transaction.support.TransactionSynchronizationManager
import se.su.dsv.scipro.data.dao.jpa.EntityManagerFactoryBean;
/**
*
* Subclasses must be annotated with @Component or similar annotation in order for autowiring of dependencies to work
* @author Martin Peters - mpeters@dsv.su.se
*
*/
@ -24,16 +24,22 @@ public abstract class AbstractWorker extends Thread {
private static AtomicInteger counter = new AtomicInteger();
protected int number;
protected String description;
@SpringBean
@Autowired
private EntityManagerFactoryBean emfBean;
private JpaTransactionManager jtm;
private TransactionStatus tx = null;
public AbstractWorker(String description){
/**
* Subclasses must be annotated with @Component or similar annotation in order for autowiring of dependencies to work
*/
public AbstractWorker(){
number = counter.incrementAndGet();
}
public void setDescription(String description){
this.description = description;
setName(description+": "+number);
}
@ -41,7 +47,6 @@ public abstract class AbstractWorker extends Thread {
public void run(){
try{
System.out.println("Adding worker "+number+" to running set");
if(!Scheduler.runningWorkers.contains(this))
Scheduler.runningWorkers.add(this);
@ -75,11 +80,11 @@ public abstract class AbstractWorker extends Thread {
}
finally{
System.out.println("Removing worker "+number+" from running set");
//System.out.println("Removing worker "+number+" from running set");
if(Scheduler.runningWorkers != null)
Scheduler.runningWorkers.remove(this);
}
System.out.println(getName()+" ends it's life");
//System.out.println(getName()+" ends it's life");
}
/**

@ -5,9 +5,9 @@ import java.util.HashSet;
import java.util.Set;
import java.util.Timer;
import org.apache.wicket.injection.web.InjectorHolder;
import org.apache.wicket.util.collections.ConcurrentHashSet;
import org.joda.time.MutableDateTime;
import org.springframework.web.context.WebApplicationContext;
public class Scheduler {
@ -15,16 +15,33 @@ public class Scheduler {
public final static Set<WorkerSchedule<AbstractWorker>> workerSchedules = new HashSet<WorkerSchedule<AbstractWorker>>();
public final static ConcurrentHashSet<AbstractWorker> runningWorkers = new ConcurrentHashSet<AbstractWorker>();
public Scheduler(){
private static Scheduler singleton = null;
private void initWorkers(WebApplicationContext ctx){
timer = new Timer("SchedulerTimer", false);
workerSchedules.add(new WorkerSchedule<AbstractWorker>(TestWorker.class, "a sunday worker", weekly(7, 23, 00), weekPeriod()));
workerSchedules.add(new WorkerSchedule<AbstractWorker>(TestWorker.class, "an hourly worker", hourly(0), hourPeriod()));
//workerSchedules.add(new WorkerSchedule<AbstractWorker>(TestWorker.class, "a once every 10s test worker", new Date(), 10000L));
setUpWorkers();
//Examples:
//workerSchedules.add(new WorkerSchedule<AbstractWorker>(TestWorker.class, "a sunday worker", weekly(7, 23, 00), weekPeriod(), ctx));
//workerSchedules.add(new WorkerSchedule<AbstractWorker>(TestWorker.class, "an hourly worker", hourly(0), hourPeriod(), ctx));
//workerSchedules.add(new WorkerSchedule<AbstractWorker>(TestWorker.class, "a once every 10s test worker", new Date(), 10000L, ctx));
//workerSchedules.add(new WorkerSchedule<AbstractWorker>(TestWorker.class, "a once every 10s test worker", new Date(), 100L, ctx));
}
private Scheduler(){
timer = new Timer("SciProSchedulerTimer", true);
}
private static void ifndefCreateScheduler(){
if(singleton == null)
singleton = new Scheduler();
}
public synchronized static Scheduler getScheduler(){
ifndefCreateScheduler();
return singleton;
}
protected Date hourly(int min){
@ -77,11 +94,12 @@ public class Scheduler {
return days+"d "+hours + "h " + minutes + "m "+seconds+"s";
}
private void setUpWorkers(){
private void scheduleWorkers(){
for(final WorkerSchedule<AbstractWorker> ws : workerSchedules){
try{
WorkerTimerTask<AbstractWorker> stt = new WorkerTimerTask<AbstractWorker>(ws, InjectorHolder.getInjector());
WorkerTimerTask<AbstractWorker> stt = new WorkerTimerTask<AbstractWorker>(ws);
timer.scheduleAtFixedRate(stt,ws.getFirstTime(),ws.getPeriod());
} catch (RuntimeException e) {
@ -89,12 +107,20 @@ public class Scheduler {
}
}
}
public void startWorking(WebApplicationContext ctx){
initWorkers(ctx);
scheduleWorkers();
}
public void stopWorking(){
timer.cancel();
for(AbstractWorker aw : runningWorkers)
aw.interrupt();
//System.out.println("Stopping scheduler and scheduled threads");
while(!runningWorkers.isEmpty()){
for(AbstractWorker aw : runningWorkers){
aw.interrupt();
runningWorkers.remove(aw);
}
}
}
}

@ -0,0 +1,46 @@
package se.su.dsv.scipro.workerthreads;
import javax.servlet.ServletContextAttributeEvent;
import javax.servlet.ServletContextAttributeListener;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.springframework.web.context.WebApplicationContext;
public class SchedulerServletContextListener implements ServletContextListener,ServletContextAttributeListener {
private Scheduler scheduler;
public SchedulerServletContextListener(){
scheduler = Scheduler.getScheduler();
}
@Override
public void contextInitialized(ServletContextEvent sce) {
sce.getServletContext().setAttribute("se.su.dsv.scipro.workerthreads.Scheduler", scheduler);
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
scheduler.stopWorking();
}
@Override
public void attributeAdded(ServletContextAttributeEvent scab) {
if(scab.getServletContext().getAttribute("org.springframework.web.context.WebApplicationContext") != null){
WebApplicationContext ctx = (WebApplicationContext) scab.getServletContext().getAttribute("org.springframework.web.context.WebApplicationContext");
scheduler.startWorking(ctx);
}
}
@Override
public void attributeRemoved(ServletContextAttributeEvent scab) {
// Ignored
}
@Override
public void attributeReplaced(ServletContextAttributeEvent scab) {
// Ignored
}
}

@ -1,6 +1,8 @@
package se.su.dsv.scipro.workerthreads;
import org.apache.wicket.spring.injection.annot.SpringBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import se.su.dsv.scipro.data.dao.interfaces.FileDescriptionDao;
import se.su.dsv.scipro.data.dao.interfaces.UserDao;
@ -11,16 +13,15 @@ import se.su.dsv.scipro.data.dataobjects.FileDescription;
* @author Martin Peters - mpeters@dsv.su.se
*
*/
@Component
public class TestWorker extends AbstractWorker {
@SpringBean
@Autowired
private UserDao userDao;
@SpringBean
@Autowired
private FileDescriptionDao fdDao;
public TestWorker(String description){
super(description);
}
public TestWorker(){ }
@Override
protected void doWork(){
@ -52,10 +53,12 @@ public class TestWorker extends AbstractWorker {
FileDescription fd = new FileDescription();
fd.setPath(getName());
fd.setName("fileName.xxx");
fd = fdDao.save(fd);
// if(number % 1 == 0)
// throw new RuntimeException("Causing crash");
this.commitTransaction();
Thread.sleep(30000);
} catch(Exception e){
this.rollbackTransaction();
throw new RuntimeException(e);

@ -5,54 +5,51 @@ import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Date;
import javax.servlet.ServletContext;
import org.apache.wicket.injection.ConfigurableInjector;
import org.apache.wicket.injection.web.InjectorHolder;
import org.apache.wicket.spring.injection.annot.SpringComponentInjector;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.ServletContextAware;
import org.springframework.web.context.support.WebApplicationContextUtils;
import se.su.dsv.scipro.SciProApplication;
/**
* @author Martin Peters - mpeters@dsv.su.se
*
* @param <T>
*/
public class WorkerSchedule<T extends AbstractWorker>implements Serializable {
public class WorkerSchedule<T extends AbstractWorker> implements Serializable {
private static final long serialVersionUID = 1L;
private Class<? extends T> clazz;
private String description;
private Date firstTime;
private long period;
private transient ApplicationContext ctx;
public WorkerSchedule(Class<? extends T> clazz, String description, Date firstTime, long period){
public WorkerSchedule(Class<? extends T> clazz, String description, Date firstTime, long period, ApplicationContext ctx){
this.description = description;
this.clazz = clazz;
this.firstTime = firstTime;
this.period = period;
this.ctx = ctx;
}
/**
* May only be called from application context where InjectorHolder has been initialized with an Injector
*/
public void forceStartOfWorkerThread(){
AbstractWorker aw = getWorkerThread();
InjectorHolder.getInjector().inject(aw);
Scheduler.runningWorkers.add(aw);
aw.start();
}
public AbstractWorker getWorkerThread() {
AbstractWorker aw = null;
try{
Constructor<? extends T> constructor = clazz.getConstructor(String.class);
aw = constructor.newInstance(description);
} catch(NoSuchMethodException e){
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return aw;
AbstractWorker aWorker = (AbstractWorker) ctx.getAutowireCapableBeanFactory().createBean(clazz,AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE,false);
aWorker.setDescription(description);
return aWorker;
}
@Override
@ -79,4 +76,5 @@ public class WorkerSchedule<T extends AbstractWorker>implements Serializable {
this.period = period;
}
}

@ -1,8 +1,6 @@
package se.su.dsv.scipro.workerthreads;
import java.util.TimerTask;
import org.apache.wicket.injection.ConfigurableInjector;
/**
*
* @author Martin Peters - mpeters@dsv.su.se
@ -12,32 +10,30 @@ import org.apache.wicket.injection.ConfigurableInjector;
public class WorkerTimerTask<T extends AbstractWorker> extends TimerTask {
private WorkerSchedule<AbstractWorker> workerSchedule;
private ConfigurableInjector injector;
public WorkerTimerTask(WorkerSchedule<AbstractWorker> workerSchedule, ConfigurableInjector injector) {
public WorkerTimerTask(WorkerSchedule<AbstractWorker> workerSchedule) {
this.workerSchedule = workerSchedule;
this.injector = injector;
}
public void run(){
public void run(){
try {
AbstractWorker aw = workerSchedule.getWorkerThread();
injector.inject(aw);
aw.start();
/*
* Enabling of this join-call means that the scheduler will never run two workers at the same time,
* the option to manually start workers is not affected and the scheduler will not fail to start scheduled
* workers because a manually started worker is running.
*/
//aw.join();
aw.join();
} catch (RuntimeException e) {
e.printStackTrace();
}
/*
catch (InterruptedException e) {
e.printStackTrace();
}
*/
}//run
}

@ -6,10 +6,10 @@
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd"
default-autowire="byName">
default-autowire="byType">
<!-- Sets up spring autowire configuration based on annotations -->
<!-- <context:annotation-config />-->
<context:annotation-config />
<context:component-scan base-package="se.su.dsv.scipro" />
<!-- STORAGE REPOSITORY CONFIG -->

@ -6,8 +6,11 @@
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd"
default-autowire="byName">
default-autowire="byType">
<!-- Sets up spring autowire configuration based on annotations -->
<context:annotation-config />
<context:component-scan base-package="se.su.dsv.scipro"/>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
@ -57,7 +60,9 @@
-= This one is not a dao, it's used to get the EntityManagerFactory for workerthreads =-
"entityManagerFactoryBean"
-->
<bean id="entityManagerFactoryBean" class="se.su.dsv.scipro.data.dao.jpa.EntityManagerFactoryBean">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<!-- Peer-related beans, autowired-->
<!--
@ -73,7 +78,7 @@
<!-- End of Peer-stuff -->
<bean class="se.su.dsv.scipro.DataInitialiser" init-method="dataInit" />
<!-- <bean class="se.su.dsv.scipro.DataInitialiser" init-method="dataInit" />-->
<!-- <bean class="se.su.dsv.scipro.datainitializers.EventTemplatesInitializer" init-method="dataInit" /> -->

@ -53,6 +53,10 @@
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>se.su.dsv.scipro.workerthreads.SchedulerServletContextListener</listener-class>
</listener>
</web-app>