View Javadoc

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