/[xmltv_parser]/trunk/libxmltv/Core/XMLTVRuntimeInstance.cs
ViewVC logotype

Contents of /trunk/libxmltv/Core/XMLTVRuntimeInstance.cs

Parent Directory Parent Directory | Revision Log Revision Log


Revision 191 - (show annotations) (download)
Sat Mar 16 20:07:53 2013 UTC (6 years, 8 months ago) by william
File size: 23766 byte(s)

1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using libxmltv.Interfaces;
6 using System.ComponentModel;
7 using System.Windows.Forms;
8 using System.Threading;
9 using System.Reflection;
10 using System.Globalization;
11 using System.Diagnostics;
12 using System.Xml.Linq;
13 using Enterprise.Logging;
14 using System.IO;
15
16 namespace libxmltv.Core
17 {
18 [Serializable]
19 internal class XMLTVRuntimeInstance : MarshalByRefObject,
20 IXMLTVRuntimeInstance,
21 ISerializer<XMLTVRuntimeInstance>,
22 IGetCreatedInstanceEvent,
23 ISetCreatedInstanceEvent,
24 IDestroyInstance,
25 IRuntimeInstanceLoader<XMLTVRuntimeInstance>
26 {
27 [NonSerialized]
28 Thread worker;
29 public XMLTVRuntimeInstance() { init(); }
30 public XMLTVRuntimeInstance(string xmlfile) : this(xmlfile, null) { }
31 public XMLTVRuntimeInstance(string xmlfile, EventHandler<EventArgs> handler)
32 : this()
33 {
34 this.OnInstanceCreated += handler;
35 worker = new Thread(new ParameterizedThreadStart(CreateInstance)); worker.Start(xmlfile);
36 }
37 private void CreateInstance(object xmlfile)
38 {
39 using (XMLTVInstance instance = new XMLTVInstance(xmlfile.ToString()))
40 {
41 this.LoadFromInstance(instance.GetInstance());
42 OnCreatedInstance(this, new EventArgs());
43 }
44 }
45
46 private void OnCreatedInstance(object sender, EventArgs e)
47 {
48 if (OnInstanceCreated != null) { OnInstanceCreated.Invoke(sender, e); }
49 }
50
51 private void init()
52 {
53 this.Source = new XMLTVSource();
54 this.Channels = new ChannelList();
55 this.Programs = new ProgramList();
56 this.XmlFile_Name = string.Empty;
57 this.XmlFile_FullName = string.Empty;
58 this.XmlDoc = string.Empty;
59 this.OnInstanceCreated = null;
60 this.ExtraEntries = new ExtraList();
61 }
62
63 #region IXMLTVRuntimeInstance members
64 private bool _IsAborting;
65 public bool IsAborting { get { return _IsAborting; } private set { _IsAborting = value; } }
66
67
68 private string _XmlFile_Name;
69 public string XmlFile_Name { get { return _XmlFile_Name; } set { _XmlFile_Name = value; } }
70 private string _XmlFile_FullName;
71 public string XmlFile_FullName { get { return _XmlFile_FullName; } set { _XmlFile_FullName = value; } }
72
73 private string _XmlDoc;
74 public string XmlDoc { get { return _XmlDoc; } set { _XmlDoc = value; } }
75 private IXMLTVSource _Source;
76 public IXMLTVSource Source { get { return _Source; } set { _Source = value; } }
77 private ChannelList _Channels;
78 public ChannelList Channels { get { return _Channels; } set { _Channels = value; } }
79 private ProgramList _Programs;
80 public ProgramList Programs { get { return _Programs; } set { _Programs = value; } }
81
82 private ExtraList _ExtraEntries;
83 public ExtraList ExtraEntries { get { return _ExtraEntries; } set { _ExtraEntries = value; } }
84 #endregion
85 #region IOnInstanceCreated members
86 [NonSerialized]
87 private EventHandler<EventArgs> _OnInstanceCreated;
88 public EventHandler<EventArgs> OnInstanceCreated { get { return _OnInstanceCreated; } set { _OnInstanceCreated = value; } }
89 #endregion
90 #region IGetCreatedInstanceEvent members
91 public EventHandler<EventArgs> GetOnInstanceCreated() { return OnInstanceCreated; }
92 #endregion
93 #region ISetCreatedInstanceEvent members
94 public void SetOnInstanceCreated(EventHandler<EventArgs> event_instance) { OnInstanceCreated = event_instance; }
95 #endregion
96 #region ISerializer<XMLTVRuntimeInstance> members
97 public IXMLTVSerializer<XMLTVRuntimeInstance> Serializer { get { return new XMLTVSerializer<XMLTVRuntimeInstance>(this); } }
98 #endregion
99 #region IDestroyInstance member
100 public void DestroyInstance()
101 {
102 xmltv_logger.Debug.WriteLine("Destoying Instance of: '{0}'", this.GetType().Name);
103 this.IsAborting = true;
104 if (worker == null)
105 {
106 xmltv_logger.Debug.WriteLine("Unable to destroy instance of: '{0}' - worker thread is null", this.GetType().Name);
107 return;
108 }
109 else
110 {
111 if (worker.IsAlive)
112 {
113 xmltv_logger.Verbose.Debug.WriteLine("Requesting Instance to Abort...");
114 while (worker.IsAlive) { worker.Abort(); Application.DoEvents(); }
115 }
116 else { xmltv_logger.Debug.WriteLine("Instance of: '{0}'- already destroyed.", this.GetType().Name); }
117 }
118 }
119 #endregion
120 #region IRuntimeInstanceLoader<XMLTVRuntimeInstance> member
121 public XMLTVRuntimeInstance LoadFromInstance(XMLTVRuntimeInstance instance)
122 {
123 if (instance == null)
124 {
125 throw new NullReferenceException("Failed to load from instance because the instance is null.");
126 }
127 xmltv_logger.Debug.WriteLine("Loading from instance...");
128 CloneFromInstance(ref instance);
129 xmltv_logger.Debug.WriteLine("Loaded from instance...");
130 if (this.Source != null)
131 {
132 xmltv_logger.Info.WriteLine("Source Loaded: '{0}' Created by '{1}' - original source file: '{2}'", this.Source.SourceName, this.Source.GeneratorName, this.XmlFile_FullName);
133 }
134 else
135 {
136 xmltv_logger.Error.WriteLine("Source Property is null.");
137 throw new NullReferenceException("Source Property is null.");
138 }
139 if (this.Channels != null)
140 {
141 this.Channels.TrimExcess();
142 xmltv_logger.Info.WriteLine("Source Loaded: '{0}' Channels from source '{1}'", this.Channels.ToArray().Count(), this.Source.SourceName);
143 }
144 else
145 {
146 xmltv_logger.Error.WriteLine("Channels Property is null.");
147 throw new NullReferenceException("Channels Property is null.");
148 }
149 if (this.Programs != null)
150 {
151 this.Programs.TrimExcess();
152 xmltv_logger.Info.WriteLine("Source Loaded: '{0}' Programs from source '{1}'", this.Programs.ToArray().Count(), this.Source.SourceName);
153 }
154 else
155 {
156 xmltv_logger.Error.WriteLine("Programs Property is null.");
157 throw new NullReferenceException("Programs Property is null.");
158 }
159 return instance;
160 }
161 #endregion
162 #region CloneFromInstance
163 private void CloneFromInstance(ref XMLTVRuntimeInstance instance)
164 {
165 xmltv_logger.Debug.WriteLine("Cloning from instance...");
166 BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
167 CultureInfo culture = CultureInfo.CurrentCulture;
168 Type t = typeof(XMLTVRuntimeInstance);
169 foreach (var field in t.GetFields(flags))
170 {
171 try
172 {
173 if (field.IsNotSerialized) { continue; }
174 var f = instance.GetType().GetField(field.Name, flags);
175 var v = f.GetValue(instance);
176 if (v != null)
177 {
178 field.SetValue(this, v);
179 }
180 else
181 {
182 xmltv_logger.Debug.WriteLine("Attempted to set field: '{0}' with a null value. The operation was aborted.", f.Name);
183 continue;
184 }
185 }
186 catch (Exception ex)
187 {
188 throw new Exception(string.Format("Unable to copy value for field: '{0}' from instance", field.Name), ex);
189 }
190 }
191 foreach (var property in t.GetProperties(flags))
192 {
193 try
194 {
195 var f = instance.GetType().GetProperty(property.Name);
196 object value = null;
197 try
198 {
199 value = f.GetValue(instance, null);
200 }
201 catch (ArgumentException ex) { if (ex.Message == "Property get method not found.") { Debug.WriteLine(ex.ToString()); } else { throw ex; } }
202 try
203 {
204 if (value != null)
205 {
206 property.SetValue(this, value, null);
207 }
208 else
209 {
210 xmltv_logger.Debug.WriteLine("Attempted to set property: '{0}' with a null value. The operation was aborted.", f.Name);
211 continue;
212 }
213 }
214 catch (ArgumentException ex) { if (ex.Message == "Property set method not found.") { Debug.WriteLine(ex.ToString()); } else { throw ex; } }
215
216 }
217 catch (Exception ex)
218 {
219 throw new Exception(string.Format("Unable to copy value for property: '{0}' from instance", property.Name), ex);
220 }
221 }
222 xmltv_logger.Debug.WriteLine("Cloned from instance...");
223 }
224 #endregion
225 }
226
227 internal class XMLTVInstance : IGetInstance<XMLTVRuntimeInstance>, IDisposable
228 {
229 public void Dispose()
230 {
231 //throw new NotImplementedException();
232 }
233
234 private XMLTVRuntimeInstance gInstance;
235 public XMLTVRuntimeInstance GetInstance() { return gInstance; }
236 public XMLTVInstance(string xmlfile)
237 {
238 try
239 {
240 CreateLoader(xmlfile);
241 CreateParser();
242 }
243 catch (ThreadAbortException ex) { Debug.WriteLine(ex.ToString()); }
244 catch (Exception ex)
245 {
246 xmltv_logger.Error.WriteLine(ex.ToString());
247 }
248 }
249
250 private void CreateLoader(string xml_file)
251 {
252 xmltv_logger.Verbose.Debug.WriteLine("Creating loader handle");
253 gInstance = new XMLTVRuntimeInstance();
254 object raw_instance = null;
255 BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
256 CultureInfo culture = CultureInfo.CurrentCulture;
257 Assembly asm = Assembly.GetExecutingAssembly();
258 var types = asm.GetTypes();
259 Type handler_type = null;
260 foreach (var type in types)
261 {
262 if (type.BaseType != null && type.BaseType == typeof(XMLTVBase<XMLTVRuntimeInstance>))
263 {
264 //xmltv_logger.Verbose.Debug.WriteLine("Type: '{0}' Base: '{1}'", type.Name, type.BaseType == null ? "none" : type.BaseType.Name);
265 object[] args = new object[] { xml_file, gInstance };
266 var iface = type.GetInterface("IXMLTVHandler", true);
267 if (iface != null)
268 {
269 var handler_prop = type.GetProperty("Handler");
270 if (handler_prop != null)
271 {
272 var ctors = type.GetConstructors(flags);
273 bool has_string_ctor = false;
274 foreach (var ctor in ctors) { if (ctor.GetParameters().Count() == 1 && ctor.GetParameters()[0].ParameterType == typeof(string)) { has_string_ctor = true; } }
275 if (!has_string_ctor) { continue; }
276 raw_instance = Activator.CreateInstance(type, flags, null, new object[] { xml_file}, culture);
277 if (raw_instance != null)
278 {
279 object handler_value = handler_prop.GetValue(raw_instance, null);
280 if (handler_value != null && handler_value.ToString() == xml_file)
281 {
282 handler_type = type;
283 break;
284 }
285 }
286 }
287 }
288 }
289 }
290 if (handler_type == null) { throw new Exception("Unable to find a compatible XMLTV Data Loader."); }
291 xmltv_logger.Verbose.Debug.WriteLine("Created loader handle");
292 raw_instance = Activator.CreateInstance(handler_type, flags, null, new object[] {xml_file , gInstance }, culture);
293 if (raw_instance == null) { throw new NullReferenceException("Found a compatible XMLTV Data Loader, but it returned invalid data."); }
294 IGetInstance<XMLTVRuntimeInstance> getter_instance = (raw_instance as IGetInstance<XMLTVRuntimeInstance>);
295 if (getter_instance != null) { gInstance = getter_instance.GetInstance(); }
296 else { throw new Exception("Found a compatible XMLTV Data Loader, but was unable to obtain the instance holding the data"); }
297 }
298 private void CreateParser()
299 {
300 var doc = XDocument.Parse(this.GetInstance().XmlDoc);
301 var root_element = doc.Root;
302 CreateHandlerForRootNode(root_element);
303 var nodes = doc.Root.Elements().ToList();
304
305 double total_nodes = nodes.Count;
306 double node_index = 0;
307 double progress = 0;
308 foreach(var node in nodes)
309 {
310 if (this.GetInstance().IsAborting)
311 {
312 break;
313 }
314 if (!CreateHandlerForNode(node)) { xmltv_logger.Verbose.Debug.WriteLine("Unable to create handler for node: '{0}'", node.Name.ToString()); }
315 node_index++;
316 progress = 100.0 * (node_index / total_nodes);
317 xmltv_logger.ReportProgress(this, new ReportProgressEventArgs((int)progress, string.Format("Loading {0} ==> {1:00}%", this.gInstance.XmlFile_Name, (int)progress)));
318 Application.DoEvents();
319 }
320 }
321
322
323 private void CreateHandlerForRootNode(XElement root)
324 {
325 if (root == null) { throw new NullReferenceException("Root element is null"); }
326 if (root.Name == null) { throw new NullReferenceException("Root element's Name is null"); }
327 var root_name = root.Name.ToString();
328 xmltv_logger.Verbose.Debug.WriteLine("Creating handler for root: '{0}'", root_name.ToString());
329 object raw_instance = null;
330 BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
331 CultureInfo culture = CultureInfo.CurrentCulture;
332 Assembly asm = Assembly.GetExecutingAssembly();
333 var types = asm.GetTypes();
334 Type handler_type = null;
335 foreach (var type in types)
336 {
337 if (type.BaseType != null && type.BaseType == typeof(XMLTVBase<XMLTVRuntimeInstance>))
338 {
339 var iface = type.GetInterface("IXMLTVHandler", true);
340 if (iface != null)
341 {
342 var handler_prop = type.GetProperty("Handler");
343 if (handler_prop != null)
344 {
345 var ctors = type.GetConstructors(flags);
346 bool has_default_ctor = false;
347 foreach (var ctor in ctors) { if (ctor.GetParameters().Count() == 0) { has_default_ctor = true; } }
348 ctors = null;
349 if (!has_default_ctor) { continue; }
350 raw_instance = Activator.CreateInstance(type, flags, null, new object[0], culture);
351 if (raw_instance != null)
352 {
353 object handler_value = handler_prop.GetValue(raw_instance, null);
354 if (handler_value != null && handler_value.ToString() == root_name)
355 {
356 handler_type = type;
357 handler_value = null;
358 raw_instance = null;
359 handler_prop = null;
360 iface = null;
361 break;
362 }
363 handler_value = null;
364 }
365 raw_instance = null;
366 }
367 handler_prop = null;
368 }
369 iface = null;
370 }
371 }
372 asm = null;
373 types = null;
374 if (handler_type == null)
375 {
376 StringBuilder node_builder = new StringBuilder();
377 node_builder.AppendFormat("<{0} ", root.Name);
378 if (root.HasAttributes) { foreach (var attribute in root.Attributes()) { node_builder.AppendFormat("{0}=\"{1}\" ", attribute.Name, attribute.Value); } }
379 string node_text = string.Format("{0}>", node_builder.ToString().TrimEnd(new char[] { ' ' }));
380 throw new Exception(string.Format("Unable to find a compatible handler to parse node: {0}", node_text));
381 }
382 xmltv_logger.Verbose.Debug.WriteLine("Created handler for root: '{0}'", root_name.ToString());
383 raw_instance = Activator.CreateInstance(handler_type, flags, null, new object[] { gInstance }, culture);
384 raw_instance = null;
385 flags = 0;
386 culture = null;
387 }
388
389 private bool CreateHandlerForNode(XElement node)
390 {
391 if (node == null) { throw new NullReferenceException("Node element is null"); }
392 if (node.Name == null) { throw new NullReferenceException("Node element's Name is null"); }
393 //var node_name = node.Name.ToString();
394
395 xmltv_logger.Verbose.Debug.WriteLine("Creating handler for node: '{0}'", node.Name.ToString());
396 object raw_instance = null;
397 BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
398 CultureInfo culture = CultureInfo.CurrentCulture;
399 Assembly asm = Assembly.GetExecutingAssembly();
400 var types = asm.GetTypes();
401 Type handler_type = null;
402 foreach (var type in types)
403 {
404 if (type.BaseType != null && type.BaseType == typeof(XMLTVBase<XMLTVRuntimeInstance>))
405 {
406 var iface = type.GetInterface("IXMLTVHandler", true);
407 if (iface != null)
408 {
409 var handler_prop = type.GetProperty("Handler");
410 if (handler_prop != null)
411 {
412 var ctors = type.GetConstructors(flags);
413 bool has_default_ctor = false;
414 foreach (var ctor in ctors) { if (ctor.GetParameters().Count() == 0) { has_default_ctor = true; } }
415 ctors = null;
416 if (!has_default_ctor) { continue; }
417 raw_instance = Activator.CreateInstance(type, flags, null, new object[0], culture);
418 if (raw_instance != null)
419 {
420 object handler_value = handler_prop.GetValue(raw_instance, null);
421 if (handler_value != null && handler_value.ToString() == node.Name.ToString())
422 {
423 handler_type = type;
424 handler_value = null;
425 raw_instance = null;
426 handler_prop = null;
427 iface = null;
428 break;
429 }
430 handler_value = null;
431 }
432 raw_instance = null;
433 }
434 handler_prop = null;
435 }
436 iface = null;
437 }
438 }
439 asm = null;
440 types = null;
441 if (handler_type == null)
442 {
443 try
444 {
445 raw_instance = Activator.CreateInstance(typeof(UnhandledNodeData), flags, null, new object[] { gInstance, node }, culture);
446 }
447 catch (Exception ex) { throw ex; }
448
449 if (raw_instance == null)
450 {
451 StringBuilder node_builder = new StringBuilder();
452 node_builder.AppendFormat("<{0} ", node.Name);
453 if (node.HasAttributes) { foreach (var attribute in node.Attributes()) { node_builder.AppendFormat("{0}=\"{1}\" ", attribute.Name, attribute.Value); } }
454 string node_text = string.Format("{0}>", node_builder.ToString().TrimEnd(new char[] { ' ' }));
455 throw new Exception(string.Format("Unable to find a compatible handler to parse node: {0}", node_text));
456 }
457 }
458 else
459 {
460 xmltv_logger.Verbose.Debug.WriteLine("Created handler for node: '{0}'", node.Name.ToString());
461 raw_instance = Activator.CreateInstance(handler_type, flags, null, new object[] { gInstance, node }, culture);
462 }
463 raw_instance = null;
464 flags = 0;
465 culture = null;
466 node = null;
467 return true;
468 }
469 #region UnhandledExtraMetaData
470 private class UnhandledNodeData : XMLTVBase<XMLTVRuntimeInstance>
471 {
472 public UnhandledNodeData() : base(null, null) { }
473 public UnhandledNodeData(XMLTVRuntimeInstance instance, XElement node)
474 : base(instance, null)
475 {
476 if (node == null) { throw new NullReferenceException("The node instance was null"); }
477 xmltv_logger.Verbose.Debug.WriteLine("Parsng unhandled node data: {0}", node.Name.ToString());
478 if (this.GetInstance() != null)
479 {
480 ExtraMetaData data = new ExtraMetaData(node);
481 instance.ExtraEntries.Add(data);
482 data = null;
483 }
484 node = null;
485 }
486 }
487 #endregion
488
489 }
490 }

  ViewVC Help
Powered by ViewVC 1.1.22