/[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 107 - (show annotations) (download)
Sun Mar 10 12:58:40 2013 UTC (7 years, 7 months ago) by william
File size: 22318 byte(s)
+ handle unparsed root nodes, just like handling unparsed program nodes

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 List<IXMLTVChannel>();
53 this.Programs = new List<IXMLTVProgram>();
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 List<IExtraMetaData>();
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 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
80 private List<IExtraMetaData> _ExtraEntries;
81 public List<IExtraMetaData> 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 if (!has_default_ctor) { continue; }
345 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 if (handler_value != null && handler_value.ToString() == root_name)
350 {
351 handler_type = type;
352 break;
353 }
354 }
355 }
356 }
357 }
358 }
359 if (handler_type == null)
360 {
361 StringBuilder node_builder = new StringBuilder();
362 node_builder.AppendFormat("<{0} ", root.Name);
363 if (root.HasAttributes) { foreach (var attribute in root.Attributes()) { node_builder.AppendFormat("{0}=\"{1}\" ", attribute.Name, attribute.Value); } }
364 string node_text = string.Format("{0}>", node_builder.ToString().TrimEnd(new char[] { ' ' }));
365 throw new Exception(string.Format("Unable to find a compatible handler to parse node: {0}", node_text));
366 }
367 xmltv_logger.Verbose.Debug.WriteLine("Created handler for root: '{0}'", root_name.ToString());
368 raw_instance = Activator.CreateInstance(handler_type, flags, null, new object[] { gInstance }, culture);
369 }
370
371 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 var iface = type.GetInterface("IXMLTVHandler", true);
389 if (iface != null)
390 {
391 var handler_prop = type.GetProperty("Handler");
392 if (handler_prop != null)
393 {
394 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 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 if (handler_type == null)
413 {
414 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 }
429 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 return true;
435 }
436 #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
454 }
455 }

  ViewVC Help
Powered by ViewVC 1.1.22