PageRenderTime 64ms CodeModel.GetById 30ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/temple/data/xml/XMLManager.as

http://github.com/MediaMonks/Temple
ActionScript | 672 lines | 383 code | 67 blank | 222 comment | 100 complexity | 12651ef394f0eead84e730b30f3a4fab MD5 | raw file
  1. /*
  2. *
  3. * Temple Library for ActionScript 3.0
  4. * Copyright Š 2010 MediaMonks B.V.
  5. * All rights reserved.
  6. *
  7. * http://code.google.com/p/templelibrary/
  8. *
  9. * Redistribution and use in source and binary forms, with or without
  10. * modification, are permitted provided that the following conditions are met:
  11. *
  12. * - Redistributions of source code must retain the above copyright notice,
  13. * this list of conditions and the following disclaimer.
  14. *
  15. * - Redistributions in binary form must reproduce the above copyright notice,
  16. * this list of conditions and the following disclaimer in the documentation
  17. * and/or other materials provided with the distribution.
  18. *
  19. * - Neither the name of the Temple Library nor the names of its contributors
  20. * may be used to endorse or promote products derived from this software
  21. * without specific prior written permission.
  22. *
  23. *
  24. * Temple Library is free software: you can redistribute it and/or modify
  25. * it under the terms of the GNU Lesser General Public License as published by
  26. * the Free Software Foundation, either version 3 of the License, or
  27. * (at your option) any later version.
  28. *
  29. * Temple Library is distributed in the hope that it will be useful,
  30. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  31. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  32. * GNU Lesser General Public License for more details.
  33. *
  34. * You should have received a copy of the GNU Lesser General Public License
  35. * along with Temple Library. If not, see <http://www.gnu.org/licenses/>.
  36. *
  37. */
  38. package temple.data.xml
  39. {
  40. import temple.data.collections.HashMap;
  41. import temple.data.encoding.IDecoder;
  42. import temple.data.url.URLData;
  43. import temple.data.url.URLManager;
  44. import temple.debug.DebugManager;
  45. import temple.debug.IDebuggable;
  46. import temple.debug.errors.TempleError;
  47. import temple.debug.errors.throwError;
  48. import temple.utils.FrameDelay;
  49. import flash.events.Event;
  50. import flash.net.URLRequestMethod;
  51. /**
  52. * The XMLManager loads XML files and parses them directly to typed DataObjects.
  53. * <p>The XMLManager makes use of the URLManager so you can (also) use names instead of url's. You don't have to load the URLManager
  54. * before using the XMLManager, the XMLManager automaticly detects if the URLManager is already loaded and loads it when if not.</p>
  55. *
  56. * <p>By setting the cache options (XMLManager.cacheXML and/or XMLManager.cacheObject) to true you can use the XMLManager as a DataManager,
  57. * since it will store loaded XML files and parsed object in cache. When loading and / or parsing a XML file again, it will take the data
  58. * from cache. This allows you to call a load method several times, without make it actually loads the XML's.
  59. * This will increase performance.</p>
  60. *
  61. * @example If you want "persons.xml" loaded and parsed to PersonData objects:
  62. *
  63. * @includeExample xml/persons.xml
  64. *
  65. * @includeExample vo/PersonData.as
  66. *
  67. * @includeExample XMLManagerExample.as
  68. *
  69. * @author Thijs Broerse
  70. */
  71. public final class XMLManager extends XMLService implements IDebuggable
  72. {
  73. // Cache options
  74. public static const DEFAULT_CACHE_SETTING:int = 0;
  75. public static const CACHE:int = 1;
  76. public static const NO_CACHE:int = 2;
  77. // Singleton
  78. private static var _instance:XMLManager;
  79. // Settings
  80. private static var _CACHE_XML:Boolean = false;
  81. private static var _CACHE_OBJECT:Boolean = false;
  82. /**
  83. * Loads an XML and parses the result to a class. When ready the callback function is called with the parsed object as argument.
  84. *
  85. * @param url The URL of the XML file
  86. * @param objectClass the class which the xml is parses to.
  87. * NOTE: Class must implement IXMLParsable!
  88. * @param node the node in the xml file. NOTE use '.' for nested nodes: "node.node.node"
  89. * @param callback the function that needs to be called when loading and parsing is complete.
  90. * NOTE: the function must accept one (and only one) argument of type objectClass (2nd argument), since the parsed object is returned
  91. * @param sendData an object (name - value) to send with the request
  92. * NOTE: sendData is not used by compaire previous loads. So allways set forceReload to true with a different sendData
  93. * @param method Method to send the sendData object (GET of POST)
  94. * @param forceReload if set to true the xml file is loaded even when it has been loaded before. If set to false, the xml file won't be loaded again
  95. * @param cacheXML indicates if the XML should be keept in memory so won't be loaded again (unless forceReload is not true)
  96. * Possible values are:
  97. * XMLManager.CACHE = cache XML file
  98. * XMLManager.NO_CACHE = do not cache XML file
  99. * XMLManager.DEFAULT_CACHE_SETTING = use the default setting (can be set using XMLManager.cacheXML)
  100. * @param cacheObject indicates if the Object should be keept in memory so won't be parsed again (unless forceReload is not true)
  101. * XMLManager.CACHE = cache object
  102. * XMLManager.NO_CACHE = do not cache object
  103. * XMLManager.DEFAULT_CACHE_SETTING = use the default setting (can be set using XMLManager.cacheObject)
  104. * @param decoder an object that decodes the loaded data before parsing. Needed when de XML is encrypted.
  105. */
  106. public static function loadObject(url:String, objectClass:Class, node:String = null, callback:Function = null, sendData:Object = null, method:String = URLRequestMethod.GET, forceReload:Boolean = false, cacheXML:int = XMLManager.DEFAULT_CACHE_SETTING, cacheObject:int = XMLManager.DEFAULT_CACHE_SETTING, decoder:IDecoder = null):XMLLoadItem
  107. {
  108. if(XMLManager.getInstance()._debug) XMLManager.getInstance().logDebug("loadObject: '" + url + "' to " + objectClass + ", callback:" + callback + ", sendData:" + sendData + ", method: '" + method + "', forceReload:" + forceReload + ", cacheXML:" + cacheXML + ", cacheObject:" + cacheObject + ", decoder:" + decoder);
  109. return XMLManager.getInstance()._load(XMLObjectData.OBJECT, url, url, objectClass, node, callback, sendData, method, forceReload, cacheXML, cacheObject, decoder);
  110. }
  111. /**
  112. * Loads an XML and parses the result to a list of objects. When ready the callback function is called with the parsed objects as array argument.
  113. *
  114. * @param url The URL of the XML file
  115. * @param objectClass the class which the xml is parses to.
  116. * NOTE: Class must implement IXMLParsable!
  117. * @param repeatingNode the repeating node in the xml file. NOTE use '.' for nested nodes: "node.node.node"
  118. * @param callback the function that needs to be called when loading and parsing is complete.
  119. * NOTE: the function must accept one (and only one) argument of type array (2nd argument), since the parsed object is returned
  120. * @param sendData an object (name - value) to send with the request
  121. * NOTE: sendData is not used by compaire previous loads. So allways set forceReload to true with a different sendData
  122. * @param method Method to send the sendData object (GET of POST)
  123. * @param forceReload if set to true the xml file is loaded even when it has been loaded before. If set to false, the xml file won't be loaded again
  124. * @param cacheXML indicates if the XML should be keept in memory so won't be loaded again (unless forceReload is not true)
  125. * Possible values are:
  126. * XMLManager.CACHE = cache XML file
  127. * XMLManager.NO_CACHE = do not cache XML file
  128. * XMLManager.DEFAULT_CACHE_SETTING = use the default setting (can be set using XMLManager.cacheXML)
  129. * @param cacheObject indicates if the List should be keept in memory so won't be parsed again (unless forceReload is not true)
  130. * Possible values are:
  131. * XMLManager.CACHE = cache list
  132. * XMLManager.NO_CACHE = do not cache list
  133. * XMLManager.DEFAULT_CACHE_SETTING = use the default setting (can be set using XMLManager.cacheObject)
  134. * @param decoder an object that decodes the loaded data before parsing. Needed when de XML is encrypted.
  135. */
  136. public static function loadList(url:String, objectClass:Class, repeatingNode:String, callback:Function = null, sendData:Object = null, method:String = URLRequestMethod.GET, forceReload:Boolean = false, cacheXML:int = XMLManager.DEFAULT_CACHE_SETTING, cacheList:int = XMLManager.DEFAULT_CACHE_SETTING, decoder:IDecoder = null):XMLLoadItem
  137. {
  138. if(XMLManager.getInstance()._debug) XMLManager.getInstance().logDebug("loadList: '" + url + "' to " + objectClass + ", callback:" + callback + ", sendData:" + sendData + ", method: '" + method + "', forceReload:" + forceReload + ", cacheXML:" + cacheXML + ", cacheObject:" + cacheList + ", decoder:" + decoder);
  139. return XMLManager.getInstance()._load(XMLObjectData.LIST, url, url, objectClass, repeatingNode, callback, sendData, method, forceReload, cacheXML, cacheList, decoder);
  140. }
  141. /**
  142. * Loads an XML and parses the result to a class. When ready the callback function is called with the parsed object as argument.
  143. *
  144. * @param name The name as defined in de url.xml by the URLManager
  145. * @param objectClass: the class which the xml is parses to.
  146. * NOTE Class must implement IXMLParsable!
  147. * @param node the node in the xml file. NOTE use '.' for nested nodes: "node.node.node"
  148. * @param callback the function that needs to be called when loading and parsing is complete.
  149. * NOTE: the function must accept one (and only one) argument of type objectClass (2nd argument), since the parsed object is returned
  150. * @param sendData an object (name - value) to send with the request
  151. * NOTE: sendData is not used by compaire previous loads. So allways set forceReload to true with a different sendData
  152. * @param method Method to send the sendData object (GET of POST)
  153. * @param forceReload if set to true the xml file is loaded even when it has been loaded before. If set to false, the xml file won't be loaded again
  154. * @param cacheXML indicates if the XML should be keept in memory so won't be loaded again (unless forceReload is not true)
  155. * Possible values are:
  156. * XMLManager.CACHE = cache XML file
  157. * XMLManager.NO_CACHE = do not cache XML file
  158. * XMLManager.DEFAULT_CACHE_SETTING = use the default setting (can be set using XMLManager.cacheXML)
  159. * @param cacheObject indicates if the Object should be keept in memory so won't be parsed again (unless forceReload is not true)
  160. * XMLManager.CACHE = cache object
  161. * XMLManager.NO_CACHE = do not cache object
  162. * XMLManager.DEFAULT_CACHE_SETTING = use the default setting (can be set using XMLManager.cacheObject)
  163. * @param decoder an object that decodes the loaded data before parsing. Needed when de XML is encrypted.
  164. */
  165. public static function loadObjectByName(name:String, objectClass:Class, node:String = null, callback:Function = null, sendData:Object = null, method:String = URLRequestMethod.GET, forceReload:Boolean = false, cacheXML:int = XMLManager.DEFAULT_CACHE_SETTING, cacheObject:int = XMLManager.DEFAULT_CACHE_SETTING, decoder:IDecoder = null):XMLLoadItem
  166. {
  167. if(XMLManager.getInstance()._debug) XMLManager.getInstance().logDebug("loadObjectByName: '" + name + "' to " + objectClass + ", callback:" + callback + ", sendData:" + sendData + ", method: '" + method + "', forceReload:" + forceReload + ", cacheXML:" + cacheXML + ", cacheObject:" + cacheObject + ", decoder:" + decoder);
  168. return XMLManager.getInstance()._load(XMLObjectData.OBJECT, name, null, objectClass, node, callback, sendData, method, forceReload, cacheXML, cacheObject, decoder);
  169. }
  170. /**
  171. * Loads an XML and parses the result to a list of objects. When ready the callback function is called with the parsed objects as array argument.
  172. *
  173. * @param name The name as defined in de url.xml by the URLManager
  174. * @param objectClass the class which the xml is parses to.
  175. * NOTE: Class must implement IXMLParsable!
  176. * @param repeatingNode the repeating node in the xml file. NOTE use '.' for nested nodes: "node.node.node"
  177. * @param callback the function that needs to be called when loading and parsing is complete.
  178. * NOTE: the function must accept one (and only one) argument of type array (2nd argument), since the parsed object is returned
  179. * @param sendData an object (name - value) to send with the request
  180. * NOTE: sendData is not used by compaire previous loads. So allways set forceReload to true with a different sendData
  181. * @param method Method to send the sendData object (GET of POST)
  182. * @param forceReload if set to true the xml file is loaded even when it has been loaded before. If set to false, the xml file won't be loaded again
  183. * @param cacheXML indicates if the XML should be keept in memory so won't be loaded again (unless forceReload is not true)
  184. * Possible values are:
  185. * XMLManager.CACHE = cache XML file
  186. * XMLManager.NO_CACHE = do not cache XML file
  187. * XMLManager.DEFAULT_CACHE_SETTING = use the default setting (can be set using XMLManager.cacheXML)
  188. * @param cacheObject indicates if the List should be keept in memory so won't be parsed again (unless forceReload is not true)
  189. * Possible values are:
  190. * XMLManager.CACHE = cache list
  191. * XMLManager.NO_CACHE = do not cache list
  192. * XMLManager.DEFAULT_CACHE_SETTING = use the default setting (can be set using XMLManager.cacheObject)
  193. * @param decoder an object that decodes the loaded data before parsing. Needed when de XML is encrypted.
  194. */
  195. public static function loadListByName(name:String, objectClass:Class, repeatingNode:String, callback:Function = null, sendData:Object = null, method:String = URLRequestMethod.GET, forceReload:Boolean = false, cacheXML:int = XMLManager.DEFAULT_CACHE_SETTING, cacheList:int = XMLManager.DEFAULT_CACHE_SETTING, decoder:IDecoder = null):XMLLoadItem
  196. {
  197. if(XMLManager.getInstance()._debug) XMLManager.getInstance().logDebug("loadListByName: '" + name + "' to " + objectClass + ", callback:" + callback + ", sendData:" + sendData + ", method: '" + method + "', forceReload:" + forceReload + ", cacheXML:" + cacheXML + ", cacheObject:" + cacheList + ", decoder:" + decoder);
  198. return XMLManager.getInstance()._load(XMLObjectData.LIST, name, null, objectClass, repeatingNode, callback, sendData, method, forceReload, cacheXML, cacheList, decoder);
  199. }
  200. /**
  201. * Returns true is cacheXML is on. CacheXML keeps the loaded XML file in cache and speeds up the process if this XML is used more once.
  202. * This is only the default, at every load call this value can be overruled.
  203. */
  204. public static function get cacheXML():Boolean
  205. {
  206. return XMLManager._CACHE_XML;
  207. }
  208. /**
  209. * Set default cacheXML on or off
  210. */
  211. public static function set cacheXML(value:Boolean):void
  212. {
  213. XMLManager._CACHE_XML = value;
  214. if(XMLManager.getInstance()._debug) XMLManager.getInstance().logDebug("cacheXML: " + XMLManager._CACHE_XML);
  215. }
  216. /**
  217. * Returns true is cacheObject is on. CacheObject keeps the parsed object or list in cache and speeds up the process if this Object is used more once.
  218. * This is only the default, at every load call this value can be overruled.
  219. */
  220. public static function get cacheObject():Boolean
  221. {
  222. return XMLManager._CACHE_OBJECT;
  223. }
  224. /**
  225. * Set default cacheObject on or off
  226. */
  227. public static function set cacheObject(value:Boolean):void
  228. {
  229. XMLManager._CACHE_OBJECT = value;
  230. if(XMLManager.getInstance()._debug) XMLManager.getInstance().logDebug("cacheObject: " + XMLManager._CACHE_OBJECT);
  231. }
  232. /**
  233. * Wrapper function for XMLManager.getInstance().dispatchEvent
  234. */
  235. public static function dispatchEvent(event:Event):Boolean
  236. {
  237. return XMLManager.getInstance().dispatchEvent(event);
  238. }
  239. /**
  240. * Wrapper function for XMLManager.getInstance().addEventListener
  241. */
  242. public static function addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void
  243. {
  244. XMLManager.getInstance().addEventListener(type, listener, useCapture, priority, useWeakReference);
  245. }
  246. /**
  247. * Wrapper function for XMLManager.getInstance().removeEventListener
  248. */
  249. public static function removeEventListener(type:String, listener:Function, useCapture:Boolean = false):void
  250. {
  251. XMLManager.getInstance().removeEventListener(type, listener, useCapture);
  252. }
  253. /**
  254. * Wrapper function for XMLManager.getInstance().removeAllEventsForType
  255. */
  256. public static function removeAllEventsForType(type:String):void
  257. {
  258. XMLManager.getInstance().removeAllStrongEventListenersForType(type);
  259. }
  260. /**
  261. * Wrapper function for XMLManager.getInstance().removeAllEventsForListener
  262. */
  263. public static function removeAllEventsForListener(listener:Function):void
  264. {
  265. XMLManager.getInstance().removeAllStrongEventListenersForListener(listener);
  266. }
  267. /**
  268. * Wrapper function for XMLManager.getInstance().removeAllEventListeners
  269. */
  270. public static function removeAllEventListeners():void
  271. {
  272. XMLManager.getInstance().removeAllEventListeners();
  273. }
  274. /**
  275. * Returns the instance of the XMLManager
  276. */
  277. public static function getInstance():XMLManager
  278. {
  279. if(XMLManager._instance == null) XMLManager._instance = new XMLManager();
  280. return XMLManager._instance;
  281. }
  282. // a list of all XMLLoadData objects
  283. private var _xmlLoadDataList:HashMap;
  284. private var _dispatchAllCompleteEvent:Boolean;
  285. private var _delayedAllCompleteEventCall:FrameDelay;
  286. /**
  287. * @private
  288. */
  289. public function XMLManager()
  290. {
  291. super();
  292. if (_instance) throwError(new TempleError(this, "Singleton, use XMLManager.getInstance() or use static functions"));
  293. this._xmlLoadDataList = new HashMap("XMLManager xmlLoadDataList");
  294. DebugManager.add(this);
  295. }
  296. /**
  297. * @private
  298. */
  299. override public function load(urlData:URLData, sendData:Object = null, method:String = URLRequestMethod.GET):void
  300. {
  301. throwError(new TempleError(this, "load function is not used in this class!"));
  302. // for warnings
  303. urlData;
  304. sendData;
  305. method;
  306. }
  307. /**
  308. * Data is loaded. If decoder is defined, decode data before parsing
  309. */
  310. override protected function handleLoaderEvent(event:XMLLoaderEvent):void
  311. {
  312. var xmlUrlData:XMLLoadItem = XMLLoadItem(this._xmlLoadDataList[event.name]);
  313. if(event.data && xmlUrlData.decoder)
  314. {
  315. if(this._debug) this.logDebug("handleLoaderEvent: data before decoding: " + event.data);
  316. event.data = XML(xmlUrlData.decoder.decode(event.data));
  317. if(this._debug) this.logDebug("handleLoaderEvent: data after decoding: " + event.data);
  318. }
  319. super.handleLoaderEvent(event);
  320. }
  321. override protected function processData(data:XML, name:String):void
  322. {
  323. if(this._debug) this.logDebug("processData: '" + name + "' " + data);
  324. var xmlUrlData:XMLLoadItem = XMLLoadItem(this._xmlLoadDataList[name]);
  325. xmlUrlData._xml = data;
  326. for(var i:int = xmlUrlData.xmlObjectDataList.length - 1;i > -1; --i)
  327. {
  328. var xmlObjectData:XMLObjectData = xmlUrlData.xmlObjectDataList[i];
  329. var object:Object = this.getXMLNode(data, xmlObjectData.node, xmlObjectData.type == XMLObjectData.OBJECT ? XML : XMLList);
  330. if(object == null)
  331. {
  332. this.dispatchEvent(new XMLServiceEvent(XMLServiceEvent.PARSE_ERROR, null, null, null));
  333. this.logError("processData: node '" + xmlObjectData.node + "' does not exist");
  334. }
  335. else
  336. {
  337. if(this._debug && xmlObjectData.node != null) this.logDebug("processData: node = '" + xmlObjectData.node + "' ");
  338. if(this._debug) this.logDebug("processData: object = '" + object + "' ");
  339. var callback:Function;
  340. switch(xmlObjectData.type)
  341. {
  342. case XMLObjectData.LIST:
  343. {
  344. xmlObjectData.setList(this.parseList(XMLList(object), xmlObjectData.objectClass, name));
  345. if(this._debug) this.logDebug("processData: Complete");
  346. this.dispatchEvent(new XMLServiceEvent(XMLServiceEvent.COMPLETE, name, xmlObjectData.list, null));
  347. if(xmlObjectData.callback != null)
  348. {
  349. // Do the callback. First empty the callback before calling it!
  350. callback = xmlObjectData.callback;
  351. xmlObjectData.callback = null;
  352. callback.call(null, xmlObjectData.list);
  353. }
  354. else if(this._debug) this.logDebug("processData: no callback");
  355. break;
  356. }
  357. case XMLObjectData.OBJECT:
  358. {
  359. xmlObjectData.setObject(XMLParser.parseXML(XML(object), xmlObjectData.objectClass));
  360. if (xmlObjectData.object == null)
  361. {
  362. this.onDataParseError(name);
  363. }
  364. else
  365. {
  366. if(this._debug) this.logDebug("processData: Complete");
  367. this.dispatchEvent(new XMLServiceEvent(XMLServiceEvent.COMPLETE, name, null, xmlObjectData.object));
  368. if(xmlObjectData.callback != null)
  369. {
  370. // Do the callback. First empty the callback before calling it!
  371. callback = xmlObjectData.callback;
  372. xmlObjectData.callback = null;
  373. callback.call(null, xmlObjectData.object);
  374. }
  375. else if(this._debug) this.logDebug("processData: no callback");
  376. }
  377. break;
  378. }
  379. default:
  380. {
  381. this.logError("processData: unknown XMLData type: '" + xmlObjectData.type + "'");
  382. break;
  383. }
  384. }
  385. if(xmlObjectData.cache == false){
  386. xmlUrlData.xmlObjectDataList.splice(i, 1);
  387. if(this._debug) this.logDebug("processData: cache for XMLObjectData disabled, remove XMLObjectData");
  388. }
  389. }
  390. }
  391. xmlUrlData.setLoaded();
  392. if(xmlUrlData.cache == false)
  393. {
  394. delete this._xmlLoadDataList[name];
  395. if(this._debug) this.logDebug("processData: cache for XMLUrlData disabled, remove XMLUrlData");
  396. }
  397. }
  398. override protected function handleLoadError(event:XMLLoaderEvent):void
  399. {
  400. super.handleLoadError(event);
  401. delete this._xmlLoadDataList[event.name];
  402. }
  403. private function _load(type:int, name:String, url:String, objectClass:Class, node:String = null, callback:Function = null, sendData:Object = null, method:String = URLRequestMethod.GET, forceReload:Boolean = false, cacheXML:int = DEFAULT_CACHE_SETTING, cacheObject:int = DEFAULT_CACHE_SETTING, decoder:IDecoder = null):XMLLoadItem
  404. {
  405. // Check if we have allready loaded this file, and we don't have to reload (if xml of urlData is filled, it's loaded)
  406. var loadData:XMLLoadItem = this._xmlLoadDataList[name] as XMLLoadItem;
  407. var xmlObjectData:XMLObjectData;
  408. if(!forceReload && loadData && loadData.xml)
  409. {
  410. if(this._debug) this.logDebug("_load: get XML '" + name + "' from cache");
  411. // check if we have allready parsed this xml
  412. xmlObjectData = loadData.findXMLObjectData(objectClass, node);
  413. if(!xmlObjectData)
  414. {
  415. if(this._debug) this.logDebug("_load: parse data");
  416. // parse data
  417. xmlObjectData = new XMLObjectData(type, objectClass, node, this.getCacheSetting(cacheObject, XMLManager._CACHE_OBJECT));
  418. if(xmlObjectData.cache) loadData.addXMLObjectData(xmlObjectData);
  419. }
  420. else if(this._debug) this.logDebug("_load: get parsed object from cache");
  421. switch(type)
  422. {
  423. case XMLObjectData.OBJECT:
  424. {
  425. if(xmlObjectData.object == null)
  426. {
  427. var xml:XML = this.getXMLNode(loadData.xml, xmlObjectData.node, XML) as XML;
  428. if(xml == null)
  429. {
  430. this.dispatchEvent(new XMLServiceEvent(XMLServiceEvent.PARSE_ERROR, null, null, null));
  431. this.logError("processData: node '" + xmlObjectData.node + "' does not exist");
  432. }
  433. else
  434. {
  435. xmlObjectData.setObject(XMLParser.parseXML(xml, objectClass));
  436. }
  437. }
  438. if(callback != null && xmlObjectData.object) callback(xmlObjectData.object as objectClass);
  439. break;
  440. }
  441. case XMLObjectData.LIST:
  442. {
  443. if(xmlObjectData.list == null)
  444. {
  445. var xmlList:XMLList = this.getXMLNode(loadData.xml, xmlObjectData.node, XMLList) as XMLList;
  446. if(xmlList == null)
  447. {
  448. this.dispatchEvent(new XMLServiceEvent(XMLServiceEvent.PARSE_ERROR, null, null, null));
  449. this.logError("processData: node '" + xmlObjectData.node + "' does not exists");
  450. }
  451. else
  452. {
  453. xmlObjectData.setList(XMLParser.parseList(xmlList, objectClass));
  454. }
  455. }
  456. if(callback != null && xmlObjectData.list) callback(xmlObjectData.list);
  457. break;
  458. }
  459. }
  460. if(this._debug) this.logDebug("_load: Complete");
  461. this.dispatchEvent(new XMLServiceEvent(XMLServiceEvent.COMPLETE, name, xmlObjectData.list, xmlObjectData.object));
  462. // Wait a frame before dispatching 'all complete' event, maybe there are more loads
  463. if(!this._dispatchAllCompleteEvent)
  464. {
  465. this._dispatchAllCompleteEvent = true;
  466. this._delayedAllCompleteEventCall = new FrameDelay(this.dispatchAllCompleteEvent);
  467. }
  468. }
  469. else if(!forceReload && loadData)
  470. {
  471. // we have this object, but it's not loaded yet. Add to urlData for later parsing
  472. if(this._debug) this.logDebug("_load: loading current XML started, add to parse queue");
  473. loadData.addXMLObjectData(new XMLObjectData(type, objectClass, node, this.getCacheSetting(cacheXML, _CACHE_OBJECT), callback));
  474. }
  475. else
  476. {
  477. // we don't have the object or forceReload is true, so load it.
  478. if(this._delayedAllCompleteEventCall != null)
  479. {
  480. // We have to load stuff, but next frame the 'all complete' event is dispatched. Kill the call
  481. this._delayedAllCompleteEventCall.destruct();
  482. }
  483. if(loadData)
  484. {
  485. loadData._sendData = sendData;
  486. loadData._decoder = decoder;
  487. loadData._isLoaded = false;
  488. loadData._method = method;
  489. loadData._cache = this.getCacheSetting(cacheXML, _CACHE_OBJECT);
  490. xmlObjectData = loadData.findXMLObjectData(objectClass, node);
  491. }
  492. if(xmlObjectData == null)
  493. {
  494. xmlObjectData = new XMLObjectData(type, objectClass, node, this.getCacheSetting(cacheXML, _CACHE_OBJECT), callback);
  495. if(loadData)
  496. {
  497. loadData.addXMLObjectData(xmlObjectData);
  498. }
  499. else
  500. {
  501. loadData = this._xmlLoadDataList[name] = new XMLLoadItem(name, url, xmlObjectData, sendData, method, this.getCacheSetting(cacheXML, _CACHE_XML), decoder);
  502. }
  503. }
  504. else if(callback != null)
  505. {
  506. xmlObjectData.callback = callback;
  507. }
  508. if(url)
  509. {
  510. super.load(new URLData(url, url), sendData, method);
  511. }
  512. else if(URLManager.isLoaded())
  513. {
  514. super.load(URLManager.getURLDataByName(name), sendData, method);
  515. }
  516. else
  517. {
  518. URLManager.addEventListener(XMLServiceEvent.COMPLETE, handleURLManagerComplete);
  519. if(URLManager.isLoading() == false) URLManager.loadURLs();
  520. }
  521. }
  522. return loadData;
  523. }
  524. /**
  525. * Finds a node in a XML. Function returns Object since the result can be of type XML of XMLList
  526. * @param xml the XML object
  527. * @param node the node to find as a String. The find nested noded you can separate the nodes with a dot, like 'node.node.node'
  528. * @param returnType XML of XMLList, the return value is of this type
  529. */
  530. private function getXMLNode(xml:XML, node:String, returnType:Class):Object
  531. {
  532. if(node == null) return xml;
  533. var a:Array = node.split(".");
  534. var n:Object = xml;
  535. var leni:int = a.length;
  536. for (var i:int = 0;i < leni; i++)
  537. {
  538. n = n[a[i]];
  539. }
  540. if(n is XML && XML(n).toXMLString() == "" || n is XMLList && XMLList(n).toXMLString() == "")
  541. {
  542. this.dispatchEvent(new XMLServiceEvent(XMLServiceEvent.PARSE_ERROR, null, null, null));
  543. return null;
  544. }
  545. if(n is returnType) return n;
  546. if(returnType == XML) return n[0];
  547. var list:XMLList = new XMLList();
  548. list[0] = n;
  549. return list;
  550. }
  551. private function handleURLManagerComplete(event:XMLServiceEvent):void
  552. {
  553. URLManager.removeEventListener(XMLServiceEvent.COMPLETE, handleURLManagerComplete);
  554. for each (var xmlURLData : XMLLoadItem in this._xmlLoadDataList)
  555. {
  556. if(xmlURLData.url == null && !xmlURLData.xml)
  557. {
  558. super.load(URLManager.getURLDataByName(xmlURLData.name), xmlURLData.sendData, xmlURLData.method);
  559. }
  560. }
  561. }
  562. private function dispatchAllCompleteEvent():void
  563. {
  564. if(this._debug) this.logDebug("dispatchAllCompleteEvent: ");
  565. this.dispatchEvent(new XMLServiceEvent(XMLServiceEvent.ALL_COMPLETE));
  566. this._dispatchAllCompleteEvent = false;
  567. }
  568. private function getCacheSetting(cacheXML:int, defaultSetting:Boolean):Boolean
  569. {
  570. switch(cacheXML){
  571. case XMLManager.DEFAULT_CACHE_SETTING:
  572. {
  573. return defaultSetting;
  574. break;
  575. }
  576. case XMLManager.CACHE:
  577. {
  578. return true;
  579. break;
  580. }
  581. case XMLManager.NO_CACHE:
  582. {
  583. return true;
  584. break;
  585. }
  586. default:
  587. {
  588. throwError(new TempleError(this, "Unknown cache setting."));
  589. break;
  590. }
  591. }
  592. return true;
  593. }
  594. /**
  595. * @inheritDoc
  596. */
  597. override public function destruct():void
  598. {
  599. XMLManager._instance = null;
  600. this._xmlLoadDataList = null;
  601. this._delayedAllCompleteEventCall = null;
  602. super.destruct();
  603. }
  604. }
  605. }