FileDocCategorySizeDatePackage
WorkCoordinator.javaAPI DocGlassfish v2 API13918Fri May 04 22:34:26 BST 2007com.sun.enterprise.connectors.work

WorkCoordinator

public final class WorkCoordinator extends Object
WorkCoordinator : Coordinates one work's execution. Handles all exception conditions and does JTS coordination.
author
Binod P.G

Fields Summary
static final int
WAIT_UNTIL_START
static final int
WAIT_UNTIL_FINISH
static final int
NO_WAIT
static final int
CREATED
static final int
STARTED
static final int
COMPLETED
static final int
TIMEDOUT
private volatile int
waitMode
private volatile int
state
private final boolean
workIsBad
private final javax.resource.spi.work.Work
work
private final long
timeout
private long
startTime
private final ExecutionContext
ec
private final WorkQueue
queue
private final WorkListener
listener
private volatile WorkException
exception
private final Object
lock
private static int
seed
private final int
id
private static final Logger
logger
private WorkStats
workStats
workStats is responsible for holding all monitorable properties of a work-manager. Workstats would be null, if monitoring is *not* enabled.
Constructors Summary
public WorkCoordinator(javax.resource.spi.work.Work work, long timeout, ExecutionContext ec, WorkQueue queue, WorkListener listener, WorkStats workStats)
Constructs a coordinator

param
work A work object as submitted by the resource adapter
param
timeout timeout for the work instance
param
ec ExecutionContext object.
param
queue WorkQueue of the threadpool, to which the work will be submitted
param
listener WorkListener object from the resource adapter.


                                                                     
      
                            
                            
                            
                               
                          
        this.work = work;
        this.timeout = timeout;
        this.ec = ec;
        this.queue = queue;
        this.listener = listener;
        synchronized( WorkCoordinator.class ) {
            this.id = ++seed;
        }
        this.lock = new Object();
        this.workStats = workStats;
    
Methods Summary
private booleancheckStateBeforeLocking()
It is possible that state is modified just before the lock is obtained. So check it again. Access the variable directly to avoid nested locking.

        if (waitMode == WAIT_UNTIL_FINISH) {
            return state < COMPLETED;
        }
	if (waitMode == WAIT_UNTIL_START) {
            return state < STARTED;
        }
        return false;
    
public WorkExceptiongetException()
Retrieves the exception created during the work's execution.

return
a WorkException object.

        return exception;
    
public synchronized intgetState()
Retrieves the state of the work coordinator object.

return
Integer represnting the state.

        return state;
    
private booleanisTimedOut()

        return getState() == TIMEDOUT;
    
public voidlock()
Lock the thread upto the end of execution or start of work execution.

param
waitMode either WAIT_UNTIL_START or WAIT_UNTIL_FINISH


        if (!lockRequired()) {
            return;
        }

        try {
            synchronized (lock) {
    	        if (checkStateBeforeLocking()) {
                        if (timeout != -1) {
                            lock.wait(timeout);
                        } else {
                            lock.wait();
                        }
    	        }
            }

            if (getState() < STARTED) {
                workTimedOut(); 
            } 
            if (lockRequired()) {
                synchronized (lock) {
    	           if (checkStateBeforeLocking()) {
                           lock.wait();
    	            }
                }
            }
            
        } catch(Exception e) {
            setException(e);
        }
    
private booleanlockRequired()

        if (!proceed()) {
            return false;
        }
        if (waitMode == NO_WAIT) {
            return false;
        }
        if (waitMode == WAIT_UNTIL_FINISH) {
            return getState() < COMPLETED;
        }
	if (waitMode == WAIT_UNTIL_START) {
            return getState() < STARTED;
        }
        return false;
    
public voidpostInvoke()
Post-invoke operation. This does the following after the work is executed.
1. Releases the transaction with JTS.
2. Generates work completed event.
3. Clear the thread context.

        boolean txImported = (ec != null && ec.getXid() != null);
        try {
            J2EETransactionManager tm = Switch.getSwitch().getTransactionManager();
            if (txImported) {
                tm.release(ec.getXid());
            }
        } catch (WorkException ex) {
            setException(ex);
        } finally {
            try {
                if(workStats != null) {
                    workStats.setActiveWorkCount
                                (--workStats.currentActiveWorkCount);
                    workStats.completedWorkCount++;
                }
                
                //If exception is not null, the work has already been rejected.
                if (listener != null) {
                    if ((!isTimedOut()) && (exception == null)) {
                        listener.workCompleted(
                            new WorkEvent(this, WorkEvent.WORK_COMPLETED, work, 
                                            getException()));
                    }
                }

                //Also release the TX from the record of TX Optimizer
                if (txImported) {
                    J2EETransactionManager tm =
                    Switch.getSwitch().getTransactionManager();
                    if (tm instanceof J2EETransactionManagerOpt) {
                        ((J2EETransactionManagerOpt) tm).clearThreadTx();
                    }
                }
            } catch(Exception e) {
	        logger.log(Level.WARNING, e.getMessage());
            }
        }

        setState(COMPLETED);
        if (waitMode == WAIT_UNTIL_FINISH) {
            unLock();
        }
    
