View Javadoc

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