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

  ViewVC Help
Powered by ViewVC 1.1.22