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:
parent
e266ff3aed
commit
e2816711ed
src/main
@ -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>
|
||||
|
Loading…
x
Reference in New Issue
Block a user