PageRenderTime 209ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/src/org/actionstep/ASDebugger.as

http://github.com/shyndman/ActionStep
ActionScript | 457 lines | 293 code | 70 blank | 94 comment | 68 complexity | 53b78cf6611b6ef519ecf98a7731b69b MD5 | raw file
Possible License(s): BSD-3-Clause
  1. /* See LICENSE for copyright and terms of use */
  2. import org.actionstep.debug.ASDebuggingPanel;
  3. import org.actionstep.NSException;
  4. /**
  5. * The ActionStep debugger.
  6. *
  7. * By routing your trace output to <code>ASDebugger.debugPanelTrace</code>, you
  8. * will be shown a debug panel in your output swf that displays formatted trace
  9. * messages.
  10. *
  11. * @author Richard Kilmer
  12. * @author Tay Ray Chuan
  13. * @author Scott Hyndman
  14. */
  15. class org.actionstep.ASDebugger extends org.actionstep.NSObject {
  16. //******************************************************
  17. //* Levels
  18. //******************************************************
  19. static var ALL:Number = 6;
  20. static var DEBUG:Number = 5;
  21. static var INFO:Number = 4;
  22. static var WARNING:Number = 3;
  23. static var ERROR:Number = 2;
  24. static var FATAL:Number = 1;
  25. static var NONE:Number = 0;
  26. static var LEVELS:Array = [
  27. "[NONE]",
  28. "[FATAL]",
  29. "[ERROR]",
  30. "[WARNING]",
  31. "[INFO]",
  32. "[DEBUG]",
  33. "[ALL]"];
  34. //******************************************************
  35. //* Constants
  36. //******************************************************
  37. static var DEFAULT_HOSTNAME:String = "127.0.0.1";
  38. static var DEFAULT_PORT:Number = 4500;
  39. static var DEFAULT_PAD:String = "\t";
  40. //******************************************************
  41. //* Class members
  42. //******************************************************
  43. static var handlers:Array = [];
  44. static var instance:ASDebugger;
  45. static var block:Object;
  46. static var g_level:Number;
  47. //******************************************************
  48. //* Debug helper methods
  49. //******************************************************
  50. public static function debug(object:Object):Object {
  51. return {ASDebuggerObject:object, ASDebuggerLevel:DEBUG};
  52. }
  53. public static function info(object:Object):Object {
  54. return {ASDebuggerObject:object, ASDebuggerLevel:INFO};
  55. }
  56. public static function warning(object:Object):Object {
  57. return {ASDebuggerObject:object, ASDebuggerLevel:WARNING};
  58. }
  59. public static function error(object:Object):Object {
  60. return {ASDebuggerObject:object, ASDebuggerLevel:ERROR};
  61. }
  62. public static function fatal(object:Object):Object {
  63. return {ASDebuggerObject:object, ASDebuggerLevel:FATAL};
  64. }
  65. //******************************************************
  66. //* Member variables
  67. //******************************************************
  68. private var m_hostname:String;
  69. private var m_connected:Boolean;
  70. private var m_identifier:String;
  71. private var m_connection:XMLSocket;
  72. private var m_port:Number;
  73. private var m_pending:Array;
  74. //******************************************************
  75. //* Construction
  76. //******************************************************
  77. /**
  78. * Creates a new instance of the <code>ASDebugger</code> class.
  79. */
  80. private function ASDebugger(hostname:String, given_port:Number) {
  81. if (hostname != undefined) {
  82. this.m_hostname = hostname;
  83. } else {
  84. this.m_hostname = DEFAULT_HOSTNAME;
  85. }
  86. if (given_port != undefined) {
  87. m_port = given_port;
  88. } else {
  89. m_port = DEFAULT_PORT;
  90. }
  91. g_level = DEBUG;
  92. m_pending = [];
  93. }
  94. //******************************************************
  95. //* Trace functions
  96. //******************************************************
  97. /**
  98. * Helper function for ASDebugger.*trace functions. Parses arguments
  99. * and does some string processing, before returning an array containing
  100. * information wanted by the *trace function.
  101. *
  102. * Note: If a <code>null</code> value is returned, parsing failed, or
  103. * <code>object</code> is an instance of <code>NSException</code>
  104. *
  105. * @return <code>null</code> if failed, or <code>Array</code> if
  106. * successful
  107. */
  108. private static function processTrace(object:Object, level:Number, className:String, file:String, line:Number):Array {
  109. // We need to shift all the params if the level is not provided
  110. if (line == undefined) {
  111. line = Number(file);
  112. file = className;
  113. className = String(level);
  114. level = g_level;
  115. }
  116. if (object instanceof NSException) {
  117. NSException(object).addReference(className, file, line);
  118. return null;
  119. }
  120. if (object.ASDebuggerObject != undefined) {
  121. level = object.ASDebuggerLevel;
  122. object = object.ASDebuggerObject;
  123. }
  124. if(level == null) {
  125. if(g_level == null) {
  126. level = DEBUG;
  127. } else {
  128. level = g_level;
  129. }
  130. } else {
  131. if (level >= ALL) {
  132. level = DEBUG;
  133. }
  134. else if (level <= NONE) {
  135. level = FATAL;
  136. }
  137. }
  138. notifyHandlers(object, level, className, file, line);
  139. //don't show abs path
  140. var x:Array = file.split("/");
  141. file = x[x.length-1];
  142. //don't display for some classes
  143. var arr:Array=className.split("::");
  144. var klass:String = arr[0]; //refers to the function to helped
  145. if(block[klass]) {
  146. return null;
  147. }
  148. var func:String = arr[1]; //refers to the function to helped
  149. return [level, klass, line, func, object];
  150. }
  151. /**
  152. * Outputs a message at the supplied level. Level defaults to
  153. * INFO if not supplied. This method is used by the MTASC compiler
  154. * through using the -trace org.actionstep.ASDebugger.trace method.
  155. *
  156. * @param object The object to output (via toString)
  157. * @param level The level (DEBUG, INFO, WARNING, ERROR, FATAL)
  158. * @param className The class the trace is in
  159. * @param file The file the trace is in
  160. * @param line The line number that trace is on
  161. *
  162. */
  163. public static function trace(object:Object, level:Number, className:String, file:String, line:Number) {
  164. if (ASDebugger.instance == undefined) {
  165. ASDebugger.start(g_level);
  166. }
  167. var out:Array = processTrace.apply(arguments.callee, arguments);
  168. if(out == null) { //this means that we have to return
  169. return;
  170. }
  171. // copy out the necessary stuff
  172. level = out[0];
  173. var klass:String = out[1];
  174. line = out[2];
  175. var func:String = out[3];
  176. object=out[4];
  177. // determine whether the message should be traced based on level
  178. if (level > g_level) {
  179. return;
  180. }
  181. ASDebugger.instance.send(LEVELS[level]+" "+object.toString()+" -- "+klass+":"+line+" ("+func+")");
  182. }
  183. /**
  184. * Traces output to an instance of <code>ASDebuggingPanel</code>.
  185. */
  186. public static function debugPanelTrace(object:Object, level:Number, className:String, file:String, line:Number) {
  187. var out:Array = processTrace.apply(arguments.callee, arguments);
  188. if(out == null) {
  189. //this means that we have to return
  190. return;
  191. }
  192. //copy out the necessary stuff
  193. level = out[0];
  194. var klass:String = out[1];
  195. line = out[2];
  196. var func:String = out[3];
  197. object=out[4];
  198. // determine whether the message should be traced based on level
  199. if (level > g_level) {
  200. return;
  201. }
  202. ASDebuggingPanel.traceLine(level, object.toString(), klass, func, line);
  203. }
  204. public static function SWFConsoleTrace(object:Object, level:Number, className:String, file:String, line:Number) {
  205. var out:Array = processTrace.apply(arguments.callee, arguments);
  206. if(out == null) {
  207. //this means that we have to return
  208. return;
  209. }
  210. //copy out the necessary stuff
  211. level = out[0];
  212. var klass:String = out[1];
  213. line = out[2];
  214. var func:String = out[3];
  215. object=out[4];
  216. // determine whether the message should be traced based on level
  217. if (level > g_level) {
  218. return;
  219. }
  220. getURL("javascript:showText('" + LEVELS[level]+" "+object.toString()+" -- "+klass+":"+line+" ("+className.split("::")[1]+")')");
  221. }
  222. /**
  223. * Prints the source of flash var
  224. */
  225. public static function dump(obj:Object, level:Number):String {
  226. if(obj == null) {
  227. return null;
  228. }
  229. if(level==null) {
  230. level=0;
  231. }
  232. var margin:String = "";
  233. var len:Number=level;
  234. while(len--) {
  235. margin+=DEFAULT_PAD;
  236. }
  237. if (obj instanceof XML) {
  238. obj.constructor = XML;
  239. }
  240. switch( obj.constructor ){
  241. case Number:
  242. return obj.toString();
  243. case String:
  244. return "String(" + obj + ")";
  245. case Array:
  246. var els:Array = [];
  247. for(var key:Object in obj){
  248. els[els.length] = "\n"
  249. +margin
  250. + key
  251. + ":"
  252. + dump(obj[key], level+1);
  253. }
  254. return "Array("+els.join(", ")+")";
  255. case XML:
  256. return dumpXmlNode(obj.firstChild);
  257. case XMLNode:
  258. return dumpXmlNode(obj);
  259. case Object:
  260. case TextField: //default + dom
  261. default:
  262. if(obj.toString==Object.prototype.toString) {
  263. var els:Array = [];
  264. for(var key:Object in obj){
  265. els[els.length] = "\n"
  266. +margin
  267. + key
  268. + ":"
  269. + dump(obj[key], level+1);
  270. }
  271. return "Object("+els.join(", ")+")";
  272. } else {
  273. return obj.toString();
  274. }
  275. }
  276. }
  277. public static function dumpXmlNode(node:Object, tabs:String):String {
  278. var str:String = "";
  279. if (tabs == null) {
  280. tabs = "";
  281. }
  282. if (node.nodeValue != undefined) {
  283. str += tabs + node.nodeValue + "\n";
  284. }
  285. else if (node.nodeName != null) {
  286. str += tabs + "&lt;" + node.nodeName;
  287. for (var i:String in node.attributes) {
  288. str += " " + i + "=\"" + node.attributes[i] + "\"";
  289. }
  290. if (node.firstChild != null) {
  291. str += "&gt;\n";
  292. for (var n:Number = 0; n < node.childNodes.length; n++) {
  293. str += dumpXmlNode(node.childNodes[n], tabs + "\t");
  294. }
  295. str += tabs + "&lt;/" + node.nodeName + "&gt;\n";
  296. } else {
  297. str += " /&gt;\n";
  298. }
  299. }
  300. return str;
  301. }
  302. //******************************************************
  303. //* Handlers
  304. //******************************************************
  305. public static function addHandler(obj:Object, sel:String):Void {
  306. handlers.push({obj: obj, sel: sel});
  307. }
  308. public static function notifyHandlers(object:Object, level:Number, className:String, file:String, line:Number) {
  309. var len:Number = handlers.length;
  310. for (var i:Number = 0; i < len; i++) {
  311. var obj:Object = handlers[i].obj;
  312. var sel:String = handlers[i].sel;
  313. obj[sel].call(obj, object, level, className, file, line);
  314. }
  315. }
  316. //******************************************************
  317. //* Levels
  318. //******************************************************
  319. /**
  320. * Sets the level of the debugger
  321. *
  322. * @param level The level (DEBUG, INFO, WARNING, ERROR, FATAL)
  323. */
  324. public static function setLevel(level:Number) {
  325. if (ASDebugger.instance == undefined) {
  326. ASDebugger.start(level);
  327. } else {
  328. ASDebugger.instance.setCurrentLevel(level);
  329. }
  330. }
  331. function setCurrentLevel(value:Number) {
  332. g_level = value;
  333. }
  334. /**
  335. * Returns the level of the debugger.
  336. */
  337. function level():Number {
  338. return g_level;
  339. }
  340. public static function start(level:Number, hostname:String, given_port:Number):ASDebugger {
  341. ASDebugger.instance = new ASDebugger(hostname, given_port);
  342. if (level != undefined) {
  343. ASDebugger.instance.setCurrentLevel(level);
  344. }
  345. ASDebugger.instance.begin();
  346. return ASDebugger.instance;
  347. }
  348. public function begin() {
  349. m_connection = new XMLSocket();
  350. var self:ASDebugger = this;
  351. m_connection.onConnect = function(success:Boolean) {
  352. self.onConnect(success);
  353. };
  354. // used quotes since it's not in mtasc's intrinsics
  355. if(System.security["sandboxType"] == "localTrusted" || System.security["sandboxType"] == "remote") {
  356. m_connection.connect(m_hostname, m_port);
  357. }
  358. }
  359. public function onClose():Void {
  360. }
  361. public function onConnect(isConnected:Boolean):Void {
  362. m_connected = isConnected;
  363. if(isConnected) {
  364. block ={ };
  365. //eg:
  366. //block["org/actionstep/test/ASTestSheet.as"] = true;
  367. var x:String = "";
  368. for(var i:Object in block) {
  369. x+="\n\t"+i+"";
  370. }
  371. if(x!="") {
  372. send(">>Blocked classes:"+x);
  373. }
  374. //spit out pending messages, in chronological order
  375. for(var i:Number=0;i<m_pending.length;i++) {
  376. send(m_pending[i]);
  377. }
  378. }
  379. }
  380. public function send(message:String) {
  381. if(m_connected==true) {
  382. m_connection.send(message);
  383. } else {
  384. m_pending.push(message);
  385. }
  386. }
  387. }