/* * 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.io.Serializable; import java.lang.ref.ReferenceQueue; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import javax.batch.runtime.BatchStatus; import javax.batch.runtime.JobExecution; import org.jberet._private.BatchLogger; import org.jberet.job.model.Job; import org.jberet.runtime.AbstractStepExecution; import org.jberet.runtime.JobExecutionImpl; import org.jberet.runtime.JobInstanceImpl; import org.jberet.runtime.PartitionExecutionImpl; import org.jberet.runtime.StepExecutionImpl; import org.jberet.util.BatchUtil; import org.wildfly.security.manager.WildFlySecurityManager; public abstract class AbstractRepository implements JobRepository { final ConcurrentMap<ApplicationAndJobName, SoftReference<Job, ApplicationAndJobName>> jobs = new ConcurrentHashMap<ApplicationAndJobName, SoftReference<Job, ApplicationAndJobName>>(); final ReferenceQueue<Job> jobReferenceQueue = new ReferenceQueue<Job>(); abstract void insertJobInstance(JobInstanceImpl jobInstance); abstract void insertJobExecution(JobExecutionImpl jobExecution); abstract void insertStepExecution(StepExecutionImpl stepExecution, JobExecutionImpl jobExecution); @Override public void addJob(final ApplicationAndJobName applicationAndJobName, final Job job) { //expunge stale entries for (Object x; (x = jobReferenceQueue.poll()) != null; ) { @SuppressWarnings("unchecked") final SoftReference<Job, ApplicationAndJobName> entry = (SoftReference<Job, ApplicationAndJobName>) x; jobs.remove(entry.getKey()); } jobs.put(applicationAndJobName, new SoftReference<Job, ApplicationAndJobName>(job, jobReferenceQueue, applicationAndJobName)); } @Override public Job getJob(final ApplicationAndJobName applicationAndJobName) { final SoftReference<Job, ApplicationAndJobName> jobSoftReference = jobs.get(applicationAndJobName); return jobSoftReference != null ? jobSoftReference.get() : null; } public boolean jobExists(final String jobName) { for (final ApplicationAndJobName e : jobs.keySet()) { if (e.jobName.equals(jobName)) { return true; } } return false; } @Override public Set<String> getJobNames() { final Set<String> jobNames = new HashSet<String>(); for (final ApplicationAndJobName e : jobs.keySet()) { jobNames.add(e.jobName); } return jobNames; } @Override public void removeJob(final String jobId) { for (final Iterator<Map.Entry<ApplicationAndJobName, SoftReference<Job, ApplicationAndJobName>>> it = jobs.entrySet().iterator(); it.hasNext(); ) { final Map.Entry<ApplicationAndJobName, SoftReference<Job, ApplicationAndJobName>> next = it.next(); if (next.getKey().jobName.equals(jobId)) { BatchLogger.LOGGER.removing("Job", jobId); it.remove(); } } //cascade delete to be performed by subclasses, which have access to jobInstances and jobExecutions data structure } @Override public StepExecutionImpl createStepExecution(final String stepName) { // this stepExecution will be added to jobExecution later, after determining restart-if-complete, so that // completed steps are not added to the enclosing JobExecution // jobExecution.addStepExecution(stepExecution); return new StepExecutionImpl(stepName); } @Override public void addStepExecution(final JobExecutionImpl jobExecution, final StepExecutionImpl stepExecution) { jobExecution.addStepExecution(stepExecution); insertStepExecution(stepExecution, jobExecution); } @Override public void savePersistentData(final JobExecution jobExecution, final AbstractStepExecution stepOrPartitionExecution) { // Does nothing as the serialized data is stored in serialized form and is immutable } @Override public void updateJobExecution(final JobExecutionImpl jobExecution, final boolean fullUpdate, final boolean saveJobParameters) { jobExecution.setLastUpdatedTime(System.currentTimeMillis()); } @Override public void addPartitionExecution(final StepExecutionImpl enclosingStepExecution, final PartitionExecutionImpl partitionExecution) { enclosingStepExecution.getPartitionExecutions().add(partitionExecution); } @Override public List<PartitionExecutionImpl> getPartitionExecutions(final long stepExecutionId, final StepExecutionImpl stepExecution, final boolean notCompletedOnly, final ClassLoader classLoader) { if (stepExecution != null) { final List<PartitionExecutionImpl> partitionExecutions = stepExecution.getPartitionExecutions(); if (partitionExecutions == null) { return Collections.emptyList(); } if (partitionExecutions.isEmpty() || !notCompletedOnly) { return partitionExecutions; } final List<PartitionExecutionImpl> result = new ArrayList<PartitionExecutionImpl>(); for (final PartitionExecutionImpl sei : partitionExecutions) { if (sei.getBatchStatus() != BatchStatus.COMPLETED) { result.add(sei); } } return result; } return null; } private static <T extends Serializable> T clone(final T object) { if (WildFlySecurityManager.isChecking()) { return AccessController.doPrivileged(new PrivilegedAction<T>() { @Override public T run() { return BatchUtil.clone(object); } }); } return BatchUtil.clone(object); } }