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