2 // This file is part of the LWES .NET Binding (LWES.net)
4 // COPYRIGHT© 2009, Phillip Clark (phillip[at*flitbit[dot*org)
5 // original .NET implementation
7 // LWES.net is free software: you can redistribute it and/or modify
8 // it under the terms of the Lesser GNU General Public License as published by
9 // the Free Software Foundation, either version 3 of the License, or
10 // (at your option) any later version.
12 // LWES.net is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // Lesser GNU General Public License for more details.
17 // You should have received a copy of the Lesser GNU General Public License
18 // along with LWES.net. If not, see <http://www.gnu.org/licenses/>.
23 using System
.Collections
.Generic
;
29 using Org
.Lwes
.Properties
;
39 List
<IEventAttribute
> _attributes
;
40 SupportedEncoding _encoding
;
41 Object _sync
= new Object();
42 EventTemplate _template
;
50 /// Creates a new event with the given name.
52 public Event(string evName
)
53 : this(new EventTemplate(false, evName
), false, Constants
.CDefaultSupportedEncoding
)
58 /// Creates a new instance with an encoding.
60 /// <param name="enc">An encoding for the event.</param>
61 public Event(SupportedEncoding enc
)
62 : this(EventTemplate
.Empty
, false, enc
)
67 /// Creates a new event.
69 /// <param name="evTemplate">the event's template</param>
70 /// <param name="validating"><em>true</em> if validating should be performed on the event;
71 /// otherwise <em>false</em></param>
72 /// <param name="enc">indicates the encoding to use for the event's character data</param>
73 public Event(EventTemplate evTemplate
, bool validating
, SupportedEncoding enc
)
75 _template
= evTemplate
;
76 _validating
= validating
;
78 _attributes
= new List
<IEventAttribute
>(evTemplate
.Count
);
81 #endregion Constructors
86 /// Gets the attribute count.
88 public int AttributeCount
90 get { return _template.Count; }
94 /// Gets the encoding used when the event is encoded for binary transmission.
96 public SupportedEncoding Encoding
98 get { return _encoding; }
102 /// The event's name.
106 get { return _template.Name; }
109 #endregion Properties
114 /// Gets an attribute by name.
116 /// <param name="name">attribute name</param>
117 /// <returns>the attribute if it exists; otherwise an exception is thrown</returns>
118 /// <exception cref="ArgumentOutOfRangeException">thrown if an attribute with the given <paramref name="name"/> doesn't exist</exception>
119 public IEventAttribute
this[string name
]
124 if (!_template
.TryGetOrdinal(name
, out ord
))
125 throw new ArgumentOutOfRangeException("name", String
.Format(Resources
.Error_AttributeNotDefined
, name
));
126 return _attributes
[ord
];
131 /// Gets an attribute by ordinal position.
133 /// <param name="ord">ordinal position of the attribute</param>
134 /// <returns>an attribute at the <paramref name="ordinal"/> position given</returns>
135 /// <exception cref="ArgumentOutOfRangeException">thrown if the <paramref name="ordinal"/> is out of range</exception>
136 public IEventAttribute
this[int ord
]
140 if (0 > ord
|| ord
>= _attributes
.Count
)
141 throw new ArgumentOutOfRangeException("ordinal");
142 return _attributes
[ord
];
151 /// Gets an attribute's value.
153 /// <typeparam name="V">value type V</typeparam>
154 /// <param name="name">attribute's name.</param>
155 /// <returns>The value of the attribute, as type V</returns>
156 /// <exception cref="InvalidCastException">if the attribute's value cannot be
157 /// coerced into value type V</exception>
158 /// <exception cref="NoSuchAttributeException">thrown if an attribute with the given name
159 /// does not exist.</exception>
160 public V GetValue
<V
>(string name
)
163 if (_template
.TryGetOrdinal(name
, out ord
))
165 return _attributes
[ord
].GetValue
<V
>();
167 throw new ArgumentOutOfRangeException("name", String
.Format(Resources
.Error_AttributeNotDefined
, name
));
171 /// Sets an attribute's value.
173 /// <param name="name">the attribute's name</param>
174 /// <param name="value">the attribute's UInt16 value</param>
175 public void SetValue(string name
, UInt16
value)
178 AttributeTemplate attr
;
179 if (_template
.TryGetOrdinal(name
, out ord
))
181 attr
= _template
[ord
];
183 // Validate if necessary
184 if (_validating
&& !attr
.IsAssignable(value))
185 throw new AttributeNotSetException("name");
187 _attributes
[ord
] = _attributes
[ord
].Mutate(_template
, value);
192 // Allow for SiteID or SenderPort inherited from MetaInfoEvent
193 if (!String
.Equals(Constants
.MetaEventInfoAttributes
.SiteID
.Name
, name
)
194 && !String
.Equals(Constants
.MetaEventInfoAttributes
.SenderPort
.Name
, name
))
195 throw new ArgumentOutOfRangeException("name", String
.Format(Resources
.Error_AttributeNotDefined
, name
));
198 // Adding a new attribute
199 AppendAttribute(AttributeTemplate
.CreateTemplateForVariable(name
, 0, value), value);
203 /// Sets an attribute's value.
205 /// <param name="name">the attribute's name</param>
206 /// <param name="value">the attribute's Int16 value</param>
207 public void SetValue(string name
, Int16
value)
210 AttributeTemplate attr
;
211 if (_template
.TryGetOrdinal(name
, out ord
))
213 attr
= _template
[ord
];
215 // Validate if necessary
216 if (_validating
&& !attr
.IsAssignable(value))
217 throw new AttributeNotSetException("name");
219 _attributes
[ord
] = _attributes
[ord
].Mutate(_template
, value);
222 // Allow for Encoding inherited from MetaInfoEvent
223 if (String
.Equals(Constants
.MetaEventInfoAttributes
.Encoding
.Name
, name
))
225 // encoding must be the first attribute (when encoded), make it so
226 PrependAttribute(Constants
.MetaEventInfoAttributes
.Encoding
, value);
230 throw new ArgumentOutOfRangeException("name", String
.Format(Resources
.Error_AttributeNotDefined
, name
));
232 // Adding a new attribute
233 AppendAttribute(AttributeTemplate
.CreateTemplateForVariable(name
, 0, value), value);
237 /// Sets an attribute's value.
239 /// <param name="name">the attribute's name</param>
240 /// <param name="value">the attribute's UInt32 value</param>
241 public void SetValue(string name
, UInt32
value)
244 AttributeTemplate attr
;
245 if (_template
.TryGetOrdinal(name
, out ord
))
247 attr
= _template
[ord
];
249 // Validate if necessary
250 if (_validating
&& !attr
.IsAssignable(value))
251 throw new AttributeNotSetException("name");
253 _attributes
[ord
] = _attributes
[ord
].Mutate(_template
, value);
257 throw new ArgumentOutOfRangeException("name", String
.Format(Resources
.Error_AttributeNotDefined
, name
));
259 // Adding a new attribute
260 AppendAttribute(AttributeTemplate
.CreateTemplateForVariable(name
, 0, value), value);
264 /// Sets an attribute's value.
266 /// <param name="name">the attribute's name</param>
267 /// <param name="value">the attribute's Int32 value</param>
268 public void SetValue(string name
, Int32
value)
271 AttributeTemplate attr
;
272 if (_template
.TryGetOrdinal(name
, out ord
))
274 attr
= _template
[ord
];
276 // Validate if necessary
277 if (_validating
&& !attr
.IsAssignable(value))
278 throw new AttributeNotSetException("name");
280 _attributes
[ord
] = _attributes
[ord
].Mutate(_template
, value);
284 throw new ArgumentOutOfRangeException("name", String
.Format(Resources
.Error_AttributeNotDefined
, name
));
286 // Adding a new attribute
287 AppendAttribute(AttributeTemplate
.CreateTemplateForVariable(name
, 0, value), value);
291 /// Sets an attribute's value.
293 /// <param name="name">the attribute's name</param>
294 /// <param name="value">the attribute's String value</param>
295 public void SetValue(string name
, String
value)
298 AttributeTemplate attr
;
299 if (_template
.TryGetOrdinal(name
, out ord
))
301 attr
= _template
[ord
];
303 // Validate if necessary
304 if (_validating
&& !attr
.IsAssignable(value))
305 throw new AttributeNotSetException("name");
307 _attributes
[ord
] = _attributes
[ord
].Mutate(_template
, value);
311 throw new ArgumentOutOfRangeException("name", String
.Format(Resources
.Error_AttributeNotDefined
, name
));
313 // Adding a new attribute
314 AppendAttribute( AttributeTemplate
.CreateTemplateForVariable(name
, 0, value), value);
318 /// Sets an attribute's value.
320 /// <param name="name">the attribute's name</param>
321 /// <param name="value">the attribute's IPAddress value</param>
322 public void SetValue(string name
, IPAddress
value)
325 AttributeTemplate attr
;
326 if (_template
.TryGetOrdinal(name
, out ord
))
328 attr
= _template
[ord
];
330 // Validate if necessary
331 if (_validating
&& !attr
.IsAssignable(value))
332 throw new AttributeNotSetException("name");
334 _attributes
[ord
] = _attributes
[ord
].Mutate(_template
, value);
339 // Allow for SenderIP inherited from MetaInfoEvent
340 if (!String
.Equals(Constants
.MetaEventInfoAttributes
.SenderIP
.Name
, name
))
341 throw new ArgumentOutOfRangeException("name", String
.Format(Resources
.Error_AttributeNotDefined
, name
));
344 // Adding a new attribute
345 AppendAttribute(AttributeTemplate
.CreateTemplateForVariable(name
, 0, value), value);
349 /// Sets an attribute's value.
351 /// <param name="name">the attribute's name</param>
352 /// <param name="value">the attribute's Int64 value</param>
353 public void SetValue(string name
, Int64
value)
356 AttributeTemplate attr
;
357 if (_template
.TryGetOrdinal(name
, out ord
))
359 attr
= _template
[ord
];
361 // Validate if necessary
362 if (_validating
&& !attr
.IsAssignable(value))
363 throw new AttributeNotSetException("name");
365 _attributes
[ord
] = _attributes
[ord
].Mutate(_template
, value);
370 // Allow for ReceiptTime inherited from MetaInfoEvent
371 if (!String
.Equals(Constants
.MetaEventInfoAttributes
.ReceiptTime
.Name
, name
))
372 throw new ArgumentOutOfRangeException("name", String
.Format(Resources
.Error_AttributeNotDefined
, name
));
375 // Adding a new attribute
376 AppendAttribute(AttributeTemplate
.CreateTemplateForVariable(name
, 0, value), value);
380 /// Sets an attribute's value.
382 /// <param name="name">the attribute's name</param>
383 /// <param name="value">the attribute's UInt64 value</param>
384 public void SetValue(string name
, UInt64
value)
387 AttributeTemplate attr
;
388 if (_template
.TryGetOrdinal(name
, out ord
))
390 attr
= _template
[ord
];
392 // Validate if necessary
393 if (_validating
&& !attr
.IsAssignable(value))
394 throw new AttributeNotSetException("name");
396 _attributes
[ord
] = _attributes
[ord
].Mutate(_template
, value);
400 throw new ArgumentOutOfRangeException("name", String
.Format(Resources
.Error_AttributeNotDefined
, name
));
402 // Adding a new attribute
403 AppendAttribute(AttributeTemplate
.CreateTemplateForVariable(name
, 0, value), value);
407 /// Sets an attribute's value.
409 /// <param name="name">the attribute's name</param>
410 /// <param name="value">the attribute's Boolean value</param>
411 public void SetValue(string name
, Boolean
value)
414 AttributeTemplate attr
;
415 if (_template
.TryGetOrdinal(name
, out ord
))
417 attr
= _template
[ord
];
419 // Validate if necessary
420 if (_validating
&& !attr
.IsAssignable(value))
421 throw new AttributeNotSetException("name");
423 _attributes
[ord
] = _attributes
[ord
].Mutate(_template
, value);
427 throw new ArgumentOutOfRangeException("name", String
.Format(Resources
.Error_AttributeNotDefined
, name
));
429 // Adding a new attribute
430 AppendAttribute( AttributeTemplate
.CreateTemplateForVariable(name
, 0, value), value);
434 /// Converts the event to a string.
436 /// <returns>String containing the event.</returns>
437 public override string ToString()
439 StringBuilder s
= new StringBuilder(400);
440 s
.Append(_template
.Name
).Append(": { Name: '").Append(_template
.Name
)
441 .Append("', EsfPresent: ").Append(_template
.FromEsf
)
442 .Append(", Attributes: {");
443 if (_attributes
!= null)
446 foreach (var a
in _attributes
)
448 if (i
++ > 0) s
.Append(", ").Append(a
);
452 return s
.Append("}}").ToString();
456 /// Converts the event to a string.
458 /// <param name="humanReadable">Whether the output should be formatted for human readability</param>
459 /// <returns>string contianing the event</returns>
460 public string ToString(bool humanReadable
)
462 if (!humanReadable
) return ToString();
464 string nl
= Environment
.NewLine
;
466 StringBuilder s
= new StringBuilder(400);
467 s
.Append(_template
.Name
).Append(":").Append(nl
).Append(" { Name: '").Append(_template
.Name
)
468 .Append("'").Append(nl
).Append(" , EsfPresent: ").Append(_template
.FromEsf
)
469 .Append(nl
).Append(" , Attributes: {");
470 if (_attributes
!= null)
473 foreach (var a
in _attributes
)
475 if (i
++ > 0) s
.Append(nl
).Append(" , ").Append(a
);
479 return s
.Append(nl
).Append(" }").Append(nl
).Append(" }").ToString();
483 /// Tries to get an attribute.
485 /// <param name="name">attribute's name</param>
486 /// <param name="value">reference to a variable where the attribute will be stored upon success</param>
487 /// <returns><em>true</em> if the attribute exists; otherwise <em>false</em></returns>
488 public bool TryGetAttribute(string name
, out IEventAttribute
value)
491 if (_template
.TryGetOrdinal(name
, out ord
))
493 value = _attributes
[ord
];
496 value = default(IEventAttribute
);
501 /// Tries to get an attribute's value as a UInt16.
503 /// <param name="attr">the attribute's name</param>
504 /// <param name="value">reference to a variable to hold the value</param>
505 /// <returns><em>true</em> if the value can be retrieved as a UInt16, otherwise <em>false</em></returns>
506 public bool TryGetValue(string attr
, out ushort value)
509 if (_template
.TryGetOrdinal(attr
, out ord
))
511 return _attributes
[ord
].TryGetValue(out value);
513 value = default(ushort);
518 /// Tries to get an attribute's value as a Int16.
520 /// <param name="attr">the attribute's name</param>
521 /// <param name="value">reference to a variable to hold the value</param>
522 /// <returns><em>true</em> if the value can be retrieved as a Int16, otherwise <em>false</em></returns>
523 public bool TryGetValue(string attr
, out short value)
526 if (_template
.TryGetOrdinal(attr
, out ord
))
528 return _attributes
[ord
].TryGetValue(out value);
530 value = default(short);
535 /// Tries to get an attribute's value as a UInt32.
537 /// <param name="attr">the attribute's name</param>
538 /// <param name="value">reference to a variable to hold the value</param>
539 /// <returns><em>true</em> if the value can be retrieved as a UInt32, otherwise <em>false</em></returns>
540 public bool TryGetValue(string attr
, out uint value)
543 if (_template
.TryGetOrdinal(attr
, out ord
))
545 return _attributes
[ord
].TryGetValue(out value);
547 value = default(uint);
552 /// Tries to get an attribute's value as a Int32.
554 /// <param name="attr">the attribute's name</param>
555 /// <param name="value">reference to a variable to hold the value</param>
556 /// <returns><em>true</em> if the value can be retrieved as a Int32, otherwise <em>false</em></returns>
557 public bool TryGetValue(string attr
, out int value)
560 if (_template
.TryGetOrdinal(attr
, out ord
))
562 return _attributes
[ord
].TryGetValue(out value);
564 value = default(int);
569 /// Tries to get an attribute's value as a string.
571 /// <param name="attr">the attribute's name</param>
572 /// <param name="value">reference to a variable to hold the value</param>
573 /// <returns><em>true</em> if the value can be retrieved as a string, otherwise <em>false</em></returns>
574 public bool TryGetValue(string attr
, out string value)
577 if (_template
.TryGetOrdinal(attr
, out ord
))
579 return _attributes
[ord
].TryGetValue(out value);
581 value = default(string);
586 /// Tries to get an attribute's value as a IPAddress.
588 /// <param name="attr">the attribute's name</param>
589 /// <param name="value">reference to a variable to hold the value</param>
590 /// <returns><em>true</em> if the value can be retrieved as a IPAddress, otherwise <em>false</em></returns>
591 public bool TryGetValue(string attr
, out IPAddress
value)
594 if (_template
.TryGetOrdinal(attr
, out ord
))
596 return _attributes
[ord
].TryGetValue(out value);
598 value = default(IPAddress
);
603 /// Tries to get an attribute's value as a UInt16.
605 /// <param name="attr">the attribute's name</param>
606 /// <param name="value">reference to a variable to hold the value</param>
607 /// <returns><em>true</em> if the value can be retrieved as a UInt16, otherwise <em>false</em></returns>
608 public bool TryGetValue(string attr
, out long value)
611 if (_template
.TryGetOrdinal(attr
, out ord
))
613 return _attributes
[ord
].TryGetValue(out value);
615 value = default(long);
620 /// Tries to get an attribute's value as a UInt64.
622 /// <param name="attr">the attribute's name</param>
623 /// <param name="value">reference to a variable to hold the value</param>
624 /// <returns><em>true</em> if the value can be retrieved as a UInt64, otherwise <em>false</em></returns>
625 public bool TryGetValue(string attr
, out ulong value)
628 if (_template
.TryGetOrdinal(attr
, out ord
))
630 return _attributes
[ord
].TryGetValue(out value);
632 value = default(ulong);
637 /// Tries to get an attribute's value as a Boolean.
639 /// <param name="attr">the attribute's name</param>
640 /// <param name="value">reference to a variable to hold the value</param>
641 /// <returns><em>true</em> if the value can be retrieved as a Boolean, otherwise <em>false</em></returns>
642 public bool TryGetValue(string attr
, out bool value)
645 if (_template
.TryGetOrdinal(attr
, out ord
))
647 return _attributes
[ord
].TryGetValue(out value);
649 value = default(bool);
653 internal static Event
BinaryDecode(IEventTemplateDB db
, byte[] buffer
, int offset
, int count
)
655 Decoder dec
= Constants
.DefaultEncoding
.GetDecoder();
656 Decoder bodyDecoder
= dec
;
657 int ofs
= offset
, end_of_input
= offset
+ count
;
659 string eventName
= LwesSerializer
.ReadEVENTWORD(buffer
, ref ofs
, dec
);
660 UInt16 attributeCount
= LwesSerializer
.ReadUInt16(buffer
, ref ofs
);
663 if (!db
.TryCreateEvent(eventName
, out ev
, false, SupportedEncoding
.Default
))
665 ev
= new Event(new EventTemplate(false, eventName
), false, SupportedEncoding
.Default
);
668 for (int i
= 0; i
< attributeCount
&& ofs
< end_of_input
; i
++)
670 string attributeName
= LwesSerializer
.ReadATTRIBUTEWORD(buffer
, ref ofs
, dec
);
671 TypeToken attributeTokenType
= (TypeToken
)LwesSerializer
.ReadByte(buffer
, ref ofs
);
673 // Encoding is in the first attribute position if it is present
675 && String
.Equals(Constants
.MetaEventInfoAttributes
.Encoding
, attributeName
)
676 && attributeTokenType
== TypeToken
.UINT16
)
678 Int16 changeEncoding
= LwesSerializer
.ReadInt16(buffer
, ref ofs
);
679 bodyDecoder
= Constants
.GetEncoding(changeEncoding
).GetDecoder();
680 ev
.SetValue(Constants
.MetaEventInfoAttributes
.Encoding
.Name
, changeEncoding
);
684 switch (attributeTokenType
)
686 case TypeToken
.UINT16
:
687 ev
.SetValue(attributeName
, LwesSerializer
.ReadUInt16(buffer
, ref ofs
));
689 case TypeToken
.INT16
:
690 ev
.SetValue(attributeName
, LwesSerializer
.ReadInt16(buffer
, ref ofs
));
692 case TypeToken
.UINT32
:
693 ev
.SetValue(attributeName
, LwesSerializer
.ReadUInt32(buffer
, ref ofs
));
695 case TypeToken
.INT32
:
696 ev
.SetValue(attributeName
, LwesSerializer
.ReadInt32(buffer
, ref ofs
));
698 case TypeToken
.STRING
:
699 ev
.SetValue(attributeName
, LwesSerializer
.ReadString(buffer
, ref ofs
, bodyDecoder
));
701 case TypeToken
.IP_ADDR
:
702 ev
.SetValue(attributeName
, LwesSerializer
.ReadIPAddress(buffer
, ref ofs
));
704 case TypeToken
.INT64
:
705 ev
.SetValue(attributeName
, LwesSerializer
.ReadInt64(buffer
, ref ofs
));
707 case TypeToken
.UINT64
:
708 ev
.SetValue(attributeName
, LwesSerializer
.ReadUInt64(buffer
, ref ofs
));
710 case TypeToken
.BOOLEAN
:
711 ev
.SetValue(attributeName
, LwesSerializer
.ReadBoolean(buffer
, ref ofs
));
720 internal int BinaryEncode(byte[] buffer
, int offset
)
722 /* Encoded using the following protocol:
724 * EVENTWORD,<number of elements>,ATTRIBUTEWORD,TYPETOKEN,
725 * (UINT16|INT16|UINT32|INT32|UINT64|INT64|BOOLEAN|STRING)
726 * ...ATTRIBUTEWORD,TYPETOKEN(UINT16|INT16|UINT32|INT32|
727 * UINT64|INT64|BOOLEAN|STRING)
729 * The EVENTWORD and ATTRIBUTEWORD(s) are encoded with
730 * the default encoding, the first attribute will be the
731 * encoding for strings if present (may differ from the
732 * encoding used for EVENTWORD and ATTRIBUTEWORD(s)
734 int count
= 0, ofs
= offset
;
735 Encoder utf8
= Constants
.DefaultEncoding
.GetEncoder();
739 Encoder bodyEncoder
= Constants
.GetEncoding((short)_encoding
).GetEncoder();
741 // Encode the EVENTWORD + attribute-count
742 _template
.BinaryEncode(buffer
, ref ofs
);
744 // All of the template and dynamic attributes are encoded...
745 for (int i
= 0; i
< _attributes
.Count
; i
++)
747 count
+= _attributes
[i
].BinaryEncode(buffer
, ref ofs
, bodyEncoder
);
756 internal int CalculateEncodedByteCount()
760 Encoding enc
= Constants
.GetEncoding((short)_encoding
);
761 int count
= _template
.GetByteCount();
763 // All of the template and dynamic attributes are encoded...
764 foreach (var a
in _attributes
)
766 count
+= a
.GetByteCount(enc
);
772 private void AppendAttribute
<T
>(AttributeTemplate attr
, T
value)
776 _template
= _template
.AppendAttributes(attr
);
777 _attributes
.Add(new EventAttribute
<T
>(attr
, value));
781 private void PrependAttribute
<T
>(AttributeTemplate attr
, T
value)
785 EventTemplate et
= _template
.PrependAttributes(attr
);
786 _attributes
.Insert(0, new EventAttribute
<T
>(attr
, value));