View Javadoc

1   /*
2    * $Id: FunctionalStreamingTestComponent.java 19250 2010-08-30 16:53:14Z dirk.olmes $
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.api.MuleEventContext;
14  import org.mule.api.lifecycle.Callable;
15  import org.mule.transformer.types.DataTypeFactory;
16  import org.mule.util.ClassUtils;
17  import org.mule.util.StringMessageUtils;
18  
19  import java.io.IOException;
20  import java.io.InputStream;
21  
22  import edu.emory.mathcs.backport.java.util.concurrent.atomic.AtomicInteger;
23  
24  import org.apache.commons.logging.Log;
25  import org.apache.commons.logging.LogFactory;
26  
27  /**
28   * A service that can be used by streaming functional tests. This service accepts an
29   * EventCallback that can be used to assert the state of the current event.  To access the
30   * service when embedded in an (XML) model, make sure that the descriptor sets the
31   * singleton attribute true - see uses in TCP and FTP.
32   *
33   * Note that although this implements the full StreamingService interface, nothing is
34   * written to the output stream - this is intended as a final sink.
35   *
36   * @see org.mule.tck.functional.EventCallback
37   */
38  
39  public class FunctionalStreamingTestComponent implements Callable
40  {
41      protected transient Log logger = LogFactory.getLog(getClass());
42  
43      private static AtomicInteger count = new AtomicInteger(0);
44      private int number = count.incrementAndGet();
45  
46      public static final int STREAM_SAMPLE_SIZE = 4;
47      public static final int STREAM_BUFFER_SIZE = 4096;
48      private EventCallback eventCallback;
49      private String summary = null;
50      private long targetSize = -1;
51  
52      public FunctionalStreamingTestComponent()
53      {
54          logger.debug("creating " + toString());
55      }
56  
57      public void setEventCallback(EventCallback eventCallback, long targetSize)
58      {
59          logger.debug("setting callback: " + eventCallback + " in " + toString());
60          this.eventCallback = eventCallback;
61          this.targetSize = targetSize;
62      }
63  
64      public String getSummary()
65      {
66          return summary;
67      }
68   
69      public int getNumber()
70      {
71          return number;
72      }
73  
74      public Object onCall(MuleEventContext context) throws Exception
75      {
76          InputStream in = context.getMessage().getPayload(DataTypeFactory.create(InputStream.class));
77          try
78          {
79              logger.debug("arrived at " + toString());
80              byte[] startData = new byte[STREAM_SAMPLE_SIZE];
81              long startDataSize = 0;
82              byte[] endData = new byte[STREAM_SAMPLE_SIZE]; // ring buffer
83              long endDataSize = 0;
84              long endRingPointer = 0;
85              long streamLength = 0;
86              byte[] buffer = new byte[STREAM_BUFFER_SIZE];
87  
88              // throw data on the floor, but keep a record of size, start and end values
89              long bytesRead = 0;
90              while (bytesRead >= 0)
91              {
92                  bytesRead = read(in, buffer);
93                  if (bytesRead > 0)
94                  {
95                      if (logger.isDebugEnabled())
96                      {
97                          logger.debug("read " + bytesRead + " bytes");
98                      }
99                      
100                     streamLength += bytesRead;
101                     long startOfEndBytes = 0;
102                     for (long i = 0; startDataSize < STREAM_SAMPLE_SIZE && i < bytesRead; ++i)
103                     {
104                         startData[(int) startDataSize++] = buffer[(int) i];
105                         ++startOfEndBytes; // skip data included in startData
106                     }
107                     startOfEndBytes = Math.max(startOfEndBytes, bytesRead - STREAM_SAMPLE_SIZE);
108                     for (long i = startOfEndBytes; i < bytesRead; ++i)
109                     {
110                         ++endDataSize;
111                         endData[(int) (endRingPointer++ % STREAM_SAMPLE_SIZE)] = buffer[(int) i];
112                     }
113                     if (streamLength >= targetSize)
114                     {
115                         doCallback(startData, startDataSize,
116                                 endData, endDataSize, endRingPointer,
117                                 streamLength, context);
118                     }
119                 }
120             }
121 
122             in.close();
123         }
124         catch (Exception e)
125         {
126             in.close();
127             
128             e.printStackTrace();
129             if (logger.isDebugEnabled())
130             {
131                 logger.debug(e);
132             }
133             throw e;
134         }
135         
136         return null;
137     }
138 
139     protected int read(InputStream in, byte[] buffer) throws IOException
140     {
141         return in.read(buffer);
142     }
143 
144     private void doCallback(byte[] startData, long startDataSize,
145                             byte[] endData, long endDataSize, long endRingPointer,
146                             long streamLength, MuleEventContext context) throws Exception
147     {
148         // make a nice summary of the data
149         StringBuffer result = new StringBuffer("Received stream");
150         result.append("; length: ");
151         result.append(streamLength);
152         result.append("; '");
153 
154         for (long i = 0; i < startDataSize; ++i)
155         {
156             result.append((char) startData[(int) i]);
157         }
158 
159         long endSize = Math.min(endDataSize, STREAM_SAMPLE_SIZE);
160         if (endSize > 0)
161         {
162             result.append("...");
163             for (long i = 0; i < endSize; ++i)
164             {
165                 result.append((char) endData[(int) ((endRingPointer + i) % STREAM_SAMPLE_SIZE)]);
166             }
167         }
168         result.append("'");
169 
170         summary = result.toString();
171 
172         String msg = StringMessageUtils.getBoilerPlate("Message Received in service: "
173                 + context.getFlowConstruct().getName() + ". " + summary
174                 + "\n callback: " + eventCallback,
175                 '*', 80);
176 
177         logger.info(msg);
178 
179         if (eventCallback != null)
180         {
181             eventCallback.eventReceived(context, this);
182         }
183     }
184 
185     @Override
186     public String toString()
187     {
188         return ClassUtils.getSimpleName(getClass()) + "/" + number;
189     }
190 
191 }