PageRenderTime 33ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/modules/data/source/temple/data/xml/XMLManager.as

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