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

com.ibm.jbatch.container.callback.JobEndCallbackManagerImpl 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.callback;

import java.util.HashSet;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.batch.operations.JobSecurityException;
import javax.batch.operations.NoSuchJobExecutionException;

import com.ibm.jbatch.container.exception.BatchContainerServiceException;
import com.ibm.jbatch.spi.services.IBatchConfig;

/**
 * 
 * This isn't deprecated in the sense that it used to work... we did this function for the 
 * TCK originally and I copied it over to the RI in case we still wanted to make use of it.
 * 
 * Don't use without reworking and testing this class.
 * 
 * @deprecated
 * 
 * @author skurz
 *
 */
public class JobEndCallbackManagerImpl implements IJobEndCallbackService {

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

	private Set callbacks = new HashSet();
	private long sleepTime = 500L;

	@Override
	public synchronized void registerJobEndCallback(JobEndCallback callback) {
		callbacks.add(callback);
	}

	@Override
	public synchronized void deregisterJobEndCallback(JobEndCallback callback) {
		callbacks.remove(callback);
	}

	@Override
	public synchronized void done(long jobExecutionId) {
		if (logger.isLoggable(Level.FINER)) {            
			logger.finer("Firing callbacks for job execution id: " + jobExecutionId);
		}
		completedExecutions.add(jobExecutionId);
		JobEndCallback[] arr = callbacks.toArray(new JobEndCallback[0]);
		for (JobEndCallback callback : arr) {
			if (logger.isLoggable(Level.FINE)) {            
				logger.fine("Next registered callback: " + callback);
			}
			callback.done(jobExecutionId);
		}
		if (logger.isLoggable(Level.FINER)) {            
			logger.finer("Done firing callbacks for job execution id: " + jobExecutionId);
		}
	}

	/* (non-Javadoc)
	 * @see com.ibm.jbatch.container.services.IBatchServiceBase#init(com.ibm.jbatch.container.IBatchConfig)
	 */
	@Override
	public void init(IBatchConfig batchConfig)
			throws BatchContainerServiceException {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see com.ibm.jbatch.container.services.IBatchServiceBase#shutdown()
	 */
	@Override
	public void shutdown() throws BatchContainerServiceException {
		// TODO Auto-generated method stub

	}

	private Set completedExecutions = new HashSet();

	public long getCallbackOnTermination(long execID, JobEndCallback callback) throws NoSuchJobExecutionException, JobSecurityException {
		// First get the lock on the callback
		synchronized (callback) {          
			// If this execution is already complete, then there's no need to wait
			if (!completedExecutions.contains(execID)) {
				// While we have the lock we'll associate this callback with the execution id
				// so we can only get notified when this particular execution id completes.
				callback.setExecutionId(execID);
				try {
					callback.wait(sleepTime);
				} catch (InterruptedException e) {
					// Assume we should not continue and allow this to happen without complaint.
					// Throw a new exception.
					throw new IllegalStateException(e);
				}
				// Now either we have the result, or we've waiting long enough and are going to bail.
				if (!completedExecutions.contains(execID)) {
					throw new IllegalStateException("Still didn't see a result for executionId: " + execID + 
							".  Perhaps try increasing timeout.  Or, something else may have gone wrong.");
				}
			}            
		}

		// Not absolutely required since we should have things coded such that a registered
		// callback for some other execution doesn't interfere with correct notification of
		// completion of this execution.   However, it might reduce noise and facilitate
		// debug to clean things up.
		deregisterJobEndCallback(callback);

		return execID;
	}

	private class JobEndCallbackImpl implements JobEndCallback {
		
		// The wrapper around long is chosen so that 'null' clearly signifies 'unset',
		// since '0' does not.
		private Long executionIdObj = null;
		
		@Override
		public void done(long jobExecutionId) {
			synchronized(this) {

				// If we have set an execution id into the callback,
				// then only wake up the sleep if we have matched the
				// execution id.
				if (executionIdObj != null) {
					if (executionIdObj.longValue() == jobExecutionId) {
						this.notify();
					}
				} 

				// otherwise there is nothing to do.   We will only be sleeping
				// with an already-set execution id.
			}
		}

		public long getExecutionId() {
			return executionIdObj;
		}

		@Override
		public void setExecutionId(long jobExecutionId) {
			executionIdObj = jobExecutionId;
		}

	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy