/*
* JBoss, Home of Professional Open Source
* Copyright 2005, JBoss Inc., and individual contributors as indicated
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jbpm.pvm.internal.cmd;
import java.util.Date;
import org.jbpm.api.JbpmException;
import org.jbpm.api.cmd.Environment;
import org.jbpm.api.job.Job;
import org.jbpm.internal.log.Log;
import org.jbpm.pvm.internal.env.EnvironmentImpl;
import org.jbpm.pvm.internal.env.JobContext;
import org.jbpm.pvm.internal.job.JobImpl;
import org.jbpm.pvm.internal.jobexecutor.JobExceptionHandler;
import org.jbpm.pvm.internal.session.DbSession;
import org.jbpm.pvm.internal.tx.Transaction;
/**
* @author Tom Baeyens
*/
public class ExecuteJobCmd extends AbstractCommand<Job> {
private static final long serialVersionUID = 1L;
private static final Log log = Log.getLog(ExecuteJobCmd.class.getName());
protected Long jobDbid;
public ExecuteJobCmd(String jobId) {
if (jobId==null) {
throw new JbpmException("jobId is null");
}
jobDbid = Long.parseLong(jobId);
}
public ExecuteJobCmd(Long jobDbid) {
this.jobDbid = jobDbid;
}
public Job execute(Environment environmentInterface) throws Exception {
EnvironmentImpl environment = (EnvironmentImpl) environmentInterface;
DbSession dbSession = environment.get(DbSession.class);
if (dbSession==null) {
throw new JbpmException("no db-session configured");
}
JobImpl<?> job = (JobImpl<?>) dbSession.get(JobImpl.class, jobDbid);
// in case of decision jobs, the job might have been deleted
// before we execute it (they are in a list)
if (job != null) {
JobContext jobContext = new JobContext(job);
environment.setContext(jobContext);
try {
log.debug("executing job "+job+"...");
job.execute(environment);
log.debug("executed job "+job);
// if this job is locked too long, it could be unlocked by the lockmonitor and
// executed by another thread.
Date lockExpirationDate = job.getLockExpirationTime();
// can be null if it was rescheduled
if (lockExpirationDate != null) {
long lockExpiration = lockExpirationDate.getTime();
long currentTime = System.currentTimeMillis();
if (currentTime>lockExpiration) {
throw new JbpmException("job took too long: lock expired "+(currentTime-lockExpiration)+"ms ago");
}
}
} catch (Exception exception) {
log.error("exception while executing '"+job+"'", exception);
handleJobExecutionException(environment, job, exception);
} finally {
environment.removeContext(jobContext);
}
} else {
log.debug("job " + jobDbid + " no longer exists");
}
return job;
}
/** This transaction will be marked for rollback. A command will be associated with the
* Transaction.EVENT_AFTERCOMPLETION (after the job locks of the current transaction are
* released). Then the command will update the job with the exception details in a separate
* transaction. */
protected void handleJobExecutionException(Environment environment, JobImpl<?> job, Exception exception) {
Transaction transaction = environment.get(Transaction.class);
CommandService commandService = (CommandService) environment.get(CommandService.NAME_NEW_TX_REQUIRED_COMMAND_SERVICE);
JobExceptionHandler jobExceptionHandler = new JobExceptionHandler(job.getDbid(), exception, commandService);
transaction.registerSynchronization(jobExceptionHandler);
if (exception instanceof RuntimeException) {
throw (RuntimeException) exception;
}
throw new JbpmException("job failed: "+exception.getMessage(), exception);
}
}