/** * OLAT - Online Learning and Training<br> * http://www.olat.org * <p> * Licensed under the Apache License, Version 2.0 (the "License"); <br> * you may not use this file except in compliance with the License.<br> * You may obtain a copy of the License at * <p> * http://www.apache.org/licenses/LICENSE-2.0 * <p> * Unless required by applicable law or agreed to in writing,<br> * software distributed under the License is distributed on an "AS IS" BASIS, <br> * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> * See the License for the specific language governing permissions and <br> * limitations under the License. * <p> * Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br> * University of Zurich, Switzerland. * <hr> * <a href="http://www.openolat.org"> * OpenOLAT - Online Learning and Training</a><br> * This file has been modified by the OpenOLAT community. Changes are licensed * under the Apache 2.0 license as the original file. * <p> */ package org.olat.core.commons.services.taskexecutor.manager; import java.util.Date; import java.util.List; import java.util.UUID; import java.util.concurrent.ExecutorService; import org.olat.core.commons.persistence.DB; import org.olat.core.commons.services.taskexecutor.LongRunnable; import org.olat.core.commons.services.taskexecutor.Sequential; import org.olat.core.commons.services.taskexecutor.Task; import org.olat.core.commons.services.taskexecutor.TaskAwareRunnable; import org.olat.core.commons.services.taskexecutor.TaskExecutorManager; import org.olat.core.commons.services.taskexecutor.TaskStatus; import org.olat.core.commons.services.taskexecutor.model.DBSecureRunnable; import org.olat.core.commons.services.taskexecutor.model.PersistentTask; import org.olat.core.commons.services.taskexecutor.model.PersistentTaskRunnable; import org.olat.core.id.Identity; import org.olat.core.logging.AssertException; import org.olat.core.logging.OLog; import org.olat.core.logging.Tracing; import org.olat.core.manager.BasicManager; import org.olat.resource.OLATResource; import org.quartz.JobDetail; import org.quartz.Scheduler; import org.quartz.SchedulerException; /** * * Description:<br> * Generic task executor to run tasks in it's own threads. Use it to decouple stuff that might * takes more time than a user may is willing to wait. The task gets executed by a thread pool. * If you look for scheduled task see @see {@link org.olat.core.commons.services.scheduler} * * <P> * Initial Date: 02.05.2007 <br> * @author guido * @author srosse, stephane.rosse@frentix.com, http://www.frnetix.com */ public class TaskExecutorManagerImpl extends BasicManager implements TaskExecutorManager { private static final OLog log = Tracing.createLoggerFor(TaskExecutorManagerImpl.class); private final ExecutorService taskExecutor; private final ExecutorService sequentialTaskExecutor; private DB dbInstance; private Scheduler scheduler; private PersistentTaskDAO persistentTaskDao; /** * [used by spring] */ private TaskExecutorManagerImpl(ExecutorService mpTaskExecutor, ExecutorService sequentialTaskExecutor) { this.taskExecutor = mpTaskExecutor; this.sequentialTaskExecutor = sequentialTaskExecutor; } /** * [used by Spring] * @param scheduler */ public void setScheduler(Scheduler scheduler) { this.scheduler = scheduler; } /** * [used by Spring] * @param dbInstance */ public void setDbInstance(DB dbInstance) { this.dbInstance = dbInstance; } /** * [used by Spring] * @param persistentTaskDao */ public void setPersistentTaskDao(PersistentTaskDAO persistentTaskDao) { this.persistentTaskDao = persistentTaskDao; } public void shutdown() { taskExecutor.shutdown(); sequentialTaskExecutor.shutdown(); } @Override public void execute(Runnable task) { //wrap call to the task here to catch all errors that are may not catched yet in the task itself //like outOfMemory or other system errors. Task persistentTask = null; if(task instanceof LongRunnable) { persistentTask = persistentTaskDao.createTask(UUID.randomUUID().toString(), (LongRunnable)task); dbInstance.commit(); } else { execute(task, persistentTask, (task instanceof Sequential)); } } @Override public void execute(LongRunnable task, Identity creator, OLATResource resource, String resSubPath, Date scheduledDate) { persistentTaskDao.createTask(UUID.randomUUID().toString(), task, creator, resource, resSubPath, scheduledDate); dbInstance.commit(); } private void execute(Runnable task, Task persistentTask, boolean sequential) { if (taskExecutor != null) { if(task instanceof TaskAwareRunnable) { ((TaskAwareRunnable)task).setTask(persistentTask); } DBSecureRunnable safetask = new DBSecureRunnable(task); if(sequential) { sequentialTaskExecutor.submit(safetask); } else { taskExecutor.submit(safetask); } } else { logError("taskExecutor is not initialized (taskExecutor=null). Do not call 'runTask' before TaskExecutorModule is initialized.", null); throw new AssertException("taskExecutor is not initialized"); } } @Override public void executeTaskToDo() { try { JobDetail detail = scheduler.getJobDetail("taskExecutorJob", Scheduler.DEFAULT_GROUP); scheduler.triggerJob(detail.getName(), detail.getGroup()); } catch (SchedulerException e) { log.error("", e); } } protected void processTaskToDo() { try { List<Long> todos = persistentTaskDao.tasksToDo(); for(Long todo:todos) { PersistentTask task = persistentTaskDao.loadTaskById(todo); Runnable runnable = persistentTaskDao.deserializeTask(task); PersistentTaskRunnable command = new PersistentTaskRunnable(todo); execute(command, null, (runnable instanceof Sequential)); } } catch (Exception e) { // ups, something went completely wrong! We log this but continue next time log.error("Error while executing task todo", e); } } @Override public List<Task> getTasks(OLATResource resource) { return persistentTaskDao.findTasks(resource); } @Override public List<Identity> getModifiers(Task task) { return persistentTaskDao.getModifiers(task); } @Override public Task pickTaskForEdition(Task task) { return persistentTaskDao.pickTaskForEdition(task.getKey()); } @Override public Task returnTaskAfterEdition(Task task, TaskStatus wishedStatus) { return persistentTaskDao.returnTaskAfterEdition(task.getKey(), wishedStatus); } @Override public <T extends Runnable> T getPersistedRunnableTask(Task task, Class<T> type) { if(task instanceof PersistentTask) { PersistentTask ptask = (PersistentTask)task; @SuppressWarnings("unchecked") T runnable = (T)persistentTaskDao.deserializeTask(ptask); return runnable; } return null; } @Override public void updateAndReturn(Task task, LongRunnable runnableTask, Identity modifier, Date scheduledDate) { persistentTaskDao.updateTask(task, runnableTask, modifier, scheduledDate); } @Override public void delete(Task task) { persistentTaskDao.delete(task); } @Override public void delete(OLATResource resource) { persistentTaskDao.delete(resource); } @Override public void delete(OLATResource resource, String resSubPath) { persistentTaskDao.delete(resource, resSubPath); } }