/[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 192 - (show annotations) (download)
Sat Mar 16 20:14:46 2013 UTC (7 years, 5 months ago) by william
File size: 23652 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 xmltv_logger.Info.WriteLine("Source Loaded: '{0}' Channels from source '{1}'", this.Channels.Count, this.Source.SourceName);
142 }
143 else
144 {
145 xmltv_logger.Error.WriteLine("Channels Property is null.");
146 throw new NullReferenceException("Channels Property is null.");
147 }
148 if (this.Programs != null)
149 {
150 xmltv_logger.Info.WriteLine("Source Loaded: '{0}' Programs from source '{1}'", this.Programs.Count, this.Source.SourceName);
151 }
152 else
153 {
154 xmltv_logger.Error.WriteLine("Programs Property is null.");
155 throw new NullReferenceException("Programs Property is null.");
156 }
157 return instance;
158 }
159 #endregion
160 #region CloneFromInstance
161 private void CloneFromInstance(ref XMLTVRuntimeInstance instance)
162 {
163 xmltv_logger.Debug.WriteLine("Cloning from instance...");
164 BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
165 CultureInfo culture = CultureInfo.CurrentCulture;
166 Type t = typeof(XMLTVRuntimeInstance);
167 foreach (var field in t.GetFields(flags))
168 {
169 try
170 {
171 if (field.IsNotSerialized) { continue; }
172 var f = instance.GetType().GetField(field.Name, flags);
173 var v = f.GetValue(instance);
174 if (v != null)
175 {
176 field.SetValue(this, v);
177 }
178 else
179 {
180 xmltv_logger.Debug.WriteLine("Attempted to set field: '{0}' with a null value. The operation was aborted.", f.Name);
181 continue;
182 }
183 }
184 catch (Exception ex)
185 {
186 throw new Exception(string.Format("Unable to copy value for field: '{0}' from instance", field.Name), ex);
187 }
188 }
189 foreach (var property in t.GetProperties(flags))
190 {
191 try
192 {
193 var f = instance.GetType().GetProperty(property.Name);
194 object value = null;
195 try
196 {
197 value = f.GetValue(instance, null);
198 }
199 catch (ArgumentException ex) { if (ex.Message == "Property get method not found.") { Debug.WriteLine(ex.ToString()); } else { throw ex; } }
200 try
201 {
202 if (value != null)
203 {
204 property.SetValue(this, value, null);
205 }
206 else
207 {
208 xmltv_logger.Debug.WriteLine("Attempted to set property: '{0}' with a null value. The operation was aborted.", f.Name);
209 continue;
210 }
211 }
212 catch (ArgumentException ex) { if (ex.Message == "Property set method not found.") { Debug.WriteLine(ex.ToString()); } else { throw ex; } }
213
214 }
215 catch (Exception ex)
216 {
217 throw new Exception(string.Format("Unable to copy value for property: '{0}' from instance", property.Name), ex);
218 }
219 }
220 xmltv_logger.Debug.WriteLine("Cloned from instance...");
221 }
222 #endregion
223 }
224
225 internal class XMLTVInstance : IGetInstance<XMLTVRuntimeInstance>, IDisposable
226 {
227 public void Dispose()
228 {
229 //throw new NotImplementedException();
230 }
231
232 private XMLTVRuntimeInstance gInstance;
233 public XMLTVRuntimeInstance GetInstance() { return gInstance; }
234 public XMLTVInstance(string xmlfile)
235 {
236 try
237 {
238 CreateLoader(xmlfile);
239 CreateParser();
240 }
241 catch (ThreadAbortException ex) { Debug.WriteLine(ex.ToString()); }
242 catch (Exception ex)
243 {
244 xmltv_logger.Error.WriteLine(ex.ToString());
245 }
246 }
247
248 private void CreateLoader(string xml_file)
249 {
250 xmltv_logger.Verbose.Debug.WriteLine("Creating loader handle");
251 gInstance = new XMLTVRuntimeInstance();
252 object raw_instance = null;
253 BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
254 CultureInfo culture = CultureInfo.CurrentCulture;
255 Assembly asm = Assembly.GetExecutingAssembly();
256 var types = asm.GetTypes();
257 Type handler_type = null;
258 foreach (var type in types)
259 {
260 if (type.BaseType != null && type.BaseType == typeof(XMLTVBase<XMLTVRuntimeInstance>))
261 {
262 //xmltv_logger.Verbose.Debug.WriteLine("Type: '{0}' Base: '{1}'", type.Name, type.BaseType == null ? "none" : type.BaseType.Name);
263 object[] args = new object[] { xml_file, gInstance };
264 var iface = type.GetInterface("IXMLTVHandler", true);
265 if (iface != null)
266 {
267 var handler_prop = type.GetProperty("Handler");
268 if (handler_prop != null)
269 {
270 var ctors = type.GetConstructors(flags);
271 bool has_string_ctor = false;
272 foreach (var ctor in ctors) { if (ctor.GetParameters().Count() == 1 && ctor.GetParameters()[0].ParameterType == typeof(string)) { has_string_ctor = true; } }
273 if (!has_string_ctor) { continue; }
274 raw_instance = Activator.CreateInstance(type, flags, null, new object[] { xml_file}, culture);
275 if (raw_instance != null)
276 {
277 object handler_value = handler_prop.GetValue(raw_instance, null);
278 if (handler_value != null && handler_value.ToString() == xml_file)
279 {
280 handler_type = type;
281 break;
282 }
283 }
284 }
285 }
286 }
287 }
288 if (handler_type == null) { throw new Exception("Unable to find a compatible XMLTV Data Loader."); }
289 xmltv_logger.Verbose.Debug.WriteLine("Created loader handle");
290 raw_instance = Activator.CreateInstance(handler_type, flags, null, new object[] {xml_file , gInstance }, culture);
291 if (raw_instance == null) { throw new NullReferenceException("Found a compatible XMLTV Data Loader, but it returned invalid data."); }
292 IGetInstance<XMLTVRuntimeInstance> getter_instance = (raw_instance as IGetInstance<XMLTVRuntimeInstance>);
293 if (getter_instance != null) { gInstance = getter_instance.GetInstance(); }
294 else { throw new Exception("Found a compatible XMLTV Data Loader, but was unable to obtain the instance holding the data"); }
295 }
296 private void CreateParser()
297 {
298 var doc = XDocument.Parse(this.GetInstance().XmlDoc);
299 var root_element = doc.Root;
300 CreateHandlerForRootNode(root_element);
301 var nodes = doc.Root.Elements().ToList();
302
303 double total_nodes = nodes.Count;
304 double node_index = 0;
305 double progress = 0;
306 foreach(var node in nodes)
307 {
308 if (this.GetInstance().IsAborting)
309 {
310 break;
311 }
312 if (!CreateHandlerForNode(node)) { xmltv_logger.Verbose.Debug.WriteLine("Unable to create handler for node: '{0}'", node.Name.ToString()); }
313 node_index++;
314 progress = 100.0 * (node_index / total_nodes);
315 xmltv_logger.ReportProgress(this, new ReportProgressEventArgs((int)progress, string.Format("Loading {0} ==> {1:00}%", this.gInstance.XmlFile_Name, (int)progress)));
316 Application.DoEvents();
317 }
318 }
319
320
321 private void CreateHandlerForRootNode(XElement root)
322 {
323 if (root == null) { throw new NullReferenceException("Root element is null"); }
324 if (root.Name == null) { throw new NullReferenceException("Root element's Name is null"); }
325 var root_name = root.Name.ToString();
326 xmltv_logger.Verbose.Debug.WriteLine("Creating handler for root: '{0}'", root_name.ToString());
327 object raw_instance = null;
328 BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
329 CultureInfo culture = CultureInfo.CurrentCulture;
330 Assembly asm = Assembly.GetExecutingAssembly();
331 var types = asm.GetTypes();
332 Type handler_type = null;
333 foreach (var type in types)
334 {
335 if (type.BaseType != null && type.BaseType == typeof(XMLTVBase<XMLTVRuntimeInstance>))
336 {
337 var iface = type.GetInterface("IXMLTVHandler", true);
338 if (iface != null)
339 {
340 var handler_prop = type.GetProperty("Handler");
341 if (handler_prop != null)
342 {
343 var ctors = type.GetConstructors(flags);
344 bool has_default_ctor = false;
345 foreach (var ctor in ctors) { if (ctor.GetParameters().Count() == 0) { has_default_ctor = true; } }
346 ctors = null;
347 if (!has_default_ctor) { continue; }
348 raw_instance = Activator.CreateInstance(type, flags, null, new object[0], culture);
349 if (raw_instance != null)
350 {
351 object handler_value = handler_prop.GetValue(raw_instance, null);
352 if (handler_value != null && handler_value.ToString() == root_name)
353 {
354 handler_type = type;
355 handler_value = null;
356 raw_instance = null;
357 handler_prop = null;
358 iface = null;
359 break;
360 }
361 handler_value = null;
362 }
363 raw_instance = null;
364 }
365 handler_prop = null;
366 }
367 iface = null;
368 }
369 }
370 asm = null;
371 types = null;
372 if (handler_type == null)
373 {
374 StringBuilder node_builder = new StringBuilder();
375 node_builder.AppendFormat("<{0} ", root.Name);
376 if (root.HasAttributes) { foreach (var attribute in root.Attributes()) { node_builder.AppendFormat("{0}=\"{1}\" ", attribute.Name, attribute.Value); } }
377 string node_text = string.Format("{0}>", node_builder.ToString().TrimEnd(new char[] { ' ' }));
378 throw new Exception(string.Format("Unable to find a compatible handler to parse node: {0}", node_text));
379 }
380 xmltv_logger.Verbose.Debug.WriteLine("Created handler for root: '{0}'", root_name.ToString());
381 raw_instance = Activator.CreateInstance(handler_type, flags, null, new object[] { gInstance }, culture);
382 raw_instance = null;
383 flags = 0;
384 culture = null;
385 }
386
387 private bool CreateHandlerForNode(XElement node)
388 {
389 if (node == null) { throw new NullReferenceException("Node element is null"); }
390 if (node.Name == null) { throw new NullReferenceException("Node element's Name is null"); }
391 //var node_name = node.Name.ToString();
392
393 xmltv_logger.Verbose.Debug.WriteLine("Creating handler for node: '{0}'", node.Name.ToString());
394 object raw_instance = null;
395 BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
396 CultureInfo culture = CultureInfo.CurrentCulture;
397 Assembly asm = Assembly.GetExecutingAssembly();
398 var types = asm.GetTypes();
399 Type handler_type = null;
400 foreach (var type in types)
401 {
402 if (type.BaseType != null && type.BaseType == typeof(XMLTVBase<XMLTVRuntimeInstance>))
403 {
404 var iface = type.GetInterface("IXMLTVHandler", true);
405 if (iface != null)
406 {
407 var handler_prop = type.GetProperty("Handler");
408 if (handler_prop != null)
409 {
410 var ctors = type.GetConstructors(flags);
411 bool has_default_ctor = false;
412 foreach (var ctor in ctors) { if (ctor.GetParameters().Count() == 0) { has_default_ctor = true; } }
413 ctors = null;
414 if (!has_default_ctor) { continue; }
415 raw_instance = Activator.CreateInstance(type, flags, null, new object[0], culture);
416 if (raw_instance != null)
417 {
418 object handler_value = handler_prop.GetValue(raw_instance, null);
419 if (handler_value != null && handler_value.ToString() == node.Name.ToString())
420 {
421 handler_type = type;
422 handler_value = null;
423 raw_instance = null;
424 handler_prop = null;
425 iface = null;
426 break;
427 }
428 handler_value = null;
429 }
430 raw_instance = null;
431 }
432 handler_prop = null;
433 }
434 iface = null;
435 }
436 }
437 asm = null;
438 types = null;
439 if (handler_type == null)
440 {
441 try
442 {
443 raw_instance = Activator.CreateInstance(typeof(UnhandledNodeData), flags, null, new object[] { gInstance, node }, culture);
444 }
445 catch (Exception ex) { throw ex; }
446
447 if (raw_instance == null)
448 {
449 StringBuilder node_builder = new StringBuilder();
450 node_builder.AppendFormat("<{0} ", node.Name);
451 if (node.HasAttributes) { foreach (var attribute in node.Attributes()) { node_builder.AppendFormat("{0}=\"{1}\" ", attribute.Name, attribute.Value); } }
452 string node_text = string.Format("{0}>", node_builder.ToString().TrimEnd(new char[] { ' ' }));
453 throw new Exception(string.Format("Unable to find a compatible handler to parse node: {0}", node_text));
454 }
455 }
456 else
457 {
458 xmltv_logger.Verbose.Debug.WriteLine("Created handler for node: '{0}'", node.Name.ToString());
459 raw_instance = Activator.CreateInstance(handler_type, flags, null, new object[] { gInstance, node }, culture);
460 }
461 raw_instance = null;
462 flags = 0;
463 culture = null;
464 node = null;
465 return true;
466 }
467 #region UnhandledExtraMetaData
468 private class UnhandledNodeData : XMLTVBase<XMLTVRuntimeInstance>
469 {
470 public UnhandledNodeData() : base(null, null) { }
471 public UnhandledNodeData(XMLTVRuntimeInstance instance, XElement node)
472 : base(instance, null)
473 {
474 if (node == null) { throw new NullReferenceException("The node instance was null"); }
475 xmltv_logger.Verbose.Debug.WriteLine("Parsng unhandled node data: {0}", node.Name.ToString());
476 if (this.GetInstance() != null)
477 {
478 ExtraMetaData data = new ExtraMetaData(node);
479 instance.ExtraEntries.Add(data);
480 data = null;
481 }
482 node = null;
483 }
484 }
485 #endregion
486
487 }
488 }

  ViewVC Help
Powered by ViewVC 1.1.22