View Javadoc

1   /*
2    * $Id: FunctionalStreamingTestComponent.java 7963 2007-08-21 08:53:15Z 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.impl.model.streaming.StreamingService;
14  import org.mule.umo.UMOEventContext;
15  import org.mule.util.ClassUtils;
16  import org.mule.util.StringMessageUtils;
17  
18  import java.io.InputStream;
19  import java.io.OutputStream;
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 component that can be used by streaming functional tests. This component accepts an
27   * EventCallback that can be used to assert the state of the current event.  To access the
28   * component 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 StreamingService
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 void call(InputStream in, OutputStream unused, UMOEventContext context) throws Exception
73      {
74          try
75          {
76              logger.debug("arrived at " + toString());
77              byte[] startData = new byte[STREAM_SAMPLE_SIZE];
78              int startDataSize = 0;
79              byte[] endData = new byte[STREAM_SAMPLE_SIZE]; // ring buffer
80              int endDataSize = 0;
81              int endRingPointer = 0;
82              long streamLength = 0;
83              byte[] buffer = new byte[STREAM_BUFFER_SIZE];
84  
85              // throw data on the floor, but keep a record of size, start and end values
86              int bytesRead = 0;
87              while (bytesRead >= 0)
88              {
89                  bytesRead = in.read(buffer);
90                  if (bytesRead > 0)
91                  {
92                      if (logger.isDebugEnabled())
93                      {
94                          logger.debug("read " + bytesRead + " bytes");
95                      }
96                      streamLength += bytesRead;
97                      int startOfEndBytes = 0;
98                      for (int i = 0; startDataSize < STREAM_SAMPLE_SIZE && i < bytesRead; ++i)
99                      {
100                         startData[startDataSize++] = buffer[i];
101                         ++startOfEndBytes; // skip data included in startData
102                     }
103                     startOfEndBytes = Math.max(startOfEndBytes, bytesRead - STREAM_SAMPLE_SIZE);
104                     for (int i = startOfEndBytes; i < bytesRead; ++i)
105                     {
106                         ++endDataSize;
107                         endData[endRingPointer++ % STREAM_SAMPLE_SIZE] = buffer[i];
108                     }
109                     if (streamLength >= targetSize)
110                     {
111                         doCallback(startData, startDataSize,
112                                 endData, endDataSize, endRingPointer,
113                                 streamLength, context);
114                     }
115                 }
116             }
117 
118         }
119         catch (Exception e)
120         {
121             if (logger.isDebugEnabled())
122             {
123                 logger.debug(e);
124             }
125             throw e;
126         }
127     }
128 
129     private void doCallback(byte[] startData, int startDataSize,
130                             byte[] endData, int endDataSize, int endRingPointer,
131                             long streamLength, UMOEventContext context) throws Exception
132     {
133         // make a nice summary of the data
134         StringBuffer result = new StringBuffer("Received stream");
135         result.append("; length: ");
136         result.append(streamLength);
137         result.append("; '");
138 
139         for (int i = 0; i < startDataSize; ++i)
140         {
141             result.append((char) startData[i]);
142         }
143 
144         int endSize = Math.min(endDataSize, STREAM_SAMPLE_SIZE);
145         if (endSize > 0)
146         {
147             result.append("...");
148             for (int i = 0; i < endSize; ++i)
149             {
150                 result.append((char) endData[(endRingPointer + i) % STREAM_SAMPLE_SIZE]);
151             }
152         }
153         result.append("'");
154 
155         summary = result.toString();
156 
157         String msg = StringMessageUtils.getBoilerPlate("Message Received in component: "
158                 + context.getComponentDescriptor().getName() + ". " + summary
159                 + "\n callback: " + eventCallback,
160                 '*', 80);
161 
162         logger.info(msg);
163 
164         if (eventCallback != null)
165         {
166             eventCallback.eventReceived(context, this);
167         }
168     }
169 
170     public String toString()
171     {
172         return ClassUtils.getSimpleName(getClass()) + "/" + number;
173     }
174 
175 }