All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.ibm.jbatch.container.impl.SplitControllerImpl Maven / Gradle / Ivy

There is a newer version: 1.0
Show newest version
/*
 * Copyright 2012 International Business Machines Corp.
 * 
 * See the NOTICE file distributed with this work for additional information
 * regarding copyright ownership. Licensed 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 com.ibm.jbatch.container.impl;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.batch.operations.JobExecutionAlreadyCompleteException;
import javax.batch.operations.JobExecutionNotMostRecentException;
import javax.batch.operations.JobRestartException;
import javax.batch.operations.JobStartException;
import javax.batch.runtime.BatchStatus;

import com.ibm.jbatch.container.AbortedBeforeStartException;
import com.ibm.jbatch.container.IExecutionElementController;
import com.ibm.jbatch.container.context.impl.StepContextImpl;
import com.ibm.jbatch.container.exception.BatchContainerRuntimeException;
import com.ibm.jbatch.container.jobinstance.RuntimeJobContextJobExecutionBridge;
import com.ibm.jbatch.container.services.IBatchKernelService;
import com.ibm.jbatch.container.servicesmanager.ServicesManager;
import com.ibm.jbatch.container.servicesmanager.ServicesManagerImpl;
import com.ibm.jbatch.container.status.InternalExecutionElementStatus;
import com.ibm.jbatch.container.util.BatchWorkUnit;
import com.ibm.jbatch.container.util.PartitionDataWrapper;
import com.ibm.jbatch.jsl.model.Flow;
import com.ibm.jbatch.jsl.model.JSLJob;
import com.ibm.jbatch.jsl.model.Split;

public class SplitControllerImpl implements IExecutionElementController {

	private final static String sourceClass = SplitControllerImpl.class.getName();
	private final static Logger logger = Logger.getLogger(sourceClass);

	private final RuntimeJobContextJobExecutionBridge jobExecutionImpl;

	private volatile List parallelBatchWorkUnits;

	private final ServicesManager servicesManager;
	private final IBatchKernelService batchKernel;

	final List subJobs = new ArrayList();

	protected Split split;

	public SplitControllerImpl(RuntimeJobContextJobExecutionBridge jobExecutionImpl, Split split) {
		this.jobExecutionImpl = jobExecutionImpl;
		this.split = split;

		servicesManager = ServicesManagerImpl.getInstance();
		batchKernel = servicesManager.getBatchKernelService();

	}

	@Override
	public void stop() { 

		// It's possible we may try to stop a split before any
		// sub steps have been started.

		synchronized (subJobs) {

			if (parallelBatchWorkUnits != null) {
				for (BatchWorkUnit subJob : parallelBatchWorkUnits) {
					try {
						batchKernel.stopJob(subJob.getJobExecutionImpl().getExecutionId());
					} catch (Exception e) {
						// TODO - Is this what we want to know.  
						// Blow up if it happens to force the issue.
						throw new IllegalStateException(e);
					}
				}
			}
		}

	}

	@Override
	public InternalExecutionElementStatus execute(RuntimeJobContextJobExecutionBridge rootJobExecution) throws AbortedBeforeStartException, JobRestartException, JobStartException, JobExecutionAlreadyCompleteException, JobExecutionNotMostRecentException {
		String sourceMethod = "execute";
		if (logger.isLoggable(Level.FINER)) {
			logger.entering(sourceClass, sourceMethod);
		}

		BlockingQueue completedWorkQueue = new LinkedBlockingQueue();
		List flows = this.split.getFlows();

		parallelBatchWorkUnits = new ArrayList();

		// Build all sub jobs from flows in split
		synchronized (subJobs) {

			for (Flow flow : flows) {
				subJobs.add(PartitionedStepBuilder.buildSubJob(jobExecutionImpl.getExecutionId(), jobExecutionImpl.getJobContext(), this.split, flow, null));
			}

			for (JSLJob job : subJobs) {
				int count = batchKernel.getJobInstanceCount(job.getId());
				if (count == 0) {
					parallelBatchWorkUnits.add(batchKernel.buildNewBatchWorkUnit(job, null, null, completedWorkQueue, rootJobExecution));
				} else if (count == 1) {
					parallelBatchWorkUnits.add(batchKernel.buildRestartableBatchWorkUnit(job, null, null, completedWorkQueue, rootJobExecution));
				} else {
					throw new IllegalStateException("There is an inconsistency somewhere in the internal subjob creation");
				}
			}

		}

		// Then start or restart all subjobs in parallel
		for (BatchWorkUnit work : parallelBatchWorkUnits) {
			int count = batchKernel.getJobInstanceCount(work.getJobExecutionImpl().getJobInstance().getJobName());

			assert (count <= 1);

			if (count == 1) {
				batchKernel.startGeneratedJob(work);
			} else if (count > 1) {
				batchKernel.restartGeneratedJob(work);
			} else {
				throw new IllegalStateException("There is an inconsistency somewhere in the internal subjob creation");
			}
		}

		//check the batch status of each subJob after it's done to see if it stopped or failed
		boolean someFlowFailed = false;
		boolean someFlowStopped = false;

		for (int i=0; i < subJobs.size(); i++) {
			BatchWorkUnit batchWork;
			try {
				batchWork = completedWorkQueue.take(); //wait for each thread to finish and then look at it's status
			} catch (InterruptedException e) {
				throw new BatchContainerRuntimeException(e);
			}
			BatchStatus batchStatus = batchWork.getJobExecutionImpl().getJobContext().getBatchStatus();
			if (batchStatus.equals(BatchStatus.FAILED)) {
				if (logger.isLoggable(Level.FINE)) {
					logger.fine("Subjob " + batchWork.getJobExecutionImpl().getExecutionId() + "ended with status '" + batchStatus + "'" );
				}
				someFlowFailed = true;
			} else if (batchStatus.equals(BatchStatus.STOPPED)){
				if (logger.isLoggable(Level.FINE)) {
					logger.fine("Subjob " + batchWork.getJobExecutionImpl().getExecutionId() + "ended with status '" + batchStatus + "'" );
				}
				someFlowStopped = true;
			}
		}

		// Remember it's only an implementation detail that there even is an exit status, but maybe it will make our
		// code be more consistent?

		InternalExecutionElementStatus splitStatus = null;

		// First in order of precedence is to fail
		if (someFlowFailed) {
			splitStatus = new InternalExecutionElementStatus(BatchStatus.FAILED);
		} else if (someFlowStopped) {
			splitStatus = new InternalExecutionElementStatus(BatchStatus.STOPPED);
		} else {
			splitStatus = new InternalExecutionElementStatus(BatchStatus.COMPLETED);
		}

		if (logger.isLoggable(Level.FINER)) {
			logger.finer("Exiting with: " + splitStatus);
		}

		return splitStatus;
	}

	public void setStepContext(StepContextImpl stepContext) {
		throw new BatchContainerRuntimeException("Incorrect usage: step context is not in scope within a flow.");
	}

	@Override
	public void setAnalyzerQueue(BlockingQueue analyzerQueue) {
		// no-op
	}

	public List getParallelJobExecs() {
		return parallelBatchWorkUnits;
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy