1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package fulmine.protocol.specification;
17
18 import static fulmine.util.Utils.CLOSE_BRACE;
19
20 import java.util.Collection;
21
22 import fulmine.model.component.IComponent;
23 import fulmine.model.container.IContainer;
24 import fulmine.protocol.wire.IWireIdentityRegistry;
25 import fulmine.protocol.wire.WireIdentity;
26 import fulmine.protocol.wire.operation.BasicOperation;
27 import fulmine.protocol.wire.operation.IOperationScope;
28
29
30
31
32
33
34
35
36
37
38
39 public final class FrameWriter implements IFrameWriter
40 {
41
42
43 public FrameWriter()
44 {
45 super();
46 }
47
48
49
50
51
52
53
54
55
56
57
58
59
60 public static byte[] write(final IOperationScope scope,
61 final IContainer container, final boolean completeState)
62 {
63 final int[] headerBufferPosition = new int[1];
64 final byte[][] headerBuffer = new byte[1][1024];
65
66 final int[] dataBufferPosition = new int[1];
67 final byte[][] dataBuffer = new byte[1][1024];
68
69
70
71 container.writeState(scope, WireIdentity.get(container.getIdentity()),
72 headerBuffer, headerBufferPosition, dataBuffer, dataBufferPosition,
73 completeState);
74 scope.validate();
75
76 final byte[] frame =
77 mergeBuffers(headerBufferPosition, headerBuffer,
78 dataBufferPosition, dataBuffer);
79 return frame;
80 }
81
82
83
84
85
86
87
88
89
90 public byte[] writeComplete(final IContainer container)
91 {
92 return write(new BasicOperation(
93 container.getContext().getPermissionProfile()), container, true);
94 }
95
96
97
98
99
100
101
102
103
104 public byte[] write(final IContainer container)
105 {
106 return write(new BasicOperation(
107 container.getContext().getPermissionProfile()), container, false);
108 }
109
110
111
112
113
114
115
116
117
118
119 public byte[] writeMeta(final IContainer container)
120 {
121 final int[] headerBufferPosition = new int[1];
122 final byte[][] headerBuffer = new byte[1][1024];
123
124 final int[] dataBufferPosition = new int[1];
125 final byte[][] dataBuffer = new byte[1][1024];
126
127 writeHeaderAndData(container, null, null, new BasicOperation(null),
128 headerBuffer, headerBufferPosition, dataBuffer, dataBufferPosition,
129 false);
130
131 final byte[] frame =
132 mergeBuffers(headerBufferPosition, headerBuffer,
133 dataBufferPosition, dataBuffer);
134 return frame;
135 }
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165 public static byte[] writeNested(
166 final Collection<? extends IComponent> components,
167 final IWireIdentityRegistry registry, final IOperationScope scope,
168 final boolean completeState)
169 {
170
171 final int[] headerBufferPosition = new int[1];
172 final byte[][] headerBuffer = new byte[1][1024];
173
174 final int[] dataBufferPosition = new int[1];
175 final byte[][] dataBuffer = new byte[1][1024];
176
177
178
179 headerBufferPosition[0] = IFrameConstants.NESTED_FRAME_PREAMBLE_LENGTH;
180
181 doWriteComponents(components, registry, scope, headerBufferPosition,
182 headerBuffer, dataBufferPosition, dataBuffer, completeState);
183
184 ByteWriter.writeIntegerAsBytes(headerBufferPosition[0]
185 - IFrameConstants.NESTED_FRAME_PREAMBLE_LENGTH, headerBuffer, 0,
186 IFrameConstants.HEADER_SIZE_LENGTH);
187 ByteWriter.writeIntegerAsBytes(dataBufferPosition[0], headerBuffer,
188 IFrameConstants.HEADER_SIZE_LENGTH,
189 IFrameConstants.HEADER_SIZE_LENGTH);
190
191 final byte[] frame =
192 mergeBuffers(headerBufferPosition, headerBuffer,
193 dataBufferPosition, dataBuffer);
194 return frame;
195 }
196
197 @SuppressWarnings("boxing")
198 private static void doWriteComponents(
199 final Collection<? extends IComponent> components,
200 final IWireIdentityRegistry registry, final IOperationScope scope,
201 final int[] headerBufferPosition, final byte[][] headerBuffer,
202 final int[] dataBufferPosition, final byte[][] dataBuffer,
203 final boolean completeState)
204 {
205 for (IComponent nestedComponent : components)
206 {
207 try
208 {
209 if (nestedComponent == null)
210 {
211 StringBuffer sb = new StringBuffer();
212 java.util.List<Object> l =
213 java.util.Arrays.asList(new Object[] { components,
214 registry, scope, headerBufferPosition,
215 headerBuffer, dataBufferPosition, dataBuffer,
216 completeState });
217 sb.append("FrameWriter.doWriteComponents(").append(l).append(
218 CLOSE_BRACE);
219 System.err.println(sb.toString());
220 Thread.dumpStack();
221 }
222 else
223 {
224 final String identity = nestedComponent.getIdentity();
225 nestedComponent.writeState(scope,
226 registry.getWireIdentityFor(identity), headerBuffer,
227 headerBufferPosition, dataBuffer, dataBufferPosition,
228 completeState);
229 }
230 }
231 catch (IllegalArgumentException e)
232 {
233 throw new IllegalArgumentException(
234 "Could not write component: " + nestedComponent, e);
235 }
236 }
237 }
238
239 public static byte[] mergeBuffers(final int[] headerBufferPosition,
240 final byte[][] headerBuffer, final int[] dataBufferPosition,
241 final byte[][] dataBuffer)
242 {
243 final byte[] frame =
244 new byte[headerBufferPosition[0] + dataBufferPosition[0]];
245 System.arraycopy(headerBuffer[0], 0, frame, 0, headerBufferPosition[0]);
246 System.arraycopy(dataBuffer[0], 0, frame, headerBufferPosition[0],
247 dataBufferPosition[0]);
248 return frame;
249 }
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278 public static void writeHeaderAndData(final IContainer container,
279 final Collection<? extends IComponent> components,
280 final IWireIdentityRegistry registry, final IOperationScope scope,
281 final byte[][] headerBuffer, final int[] headerBufferPosition,
282 final byte[][] dataBuffer, final int[] dataBufferPosition,
283 final boolean completeState)
284 {
285
286
287 final byte[] bytesForString =
288 ByteWriter.getBytes(container.getIdentity());
289 final int byteCountForString = bytesForString.length;
290 final int preambleLength =
291 IFrameConstants.PREAMBLE_STATIC_SECTION_LENGTH
292 + IFrameConstants.ID_SIZE_LENGTH + byteCountForString;
293 final int[] preamblePosition = new int[] { headerBufferPosition[0] };
294 headerBufferPosition[0] += preambleLength;
295
296 if (components != null)
297 {
298 doWriteComponents(components, registry, scope,
299 headerBufferPosition, headerBuffer, dataBufferPosition,
300 dataBuffer, completeState);
301 }
302
303
304
305 final int idSize =
306 ByteWriter.writeInteger(byteCountForString, headerBuffer,
307 preamblePosition[0]);
308 if (idSize > 1)
309 {
310 throw new IllegalStateException("Identity is too long (255 max): '"
311 + container.getIdentity() + "'");
312 }
313 preamblePosition[0] += idSize;
314
315 preamblePosition[0] +=
316 ByteWriter.writeBytes(bytesForString, headerBuffer,
317 preamblePosition[0]);
318
319 final byte type = container.getType().value();
320 ByteWriter.writeIntegerAsBytes(type, headerBuffer, preamblePosition[0],
321 IFrameConstants.RECORD_TYPE_LENGTH);
322 preamblePosition[0] += IFrameConstants.RECORD_TYPE_LENGTH;
323
324 final int state = container.getDataState().ordinal();
325 ByteWriter.writeIntegerAsBytes(state, headerBuffer,
326 preamblePosition[0], IFrameConstants.RECORD_STATE_LENGTH);
327 preamblePosition[0] += IFrameConstants.RECORD_STATE_LENGTH;
328 final int domain = container.getDomain().value();
329 ByteWriter.writeIntegerAsBytes(domain, headerBuffer,
330 preamblePosition[0], IFrameConstants.RECORD_DOMAIN_LENGTH);
331 preamblePosition[0] += IFrameConstants.RECORD_DOMAIN_LENGTH;
332
333 preamblePosition[0] += IFrameConstants.UNUSED_LENGTH;
334
335 ByteWriter.writeIntegerAsBytes(
336 headerBufferPosition[0] - preambleLength, headerBuffer,
337 preamblePosition[0], IFrameConstants.HEADER_SIZE_LENGTH);
338 preamblePosition[0] += IFrameConstants.HEADER_SIZE_LENGTH;
339
340 ByteWriter.writeIntegerAsBytes(dataBufferPosition[0], headerBuffer,
341 preamblePosition[0], IFrameConstants.DATA_SIZE_LENGTH);
342 preamblePosition[0] += IFrameConstants.DATA_SIZE_LENGTH;
343 }
344 }