View Javadoc

1   /*
2      Copyright 2007 Ramon Servadei
3   
4      Licensed under the Apache License, Version 2.0 (the "License");
5      you may not use this file except in compliance with the License.
6      You may obtain a copy of the License at
7   
8          http://www.apache.org/licenses/LICENSE-2.0
9   
10     Unless required by applicable law or agreed to in writing, software
11     distributed under the License is distributed on an "AS IS" BASIS,
12     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13     See the License for the specific language governing permissions and
14     limitations under the License.
15   */
16  package fulmine.protocol.specification;
17  
18  import fulmine.Addressable;
19  import fulmine.Domain;
20  import fulmine.IAddressable;
21  import fulmine.Type;
22  import fulmine.context.IFrameworkContext;
23  import fulmine.event.EventFrameExecution;
24  import fulmine.model.container.IContainer;
25  import fulmine.model.container.IContainer.DataState;
26  import fulmine.protocol.wire.operation.BasicOperation;
27  import fulmine.protocol.wire.operation.IOperationScope;
28  
29  /**
30   * A utility class for reading fulmine delta (FD) protocol frames. Thread safe.
31   * <p>
32   * Please refer to the "Fulmine Delta Transmission Protocol" specification for a
33   * complete description of the fulmine serialisation technique.
34   * 
35   * @see IFrameConstants
36   * @author Ramon Servadei
37   * 
38   */
39  public final class FrameReader implements IFrameReader
40  {
41  
42      /**
43       * Allows a thread to signal it is executing in a FrameReader context. This
44       * allows remote containers to be altered by applying changes from frames.
45       */
46      public final static ThreadLocal<Boolean> inContext =
47          new ThreadLocal<Boolean>()
48          {
49              @Override
50              protected Boolean initialValue()
51              {
52                  return Boolean.FALSE;
53              }
54          };
55  
56      /**
57       * Determine if the thread is executing in a FrameReader context. Only in
58       * this context can remote containers be mutated as they are being updated
59       * from a wire frame.
60       * 
61       * @return <code>true</code> if the executing thread in a FrameReader
62       *         context.
63       */
64      public static boolean inContext()
65      {
66          return (inContext.get() != null && inContext.get().booleanValue());
67      }
68  
69      /** Standard constructor */
70      public FrameReader()
71      {
72          super();
73      }
74  
75      /**
76       * Reads an FD frame holding the state of a container. The container to
77       * process the frame is located or created by this method.
78       * 
79       * @param frame
80       *            the byte[] holding the wire state of a container.
81       */
82      public static void debug(byte[] frame)
83      {
84          // find the identity key of the component this frame is for
85          int identityLength =
86              ByteReader.readInteger(frame, 0, IFrameConstants.ID_SIZE_LENGTH);
87          String identity =
88              ByteReader.readString(frame, IFrameConstants.ID_SIZE_LENGTH,
89                  identityLength);
90          final int recordTypeStart =
91              IFrameConstants.ID_SIZE_LENGTH + identityLength;
92          byte recordType =
93              (byte) ByteReader.readInteger(frame, recordTypeStart,
94                  IFrameConstants.RECORD_TYPE_LENGTH);
95          int recordState =
96              ByteReader.readInteger(frame, recordTypeStart
97                  + IFrameConstants.RECORD_TYPE_LENGTH,
98                  IFrameConstants.RECORD_STATE_LENGTH);
99          byte recordDomain =
100             (byte) ByteReader.readInteger(frame, recordTypeStart
101                 + IFrameConstants.RECORD_TYPE_LENGTH
102                 + IFrameConstants.RECORD_STATE_LENGTH,
103                 IFrameConstants.RECORD_DOMAIN_LENGTH);
104 
105         int headerSizeStart =
106             identityLength + IFrameConstants.ID_SIZE_LENGTH
107                 + IFrameConstants.HEADER_SIZE_START;
108 
109         int headerLength =
110             ByteReader.readInteger(frame, headerSizeStart,
111                 IFrameConstants.HEADER_SIZE_LENGTH);
112 
113         int dataSizeStart =
114             identityLength + IFrameConstants.ID_SIZE_LENGTH
115                 + IFrameConstants.DATA_SIZE_START;
116         int dataLength =
117             ByteReader.readInteger(frame, dataSizeStart,
118                 IFrameConstants.DATA_SIZE_LENGTH);
119 
120         System.out.println("Record ID size=" + identityLength);
121         System.out.println("Record ID=" + identity);
122         System.out.println("Record type=" + recordType);
123         System.out.println("Record state=" + recordState);
124         System.out.println("Record domain=" + recordDomain);
125         System.out.println("Header size=" + headerLength);
126         System.out.println("Data size=" + dataLength);
127 
128     }
129 
130     public IAddressable getRemoteContainerDetailsFromFrame(final byte[] frame,
131         String remoteContextIdentity)
132     {
133         // find the identity key of the component this frame is for
134         final int identityLength =
135             ByteReader.readInteger(frame, 0, IFrameConstants.ID_SIZE_LENGTH);
136         final String identity =
137             ByteReader.readString(frame, IFrameConstants.ID_SIZE_LENGTH,
138                 identityLength);
139         final int recordTypeStart =
140             IFrameConstants.ID_SIZE_LENGTH + identityLength;
141         final byte recordType =
142             (byte) ByteReader.readInteger(frame, recordTypeStart,
143                 IFrameConstants.RECORD_TYPE_LENGTH);
144         final byte domain =
145             (byte) ByteReader.readInteger(frame, recordTypeStart
146                 + IFrameConstants.RECORD_TYPE_LENGTH
147                 + IFrameConstants.RECORD_STATE_LENGTH,
148                 IFrameConstants.RECORD_DOMAIN_LENGTH);
149         // get the referenced container, creating if required
150         return new Addressable(identity, Type.get(recordType),
151             Domain.get(domain));
152     }
153 
154     /**
155      * Get the remote container for the frame. The container to process the
156      * frame is located or created by this method.
157      * 
158      * @param frame
159      *            the byte[] holding the wire state of a container.
160      * @param remoteContextIdentity
161      *            the identity of the remote context this frame is from
162      * @param context
163      *            the context to use to create the remote {@link IContainer}
164      * @return the remote {@link IContainer} for the frame.
165      */
166     public IContainer getRemoteContainerForFrame(final byte[] frame,
167         String remoteContextIdentity, final IFrameworkContext context)
168     {
169         try
170         {
171             FrameReader.inContext.set(Boolean.TRUE);
172             IAddressable identity =
173                 getRemoteContainerDetailsFromFrame(frame, remoteContextIdentity);
174             return context.getRemoteContainer(remoteContextIdentity,
175                 identity.getIdentity(), identity.getType(),
176                 identity.getDomain());
177         }
178         finally
179         {
180             FrameReader.inContext.remove();
181         }
182     }
183 
184     /**
185      * Reads an FD frame holding the state of a container. The container to
186      * process the frame is located or created by this method.
187      * 
188      * @param frame
189      *            the byte[] holding the wire state of a container.
190      * @param remoteContextIdentity
191      *            the identity of the remote context this frame is from
192      * 
193      * @param context
194      *            the context to use to create the remote {@link IContainer}
195      * @return the remote {@link IContainer} with the state in the frame applied
196      */
197     public IContainer read(byte[] frame, String remoteContextIdentity,
198         IFrameworkContext context)
199     {
200         try
201         {
202             FrameReader.inContext.set(Boolean.TRUE);
203             // find the identity key of the component this frame is for
204             final int identityLength =
205                 ByteReader.readInteger(frame, 0, IFrameConstants.ID_SIZE_LENGTH);
206             final String identity =
207                 ByteReader.readString(frame, IFrameConstants.ID_SIZE_LENGTH,
208                     identityLength);
209             final int recordTypeStart =
210                 IFrameConstants.ID_SIZE_LENGTH + identityLength;
211             final byte recordType =
212                 (byte) ByteReader.readInteger(frame, recordTypeStart,
213                     IFrameConstants.RECORD_TYPE_LENGTH);
214             final int recordState =
215                 ByteReader.readInteger(frame, recordTypeStart
216                     + IFrameConstants.RECORD_TYPE_LENGTH,
217                     IFrameConstants.RECORD_STATE_LENGTH);
218             final byte domain =
219                 (byte) ByteReader.readInteger(frame, recordTypeStart
220                     + IFrameConstants.RECORD_TYPE_LENGTH
221                     + IFrameConstants.RECORD_STATE_LENGTH,
222                     IFrameConstants.RECORD_DOMAIN_LENGTH);
223 
224             // get the referenced container, creating if required
225             final IContainer container =
226                 context.getRemoteContainer(remoteContextIdentity, identity,
227                     Type.get(recordType), Domain.get(domain));
228             final BasicOperation scope =
229                 new BasicOperation(context.getPermissionProfile());
230 
231             /*
232              * read the state, this will create the 'object graph' any created
233              * nested containers will have a separate frame because the creation
234              * will re-enter this method
235              */
236             container.beginFrame(new EventFrameExecution());
237             try
238             {
239                 container.readState(scope, frame, 0, frame.length);
240                 container.setState(DataState.fromOrdinal(recordState));
241             }
242             finally
243             {
244                 // now trigger events
245                 container.endFrame();
246             }
247             scope.validate();
248             return container;
249         }
250         finally
251         {
252             FrameReader.inContext.remove();
253         }
254     }
255 
256     /**
257      * Read a nested FD frame that is composed of SWF fields/fields.
258      * 
259      * @param scope
260      *            the scope of the read operation
261      * @param buffer
262      *            the buffer holding the nested FD frame
263      * @param start
264      *            the start in the buffer for the nested FD frame
265      * @param numberOfBytes
266      *            the length of the nested FD frame
267      * @param readerTask
268      *            the task to invoke for each component/component in the nested
269      *            FD frame as it is parsed
270      */
271     public static void readNestedSWF(final IOperationScope scope,
272         final byte[] buffer, final int start, final int numberOfBytes,
273         final FieldReader.IFieldReaderTask readerTask)
274     {
275         final int[] headerStart = new int[1];
276         final int[] headerLen = new int[1];
277         final int[] dataStart = new int[1];
278         final int[] dataLen = new int[1];
279         findNestedHeaderAndDataBufferPositions(buffer, start, headerStart,
280             headerLen, dataStart, dataLen);
281         if (headerLen[0] != 0)
282         {
283             FieldReader.readSWFFieldSpecs(scope, buffer, headerStart[0],
284                 headerLen[0], dataStart[0], dataLen[0], readerTask);
285         }
286     }
287 
288     /**
289      * Read a nested FD frame that is composed of IWF fields/fields.
290      * 
291      * @param scope
292      *            the scope of the read operation
293      * @param buffer
294      *            the buffer holding the nested FD frame
295      * @param start
296      *            the start in the buffer for the nested FD frame
297      * @param numberOfBytes
298      *            the length of the nested FD frame
299      * @param readerTask
300      *            the task to invoke for each component/component in the nested
301      *            FD frame as it is parsed
302      */
303     public static void readNestedIWF(final IOperationScope scope,
304         final byte[] buffer, final int start, final int numberOfBytes,
305         final FieldReader.IFieldReaderTask readerTask)
306     {
307         final int[] headerStart = new int[1];
308         final int[] headerLen = new int[1];
309         final int[] dataStart = new int[1];
310         final int[] dataLen = new int[1];
311         findNestedHeaderAndDataBufferPositions(buffer, start, headerStart,
312             headerLen, dataStart, dataLen);
313         FieldReader.readIWFFieldSpecs(scope, buffer, headerStart[0],
314             headerLen[0], dataStart[0], dataLen[0], readerTask);
315     }
316 
317     /**
318      * Identify the header and data buffers within the frame.
319      * 
320      * @param frame
321      *            the byte[] holding the header and data buffers
322      * @param start
323      *            the position in the byte[] where the frame starts
324      * @param headerStart
325      *            headerStart[0] will hold the position where the header buffer
326      *            starts in the frame
327      * @param headerLength
328      *            headerLength[0] will hold the length of the header
329      * @param dataStart
330      *            dataStart[0] will hold the position where the data buffer
331      *            starts in the frame
332      * @param dataLength
333      *            dataLength[0] will hold the length of the data
334      */
335     public static void findHeaderAndDataBufferPositions(final byte[] frame,
336         final int start, final int[] headerStart, final int[] headerLength,
337         final int[] dataStart, final int[] dataLength)
338     {
339         final int dynamicSectionSize =
340             IFrameConstants.ID_SIZE_LENGTH
341                 + ByteReader.readInteger(frame, start,
342                     IFrameConstants.ID_SIZE_LENGTH);
343         headerStart[0] =
344             start + dynamicSectionSize
345                 + IFrameConstants.PREAMBLE_STATIC_SECTION_LENGTH;
346         final int headerSizeStart =
347             start + dynamicSectionSize + IFrameConstants.HEADER_SIZE_START;
348 
349         headerLength[0] =
350             ByteReader.readInteger(frame, headerSizeStart,
351                 IFrameConstants.HEADER_SIZE_LENGTH);
352 
353         dataStart[0] = headerLength[0] + headerStart[0];
354         final int dataSizeStart =
355             start + dynamicSectionSize + IFrameConstants.DATA_SIZE_START;
356         dataLength[0] =
357             ByteReader.readInteger(frame, dataSizeStart,
358                 IFrameConstants.DATA_SIZE_LENGTH);
359     }
360 
361     /**
362      * Identify the header and data buffers of a nested frame.
363      * 
364      * @param buffer
365      * @param start
366      * @param headerStart
367      * @param headerLen
368      * @param dataStart
369      * @param dataLen
370      */
371     private static void findNestedHeaderAndDataBufferPositions(byte[] buffer,
372         int start, int[] headerStart, int[] headerLen, int[] dataStart,
373         int[] dataLen)
374     {
375         headerStart[0] = IFrameConstants.NESTED_FRAME_PREAMBLE_LENGTH + start;
376         headerLen[0] =
377             ByteReader.readInteger(buffer, start,
378                 IFrameConstants.HEADER_SIZE_LENGTH);
379         dataStart[0] = headerStart[0] + headerLen[0];
380         dataLen[0] =
381             ByteReader.readInteger(buffer, IFrameConstants.HEADER_SIZE_LENGTH
382                 + start, IFrameConstants.DATA_SIZE_LENGTH);
383     }
384 }