1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package fulmine.model.field.containerdefinition;
17
18 import static fulmine.util.Utils.logException;
19
20 import java.util.Collection;
21 import java.util.LinkedHashMap;
22 import java.util.List;
23 import java.util.Map;
24 import java.util.Set;
25
26 import fulmine.Type;
27 import fulmine.context.IPermissionProfile;
28 import fulmine.model.container.AbstractDynamicContainer;
29 import fulmine.model.container.IContainer;
30 import fulmine.model.field.AbstractField;
31 import fulmine.model.field.IField;
32 import fulmine.protocol.specification.FieldReader;
33 import fulmine.protocol.specification.FieldWriter;
34 import fulmine.protocol.specification.FrameReader;
35 import fulmine.protocol.specification.FrameWriter;
36 import fulmine.protocol.wire.IWireIdentity;
37 import fulmine.protocol.wire.SWFWireIdentityRegistry;
38 import fulmine.protocol.wire.WireIdentity;
39 import fulmine.protocol.wire.operation.IOperationScope;
40 import fulmine.util.collection.CollectionFactory;
41 import fulmine.util.collection.CollectionUtils;
42 import fulmine.util.log.AsyncLog;
43 import fulmine.util.reference.is;
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63 public final class ContainerDefinitionField extends AbstractField implements
64 IContainerDefinitionField
65 {
66
67 private final static AsyncLog LOG =
68 new AsyncLog(ContainerDefinitionField.class);
69
70 @Override
71 protected AsyncLog getLog()
72 {
73 return LOG;
74 }
75
76
77 static final byte REMOVE_FIELD = -1;
78
79
80
81
82
83
84 private final class ReaderTask implements FieldReader.IFieldReaderTask
85 {
86 public void read(IOperationScope scope, int fieldId, byte[] dataBuffer,
87 int dataStart, int dataLen)
88 {
89 throw new IllegalStateException(
90 "reading IWF fields is invalid for a container definition");
91 }
92
93 public void read(IOperationScope scope, String fieldId,
94 byte[] dataBuffer, int dataStart, int dataLen)
95 {
96
97 DescriptorField desc = new DescriptorField(fieldId);
98 desc.readState(scope, dataBuffer, dataStart, dataLen);
99 if (desc.getDataType() == REMOVE_FIELD)
100 {
101 final IField field =
102 ContainerDefinitionField.this.getContainer().get(fieldId);
103 if (field != null)
104 {
105 ContainerDefinitionField.this.getContainer().remove(field);
106 }
107
108
109 remove(desc);
110 }
111 else
112 {
113
114
115
116
117
118 add(desc);
119 }
120 }
121 }
122
123
124
125
126
127
128
129 int wireCodeCounter = Type.CONTAINER_DEFINITION.value() + 1;
130
131
132
133
134
135 private Map<String, DescriptorField> fields =
136 new LinkedHashMap<String, DescriptorField>(1);
137
138
139 private Map<Integer, DescriptorField> descriptorFields =
140 CollectionFactory.newMap(1);
141
142
143 private List<DescriptorField> changes = CollectionFactory.newList(1);
144
145
146 private boolean dynamic = true;
147
148
149
150
151
152
153
154 public ContainerDefinitionField(String definition, IField... fields)
155 {
156 super(definition, Type.CONTAINER_DEFINITION,
157 IPermissionProfile.DEFAULT_APPLICATION,
158 IPermissionProfile.DEFAULT_PERMISSION);
159 setContainer(null);
160 for (IField field : fields)
161 {
162 try
163 {
164 add(field);
165 }
166 catch (Exception e)
167 {
168 logException(LOG, field, e);
169 }
170 }
171 this.dynamic = false;
172 }
173
174
175
176
177
178
179
180 public ContainerDefinitionField(AbstractDynamicContainer container)
181 {
182 super(container.getIdentity(), Type.CONTAINER_DEFINITION,
183 IPermissionProfile.DEFAULT_APPLICATION,
184 IPermissionProfile.DEFAULT_PERMISSION);
185 setContainer(container);
186 }
187
188 public boolean isDynamic()
189 {
190 return this.dynamic;
191 }
192
193 public void add(IField field)
194 {
195 if (!this.dynamic)
196 {
197 throw new IllegalStateException(
198 "Cannot call add on a static container definition");
199 }
200
201
202
203
204
205
206 if (this.equals(field)
207 || (getContainer() != null && !getContainer().isLocal()))
208 {
209 return;
210 }
211
212
213
214
215
216 final DescriptorField desc = new DescriptorField(field.getIdentity());
217 desc.setWireCode(this.wireCodeCounter++);
218 desc.setDataType(field.getType().value());
219 desc.setPermission(field.getPermission());
220 desc.setApplication(field.getApplication());
221 add(desc);
222 getChanges().add(desc);
223 notifyChange();
224 }
225
226 private void add(final DescriptorField desc)
227 {
228 getFields().put(desc.getIdentity(), desc);
229 getDescriptorFields().put(Integer.valueOf(desc.getWireCode()), desc);
230 }
231
232 public void remove(IField field)
233 {
234 if (!this.dynamic)
235 {
236 throw new IllegalStateException(
237 "Cannot call remove on a static container definition");
238 }
239 final DescriptorField remove = getFields().get(field.getIdentity());
240 if (remove != null)
241 {
242 remove.setDataType(REMOVE_FIELD);
243 getChanges().add(remove);
244 notifyChange();
245 }
246 else
247 {
248 if (getLog().isDebugEnabled())
249 {
250 getLog().debug("No field descriptor for " + field.getIdentity());
251 }
252 }
253 }
254
255 public String getIdentityFor(IWireIdentity wireId)
256 {
257 if (wireId.isIntegerWireFormat())
258 {
259 return getIdentityForWireCode(wireId.getAsInteger());
260 }
261 throw new IllegalArgumentException(
262 "Cannot work with an SWF wire identity");
263 }
264
265 public IWireIdentity getWireIdentityFor(String identity)
266 {
267 return WireIdentity.get(getWireCodeForIdentity(identity));
268 }
269
270 public String getIdentityForWireCode(int wireCode)
271 {
272 final IField field =
273 getDescriptorFields().get(Integer.valueOf(wireCode));
274 if (field != null)
275 {
276 return field.getIdentity();
277 }
278 throw new IllegalArgumentException("No field found for wire code "
279 + wireCode + ", codes are: "
280 + CollectionUtils.toFormattedString(getDescriptorFields()));
281 }
282
283 public int getWireCodeForIdentity(String identity)
284 {
285 if (getIdentity().equals(identity))
286 {
287 return Type.CONTAINER_DEFINITION.value();
288 }
289 final IField field = getFields().get(identity);
290 if (field != null)
291 {
292 final int fieldWireCode = ((DescriptorField) field).getWireCode();
293 return fieldWireCode;
294 }
295 throw new IllegalArgumentException("No field found for " + identity);
296 }
297
298 @Override
299 protected boolean doReadState(IOperationScope scope, byte[] buffer,
300 int start, int numberOfBytes) throws Exception
301 {
302
303 FrameReader.readNestedSWF(scope, buffer, start, numberOfBytes,
304 this.new ReaderTask());
305 return true;
306 }
307
308 @Override
309 protected boolean doWriteState(IOperationScope scope, IWireIdentity wireId,
310 byte[][] headerBuffer, int[] headerBufferPosition, byte[][] dataBuffer,
311 int[] dataBufferPosition, boolean completeState) throws Exception
312 {
313 final Collection<DescriptorField> fieldsToWrite =
314 (completeState ? getFields().values() : getChanges());
315 if (fieldsToWrite.size() == 0)
316 {
317 if (LOG.isDebugEnabled())
318 {
319 LOG.debug("No changes to write for " + this);
320 }
321 return true;
322 }
323 if (LOG.isDebugEnabled())
324 {
325 LOG.debug("Writing " + fieldsToWrite);
326 }
327 final byte[] frame =
328 FrameWriter.writeNested(fieldsToWrite,
329 new SWFWireIdentityRegistry(), scope, completeState);
330 FieldWriter.writeRawBytesField(wireId, frame, headerBuffer,
331 headerBufferPosition, dataBuffer, dataBufferPosition);
332 for (DescriptorField field : getChanges())
333 {
334 try
335 {
336 if (field.getDataType() == REMOVE_FIELD)
337 {
338 remove(field);
339 }
340 }
341 catch (Exception e)
342 {
343 logException(LOG, field, e);
344 }
345 }
346 return true;
347 }
348
349 private void remove(DescriptorField field)
350 {
351 try
352 {
353 getDescriptorFields().remove(
354 Integer.valueOf(getWireCodeForIdentity(field.getIdentity())));
355 }
356 catch (Exception e)
357 {
358 logException(getLog(), "Did not find wire code for " + field
359 + " to remove", e);
360 }
361 try
362 {
363 getFields().remove(field.getIdentity());
364 }
365 catch (Exception e)
366 {
367 logException(getLog(), "Did not find " + field + " to remove", e);
368 }
369 }
370
371 public void populate(IContainer container)
372 {
373 final Collection<DescriptorField> values = getFields().values();
374 for (DescriptorField descriptorField : values)
375 {
376 try
377 {
378 container.add(descriptorField.createField());
379 }
380 catch (Exception e)
381 {
382 logException(LOG, descriptorField, e);
383 }
384 }
385 }
386
387
388
389
390 private void notifyChange()
391 {
392 if (getContainer() != null)
393 {
394 getContainer().addEvent(this);
395 }
396 }
397
398 public String[] getComponentIdentities()
399 {
400 final Set<String> keySet = getFields().keySet();
401 return keySet.toArray(new String[keySet.size()]);
402 }
403
404 @Override
405 protected void doComponentDestroy()
406 {
407 super.doComponentDestroy();
408
409 getChanges().clear();
410 getFields().clear();
411 getDescriptorFields().clear();
412 }
413
414 public String getValueAsString()
415 {
416 return (this.dynamic ? "dynamic" : "static") + getFields().values();
417 }
418
419 public void resetChanges()
420 {
421 getChanges().clear();
422 }
423
424 public boolean containsDefinition(int wireCode)
425 {
426 return getDescriptorFields().containsKey(Integer.valueOf(wireCode));
427 }
428
429 public IField createField(int wireCode)
430 {
431 return getDescriptorFields().get(Integer.valueOf(wireCode)).createField();
432 }
433
434 public Object getValue()
435 {
436 return getValueAsString();
437 }
438
439 public byte getApplication(int wireCode)
440 {
441 return getDescriptorFields().get(Integer.valueOf(wireCode)).getApplication();
442 }
443
444 public short getPermission(int wireCode)
445 {
446 return getDescriptorFields().get(Integer.valueOf(wireCode)).getPermission();
447 }
448
449 void setFields(Map<String, DescriptorField> fields)
450 {
451 this.fields = fields;
452 }
453
454 Map<String, DescriptorField> getFields()
455 {
456 return this.fields;
457 }
458
459 void setDescriptorFields(Map<Integer, DescriptorField> descriptorFields)
460 {
461 this.descriptorFields = descriptorFields;
462 }
463
464 Map<Integer, DescriptorField> getDescriptorFields()
465 {
466 return this.descriptorFields;
467 }
468
469 void setChanges(List<DescriptorField> changes)
470 {
471 this.changes = changes;
472 }
473
474 List<DescriptorField> getChanges()
475 {
476 return this.changes;
477 }
478
479 @Override
480 public boolean equals(Object obj)
481 {
482 if (is.same(this, obj))
483 {
484 return true;
485 }
486 if (is.differentClass(this, obj))
487 {
488 return false;
489 }
490 return super.equals(obj);
491
492
493
494
495 }
496
497 @Override
498 public Object clone() throws CloneNotSupportedException
499 {
500 final ContainerDefinitionField clone =
501 (ContainerDefinitionField) super.clone();
502
503 List<DescriptorField> changes = CollectionFactory.newList();
504 clone.setChanges(changes);
505 clone.getChanges().addAll(getChanges());
506 Map<String, DescriptorField> fields = CollectionFactory.newMap();
507 clone.setFields(fields);
508 clone.getFields().putAll(getFields());
509 Map<Integer, DescriptorField> descriptorFields =
510 CollectionFactory.newMap();
511 clone.setDescriptorFields(descriptorFields);
512 clone.getDescriptorFields().putAll(getDescriptorFields());
513 return clone;
514 }
515
516 }