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

  ViewVC Help
Powered by ViewVC 1.1.22