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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 107 - (hide annotations) (download)
Sun Mar 10 12:58:40 2013 UTC (7 years, 8 months ago) by william
File size: 22318 byte(s)
+ handle unparsed root nodes, just like handling unparsed program nodes

1 william 36 using System;
2     using System.Collections.Generic;
3     using System.Linq;
4     using System.Text;
5     using libxmltv.Interfaces;
6 william 46 using System.ComponentModel;
7 william 54 using System.Windows.Forms;
8     using System.Threading;
9 william 56 using System.Reflection;
10     using System.Globalization;
11     using System.Diagnostics;
12 william 73 using System.Xml.Linq;
13 william 36
14     namespace libxmltv.Core
15     {
16 william 49 [Serializable]
17 william 56 internal class XMLTVRuntimeInstance : MarshalByRefObject,
18     IXMLTVRuntimeInstance,
19     ISerializer<XMLTVRuntimeInstance>,
20     IGetCreatedInstanceEvent,
21     ISetCreatedInstanceEvent,
22     IDestroyInstance,
23     IRuntimeInstanceLoader<XMLTVRuntimeInstance>
24 william 36 {
25 william 56 [NonSerialized]
26 william 54 Thread worker;
27 william 72 public XMLTVRuntimeInstance() { init(); }
28     public XMLTVRuntimeInstance(string xmlfile) : this(xmlfile, null) { }
29     public XMLTVRuntimeInstance(string xmlfile, EventHandler<EventArgs> handler)
30     : this()
31 william 56 {
32 william 72 this.OnInstanceCreated += handler;
33     worker = new Thread(new ParameterizedThreadStart(CreateInstance)); worker.Start(xmlfile);
34 william 56 }
35 william 72 private void CreateInstance(object xmlfile)
36 william 54 {
37 william 72 using (XMLTVInstance instance = new XMLTVInstance(xmlfile.ToString()))
38 william 45 {
39 william 72 this.LoadFromInstance(instance.GetInstance());
40     OnCreatedInstance(this, new EventArgs());
41 william 45 }
42     }
43 william 72
44     private void OnCreatedInstance(object sender, EventArgs e)
45     {
46     if (OnInstanceCreated != null) { OnInstanceCreated.Invoke(sender, e); }
47     }
48 william 36
49 william 72 private void init()
50     {
51 william 77 this.Source = new XMLTVSource();
52 william 73 this.Channels = new List<IXMLTVChannel>();
53     this.Programs = new List<IXMLTVProgram>();
54 william 72 this.XmlFile_Name = string.Empty;
55     this.XmlFile_FullName = string.Empty;
56     this.XmlDoc = string.Empty;
57     this.OnInstanceCreated = null;
58 william 107 this.ExtraEntries = new List<IExtraMetaData>();
59 william 72 }
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 william 56 private string _XmlDoc;
72 william 73 public string XmlDoc { get { return _XmlDoc; } set { _XmlDoc = value; } }
73 william 77 private IXMLTVSource _Source;
74     public IXMLTVSource Source { get { return _Source; } set { _Source = value; } }
75 william 73 private List<IXMLTVChannel> _Channels;
76     public List<IXMLTVChannel> Channels { get { return _Channels; } set { _Channels = value; } }
77     private List<IXMLTVProgram> _Programs;
78     public List<IXMLTVProgram> Programs { get { return _Programs; } set { _Programs = value; } }
79 william 107
80     private List<IExtraMetaData> _ExtraEntries;
81     public List<IExtraMetaData> ExtraEntries { get { return _ExtraEntries; } set { _ExtraEntries = value; } }
82 william 72 #endregion
83     #region IOnInstanceCreated members
84 william 56 [NonSerialized]
85     private EventHandler<EventArgs> _OnInstanceCreated;
86     public EventHandler<EventArgs> OnInstanceCreated { get { return _OnInstanceCreated; } set { _OnInstanceCreated = value; } }
87 william 72 #endregion
88     #region IGetCreatedInstanceEvent members
89 william 54 public EventHandler<EventArgs> GetOnInstanceCreated() { return OnInstanceCreated; }
90 william 72 #endregion
91     #region ISetCreatedInstanceEvent members
92 william 54 public void SetOnInstanceCreated(EventHandler<EventArgs> event_instance) { OnInstanceCreated = event_instance; }
93 william 72 #endregion
94     #region ISerializer<XMLTVRuntimeInstance> members
95     public IXMLTVSerializer<XMLTVRuntimeInstance> Serializer { get { return new XMLTVSerializer<XMLTVRuntimeInstance>(this); } }
96     #endregion
97     #region IDestroyInstance member
98 william 54 public void DestroyInstance()
99 william 46 {
100 william 55 xmltv_logger.Debug.WriteLine("Destoying Instance of: '{0}'", this.GetType().Name);
101 william 54 this.IsAborting = true;
102     if (worker == null)
103 william 46 {
104 william 55 xmltv_logger.Debug.WriteLine("Unable to destroy instance of: '{0}' - worker thread is null", this.GetType().Name);
105 william 54 return;
106 william 46 }
107 william 54 else
108     {
109     if (worker.IsAlive)
110     {
111 william 55 xmltv_logger.Verbose.Debug.WriteLine("Requesting Instance to Abort...");
112 william 72 while (worker.IsAlive) { worker.Abort(); Application.DoEvents(); }
113 william 54 }
114 william 72 else { xmltv_logger.Debug.WriteLine("Instance of: '{0}'- already destroyed.", this.GetType().Name); }
115 william 54 }
116 william 46 }
117 william 72 #endregion
118     #region IRuntimeInstanceLoader<XMLTVRuntimeInstance> member
119 william 56 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 william 72 xmltv_logger.Debug.WriteLine("Loading from instance...");
126 william 76 CloneFromInstance(ref instance);
127     xmltv_logger.Debug.WriteLine("Loaded from instance...");
128 william 72 if (this.Source != null)
129 william 56 {
130 william 77 xmltv_logger.Info.WriteLine("Source Loaded: '{0}' Created by '{1}' - original source file: '{2}'", this.Source.SourceName, this.Source.GeneratorName, this.XmlFile_FullName);
131 william 56 }
132     else
133     {
134 william 72 xmltv_logger.Error.WriteLine("Source Property is null.");
135     throw new NullReferenceException("Source Property is null.");
136 william 56 }
137 william 72 if (this.Channels != null)
138 william 56 {
139 william 77 xmltv_logger.Info.WriteLine("Source Loaded: '{0}' Channels from source '{1}'", this.Channels.Count, this.Source.SourceName);
140 william 56 }
141     else
142     {
143 william 72 xmltv_logger.Error.WriteLine("Channels Property is null.");
144     throw new NullReferenceException("Channels Property is null.");
145 william 56 }
146 william 72 if (this.Programs != null)
147 william 56 {
148 william 77 xmltv_logger.Info.WriteLine("Source Loaded: '{0}' Programs from source '{1}'", this.Programs.Count, this.Source.SourceName);
149 william 56 }
150     else
151     {
152 william 72 xmltv_logger.Error.WriteLine("Programs Property is null.");
153     throw new NullReferenceException("Programs Property is null.");
154 william 76 }
155 william 56 return instance;
156     }
157 william 72 #endregion
158     #region CloneFromInstance
159 william 56 private void CloneFromInstance(ref XMLTVRuntimeInstance instance)
160     {
161 william 72 xmltv_logger.Debug.WriteLine("Cloning from instance...");
162 william 56 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 william 72 if (field.IsNotSerialized) { continue; }
170     var f = instance.GetType().GetField(field.Name, flags);
171     var v = f.GetValue(instance);
172     if (v != null)
173 william 56 {
174 william 72 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 william 56 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 william 72 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 william 56 }
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 william 72 xmltv_logger.Debug.WriteLine("Cloned from instance...");
219 william 56 }
220 william 72 #endregion
221 william 36 }
222    
223 william 72 internal class XMLTVInstance : IGetInstance<XMLTVRuntimeInstance>, IDisposable
224 william 36 {
225 william 73 public void Dispose()
226     {
227     //throw new NotImplementedException();
228     }
229    
230 william 72 private XMLTVRuntimeInstance gInstance;
231     public XMLTVRuntimeInstance GetInstance() { return gInstance; }
232     public XMLTVInstance(string xmlfile)
233     {
234     try
235     {
236     CreateLoader(xmlfile);
237 william 73 CreateParser();
238 william 72 }
239 william 79 catch (ThreadAbortException ex) { Debug.WriteLine(ex.ToString()); }
240 william 72 catch (Exception ex)
241     {
242     xmltv_logger.Error.WriteLine(ex.ToString());
243     }
244 william 36 }
245    
246 william 72 private void CreateLoader(string xml_file)
247 william 36 {
248 william 81 xmltv_logger.Verbose.Debug.WriteLine("Creating loader handle");
249 william 72 gInstance = new XMLTVRuntimeInstance();
250     object raw_instance = null;
251 william 81 BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
252     CultureInfo culture = CultureInfo.CurrentCulture;
253 william 72 Assembly asm = Assembly.GetExecutingAssembly();
254     var types = asm.GetTypes();
255 william 81 Type handler_type = null;
256 william 72 foreach (var type in types)
257     {
258     if (type.BaseType != null && type.BaseType == typeof(XMLTVBase<XMLTVRuntimeInstance>))
259     {
260 william 81 //xmltv_logger.Verbose.Debug.WriteLine("Type: '{0}' Base: '{1}'", type.Name, type.BaseType == null ? "none" : type.BaseType.Name);
261 william 72 object[] args = new object[] { xml_file, gInstance };
262 william 81 var iface = type.GetInterface("IXMLTVHandler", true);
263     if (iface != null)
264 william 72 {
265 william 81 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 william 72 }
284     }
285     }
286 william 81 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 william 72 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 william 36 }
294 william 73 private void CreateParser()
295 william 36 {
296 william 73 var doc = XDocument.Parse(this.GetInstance().XmlDoc);
297 william 76 var root_element = doc.Root;
298 william 74 CreateHandlerForRootNode(root_element);
299 william 76 var nodes = doc.Root.Elements().ToList();
300 william 72
301 william 76 double total_nodes = nodes.Count;
302     double node_index = 0;
303     double progress = 0;
304 william 74 foreach(var node in nodes)
305     {
306 william 78 if (this.GetInstance().IsAborting)
307     {
308     break;
309     }
310 william 76 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 william 74 }
316 william 36 }
317 william 44
318 william 73
319 william 74 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 william 73 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 william 81 {
335     var iface = type.GetInterface("IXMLTVHandler", true);
336     if (iface != null)
337 william 73 {
338     var handler_prop = type.GetProperty("Handler");
339     if (handler_prop != null)
340     {
341 william 81 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     if (!has_default_ctor) { continue; }
345 william 73 raw_instance = Activator.CreateInstance(type, flags, null, new object[0], culture);
346     if (raw_instance != null)
347     {
348     object handler_value = handler_prop.GetValue(raw_instance, null);
349 william 74 if (handler_value != null && handler_value.ToString() == root_name)
350 william 73 {
351     handler_type = type;
352     break;
353     }
354 william 81 }
355 william 73 }
356     }
357     }
358     }
359 william 82 if (handler_type == null)
360     {
361     StringBuilder node_builder = new StringBuilder();
362     node_builder.AppendFormat("<{0} ", root.Name);
363 william 83 if (root.HasAttributes) { foreach (var attribute in root.Attributes()) { node_builder.AppendFormat("{0}=\"{1}\" ", attribute.Name, attribute.Value); } }
364 william 82 string node_text = string.Format("{0}>", node_builder.ToString().TrimEnd(new char[] { ' ' }));
365 william 83 throw new Exception(string.Format("Unable to find a compatible handler to parse node: {0}", node_text));
366 william 82 }
367 william 74 xmltv_logger.Verbose.Debug.WriteLine("Created handler for root: '{0}'", root_name.ToString());
368 william 73 raw_instance = Activator.CreateInstance(handler_type, flags, null, new object[] { gInstance }, culture);
369 william 44 }
370 william 72
371 william 74 private bool CreateHandlerForNode(XElement node)
372     {
373     if (node == null) { throw new NullReferenceException("Node element is null"); }
374     if (node.Name == null) { throw new NullReferenceException("Node element's Name is null"); }
375     var node_name = node.Name.ToString();
376    
377     xmltv_logger.Verbose.Debug.WriteLine("Creating handler for node: '{0}'", node_name.ToString());
378     object raw_instance = null;
379     BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
380     CultureInfo culture = CultureInfo.CurrentCulture;
381     Assembly asm = Assembly.GetExecutingAssembly();
382     var types = asm.GetTypes();
383     Type handler_type = null;
384     foreach (var type in types)
385     {
386     if (type.BaseType != null && type.BaseType == typeof(XMLTVBase<XMLTVRuntimeInstance>))
387     {
388 william 81 var iface = type.GetInterface("IXMLTVHandler", true);
389     if (iface != null)
390 william 74 {
391     var handler_prop = type.GetProperty("Handler");
392     if (handler_prop != null)
393     {
394 william 81 var ctors = type.GetConstructors(flags);
395     bool has_default_ctor = false;
396     foreach (var ctor in ctors) { if (ctor.GetParameters().Count() == 0) { has_default_ctor = true; } }
397     if (!has_default_ctor) { continue; }
398 william 74 raw_instance = Activator.CreateInstance(type, flags, null, new object[0], culture);
399     if (raw_instance != null)
400     {
401     object handler_value = handler_prop.GetValue(raw_instance, null);
402     if (handler_value != null && handler_value.ToString() == node_name)
403     {
404     handler_type = type;
405     break;
406     }
407     }
408     }
409     }
410     }
411     }
412 william 107 if (handler_type == null)
413 william 82 {
414 william 107 try
415     {
416     raw_instance = Activator.CreateInstance(typeof(UnhandledNodeData), flags, null, new object[] { gInstance, node }, culture);
417     }
418     catch (Exception ex) { throw ex; }
419    
420     if (raw_instance == null)
421     {
422     StringBuilder node_builder = new StringBuilder();
423     node_builder.AppendFormat("<{0} ", node.Name);
424     if (node.HasAttributes) { foreach (var attribute in node.Attributes()) { node_builder.AppendFormat("{0}=\"{1}\" ", attribute.Name, attribute.Value); } }
425     string node_text = string.Format("{0}>", node_builder.ToString().TrimEnd(new char[] { ' ' }));
426     throw new Exception(string.Format("Unable to find a compatible handler to parse node: {0}", node_text));
427     }
428 william 82 }
429 william 107 else
430     {
431     xmltv_logger.Verbose.Debug.WriteLine("Created handler for node: '{0}'", node_name.ToString());
432     raw_instance = Activator.CreateInstance(handler_type, flags, null, new object[] { gInstance, node }, culture);
433     }
434 william 74 return true;
435     }
436 william 107 #region UnhandledExtraMetaData
437     private class UnhandledNodeData : XMLTVBase<XMLTVRuntimeInstance>
438     {
439     public UnhandledNodeData() : base(null, null) { }
440     public UnhandledNodeData(XMLTVRuntimeInstance instance, XElement node)
441     : base(instance, null)
442     {
443     if (node == null) { throw new NullReferenceException("The node instance was null"); }
444     xmltv_logger.Verbose.Debug.WriteLine("Parsng unhandled node data: {0}", node.Name.ToString());
445     if (this.GetInstance() != null)
446     {
447     ExtraMetaData data = new ExtraMetaData(node);
448     instance.ExtraEntries.Add(data);
449     }
450     }
451     }
452     #endregion
453 william 72
454 william 36 }
455     }

  ViewVC Help
Powered by ViewVC 1.1.22