/* * Copyright (c) 2013-2015 Red Hat, Inc. and/or its affiliates. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Cheng Fang - Initial API and implementation */ package org.jberet.repository; import java.lang.ref.ReferenceQueue; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import javax.batch.runtime.JobExecution; import javax.batch.runtime.JobInstance; import javax.batch.runtime.StepExecution; import org.jberet._private.BatchLogger; import org.jberet.job.model.Job; import org.jberet.runtime.JobExecutionImpl; import org.jberet.runtime.JobInstanceImpl; import org.jberet.runtime.StepExecutionImpl; public abstract class AbstractPersistentRepository extends AbstractRepository implements JobRepository { final ConcurrentMap<Long, SoftReference<JobExecutionImpl, Long>> jobExecutions = new ConcurrentHashMap<Long, SoftReference<JobExecutionImpl, Long>>(); final ConcurrentMap<Long, SoftReference<JobInstanceImpl, Long>> jobInstances = new ConcurrentHashMap<Long, SoftReference<JobInstanceImpl, Long>>(); final ReferenceQueue<JobExecutionImpl> jobExecutionReferenceQueue = new ReferenceQueue<JobExecutionImpl>(); final ReferenceQueue<JobInstanceImpl> jobInstanceReferenceQueue = new ReferenceQueue<JobInstanceImpl>(); abstract void insertJobInstance(JobInstanceImpl jobInstance); abstract void insertJobExecution(JobExecutionImpl jobExecution); abstract void insertStepExecution(StepExecutionImpl stepExecution, JobExecutionImpl jobExecution); abstract List<StepExecution> selectStepExecutions(final Long jobExecutionId, final ClassLoader classLoader); @Override public void removeJob(final String jobId) { super.removeJob(jobId); //perform cascade delete for (final Iterator<Map.Entry<Long, SoftReference<JobInstanceImpl, Long>>> it = jobInstances.entrySet().iterator(); it.hasNext(); ) { final JobInstanceImpl ji = it.next().getValue().get(); if (ji != null && ji.getJobName().equals(jobId)) { BatchLogger.LOGGER.removing(JobInstance.class.getName(), String.valueOf(ji.getInstanceId())); it.remove(); } } for (final Iterator<Map.Entry<Long, SoftReference<JobExecutionImpl, Long>>> it = jobExecutions.entrySet().iterator(); it.hasNext(); ) { final JobExecutionImpl je = it.next().getValue().get(); if (je != null && je.getJobName().equals(jobId)) { if (je.getJobParameters() != null) { je.getJobParameters().clear(); } BatchLogger.LOGGER.removing(JobExecution.class.getName(), String.valueOf(je.getExecutionId())); it.remove(); } } } @Override public void removeJobExecutions(final JobExecutionSelector jobExecutionSelector) { final Collection<Long> allJobExecutionIds = jobExecutions.keySet(); for (final Iterator<Map.Entry<Long, SoftReference<JobExecutionImpl, Long>>> it = jobExecutions.entrySet().iterator(); it.hasNext(); ) { final JobExecutionImpl je = it.next().getValue().get(); if (je != null && (jobExecutionSelector == null || jobExecutionSelector.select(je, allJobExecutionIds))) { if (je.getJobParameters() != null) { je.getJobParameters().clear(); } BatchLogger.LOGGER.removing(JobExecution.class.getName(), String.valueOf(je.getExecutionId())); it.remove(); } } } @Override public JobInstanceImpl createJobInstance(final Job job, final String applicationName, final ClassLoader classLoader) { //expunge stale entries for (Object x; (x = jobInstanceReferenceQueue.poll()) != null; ) { @SuppressWarnings("unchecked") final SoftReference<JobInstanceImpl, Long> entry = (SoftReference<JobInstanceImpl, Long>) x; jobInstances.remove(entry.getKey()); } final JobInstanceImpl jobInstance = new JobInstanceImpl(job, applicationName, job.getId()); insertJobInstance(jobInstance); final Long instanceId = jobInstance.getInstanceId(); jobInstances.put(instanceId, new SoftReference<JobInstanceImpl, Long>(jobInstance, jobInstanceReferenceQueue, instanceId)); return jobInstance; } @Override public void removeJobInstance(final long jobInstanceIdToRemove) { BatchLogger.LOGGER.removing(JobInstance.class.getName(), String.valueOf(jobInstanceIdToRemove)); jobInstances.remove(jobInstanceIdToRemove); } @Override public JobInstanceImpl getJobInstance(final long jobInstanceId) { final SoftReference<JobInstanceImpl, Long> jobInstanceSoftReference = jobInstances.get(jobInstanceId); return jobInstanceSoftReference != null ? jobInstanceSoftReference.get() : null; } @Override public JobExecutionImpl createJobExecution(final JobInstanceImpl jobInstance, final Properties jobParameters) { //expunge stale entries for (Object x; (x = jobExecutionReferenceQueue.poll()) != null; ) { @SuppressWarnings("unchecked") final SoftReference<JobExecutionImpl, Long> entry = (SoftReference<JobExecutionImpl, Long>) x; jobExecutions.remove(entry.getKey()); } final JobExecutionImpl jobExecution = new JobExecutionImpl(jobInstance, jobParameters); insertJobExecution(jobExecution); final Long executionId = jobExecution.getExecutionId(); jobExecutions.put(executionId, new SoftReference<JobExecutionImpl, Long>(jobExecution, jobExecutionReferenceQueue, executionId)); jobInstance.addJobExecution(jobExecution); return jobExecution; } @Override public JobExecutionImpl getJobExecution(final long jobExecutionId) { final SoftReference<JobExecutionImpl, Long> jobExecutionSoftReference = jobExecutions.get(jobExecutionId); return jobExecutionSoftReference != null ? jobExecutionSoftReference.get() : null; } @Override public List<StepExecution> getStepExecutions(final long jobExecutionId, final ClassLoader classLoader) { //check cache first, if not found, then retrieve from database final List<StepExecution> stepExecutions; final SoftReference<JobExecutionImpl, Long> ref = jobExecutions.get(jobExecutionId); final JobExecutionImpl jobExecution = (ref != null) ? ref.get() : null; if (jobExecution == null) { stepExecutions = selectStepExecutions(jobExecutionId, classLoader); } else { final List<StepExecution> stepExecutions1 = jobExecution.getStepExecutions(); if (stepExecutions1.isEmpty()) { stepExecutions = selectStepExecutions(jobExecutionId, classLoader); } else { stepExecutions = stepExecutions1; } } return stepExecutions; } @Override public StepExecutionImpl findOriginalStepExecutionForRestart(final String stepName, final JobExecutionImpl jobExecutionToRestart, final ClassLoader classLoader) { for (final StepExecution stepExecution : jobExecutionToRestart.getStepExecutions()) { if (stepName.equals(stepExecution.getStepName())) { return (StepExecutionImpl) stepExecution; } } return null; } }