public voidpreInvoke()
Pre-invoke operation. This does the following
1. Notifies the  WorkManager.startWork  method.
2. Checks whether the wok has already been timed out.
3. Recreates the transaction with JTS.

       
        // If the work is just scheduled, check whether it has timed out or not. 
        if (waitMode == NO_WAIT && timeout > -1) {
           long elapsedTime = System.currentTimeMillis() - startTime ;
           
           if(workStats != null) {
               workStats.setWorkWaitTime(elapsedTime);
           }
           
           if (elapsedTime > timeout) {
               workTimedOut();
           }
        }

        // Change the status to started.
        setState(STARTED);

        if (waitMode == WAIT_UNTIL_START) {
            unLock();
        }

        // If the work is timed out then return.
        if (!proceed()) {
            if (workStats != null) {
                workStats.decrementWaitQueueLength();
            }
            return;
        }

        // All set to do start the work. So send the event.
        if (listener != null) {
            listener.workStarted(
                new WorkEvent(this, WorkEvent.WORK_STARTED, work, null));
        }


        try {
            J2EETransactionManager tm = Switch.getSwitch().getTransactionManager();
            if (ec != null && ec.getXid() != null) {
                tm.recreate(ec.getXid(), ec.getTransactionTimeout());
            }
        } catch(WorkException we) {
            this.exception = we;
        } catch(Exception e) {
            setException(e);
        }

        if(workStats != null) {
            workStats.setActiveWorkCount(++workStats.currentActiveWorkCount);
            workStats.decrementWaitQueueLength();
        }
        
    
public booleanproceed()
Checks the work is good to proceed with further processing.

return
true if the work is good and false if it is bad.

        return  !isTimedOut() && exception == null;
    
public voidsetException(java.lang.Throwable e)
Accepts an exception object and converts to a WorkException object.

param
e Throwable object.

        if (getState() < STARTED ) {
            if (e instanceof WorkRejectedException) {
                exception = (WorkException) e;
            } else if (e instanceof WorkException) {
                WorkException we = (WorkException) e;
                exception = new WorkRejectedException(we);
                exception.setErrorCode(we.getErrorCode());
            } else {
                exception = new WorkRejectedException(e);
                exception.setErrorCode(WorkException.UNDEFINED);
            }  
        } else {
            if (e instanceof WorkCompletedException) {
                exception = (WorkException) e;
            } else if (e instanceof WorkException) {
                WorkException we = (WorkException) e;
                exception = new WorkCompletedException(we);
                exception.setErrorCode(we.getErrorCode());
            } else {
                exception = new WorkCompletedException(e);
                exception.setErrorCode(WorkException.UNDEFINED);
            }  
        }
    
public synchronized voidsetState(int state)
Sets the state of the work coordinator object

param
state CREATED or Either STARTED or COMPLETED or TIMEDOUT

        this.state = state;
    
public voidsubmitWork(int waitMode)
Submits the work to the queue and generates a work accepted event.

        this.waitMode = waitMode;
        this.startTime = System.currentTimeMillis();
        if (listener != null) {
            listener.workAccepted(
                new WorkEvent(this, WorkEvent.WORK_ACCEPTED, work, null));
        }
        if(workStats != null) {
            workStats.submittedWorkCount++;
            workStats.incrementWaitQueueLength();
        }
        queue.addWork( new OneWork(work, this));
    
public java.lang.StringtoString()
Returns the string representation of WorkCoordinator.

return
Unique identification concatenated by work object.

        return id + ":" + work;
    
private voidunLock()
Unlocks the thread.

        try {
            synchronized (lock) {
                lock.notify();
            }
        } catch(Exception e) {
            setException(e);
        }
    
private voidworkTimedOut()
Times out the thread

        setState(TIMEDOUT);
        exception = new WorkRejectedException();
        exception.setErrorCode(WorkException.START_TIMED_OUT);
        if (listener != null) {
            listener.workRejected(
                new WorkEvent(this, WorkEvent.WORK_REJECTED, work, exception));
        }
        if(workStats != null) {
            workStats.rejectedWorkCount++;
            workStats.setActiveWorkCount(--workStats.currentActiveWorkCount);
        }