Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. /*
  2. * Copyright (c) 2006-2007 Chris Smith, Shane Mc Cormack, Gregory Holmes
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a copy
  5. * of this software and associated documentation files (the "Software"), to deal
  6. * in the Software without restriction, including without limitation the rights
  7. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. * copies of the Software, and to permit persons to whom the Software is
  9. * furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  20. * SOFTWARE.
  21. */
  22. package com.dmdirc.commandparser.commands.global;
  23. import com.dmdirc.Main;
  24. import com.dmdirc.Server;
  25. import com.dmdirc.commandparser.CommandManager;
  26. import com.dmdirc.commandparser.commands.GlobalCommand;
  27. import com.dmdirc.commandparser.commands.IntelligentCommand;
  28. import com.dmdirc.config.ConfigManager;
  29. import com.dmdirc.config.Identity;
  30. import com.dmdirc.config.IdentityManager;
  31. import com.dmdirc.logger.ErrorLevel;
  32. import com.dmdirc.logger.Logger;
  33. import com.dmdirc.ui.input.AdditionalTabTargets;
  34. import com.dmdirc.ui.interfaces.InputWindow;
  35. import com.dmdirc.updater.UpdateChecker;
  36. import java.io.Serializable;
  37. import java.util.Comparator;
  38. import java.util.List;
  39. import java.util.Map;
  40. import java.util.Map.Entry;
  41. import java.util.TreeSet;
  42. /**
  43. * Provides various handy ways to test or debug the client.
  44. *
  45. * @author Chris
  46. */
  47. public class Debug extends GlobalCommand implements IntelligentCommand {
  48. /**
  49. * Creates a new instance of Debug.
  50. */
  51. public Debug() {
  52. CommandManager.registerCommand(this);
  53. }
  54. /** {@inheritDoc} */
  55. @Override
  56. public void execute(final InputWindow origin, final boolean isSilent, final String ... args) {
  57. if (args.length == 0) {
  58. showUsage(origin, isSilent, "debug", "<debug command> [options]");
  59. } else if ("error".equals(args[0])) {
  60. doError(args);
  61. } else if ("fakeupdate".equals(args[0])) {
  62. doFakeUpdate();
  63. } else if ("showraw".equals(args[0])) {
  64. doShowRaw(origin, isSilent);
  65. } else if ("configstats".equals(args[0])) {
  66. doConfigStats(origin, isSilent);
  67. } else if ("configinfo".equals(args[0])) {
  68. doConfigInfo(origin, isSilent);
  69. } else if ("globalconfiginfo".equals(args[0])) {
  70. doGlobalConfigInfo(origin, isSilent);
  71. } else if ("colourspam".equals(args[0])) {
  72. doColourSpam(origin, isSilent);
  73. } else if ("meminfo".equals(args[0])) {
  74. doMemInfo(origin, isSilent);
  75. } else if ("rungc".equals(args[0])) {
  76. doGarbage(origin, isSilent);
  77. } else if ("forceupdate".equals(args[0])) {
  78. doForceUpdate();
  79. } else if ("serverinfo".equals(args[0])) {
  80. doServerInfo(origin, isSilent);
  81. } else if ("benchmark".equals(args[0])) {
  82. doBenchmark(origin, isSilent);
  83. } else if ("firstrun".equals(args[0])) {
  84. Main.getUI().showFirstRunWizard();
  85. } else if ("migration".equals(args[0])) {
  86. Main.getUI().showMigrationWizard();
  87. } else {
  88. sendLine(origin, isSilent, FORMAT_ERROR, "Unknown debug action.");
  89. }
  90. }
  91. /**
  92. * Generates a fake error.
  93. *
  94. * @param args The arguments that were passed to the command
  95. */
  96. private void doError(final String ... args) {
  97. ErrorLevel el = ErrorLevel.HIGH;
  98. if (args.length > 2) {
  99. String level = args[2];
  100. if (level.equals("low")) {
  101. el = ErrorLevel.LOW;
  102. } else if (level.equals("medium")) {
  103. el = ErrorLevel.MEDIUM;
  104. } else if (level.equals("fatal")) {
  105. el = ErrorLevel.FATAL;
  106. } else if (level.equals("unknown")) {
  107. el = ErrorLevel.UNKNOWN;
  108. }
  109. }
  110. if (args.length > 1 && args[1].equals("user")) {
  111. Logger.userError(el, "Debug error message");
  112. } else {
  113. Logger.appError(el, "Debug error message", new Exception());
  114. }
  115. }
  116. /**
  117. * Fakes an available update.
  118. */
  119. private void doFakeUpdate() {
  120. new UpdateChecker().doUpdateAvailable("outofdate dummy 1337 0 http://www.example.com/");
  121. }
  122. /**
  123. * Attempts to show the server's raw window.
  124. *
  125. * @param origin The window this command was executed in
  126. * @param isSilent Whether this command has been silenced or not
  127. */
  128. private void doShowRaw(final InputWindow origin, final boolean isSilent) {
  129. if (origin == null || origin.getContainer() == null
  130. || origin.getContainer().getServer() == null) {
  131. sendLine(origin, isSilent, FORMAT_ERROR, "Cannot show raw window here.");
  132. } else {
  133. origin.getContainer().getServer().addRaw();
  134. }
  135. }
  136. /**
  137. * Shows stats related to the config system.
  138. *
  139. * @param origin The window this command was executed in
  140. * @param isSilent Whether this command has been silenced or not
  141. */
  142. private void doConfigStats(final InputWindow origin, final boolean isSilent) {
  143. final TreeSet<Entry<String, Integer>> sortedStats =
  144. new TreeSet<Entry<String, Integer>>(new ValueComparator());
  145. sortedStats.addAll(ConfigManager.getStats().entrySet());
  146. for (Map.Entry<String, Integer> entry : sortedStats) {
  147. sendLine(origin, isSilent, FORMAT_OUTPUT,
  148. entry.getKey() + " - " + entry.getValue());
  149. }
  150. }
  151. /**
  152. * Shows memory usage information.
  153. *
  154. * @param origin The window this command was executed in
  155. * @param isSilent Whether this command has been silenced or not
  156. */
  157. private void doMemInfo(final InputWindow origin, final boolean isSilent) {
  158. sendLine(origin, isSilent, FORMAT_OUTPUT, "Total Memory: "
  159. + Runtime.getRuntime().totalMemory());
  160. sendLine(origin, isSilent, FORMAT_OUTPUT, "Free Memory: "
  161. + Runtime.getRuntime().freeMemory());
  162. sendLine(origin, isSilent, FORMAT_OUTPUT, "Used Memory: "
  163. + (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()));
  164. }
  165. /**
  166. * Outputs 100 lines containing various colours.
  167. *
  168. * @param origin The window this command was executed in
  169. * @param isSilent Whether this command has been silenced or not
  170. */
  171. private void doColourSpam(final InputWindow origin, final boolean isSilent) {
  172. for (int i = 0; i < 100; i++) {
  173. sendLine(origin, isSilent, FORMAT_OUTPUT, ((char) 3) + "5Colour! "
  174. + ((char) 3) + "6Colour! " + ((char) 3) + "7Colour! "
  175. + ((char) 3) + "6Colour! " + ((char) 3) + "7Colour! "
  176. + ((char) 3) + "6Colour! " + ((char) 3) + "7Colour! "
  177. + ((char) 3) + "6Colour! " + ((char) 3) + "7Colour! ");
  178. }
  179. }
  180. /**
  181. * Manually runs the garbage collector.
  182. *
  183. * @param origin The window this command was executed in
  184. * @param isSilent Whether this command has been silenced or not
  185. */
  186. private void doGarbage(final InputWindow origin, final boolean isSilent) {
  187. System.gc();
  188. sendLine(origin, isSilent, FORMAT_OUTPUT, "Invoked garbage collector.");
  189. }
  190. /**
  191. * Shows information about the config manager.
  192. *
  193. * @param origin The window this command was executed in
  194. * @param isSilent Whether this command has been silenced or not
  195. */
  196. private void doConfigInfo(final InputWindow origin, final boolean isSilent) {
  197. for (Identity source : origin.getConfigManager().getSources()) {
  198. sendLine(origin, isSilent, FORMAT_OUTPUT, source.getTarget() + " - "
  199. + source + "(" + source.getTarget().getOrder() + ")");
  200. }
  201. }
  202. /**
  203. * Shows information about the global config manager.
  204. *
  205. * @param origin The window this command was executed in
  206. * @param isSilent Whether this command has been silenced or not
  207. */
  208. private void doGlobalConfigInfo(final InputWindow origin, final boolean isSilent) {
  209. for (Identity source : IdentityManager.getGlobalConfig().getSources()) {
  210. sendLine(origin, isSilent, FORMAT_OUTPUT, source.getTarget() + " - "
  211. + source + "(" + source.getTarget().getOrder() + ")");
  212. }
  213. }
  214. /**
  215. * Forces the update checker to check for updates.
  216. */
  217. private void doForceUpdate() {
  218. new Thread(new UpdateChecker(), "Forced update checker").start();
  219. }
  220. /**
  221. * Shows information about the current server.
  222. *
  223. * @param origin The window this command was executed in
  224. * @param isSilent Whether this command has been silenced or not
  225. */
  226. private void doServerInfo(final InputWindow origin, final boolean isSilent) {
  227. if (origin.getContainer().getServer() == null) {
  228. sendLine(origin, isSilent, FORMAT_ERROR, "This window isn't connected to a server");
  229. } else {
  230. final Server server = origin.getContainer().getServer();
  231. sendLine(origin, isSilent, FORMAT_OUTPUT, "Server name: " + server.getName());
  232. sendLine(origin, isSilent, FORMAT_OUTPUT, "Actual name: "
  233. + server.getParser().getServerName());
  234. sendLine(origin, isSilent, FORMAT_OUTPUT, "Network: " + server.getNetwork());
  235. sendLine(origin, isSilent, FORMAT_OUTPUT, "IRCd: "
  236. + server.getParser().getIRCD(false) + " - "
  237. + server.getParser().getIRCD(true));
  238. sendLine(origin, isSilent, FORMAT_OUTPUT, "Modes: "
  239. + server.getParser().getBoolChanModes() + " "
  240. + server.getParser().getListChanModes() + " "
  241. + server.getParser().getSetOnlyChanModes() + " "
  242. + server.getParser().getSetUnsetChanModes());
  243. }
  244. }
  245. /**
  246. * Benchmarks the textpane.
  247. *
  248. * @param origin The window this command was executed in
  249. * @param isSilent Whether this command has been silenced or not
  250. */
  251. private void doBenchmark(final InputWindow origin, final boolean isSilent) {
  252. long[] results = new long[10];
  253. for (int i = 0; i < results.length; i++) {
  254. long start = System.nanoTime();
  255. for (int j = 0; j < 5000; j++) {
  256. origin.addLine(FORMAT_OUTPUT, "This is a benchmark. Lorem ipsum doler...");
  257. }
  258. long end = System.nanoTime();
  259. results[i] = end - start;
  260. }
  261. for (int i = 0; i < results.length; i++) {
  262. origin.addLine(FORMAT_OUTPUT, "Iteration " + i + ": " + results[i] + " nanoseconds.");
  263. }
  264. }
  265. /** {@inheritDoc} */
  266. @Override
  267. public String getName() {
  268. return "debug";
  269. }
  270. /** {@inheritDoc} */
  271. @Override
  272. public boolean showInHelp() {
  273. return false;
  274. }
  275. /** {@inheritDoc} */
  276. @Override
  277. public String getHelp() {
  278. return null;
  279. }
  280. /** {@inheritDoc} */
  281. @Override
  282. public AdditionalTabTargets getSuggestions(int arg, List<String> previousArgs) {
  283. final AdditionalTabTargets res = new AdditionalTabTargets();
  284. res.setIncludeNormal(false);
  285. if (arg == 0) {
  286. res.add("error");
  287. res.add("fakeupdate");
  288. res.add("showraw");
  289. res.add("colourspam");
  290. res.add("configstats");
  291. res.add("meminfo");
  292. res.add("rungc");
  293. res.add("configinfo");
  294. res.add("globalconfiginfo");
  295. res.add("forceupdate");
  296. res.add("serverinfo");
  297. res.add("benchmark");
  298. res.add("firstrun");
  299. res.add("migration");
  300. } else if (arg == 1 && "error".equals(previousArgs.get(0))) {
  301. res.add("user");
  302. res.add("app");
  303. } else if (arg == 2 && "error".equals(previousArgs.get(0))) {
  304. res.add("low");
  305. res.add("medium");
  306. res.add("high");
  307. res.add("fatal");
  308. res.add("unknown");
  309. }
  310. return res;
  311. }
  312. /** Reverse value comparator for a map entry. */
  313. private static class ValueComparator implements
  314. Comparator<Entry<String, Integer>>, Serializable {
  315. /**
  316. * A version number for this class. It should be changed whenever the
  317. * class structure is changed (or anything else that would prevent
  318. * serialized objects being unserialized with the new class).
  319. */
  320. private static final long serialVersionUID = 1;
  321. /** Instantiates a new ValueComparator. */
  322. public ValueComparator() {
  323. super();
  324. }
  325. /** {@inheritDoc} */
  326. @Override
  327. public int compare(final Entry<String, Integer> o1,
  328. final Entry<String, Integer> o2) {
  329. int returnValue = o1.getValue().compareTo(o2.getValue()) * -1;
  330. if (returnValue == 0) {
  331. returnValue = o1.getKey().compareToIgnoreCase(o2.getKey());
  332. }
  333. return returnValue;
  334. }
  335. }
  336. }