Coverage Report - org.mule.impl.work.WorkerContext
 
Classes in this File Line Coverage Branch Coverage Complexity
WorkerContext
59%
36/61
25%
6/24
1.8
WorkerContext$1
17%
1/6
0%
0/6
1.8
 
 1  
 /*
 2  
  * $Id: WorkerContext.java 7963 2007-08-21 08:53:15Z dirk.olmes $
 3  
  * --------------------------------------------------------------------------------------
 4  
  * Copyright (c) MuleSource, Inc.  All rights reserved.  http://www.mulesource.com
 5  
  *
 6  
  * The software in this package is published under the terms of the CPAL v1.0
 7  
  * license, a copy of which has been included with this distribution in the
 8  
  * LICENSE.txt file.
 9  
  */
 10  
 
 11  
 /**
 12  
  *
 13  
  * Copyright 2004 The Apache Software Foundation
 14  
  *
 15  
  *  Licensed under the Apache License, Version 2.0 (the "License");
 16  
  *  you may not use this file except in compliance with the License.
 17  
  *  You may obtain a copy of the License at
 18  
  *
 19  
  *     http://www.apache.org/licenses/LICENSE-2.0
 20  
  *
 21  
  *  Unless required by applicable law or agreed to in writing, software
 22  
  *  distributed under the License is distributed on an "AS IS" BASIS,
 23  
  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 24  
  *  See the License for the specific language governing permissions and
 25  
  *  limitations under the License.
 26  
  */
 27  
 
 28  
 package org.mule.impl.work;
 29  
 
 30  
 import org.mule.util.concurrent.Latch;
 31  
 
 32  
 import javax.resource.spi.work.ExecutionContext;
 33  
 import javax.resource.spi.work.Work;
 34  
 import javax.resource.spi.work.WorkAdapter;
 35  
 import javax.resource.spi.work.WorkCompletedException;
 36  
 import javax.resource.spi.work.WorkEvent;
 37  
 import javax.resource.spi.work.WorkException;
 38  
 import javax.resource.spi.work.WorkListener;
 39  
 import javax.resource.spi.work.WorkRejectedException;
 40  
 
 41  
 import org.apache.commons.logging.Log;
 42  
 import org.apache.commons.logging.LogFactory;
 43  
 
 44  
 /**
 45  
  * <code>WorkerContext</code> TODO
 46  
  */
 47  
 public class WorkerContext implements Work
 48  
 {
 49  
 
 50  
     /**
 51  
      * logger used by this class
 52  
      */
 53  4
     protected static final Log logger = LogFactory.getLog(WorkerContext.class);
 54  
 
 55  
     /**
 56  
      * Null WorkListener used as the default WorkListener.
 57  
      */
 58  2
     private static final WorkListener NULL_WORK_LISTENER = new WorkAdapter()
 59  
     {
 60  2
         public void workRejected(WorkEvent event)
 61  
         {
 62  0
             if (event.getException() != null)
 63  
             {
 64  0
                 if (event.getException() instanceof WorkCompletedException
 65  
                     && event.getException().getCause() != null)
 66  
                 {
 67  0
                     logger.error(event.getWork().toString(), event.getException().getCause());
 68  
                 }
 69  
                 else
 70  
                 {
 71  0
                     logger.error(event.getWork().toString(), event.getException());
 72  
                 }
 73  
             }
 74  0
         }
 75  
     };
 76  
 
 77  
     /**
 78  
      * Priority of the thread, which will execute this work.
 79  
      */
 80  
     private int threadPriority;
 81  
 
 82  
     /**
 83  
      * Actual work to be executed.
 84  
      */
 85  
     private Work worker;
 86  
 
 87  
     /**
 88  
      * System.currentTimeMillis() when the wrapped Work has been accepted.
 89  
      */
 90  
     private long acceptedTime;
 91  
 
 92  
     /**
 93  
      * Number of times that the execution of this work has been tried.
 94  
      */
 95  
     private int retryCount;
 96  
 
 97  
     /**
 98  
      * Time duration (in milliseconds) within which the execution of the Work
 99  
      * instance must start.
 100  
      */
 101  
     private long startTimeOut;
 102  
 
 103  
     /**
 104  
      * Execution context of the actual work to be executed.
 105  
      */
 106  
     private final ExecutionContext executionContext;
 107  
 
 108  
     /**
 109  
      * Listener to be notified during the life-cycle of the work treatment.
 110  
      */
 111  72
     private WorkListener workListener = NULL_WORK_LISTENER;
 112  
 
 113  
     /**
 114  
      * Work exception, if any.
 115  
      */
 116  
     private WorkException workException;
 117  
 
 118  
     /**
 119  
      * A latch, which is released when the work is started.
 120  
      */
 121  72
     private final Latch startLatch = new Latch();
 122  
 
 123  
     /**
 124  
      * A latch, which is released when the work is completed.
 125  
      */
 126  72
     private final Latch endLatch = new Latch();
 127  
 
 128  
     /**
 129  
      * Create a WorkWrapper.
 130  
      * 
 131  
      * @param work Work to be wrapped.
 132  
      */
 133  
     public WorkerContext(Work work)
 134  6
     {
 135  6
         worker = work;
 136  6
         executionContext = null;
 137  6
     }
 138  
 
 139  
     /**
 140  
      * Create a WorkWrapper with the specified execution context.
 141  
      * 
 142  
      * @param aWork Work to be wrapped.
 143  
      * @param aStartTimeout a time duration (in milliseconds) within which the
 144  
      *            execution of the Work instance must start.
 145  
      * @param execContext an object containing the execution context with which the
 146  
      *            submitted Work instance must be executed.
 147  
      * @param workListener an object which would be notified when the various Work
 148  
      *            processing events (work accepted, work rejected, work started,
 149  
      */
 150  
     public WorkerContext(Work aWork,
 151  
                          long aStartTimeout,
 152  
                          ExecutionContext execContext,
 153  
                          WorkListener workListener)
 154  66
     {
 155  66
         worker = aWork;
 156  66
         startTimeOut = aStartTimeout;
 157  66
         executionContext = execContext;
 158  66
         if (null != workListener)
 159  
         {
 160  66
             this.workListener = workListener;
 161  
         }
 162  66
     }
 163  
 
 164  
     /*
 165  
      * (non-Javadoc)
 166  
      * 
 167  
      * @see javax.resource.spi.work.Work#release()
 168  
      */
 169  
     public void release()
 170  
     {
 171  0
         worker.release();
 172  0
     }
 173  
 
 174  
     /**
 175  
      * Defines the thread priority level of the thread, which will be dispatched to
 176  
      * process this work. This priority level must be the same one for a given
 177  
      * resource adapter.
 178  
      * 
 179  
      * @param aPriority Priority of the thread to be used to process the wrapped Work
 180  
      *            instance.
 181  
      */
 182  
     public void setThreadPriority(int aPriority)
 183  
     {
 184  70
         threadPriority = aPriority;
 185  70
     }
 186  
 
 187  
     /**
 188  
      * Gets the priority level of the thread, which will be dispatched to process
 189  
      * this work. This priority level must be the same one for a given resource
 190  
      * adapter.
 191  
      * 
 192  
      * @return The priority level of the thread to be dispatched to process the
 193  
      *         wrapped Work instance.
 194  
      */
 195  
     public int getThreadPriority()
 196  
     {
 197  0
         return threadPriority;
 198  
     }
 199  
 
 200  
     /**
 201  
      * Call-back method used by a Work executor in order to notify this instance that
 202  
      * the wrapped Work instance has been accepted.
 203  
      * 
 204  
      * @param anObject Object on which the event initially occurred. It should be the
 205  
      *            work executor.
 206  
      */
 207  
     public synchronized void workAccepted(Object anObject)
 208  
     {
 209  72
         acceptedTime = System.currentTimeMillis();
 210  72
         workListener.workAccepted(new WorkEvent(anObject, WorkEvent.WORK_ACCEPTED, worker, null));
 211  72
     }
 212  
 
 213  
     /**
 214  
      * System.currentTimeMillis() when the Work has been accepted. This method can be
 215  
      * used to compute the duration of a work.
 216  
      * 
 217  
      * @return When the work has been accepted.
 218  
      */
 219  
     public synchronized long getAcceptedTime()
 220  
     {
 221  2
         return acceptedTime;
 222  
     }
 223  
 
 224  
     /**
 225  
      * Gets the time duration (in milliseconds) within which the execution of the
 226  
      * Work instance must start.
 227  
      * 
 228  
      * @return Time out duration.
 229  
      */
 230  
     public long getStartTimeout()
 231  
     {
 232  0
         return startTimeOut;
 233  
     }
 234  
 
 235  
     /**
 236  
      * Used by a Work executor in order to know if this work, which should be
 237  
      * accepted but not started has timed out. This method MUST be called prior to
 238  
      * retry the execution of a Work.
 239  
      * 
 240  
      * @return true if the Work has timed out and false otherwise.
 241  
      */
 242  
     public synchronized boolean isTimedOut()
 243  
     {
 244  
 
 245  
         // A value of 0 means that the work never times out.
 246  
         // ??? really?
 247  72
         if (0 == startTimeOut || startTimeOut == MuleWorkManager.INDEFINITE)
 248  
         {
 249  72
             return false;
 250  
         }
 251  0
         boolean isTimeout = acceptedTime + startTimeOut > 0
 252  
                             && System.currentTimeMillis() > acceptedTime + startTimeOut;
 253  0
         if (logger.isDebugEnabled())
 254  
         {
 255  0
             logger.debug(this + " accepted at " + acceptedTime
 256  
                          + (isTimeout ? " has timed out." : " has not timed out. ") + retryCount
 257  
                          + " retries have been performed.");
 258  
         }
 259  0
         if (isTimeout)
 260  
         {
 261  0
             workException = new WorkRejectedException(this + " has timed out.", WorkException.START_TIMED_OUT);
 262  0
             workListener.workRejected(new WorkEvent(this, WorkEvent.WORK_REJECTED, worker, workException));
 263  0
             return true;
 264  
         }
 265  0
         retryCount++;
 266  0
         return isTimeout;
 267  
     }
 268  
 
 269  
     /**
 270  
      * Gets the WorkException, if any, thrown during the execution.
 271  
      * 
 272  
      * @return WorkException, if any.
 273  
      */
 274  
     public synchronized WorkException getWorkException()
 275  
     {
 276  72
         return workException;
 277  
     }
 278  
 
 279  
     /*
 280  
      * (non-Javadoc)
 281  
      * 
 282  
      * @see java.lang.Runnable#run()
 283  
      */
 284  
     public void run()
 285  
     {
 286  72
         if (isTimedOut())
 287  
         {
 288  
             // In case of a time out, one releases the start and end latches
 289  
             // to prevent a dead-lock.
 290  0
             startLatch.countDown();
 291  0
             endLatch.countDown();
 292  0
             return;
 293  
         }
 294  
         // Implementation note: the work listener is notified prior to release
 295  
         // the start lock. This behavior is intentional and seems to be the
 296  
         // more conservative.
 297  72
         workListener.workStarted(new WorkEvent(this, WorkEvent.WORK_STARTED, worker, null));
 298  72
         startLatch.countDown();
 299  
         // Implementation note: we assume this is being called without an
 300  
         // interesting TransactionContext,
 301  
         // and ignore/replace whatever is associated with the current thread.
 302  
         try
 303  
         {
 304  72
             if (executionContext == null || executionContext.getXid() == null)
 305  
             {
 306  
                 // TODO currently unused, see below
 307  
                 // ExecutionContext context = new ExecutionContext();
 308  
                 try
 309  
                 {
 310  72
                     worker.run();
 311  
                 }
 312  
                 finally
 313  0
                 {
 314  
                     // ExecutionContext returningContext = new
 315  
                     // ExecutionContext();
 316  
                     // if (context != returningContext) {
 317  
                     // throw new WorkCompletedException("Wrong
 318  
                     // TransactionContext on return from work done");
 319  
                     // }
 320  72
                 }
 321  
                 // TODO should we commit the txContext to flush any leftover
 322  
                 // state???
 323  
             }
 324  
             else
 325  
             {
 326  
                 // try {
 327  
                 // long transactionTimeout =
 328  
                 // executionContext.getTransactionTimeout();
 329  
                 // //translate -1 value to 0 to indicate default transaction
 330  
                 // timeout.
 331  
                 // transactionContextManager.begin(executionContext.getXid(),
 332  
                 // transactionTimeout == -1 ? 0 : transactionTimeout);
 333  
                 // } catch (XAException e) {
 334  
                 // throw new WorkCompletedException("Transaction import failed
 335  
                 // for xid " + executionContext.getXid(),
 336  
                 // WorkCompletedException.TX_RECREATE_FAILED).initCause(e);
 337  
                 // } catch (InvalidTransactionException e) {
 338  
                 // throw new WorkCompletedException("Transaction import failed
 339  
                 // for xid " + executionContext.getXid(),
 340  
                 // WorkCompletedException.TX_RECREATE_FAILED).initCause(e);
 341  
                 // } catch (SystemException e) {
 342  
                 // throw new WorkCompletedException("Transaction import failed
 343  
                 // for xid " + executionContext.getXid(),
 344  
                 // WorkCompletedException.TX_RECREATE_FAILED).initCause(e);
 345  
                 // } catch (ImportedTransactionActiveException e) {
 346  
                 // throw new WorkCompletedException("Transaction already active
 347  
                 // for xid " + executionContext.getXid(),
 348  
                 // WorkCompletedException.TX_CONCURRENT_WORK_DISALLOWED);
 349  
                 // }
 350  
                 try
 351  
                 {
 352  0
                     worker.run();
 353  
                 }
 354  
                 finally
 355  0
                 {
 356  
                     // transactionContextManager.end(executionContext.getXid());
 357  0
                 }
 358  
 
 359  
             }
 360  72
             workListener.workCompleted(new WorkEvent(this, WorkEvent.WORK_COMPLETED, worker, null));
 361  
         }
 362  0
         catch (Throwable e)
 363  
         {
 364  0
             workException = (WorkException)(e instanceof WorkCompletedException
 365  
                             ? e : new WorkCompletedException("Unknown error",
 366  
                                 WorkCompletedException.UNDEFINED).initCause(e));
 367  0
             workListener.workCompleted(new WorkEvent(this, WorkEvent.WORK_REJECTED, worker, workException));
 368  
         }
 369  
         finally
 370  
         {
 371  72
             endLatch.countDown();
 372  72
         }
 373  72
     }
 374  
 
 375  
     /**
 376  
      * Provides a latch, which can be used to wait the start of a work execution.
 377  
      * 
 378  
      * @return Latch that a caller can acquire to wait for the start of a work
 379  
      *         execution.
 380  
      */
 381  
     public Latch provideStartLatch()
 382  
     {
 383  2
         return startLatch;
 384  
     }
 385  
 
 386  
     /**
 387  
      * Provides a latch, which can be used to wait the end of a work execution.
 388  
      * 
 389  
      * @return Latch that a caller can acquire to wait for the end of a work
 390  
      *         execution.
 391  
      */
 392  
     public Latch provideEndLatch()
 393  
     {
 394  0
         return endLatch;
 395  
     }
 396  
 
 397  
     public String toString()
 398  
     {
 399  0
         return "Work: " + worker;
 400  
     }
 401  
 }