| /******************************************************************************* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| *******************************************************************************/ |
| package org.apache.ofbiz.service.job; |
| |
| import java.io.IOException; |
| import java.sql.Timestamp; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.Date; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.concurrent.ConcurrentHashMap; |
| import java.util.concurrent.RejectedExecutionException; |
| |
| import org.apache.ofbiz.base.config.GenericConfigException; |
| import org.apache.ofbiz.base.util.Assert; |
| import org.apache.ofbiz.base.util.Debug; |
| import org.apache.ofbiz.base.util.UtilDateTime; |
| import org.apache.ofbiz.base.util.UtilMisc; |
| import org.apache.ofbiz.base.util.UtilProperties; |
| import org.apache.ofbiz.base.util.UtilValidate; |
| import org.apache.ofbiz.entity.Delegator; |
| import org.apache.ofbiz.entity.GenericEntityException; |
| import org.apache.ofbiz.entity.GenericValue; |
| import org.apache.ofbiz.entity.condition.EntityCondition; |
| import org.apache.ofbiz.entity.condition.EntityExpr; |
| import org.apache.ofbiz.entity.condition.EntityJoinOperator; |
| import org.apache.ofbiz.entity.condition.EntityOperator; |
| import org.apache.ofbiz.entity.serialize.SerializeException; |
| import org.apache.ofbiz.entity.serialize.XmlSerializer; |
| import org.apache.ofbiz.entity.transaction.TransactionUtil; |
| import org.apache.ofbiz.entity.util.EntityListIterator; |
| import org.apache.ofbiz.entity.util.EntityQuery; |
| import org.apache.ofbiz.service.DispatchContext; |
| import org.apache.ofbiz.service.LocalDispatcher; |
| import org.apache.ofbiz.service.ServiceContainer; |
| import org.apache.ofbiz.service.calendar.RecurrenceInfo; |
| import org.apache.ofbiz.service.calendar.RecurrenceInfoException; |
| import org.apache.ofbiz.service.config.ServiceConfigUtil; |
| import org.apache.ofbiz.service.config.model.RunFromPool; |
| |
| import com.ibm.icu.util.Calendar; |
| |
| /** |
| * Job manager. The job manager queues and manages jobs. Client code can queue a job to be run immediately |
| * by calling the {@link #runJob(Job)} method, or schedule a job to be run later by calling the |
| * {@link #schedule(String, String, String, Map, long, int, int, int, long, int)} method. |
| * Scheduled jobs are persisted in the JobSandbox entity. |
| * <p>A scheduled job's start time is an approximation - the actual start time will depend |
| * on the job manager/job poller configuration (poll interval) and the load on the server. |
| * Scheduled jobs might be rescheduled if the server is busy. Therefore, applications |
| * requiring a precise job start time should use a different mechanism to schedule the job.</p> |
| */ |
| public final class JobManager { |
| |
| public static final String module = JobManager.class.getName(); |
| public static final String instanceId = UtilProperties.getPropertyValue("general", "unique.instanceId", "ofbiz0"); |
| private static final ConcurrentHashMap<String, JobManager> registeredManagers = new ConcurrentHashMap<String, JobManager>(); |
| private static boolean isShutDown = false; |
| |
| private static void assertIsRunning() { |
| if (isShutDown) { |
| throw new IllegalStateException("OFBiz shutting down"); |
| } |
| } |
| |
| /** |
| * Returns a <code>JobManager</code> instance. |
| * @param delegator |
| * @param enablePoller Enables polling of the JobSandbox entity. |
| * @throws IllegalStateException if the Job Manager is shut down. |
| */ |
| public static JobManager getInstance(Delegator delegator, boolean enablePoller) { |
| assertIsRunning(); |
| Assert.notNull("delegator", delegator); |
| JobManager jm = registeredManagers.get(delegator.getDelegatorName()); |
| if (jm == null) { |
| jm = new JobManager(delegator); |
| registeredManagers.putIfAbsent(delegator.getDelegatorName(), jm); |
| jm = registeredManagers.get(delegator.getDelegatorName()); |
| if (enablePoller) { |
| JobPoller.registerJobManager(jm); |
| } |
| } |
| return jm; |
| } |
| |
| /** |
| * Shuts down all job managers. This method is called when OFBiz shuts down. |
| */ |
| public static void shutDown() { |
| isShutDown = true; |
| JobPoller.getInstance().stop(); |
| } |
| |
| private final Delegator delegator; |
| private boolean crashedJobsReloaded = false; |
| |
| private JobManager(Delegator delegator) { |
| this.delegator = delegator; |
| } |
| |
| /** Returns the Delegator. */ |
| public Delegator getDelegator() { |
| return this.delegator; |
| } |
| |
| /** Returns the LocalDispatcher. */ |
| public LocalDispatcher getDispatcher() { |
| LocalDispatcher thisDispatcher = ServiceContainer.getLocalDispatcher(delegator.getDelegatorName(), delegator); |
| return thisDispatcher; |
| } |
| |
| /** |
| * Get a List of each threads current state. |
| * |
| * @return List containing a Map of each thread's state. |
| */ |
| public Map<String, Object> getPoolState() { |
| return JobPoller.getInstance().getPoolState(); |
| } |
| |
| /** |
| * Return true if the jobManager can run job. |
| * |
| * @return boolean. |
| */ |
| public boolean isAvailable() { |
| try { |
| //check if a lock is enable for the period on entity JobManagerLock |
| EntityCondition condition = EntityCondition.makeCondition(UtilMisc.toList( |
| EntityCondition.makeConditionDate("fromDate", "thruDate"), |
| EntityCondition.makeCondition(UtilMisc.toList( |
| EntityCondition.makeCondition("instanceId", instanceId), |
| EntityCondition.makeCondition("instanceId", "_NA_")) |
| , EntityJoinOperator.OR) |
| ), EntityJoinOperator.AND); |
| return delegator.findCountByCondition("JobManagerLock", condition, null, null) == 0; |
| } catch (GenericEntityException e) { |
| Debug.logWarning(e, "Exception thrown while check lock on JobManager : " + instanceId, module); |
| return false; |
| } |
| } |
| |
| private static List<String> getRunPools() throws GenericConfigException { |
| List<RunFromPool> runFromPools = ServiceConfigUtil.getServiceEngine().getThreadPool().getRunFromPools(); |
| List<String> readPools = new ArrayList<String>(runFromPools.size()); |
| for (RunFromPool runFromPool : runFromPools) { |
| readPools.add(runFromPool.getName()); |
| } |
| return readPools; |
| } |
| |
| /** |
| * Scans the JobSandbox entity and returns a list of jobs that are due to run. |
| * Returns an empty list if there are no jobs due to run. |
| * This method is called by the {@link JobPoller} polling thread. |
| */ |
| protected List<Job> poll(int limit) { |
| assertIsRunning(); |
| // The rest of this method logs exceptions and does not throw them. |
| // The idea is to keep the JobPoller working even when a database |
| // connection is not available (possible on a saturated server). |
| DispatchContext dctx = getDispatcher().getDispatchContext(); |
| if (dctx == null) { |
| Debug.logWarning("Unable to locate DispatchContext object; not running job!", module); |
| return Collections.emptyList(); |
| } |
| // basic query |
| List<EntityExpr> expressions = UtilMisc.toList(EntityCondition.makeCondition("runTime", EntityOperator.LESS_THAN_EQUAL_TO, UtilDateTime.nowTimestamp()), |
| EntityCondition.makeCondition("startDateTime", EntityOperator.EQUALS, null), |
| EntityCondition.makeCondition("cancelDateTime", EntityOperator.EQUALS, null), |
| EntityCondition.makeCondition("runByInstanceId", EntityOperator.EQUALS, null)); |
| // limit to just defined pools |
| List<String> pools = null; |
| try { |
| pools = getRunPools(); |
| } catch (GenericConfigException e) { |
| Debug.logWarning(e, "Unable to get run pools - not running job: ", module); |
| return Collections.emptyList(); |
| } |
| List<EntityExpr> poolsExpr = UtilMisc.toList(EntityCondition.makeCondition("poolId", EntityOperator.EQUALS, null)); |
| if (!pools.isEmpty()) { |
| for (String poolName : pools) { |
| poolsExpr.add(EntityCondition.makeCondition("poolId", EntityOperator.EQUALS, poolName)); |
| } |
| } |
| List<Job> poll = new ArrayList<Job>(limit); |
| // make the conditions |
| EntityCondition baseCondition = EntityCondition.makeCondition(expressions); |
| EntityCondition poolCondition = EntityCondition.makeCondition(poolsExpr, EntityOperator.OR); |
| EntityCondition mainCondition = EntityCondition.makeCondition(UtilMisc.toList(baseCondition, poolCondition)); |
| EntityListIterator jobsIterator = null; |
| boolean beganTransaction = false; |
| try { |
| beganTransaction = TransactionUtil.begin(); |
| if (!beganTransaction) { |
| Debug.logWarning("Unable to poll JobSandbox for jobs; unable to begin transaction.", module); |
| return poll; |
| } |
| jobsIterator = EntityQuery.use(delegator).from("JobSandbox").where(mainCondition).orderBy("runTime").queryIterator(); |
| GenericValue jobValue = jobsIterator.next(); |
| while (jobValue != null) { |
| // Claim ownership of this value. Using storeByCondition to avoid a race condition. |
| List<EntityExpr> updateExpression = UtilMisc.toList(EntityCondition.makeCondition("jobId", EntityOperator.EQUALS, jobValue.get("jobId")), EntityCondition.makeCondition("runByInstanceId", EntityOperator.EQUALS, null)); |
| int rowsUpdated = delegator.storeByCondition("JobSandbox", UtilMisc.toMap("runByInstanceId", instanceId), EntityCondition.makeCondition(updateExpression)); |
| if (rowsUpdated == 1) { |
| poll.add(new PersistedServiceJob(dctx, jobValue, null)); |
| if (poll.size() == limit) { |
| break; |
| } |
| } |
| jobValue = jobsIterator.next(); |
| } |
| TransactionUtil.commit(beganTransaction); |
| } catch (Throwable t) { |
| String errMsg = "Exception thrown while polling JobSandbox: "; |
| try { |
| TransactionUtil.rollback(beganTransaction, errMsg, t); |
| } catch (GenericEntityException e) { |
| Debug.logWarning(e, "Exception thrown while rolling back transaction: ", module); |
| } |
| Debug.logWarning(t, errMsg, module); |
| return Collections.emptyList(); |
| } finally { |
| if (jobsIterator != null) { |
| try { |
| jobsIterator.close(); |
| } catch (GenericEntityException e) { |
| Debug.logWarning(e, module); |
| } |
| } |
| } |
| if (poll.isEmpty()) { |
| // No jobs to run, see if there are any jobs to purge |
| Calendar cal = Calendar.getInstance(); |
| try { |
| int daysToKeep = ServiceConfigUtil.getServiceEngine().getThreadPool().getPurgeJobDays(); |
| cal.add(Calendar.DAY_OF_YEAR, -daysToKeep); |
| } catch (GenericConfigException e) { |
| Debug.logWarning(e, "Unable to get purge job days: ", module); |
| return Collections.emptyList(); |
| } |
| Timestamp purgeTime = new Timestamp(cal.getTimeInMillis()); |
| List<EntityExpr> finExp = UtilMisc.toList(EntityCondition.makeCondition("finishDateTime", EntityOperator.NOT_EQUAL, null), EntityCondition.makeCondition("finishDateTime", EntityOperator.LESS_THAN, purgeTime)); |
| List<EntityExpr> canExp = UtilMisc.toList(EntityCondition.makeCondition("cancelDateTime", EntityOperator.NOT_EQUAL, null), EntityCondition.makeCondition("cancelDateTime", EntityOperator.LESS_THAN, purgeTime)); |
| EntityCondition doneCond = EntityCondition.makeCondition(UtilMisc.toList(EntityCondition.makeCondition(canExp), EntityCondition.makeCondition(finExp)), EntityOperator.OR); |
| mainCondition = EntityCondition.makeCondition(UtilMisc.toList(EntityCondition.makeCondition("runByInstanceId", instanceId), doneCond)); |
| beganTransaction = false; |
| jobsIterator = null; |
| try { |
| beganTransaction = TransactionUtil.begin(); |
| if (!beganTransaction) { |
| Debug.logWarning("Unable to poll JobSandbox for jobs; unable to begin transaction.", module); |
| return Collections.emptyList(); |
| } |
| jobsIterator = EntityQuery.use(delegator).from("JobSandbox").where(mainCondition).orderBy("jobId").queryIterator(); |
| GenericValue jobValue = jobsIterator.next(); |
| while (jobValue != null) { |
| poll.add(new PurgeJob(jobValue)); |
| if (poll.size() == limit) { |
| break; |
| } |
| jobValue = jobsIterator.next(); |
| } |
| TransactionUtil.commit(beganTransaction); |
| } catch (Throwable t) { |
| String errMsg = "Exception thrown while polling JobSandbox: "; |
| try { |
| TransactionUtil.rollback(beganTransaction, errMsg, t); |
| } catch (GenericEntityException e) { |
| Debug.logWarning(e, "Exception thrown while rolling back transaction: ", module); |
| } |
| Debug.logWarning(t, errMsg, module); |
| return Collections.emptyList(); |
| } finally { |
| if (jobsIterator != null) { |
| try { |
| jobsIterator.close(); |
| } catch (GenericEntityException e) { |
| Debug.logWarning(e, module); |
| } |
| } |
| } |
| } |
| return poll; |
| } |
| |
| public synchronized void reloadCrashedJobs() { |
| assertIsRunning(); |
| if (crashedJobsReloaded) { |
| return; |
| } |
| List<GenericValue> crashed = null; |
| List<EntityExpr> statusExprList = UtilMisc.toList(EntityCondition.makeCondition("statusId", EntityOperator.EQUALS, "SERVICE_PENDING"), |
| EntityCondition.makeCondition("statusId", EntityOperator.EQUALS, "SERVICE_QUEUED"), |
| EntityCondition.makeCondition("statusId", EntityOperator.EQUALS, "SERVICE_RUNNING")); |
| EntityCondition statusCondition = EntityCondition.makeCondition(statusExprList, EntityOperator.OR); |
| EntityCondition mainCondition = EntityCondition.makeCondition(UtilMisc.toList(EntityCondition.makeCondition("runByInstanceId", instanceId), statusCondition)); |
| try { |
| crashed = EntityQuery.use(delegator).from("JobSandbox").where(mainCondition).orderBy("startDateTime").queryList(); |
| } catch (GenericEntityException e) { |
| Debug.logWarning(e, "Unable to load crashed jobs", module); |
| } |
| if (UtilValidate.isNotEmpty(crashed)) { |
| int rescheduled = 0; |
| Timestamp now = UtilDateTime.nowTimestamp(); |
| for (GenericValue job : crashed) { |
| try { |
| if (Debug.infoOn()) Debug.logInfo("Scheduling Job : " + job, module); |
| String pJobId = job.getString("parentJobId"); |
| if (pJobId == null) { |
| pJobId = job.getString("jobId"); |
| } |
| GenericValue newJob = GenericValue.create(job); |
| newJob.set("statusId", "SERVICE_PENDING"); |
| newJob.set("runTime", now); |
| newJob.set("previousJobId", job.getString("jobId")); |
| newJob.set("parentJobId", pJobId); |
| newJob.set("startDateTime", null); |
| newJob.set("runByInstanceId", null); |
| //don't set a recurrent schedule on the new job, run it just one time |
| newJob.set("tempExprId", null); |
| newJob.set("recurrenceInfoId", null); |
| delegator.createSetNextSeqId(newJob); |
| // set the cancel time on the old job to the same as the re-schedule time |
| job.set("statusId", "SERVICE_CRASHED"); |
| job.set("cancelDateTime", now); |
| delegator.store(job); |
| rescheduled++; |
| } catch (GenericEntityException e) { |
| Debug.logWarning(e, module); |
| } |
| } |
| if (Debug.infoOn()) |
| Debug.logInfo("-- " + rescheduled + " jobs re-scheduled", module); |
| } else { |
| if (Debug.infoOn()) |
| Debug.logInfo("No crashed jobs to re-schedule", module); |
| } |
| crashedJobsReloaded = true; |
| } |
| |
| /** Queues a Job to run now. |
| * @throws IllegalStateException if the Job Manager is shut down. |
| * @throws RejectedExecutionException if the poller is stopped. |
| */ |
| public void runJob(Job job) throws JobManagerException { |
| assertIsRunning(); |
| if (job.isValid()) { |
| JobPoller.getInstance().queueNow(job); |
| } |
| } |
| |
| /** |
| * Schedule a job to start at a specific time with specific recurrence info |
| * |
| * @param serviceName |
| * The name of the service to invoke |
| *@param context |
| * The context for the service |
| *@param startTime |
| * The time in milliseconds the service should run |
| *@param frequency |
| * The frequency of the recurrence (HOURLY,DAILY,MONTHLY,etc) |
| *@param interval |
| * The interval of the frequency recurrence |
| *@param count |
| * The number of times to repeat |
| */ |
| public void schedule(String serviceName, Map<String, ? extends Object> context, long startTime, int frequency, int interval, int count) throws JobManagerException { |
| schedule(serviceName, context, startTime, frequency, interval, count, 0); |
| } |
| |
| /** |
| * Schedule a job to start at a specific time with specific recurrence info |
| * |
| * @param serviceName |
| * The name of the service to invoke |
| *@param context |
| * The context for the service |
| *@param startTime |
| * The time in milliseconds the service should run |
| *@param frequency |
| * The frequency of the recurrence (HOURLY,DAILY,MONTHLY,etc) |
| *@param interval |
| * The interval of the frequency recurrence |
| *@param count |
| * The number of times to repeat |
| *@param endTime |
| * The time in milliseconds the service should expire |
| */ |
| public void schedule(String serviceName, Map<String, ? extends Object> context, long startTime, int frequency, int interval, int count, long endTime) throws JobManagerException { |
| schedule(null, serviceName, context, startTime, frequency, interval, count, endTime); |
| } |
| |
| /** |
| * Schedule a job to start at a specific time with specific recurrence info |
| * |
| * @param serviceName |
| * The name of the service to invoke |
| *@param context |
| * The context for the service |
| *@param startTime |
| * The time in milliseconds the service should run |
| *@param frequency |
| * The frequency of the recurrence (HOURLY,DAILY,MONTHLY,etc) |
| *@param interval |
| * The interval of the frequency recurrence |
| *@param endTime |
| * The time in milliseconds the service should expire |
| */ |
| public void schedule(String serviceName, Map<String, ? extends Object> context, long startTime, int frequency, int interval, long endTime) throws JobManagerException { |
| schedule(serviceName, context, startTime, frequency, interval, -1, endTime); |
| } |
| |
| /** |
| * Schedule a job to start at a specific time with specific recurrence info |
| * |
| * @param poolName |
| * The name of the pool to run the service from |
| *@param serviceName |
| * The name of the service to invoke |
| *@param context |
| * The context for the service |
| *@param startTime |
| * The time in milliseconds the service should run |
| *@param frequency |
| * The frequency of the recurrence (HOURLY,DAILY,MONTHLY,etc) |
| *@param interval |
| * The interval of the frequency recurrence |
| *@param count |
| * The number of times to repeat |
| *@param endTime |
| * The time in milliseconds the service should expire |
| */ |
| public void schedule(String poolName, String serviceName, Map<String, ? extends Object> context, long startTime, int frequency, |
| int interval, int count, long endTime) throws JobManagerException { |
| schedule(null, null, serviceName, context, startTime, frequency, interval, count, endTime, -1); |
| } |
| |
| /** |
| * Schedule a job to start at a specific time with specific recurrence info |
| * |
| * @param poolName |
| * The name of the pool to run the service from |
| *@param serviceName |
| * The name of the service to invoke |
| *@param dataId |
| * The persisted context (RuntimeData.runtimeDataId) |
| *@param startTime |
| * The time in milliseconds the service should run |
| */ |
| public void schedule(String poolName, String serviceName, String dataId, long startTime) throws JobManagerException { |
| schedule(null, poolName, serviceName, dataId, startTime, -1, 0, 1, 0, -1); |
| } |
| |
| /** |
| * Schedule a job to start at a specific time with specific recurrence info |
| * |
| * @param jobName |
| * The name of the job |
| *@param poolName |
| * The name of the pool to run the service from |
| *@param serviceName |
| * The name of the service to invoke |
| *@param context |
| * The context for the service |
| *@param startTime |
| * The time in milliseconds the service should run |
| *@param frequency |
| * The frequency of the recurrence (HOURLY,DAILY,MONTHLY,etc) |
| *@param interval |
| * The interval of the frequency recurrence |
| *@param count |
| * The number of times to repeat |
| *@param endTime |
| * The time in milliseconds the service should expire |
| *@param maxRetry |
| * The max number of retries on failure (-1 for no max) |
| */ |
| public void schedule(String jobName, String poolName, String serviceName, Map<String, ? extends Object> context, long startTime, |
| int frequency, int interval, int count, long endTime, int maxRetry) throws JobManagerException { |
| // persist the context |
| String dataId = null; |
| try { |
| GenericValue runtimeData = delegator.makeValue("RuntimeData"); |
| runtimeData.set("runtimeInfo", XmlSerializer.serialize(context)); |
| runtimeData = delegator.createSetNextSeqId(runtimeData); |
| dataId = runtimeData.getString("runtimeDataId"); |
| } catch (GenericEntityException ee) { |
| throw new JobManagerException(ee.getMessage(), ee); |
| } catch (SerializeException se) { |
| throw new JobManagerException(se.getMessage(), se); |
| } catch (IOException ioe) { |
| throw new JobManagerException(ioe.getMessage(), ioe); |
| } |
| // schedule the job |
| schedule(jobName, poolName, serviceName, dataId, startTime, frequency, interval, count, endTime, maxRetry); |
| } |
| |
| /** |
| * Schedule a job to start at a specific time with specific recurrence info |
| * |
| * @param jobName |
| * The name of the job |
| *@param poolName |
| * The name of the pool to run the service from |
| *@param serviceName |
| * The name of the service to invoke |
| *@param dataId |
| * The persisted context (RuntimeData.runtimeDataId) |
| *@param startTime |
| * The time in milliseconds the service should run |
| *@param frequency |
| * The frequency of the recurrence (HOURLY,DAILY,MONTHLY,etc) |
| *@param interval |
| * The interval of the frequency recurrence |
| *@param count |
| * The number of times to repeat |
| *@param endTime |
| * The time in milliseconds the service should expire |
| *@param maxRetry |
| * The max number of retries on failure (-1 for no max) |
| * @throws IllegalStateException if the Job Manager is shut down. |
| */ |
| public void schedule(String jobName, String poolName, String serviceName, String dataId, long startTime, int frequency, int interval, |
| int count, long endTime, int maxRetry) throws JobManagerException { |
| assertIsRunning(); |
| // create the recurrence |
| String infoId = null; |
| if (frequency > -1 && count != 0) { |
| try { |
| RecurrenceInfo info = RecurrenceInfo.makeInfo(delegator, startTime, frequency, interval, count); |
| infoId = info.primaryKey(); |
| } catch (RecurrenceInfoException e) { |
| throw new JobManagerException(e.getMessage(), e); |
| } |
| } |
| // set the persisted fields |
| if (UtilValidate.isEmpty(jobName)) { |
| jobName = Long.toString((new Date().getTime())); |
| } |
| Map<String, Object> jFields = UtilMisc.<String, Object> toMap("jobName", jobName, "runTime", new java.sql.Timestamp(startTime), |
| "serviceName", serviceName, "statusId", "SERVICE_PENDING", "recurrenceInfoId", infoId, "runtimeDataId", dataId); |
| // set the pool ID |
| if (UtilValidate.isNotEmpty(poolName)) { |
| jFields.put("poolId", poolName); |
| } else { |
| try { |
| jFields.put("poolId", ServiceConfigUtil.getServiceEngine().getThreadPool().getSendToPool()); |
| } catch (GenericConfigException e) { |
| throw new JobManagerException(e.getMessage(), e); |
| } |
| } |
| // set the loader name |
| jFields.put("loaderName", delegator.getDelegatorName()); |
| // set the max retry |
| jFields.put("maxRetry", Long.valueOf(maxRetry)); |
| jFields.put("currentRetryCount", new Long(0)); |
| // create the value and store |
| GenericValue jobV; |
| try { |
| jobV = delegator.makeValue("JobSandbox", jFields); |
| delegator.createSetNextSeqId(jobV); |
| } catch (GenericEntityException e) { |
| throw new JobManagerException(e.getMessage(), e); |
| } |
| } |
| } |