Coverage Report - org.mule.tck.functional.FunctionalTestComponent
 
Classes in this File Line Coverage Branch Coverage Complexity
FunctionalTestComponent
35%
33/94
5%
2/42
1.897
 
 1  
 /*
 2  
  * $Id: FunctionalTestComponent.java 12181 2008-06-26 20:05:55Z 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  
 package org.mule.tck.functional;
 12  
 
 13  
 import org.mule.MuleServer;
 14  
 import org.mule.RequestContext;
 15  
 import org.mule.api.MuleContext;
 16  
 import org.mule.api.MuleEventContext;
 17  
 import org.mule.api.MuleException;
 18  
 import org.mule.api.MuleMessage;
 19  
 import org.mule.api.lifecycle.Callable;
 20  
 import org.mule.api.lifecycle.Disposable;
 21  
 import org.mule.api.lifecycle.Initialisable;
 22  
 import org.mule.tck.exceptions.FunctionalTestException;
 23  
 import org.mule.util.NumberUtils;
 24  
 import org.mule.util.StringMessageUtils;
 25  
 import org.mule.util.expression.ExpressionEvaluatorManager;
 26  
 
 27  
 import java.util.List;
 28  
 
 29  
 import edu.emory.mathcs.backport.java.util.concurrent.CopyOnWriteArrayList;
 30  
 
 31  
 import org.apache.commons.logging.Log;
 32  
 import org.apache.commons.logging.LogFactory;
 33  
 
 34  
 /**
 35  
  * <code>FunctionalTestComponent</code> is a service that can be used by
 36  
  * functional tests. This service accepts an EventCallback that can be used to
 37  
  * assert the state of the current event.
 38  
  * <p/>
 39  
  * Also, this service fires {@link org.mule.tck.functional.FunctionalTestNotification} via Mule for every message received.
 40  
  * Tests can register with Mule to receive these events by implementing
 41  
  * {@link org.mule.tck.functional.FunctionalTestNotificationListener}.
 42  
  *
 43  
  * @see EventCallback
 44  
  * @see FunctionalTestNotification
 45  
  * @see FunctionalTestNotificationListener
 46  
  */
 47  
 
 48  42
 public class FunctionalTestComponent implements Callable, Initialisable, Disposable
 49  
 {
 50  42
     protected transient Log logger = LogFactory.getLog(getClass());
 51  
 
 52  
     public static final int STREAM_SAMPLE_SIZE = 4;
 53  
     public static final int STREAM_BUFFER_SIZE = 4096;
 54  
     private EventCallback eventCallback;
 55  42
     private Object returnData = null;
 56  42
     private boolean throwException = false;
 57  42
     private boolean enableMessageHistory = true;
 58  42
     private boolean enableNotifications = true;
 59  42
     private boolean doInboundTransform = true;
 60  
     private String appendString;
 61  
     private Class exceptionToThrow;
 62  42
     private long waitTime = 0;
 63  
 
 64  
     /**
 65  
      * Keeps a list of any messages received on this service. Note that only references
 66  
      * to the messages (objects) are stored, so any subsequent changes to the objects
 67  
      * will change the history.
 68  
      */
 69  
     private List messageHistory;
 70  
 
 71  
     public void initialise()
 72  
     {
 73  42
         if (enableMessageHistory)
 74  
         {
 75  30
             messageHistory = new CopyOnWriteArrayList();
 76  
         }
 77  42
     }
 78  
 
 79  
     public void dispose()
 80  
     {
 81  
         // nothing to do
 82  60
     }
 83  
 
 84  
     /**
 85  
      * {@inheritDoc}
 86  
      */
 87  
     public Object onCall(MuleEventContext context) throws Exception
 88  
     {
 89  0
         if (isThrowException())
 90  
         {
 91  0
             throwException();
 92  
         }
 93  0
         return process(getMessageFromContext(context), context);
 94  
     }
 95  
 
 96  
     private Object getMessageFromContext(MuleEventContext context) throws MuleException
 97  
     {
 98  0
         if(isDoInboundTransform())
 99  
         {
 100  0
             Object o = context.transformMessage();
 101  0
             if(getAppendString()!=null && !(o instanceof String))
 102  
             {
 103  0
                 o = context.transformMessageToString();
 104  
             }
 105  0
             return o;
 106  
         }
 107  0
         else if(getAppendString()!=null)
 108  
         {
 109  0
             return context.getMessageAsString();
 110  
         }
 111  
         else
 112  
         {
 113  0
             return context.getMessage().getPayload();
 114  
         }
 115  
     }
 116  
 
 117  
     /**
 118  
      * This method is used by some WebServices tests where you don' want to be introducing the {@link org.mule.api.MuleEventContext} as
 119  
      * a complex type.
 120  
      *
 121  
      * @param data the event data received
 122  
      * @return the processed message
 123  
      * @throws Exception
 124  
      */
 125  
     public Object onReceive(Object data) throws Exception
 126  
     {
 127  0
         MuleEventContext context = RequestContext.getEventContext();
 128  
 
 129  0
         if (isThrowException())
 130  
         {
 131  0
             throwException();
 132  
         }
 133  0
         return process(data, context);
 134  
     }
 135  
 
 136  
 
 137  
     /**
 138  
      * Always throws a {@link org.mule.tck.exceptions.FunctionalTestException}.  This methodis only called if
 139  
      * {@link #isThrowException()} is true.
 140  
      *
 141  
      * @throws FunctionalTestException or the exception specified in 'exceptionType
 142  
      */
 143  
     protected void throwException() throws Exception
 144  
     {
 145  0
         if (getExceptionToThrow() != null)
 146  
         {
 147  0
             throw (Exception)getExceptionToThrow().newInstance();
 148  
         }
 149  
         else
 150  
         {
 151  0
             throw new FunctionalTestException();
 152  
         }
 153  
     }
 154  
 
 155  
     /**
 156  
      * Will append the value of {@link #getAppendString()} to the contents of the message. This has a side affect
 157  
      * that the inbound message will be converted to a string and the return payload will be a string.
 158  
      * Note that the value of {@link #getAppendString()} can contain expressions.
 159  
      *
 160  
      * @param contents the string vlaue of the current message payload
 161  
      * @param message  the current message
 162  
      * @return a concatenated string of the current payload and the appendString
 163  
      */
 164  
     protected String append(String contents, MuleMessage message)
 165  
     {
 166  0
         return contents + ExpressionEvaluatorManager.parse(appendString, message);
 167  
     }
 168  
 
 169  
     /**
 170  
      * The service method that implements the test component logic.  This method can be called publically through
 171  
      * either {@link #onCall(org.mule.api.MuleEventContext)} or {@link #onReceive(Object)}
 172  
      *
 173  
      * @param data    The message payload
 174  
      * @param context the current {@link org.mule.api.MuleEventContext}
 175  
      * @return a new message payload according to the configuration of the component
 176  
      * @throws Exception if there is a general failure or if {@link #isThrowException()} is true.
 177  
      */
 178  
     protected Object process(Object data, MuleEventContext context) throws Exception
 179  
     {
 180  0
         if (enableMessageHistory)
 181  
         {
 182  0
             messageHistory.add(data);
 183  
         }
 184  
 
 185  0
         String msg = StringMessageUtils.getBoilerPlate("Message Received in service: "
 186  
                 + context.getService().getName() + ". Content is: "
 187  
                 + StringMessageUtils.truncate(data.toString(), 100, true), '*', 80);
 188  
 
 189  0
         logger.info(msg);
 190  
 
 191  0
         if (eventCallback != null)
 192  
         {
 193  0
             eventCallback.eventReceived(context, this);
 194  
         }
 195  
 
 196  
         Object replyMessage;
 197  0
         if (returnData != null)
 198  
         {
 199  0
             if (returnData instanceof String && ExpressionEvaluatorManager.isValidExpression(returnData.toString()))
 200  
             {
 201  0
                 replyMessage = ExpressionEvaluatorManager.parse(returnData.toString(), context.getMessage());
 202  
             }
 203  
             else
 204  
             {
 205  0
                 replyMessage = returnData;
 206  
             }
 207  
         }
 208  
         else
 209  
         {
 210  0
             if (appendString != null)
 211  
             {
 212  0
                 replyMessage = append(data.toString(), context.getMessage());
 213  
             }
 214  
             else
 215  
             {
 216  0
                 replyMessage = data;
 217  
             }
 218  
         }
 219  
 
 220  0
         if (isEnableNotifications())
 221  
         {
 222  0
             MuleContext muleContext = context.getMuleContext();
 223  0
             if (muleContext == null)
 224  
             {
 225  0
                 logger.warn("No MuleContext available from MuleEventContext");
 226  0
                 muleContext = MuleServer.getMuleContext();
 227  
             }
 228  0
             muleContext.fireNotification(
 229  
                     new FunctionalTestNotification(context, replyMessage, FunctionalTestNotification.EVENT_RECEIVED));
 230  
         }
 231  
 
 232  
         //Time to wait before returning
 233  0
         if(waitTime > 0)
 234  
         {
 235  
             try
 236  
             {
 237  0
                 Thread.sleep(waitTime);
 238  
             }
 239  0
             catch (InterruptedException e)
 240  
             {
 241  0
                 logger.info("FunctionalTestComponent waitTime was interrupted");
 242  0
             }
 243  
         }
 244  0
         return replyMessage;
 245  
     }
 246  
 
 247  
     /**
 248  
      * An event callback is called when a message is received by the service.
 249  
      * An MuleEvent callback isn't strictly required but it is usfal for performing assertions
 250  
      * on the current message being received.
 251  
      * Note that the FunctionalTestComponent should be made a singleton
 252  
      * {@link org.mule.api.UMODescriptor#setSingleton} when using MuleEvent callbacks
 253  
      * <p/>
 254  
      * Another option is to register a {@link org.mule.tck.functional.FunctionalTestNotificationListener} with Mule and this
 255  
      * will deleiver a {@link org.mule.tck.functional.FunctionalTestNotification} for every message received by this service
 256  
      *
 257  
      * @return the callback to call when a message is received
 258  
      * @see org.mule.api.UMODescriptor
 259  
      * @see FunctionalTestNotification
 260  
      * @see FunctionalTestNotificationListener
 261  
      */
 262  
     public EventCallback getEventCallback()
 263  
     {
 264  10
         return eventCallback;
 265  
     }
 266  
 
 267  
     /**
 268  
      * An event callback is called when a message is received by the service.
 269  
      * An MuleEvent callback isn't strictly required but it is usfal for performing assertions
 270  
      * on the current message being received.
 271  
      * Note that the FunctionalTestComponent should be made a singleton
 272  
      * {@link org.mule.api.UMODescriptor#setSingleton} when using MuleEvent callbacks
 273  
      * <p/>
 274  
      * Another option is to register a {@link org.mule.tck.functional.FunctionalTestNotificationListener} with Mule and this
 275  
      * will deleiver a {@link org.mule.tck.functional.FunctionalTestNotification} for every message received by this service
 276  
      *
 277  
      * @param eventCallback the callback to call when a message is received
 278  
      * @see org.mule.api.UMODescriptor
 279  
      * @see FunctionalTestNotification
 280  
      * @see FunctionalTestNotificationListener
 281  
      */
 282  
     public void setEventCallback(EventCallback eventCallback)
 283  
     {
 284  12
         this.eventCallback = eventCallback;
 285  12
     }
 286  
 
 287  
     /**
 288  
      * Often you will may want to return a fixed message payload to simulate and external system call.
 289  
      * This can be done using the 'returnData' property. Note that you can return complex objects by
 290  
      * using the <container-property> element in the Xml configuration.
 291  
      *
 292  
      * @return the message payload to always return from this service instance
 293  
      */
 294  
     public Object getReturnData()
 295  
     {
 296  6
         return returnData;
 297  
     }
 298  
 
 299  
     /**
 300  
      * Often you will may want to return a fixed message payload to simulate and external system call.
 301  
      * This can be done using the 'returnData' property. Note that you can return complex objects by
 302  
      * using the <container-property> element in the Xml configuration.
 303  
      *
 304  
      * @param returnData the message payload to always return from this service instance
 305  
      */
 306  
     public void setReturnData(Object returnData)
 307  
     {
 308  12
         this.returnData = returnData;
 309  12
     }
 310  
 
 311  
     /**
 312  
      * Sometimes you will want the service to always throw an exception, if this is the case you can
 313  
      * set the 'throwException' property to true.
 314  
      *
 315  
      * @return throwException true if an exception should always be thrown from this instance.
 316  
      *         If the {@link #returnData} property is set and is of type
 317  
      *         java.lang.Exception, that exception will be thrown.
 318  
      */
 319  
     public boolean isThrowException()
 320  
     {
 321  2
         return throwException;
 322  
     }
 323  
 
 324  
     /**
 325  
      * Sometimes you will want the service to always throw an exception, if this is the case you can
 326  
      * set the 'throwException' property to true.
 327  
      *
 328  
      * @param throwException true if an exception should always be thrown from this instance.
 329  
      *                       If the {@link #returnData} property is set and is of type
 330  
      *                       java.lang.Exception, that exception will be thrown.
 331  
      */
 332  
     public void setThrowException(boolean throwException)
 333  
     {
 334  6
         this.throwException = throwException;
 335  6
     }
 336  
 
 337  
     public boolean isEnableMessageHistory()
 338  
     {
 339  6
         return enableMessageHistory;
 340  
     }
 341  
 
 342  
     public void setEnableMessageHistory(boolean enableMessageHistory)
 343  
     {
 344  12
         this.enableMessageHistory = enableMessageHistory;
 345  12
     }
 346  
 
 347  
     /**
 348  
      * If enableMessageHistory = true, returns the number of messages received by this service.
 349  
      */
 350  
     public int getReceivedMessages()
 351  
     {
 352  0
         if (messageHistory != null)
 353  
         {
 354  0
             return messageHistory.size();
 355  
         }
 356  
         else
 357  
         {
 358  0
             return NumberUtils.INTEGER_MINUS_ONE.intValue();
 359  
         }
 360  
     }
 361  
 
 362  
     /**
 363  
      * If enableMessageHistory = true, returns a message received by the service in chronological order.
 364  
      * For example, getReceivedMessage(1) returns the first message received by the service,
 365  
      * getReceivedMessage(2) returns the second message received by the service, etc.
 366  
      */
 367  
     public Object getReceivedMessage(int number)
 368  
     {
 369  0
         Object message = null;
 370  0
         if (messageHistory != null)
 371  
         {
 372  0
             if (number <= messageHistory.size())
 373  
             {
 374  0
                 message = messageHistory.get(number - 1);
 375  
             }
 376  
         }
 377  0
         return message;
 378  
     }
 379  
 
 380  
     /**
 381  
      * If enableMessageHistory = true, returns the last message received by the service in chronological order.
 382  
      */
 383  
     public Object getLastReceivedMessage()
 384  
     {
 385  0
         if (messageHistory != null)
 386  
         {
 387  0
             return messageHistory.get(messageHistory.size() - 1);
 388  
         }
 389  
         else
 390  
         {
 391  0
             return null;
 392  
         }
 393  
     }
 394  
 
 395  
     public String getAppendString()
 396  
     {
 397  6
         return appendString;
 398  
     }
 399  
 
 400  
     public void setAppendString(String appendString)
 401  
     {
 402  6
         this.appendString = appendString;
 403  6
     }
 404  
 
 405  
     public boolean isEnableNotifications()
 406  
     {
 407  6
         return enableNotifications;
 408  
     }
 409  
 
 410  
     public void setEnableNotifications(boolean enableNotifications)
 411  
     {
 412  6
         this.enableNotifications = enableNotifications;
 413  6
     }
 414  
 
 415  
     public Class getExceptionToThrow()
 416  
     {
 417  4
         return exceptionToThrow;
 418  
     }
 419  
 
 420  
     public void setExceptionToThrow(Class exceptionToThrow)
 421  
     {
 422  6
         this.exceptionToThrow = exceptionToThrow;
 423  6
     }
 424  
 
 425  
     public long getWaitTime()
 426  
     {
 427  0
         return waitTime;
 428  
     }
 429  
 
 430  
     public void setWaitTime(long waitTime)
 431  
     {
 432  0
         this.waitTime = waitTime;
 433  0
     }
 434  
 
 435  
     public boolean isDoInboundTransform()
 436  
     {
 437  0
         return doInboundTransform;
 438  
     }
 439  
 
 440  
     public void setDoInboundTransform(boolean doInboundTransform)
 441  
     {
 442  0
         this.doInboundTransform = doInboundTransform;
 443  0
     }
 444  
 }