PageRenderTime 62ms CodeModel.GetById 36ms RepoModel.GetById 0ms app.codeStats 0ms

/src/net/sourceforge/kolmafia/StaticEntity.java

http://github.com/mkszuba/kolmafia
Java | 777 lines | 583 code | 151 blank | 43 comment | 124 complexity | 668640e122c1bbfa2743e416ed2d2046 MD5 | raw file
Possible License(s): Apache-2.0, MPL-2.0-no-copyleft-exception, BSD-3-Clause
  1. /**
  2. * Copyright (c) 2005-2013, KoLmafia development team
  3. * http://kolmafia.sourceforge.net/
  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
  8. * are met:
  9. *
  10. * [1] Redistributions of source code must retain the above copyright
  11. * notice, this list of conditions and the following disclaimer.
  12. * [2] Redistributions in binary form must reproduce the above copyright
  13. * notice, this list of conditions and the following disclaimer in
  14. * the documentation and/or other materials provided with the
  15. * distribution.
  16. * [3] Neither the name "KoLmafia" nor the names of its contributors may
  17. * be used to endorse or promote products derived from this software
  18. * without specific prior written permission.
  19. *
  20. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  21. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  22. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  23. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  24. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  25. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  26. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  27. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  28. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  30. * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  31. * POSSIBILITY OF SUCH DAMAGE.
  32. */
  33. package net.sourceforge.kolmafia;
  34. import java.awt.Container;
  35. import java.awt.Frame;
  36. import java.io.BufferedReader;
  37. import java.io.File;
  38. import java.io.IOException;
  39. import java.io.InputStreamReader;
  40. import java.io.PrintStream;
  41. import java.util.ArrayList;
  42. import java.util.Iterator;
  43. import java.util.StringTokenizer;
  44. import net.java.dev.spellcast.utilities.ActionPanel;
  45. import net.java.dev.spellcast.utilities.DataUtilities;
  46. import net.sourceforge.kolmafia.KoLConstants;
  47. import net.sourceforge.kolmafia.preferences.Preferences;
  48. import net.sourceforge.kolmafia.request.GenericRequest;
  49. import net.sourceforge.kolmafia.swingui.DescriptionFrame;
  50. import net.sourceforge.kolmafia.swingui.panel.GenericPanel;
  51. import net.sourceforge.kolmafia.utilities.FileUtilities;
  52. import net.sourceforge.kolmafia.utilities.PauseObject;
  53. import net.sourceforge.kolmafia.utilities.StringUtilities;
  54. public abstract class StaticEntity
  55. {
  56. private static int usesSystemTray = 0;
  57. private static int usesRelayWindows = 0;
  58. private static boolean isGUIRequired = false;
  59. private static boolean isHeadless = System.getProperty( "java.awt.headless", "" ).equals( "true" );
  60. public static final ArrayList<ActionPanel> existingPanels = new ArrayList<ActionPanel>();
  61. private static ActionPanel[] panelArray = new GenericPanel[ 0 ];
  62. public static String backtraceTrigger = null;
  63. public static final String getVersion()
  64. {
  65. return StaticEntity.getVersion( false );
  66. }
  67. public static final String getVersion( final boolean forceRevision )
  68. {
  69. String version = KoLConstants.VERSION_NAME;
  70. if ( !KoLConstants.RELEASED || forceRevision )
  71. {
  72. int revision = StaticEntity.getRevision();
  73. if ( revision != 0 )
  74. {
  75. version += " r" + revision;
  76. }
  77. }
  78. return version;
  79. }
  80. public static final int getRevision()
  81. {
  82. if ( KoLConstants.REVISION == null )
  83. {
  84. return 0;
  85. }
  86. int colonIndex = KoLConstants.REVISION.indexOf( ":" );
  87. String revision = KoLConstants.REVISION;
  88. if ( colonIndex != -1 )
  89. {
  90. revision = KoLConstants.REVISION.substring( 0, colonIndex );
  91. }
  92. else if ( KoLConstants.REVISION.endsWith( "M" ) )
  93. {
  94. revision = KoLConstants.REVISION.substring( 0, KoLConstants.REVISION.length() - 1 );
  95. }
  96. return StringUtilities.isNumeric( revision ) ? StringUtilities.parseInt( revision ) : 0;
  97. }
  98. public static final int parseRevision( String version )
  99. {
  100. if ( version == null )
  101. {
  102. return 0;
  103. }
  104. if ( version.startsWith( "KoLmafia r" ) )
  105. {
  106. version = version.substring( 10 );
  107. }
  108. return StringUtilities.isNumeric( version ) ? StringUtilities.parseInt( version ) : 0;
  109. }
  110. public static final void setGUIRequired( boolean isGUIRequired )
  111. {
  112. StaticEntity.isGUIRequired = isGUIRequired;
  113. }
  114. public static final boolean isGUIRequired()
  115. {
  116. return StaticEntity.isGUIRequired && !StaticEntity.isHeadless;
  117. }
  118. public static final void registerPanel( final ActionPanel panel )
  119. {
  120. synchronized ( StaticEntity.existingPanels )
  121. {
  122. StaticEntity.existingPanels.add( panel );
  123. StaticEntity.getExistingPanels();
  124. }
  125. }
  126. public static final void unregisterPanel( final ActionPanel panel )
  127. {
  128. synchronized ( StaticEntity.existingPanels )
  129. {
  130. StaticEntity.existingPanels.remove( panel );
  131. StaticEntity.getExistingPanels();
  132. }
  133. }
  134. public static final void unregisterPanels( final Container container )
  135. {
  136. boolean removedPanel = false;
  137. synchronized ( StaticEntity.existingPanels )
  138. {
  139. Iterator panelIterator = StaticEntity.existingPanels.iterator();
  140. while ( panelIterator.hasNext() )
  141. {
  142. ActionPanel panel = (ActionPanel) panelIterator.next();
  143. if ( container.isAncestorOf( panel ) )
  144. {
  145. panel.dispose();
  146. panelIterator.remove();
  147. removedPanel = true;
  148. }
  149. }
  150. }
  151. if ( removedPanel )
  152. {
  153. StaticEntity.getExistingPanels();
  154. }
  155. }
  156. public static final ActionPanel[] getExistingPanels()
  157. {
  158. synchronized ( StaticEntity.existingPanels )
  159. {
  160. boolean needsRefresh = StaticEntity.panelArray.length != StaticEntity.existingPanels.size();
  161. if ( !needsRefresh )
  162. {
  163. for ( int i = 0; i < StaticEntity.panelArray.length && !needsRefresh; ++i )
  164. {
  165. needsRefresh = StaticEntity.panelArray[ i ] != StaticEntity.existingPanels.get( i );
  166. }
  167. }
  168. if ( needsRefresh )
  169. {
  170. StaticEntity.panelArray = new ActionPanel[ StaticEntity.existingPanels.size() ];
  171. StaticEntity.existingPanels.toArray( StaticEntity.panelArray );
  172. }
  173. return StaticEntity.panelArray;
  174. }
  175. }
  176. public static final boolean isHeadless()
  177. {
  178. return StaticEntity.isHeadless;
  179. }
  180. public static final boolean usesSystemTray()
  181. {
  182. if ( StaticEntity.usesSystemTray == 0 )
  183. {
  184. StaticEntity.usesSystemTray = 2;
  185. boolean useTrayIcon = Preferences.getBoolean( "useSystemTrayIcon" );
  186. if ( !System.getProperty( "os.name" ).startsWith( "Windows" ) )
  187. {
  188. useTrayIcon = false;
  189. }
  190. String javaArchitecture = System.getProperty( "sun.arch.data.model" );
  191. if ( javaArchitecture == null || !javaArchitecture.equals( "32" ) )
  192. {
  193. useTrayIcon = false;
  194. }
  195. if ( useTrayIcon )
  196. {
  197. try
  198. {
  199. FileUtilities.loadLibrary( KoLConstants.IMAGE_LOCATION, "", "TrayIcon12.dll" );
  200. StaticEntity.usesSystemTray = 1;
  201. }
  202. catch ( Exception e )
  203. {
  204. }
  205. }
  206. }
  207. return StaticEntity.usesSystemTray == 1;
  208. }
  209. public static final boolean usesRelayWindows()
  210. {
  211. if ( StaticEntity.usesRelayWindows == 0 )
  212. {
  213. StaticEntity.usesRelayWindows = Preferences.getBoolean( "useRelayWindows" ) ? 1 : 2;
  214. }
  215. return StaticEntity.usesRelayWindows == 1;
  216. }
  217. /**
  218. * A method used to open a new <code>DescriptionFrame</code> which
  219. * displays the given location, relative to the KoL home directory for
  220. * the current session.
  221. */
  222. public static final void openDescriptionFrame( final String location )
  223. {
  224. DescriptionFrame.showRequest( RequestEditorKit.extractRequest( location ) );
  225. }
  226. public static final boolean executeCountdown( final String message, final int seconds )
  227. {
  228. PauseObject pauser = new PauseObject();
  229. StringBuffer actualMessage = new StringBuffer( message );
  230. for ( int i = seconds; i > 0 && KoLmafia.permitsContinue(); --i )
  231. {
  232. boolean shouldDisplay = false;
  233. // If it's the first count, then it should definitely be shown
  234. // for the countdown.
  235. if ( i == seconds )
  236. {
  237. shouldDisplay = true;
  238. }
  239. else if ( i >= 1800 )
  240. {
  241. shouldDisplay = i % 600 == 0;
  242. }
  243. else if ( i >= 600 )
  244. {
  245. shouldDisplay = i % 300 == 0;
  246. }
  247. else if ( i >= 300 )
  248. {
  249. shouldDisplay = i % 120 == 0;
  250. }
  251. else if ( i >= 60 )
  252. {
  253. shouldDisplay = i % 60 == 0;
  254. }
  255. else if ( i >= 15 )
  256. {
  257. shouldDisplay = i % 15 == 0;
  258. }
  259. else if ( i >= 5 )
  260. {
  261. shouldDisplay = i % 5 == 0;
  262. }
  263. else
  264. {
  265. shouldDisplay = true;
  266. }
  267. // Only display the message if it should be displayed based on
  268. // the above checks.
  269. if ( shouldDisplay )
  270. {
  271. actualMessage.setLength( message.length() );
  272. if ( i >= 60 )
  273. {
  274. int minutes = i / 60;
  275. actualMessage.append( minutes );
  276. actualMessage.append( minutes == 1 ? " minute" : " minutes" );
  277. if ( i % 60 != 0 )
  278. {
  279. actualMessage.append( ", " );
  280. }
  281. }
  282. if ( i % 60 != 0 )
  283. {
  284. actualMessage.append( i % 60 );
  285. actualMessage.append( i % 60 == 1 ? " second" : " seconds" );
  286. }
  287. actualMessage.append( "..." );
  288. KoLmafia.updateDisplay( actualMessage.toString() );
  289. }
  290. pauser.pause( 1000 );
  291. }
  292. return KoLmafia.permitsContinue();
  293. }
  294. public static final void printStackTrace()
  295. {
  296. StaticEntity.printStackTrace( "Forced stack trace" );
  297. }
  298. public static final void printStackTrace( final String message )
  299. {
  300. StaticEntity.printStackTrace( new Exception( message ), message );
  301. }
  302. public static final void printStackTrace( final Throwable t )
  303. {
  304. StaticEntity.printStackTrace( t, "" );
  305. }
  306. public static final void printStackTrace( final Throwable t, final String message )
  307. {
  308. StaticEntity.printStackTrace( t, message, false );
  309. }
  310. public static final void printStackTrace( final Throwable t, final String message, final boolean printOnlyCause )
  311. {
  312. // Next, print all the information to the debug log so that
  313. // it can be sent.
  314. boolean shouldOpenStream = !RequestLogger.isDebugging();
  315. if ( shouldOpenStream )
  316. {
  317. RequestLogger.openDebugLog();
  318. }
  319. String printMsg;
  320. if ( message.startsWith( "Backtrace" ) )
  321. {
  322. StaticEntity.backtraceTrigger = null;
  323. printMsg = "Backtrace triggered, debug log printed.";
  324. }
  325. else if ( !message.equals( "" ) )
  326. {
  327. printMsg = message;
  328. }
  329. else
  330. {
  331. printMsg = "Unexpected error, debug log printed.";
  332. }
  333. KoLmafia.updateDisplay( printMsg );
  334. RequestLogger.updateSessionLog( printMsg );
  335. Throwable cause = t.getCause();
  336. if ( cause == null || !printOnlyCause )
  337. {
  338. StaticEntity.printStackTrace( t, message, RequestLogger.getDebugStream() );
  339. }
  340. if ( cause != null )
  341. {
  342. StaticEntity.printStackTrace( cause, message, RequestLogger.getDebugStream() );
  343. }
  344. if ( shouldOpenStream )
  345. {
  346. RequestLogger.closeDebugLog();
  347. }
  348. }
  349. private static final void printStackTrace( final Throwable t, final String message, final PrintStream ostream )
  350. {
  351. ostream.println( t.getClass() + ": " + t.getMessage() );
  352. t.printStackTrace( ostream );
  353. ostream.println( message );
  354. }
  355. private static File getJDKWorkingDirectory()
  356. {
  357. File currentJavaHome = new File( System.getProperty( "java.home" ) );
  358. if ( StaticEntity.hasJDKBinaries( currentJavaHome ) )
  359. {
  360. return currentJavaHome;
  361. }
  362. File javaInstallFolder = currentJavaHome.getParentFile();
  363. if ( StaticEntity.hasJDKBinaries( javaInstallFolder ) )
  364. {
  365. return javaInstallFolder;
  366. }
  367. File[] possibleJavaHomes = javaInstallFolder.listFiles();
  368. for ( int i = 0; i < possibleJavaHomes.length; ++i )
  369. {
  370. if ( StaticEntity.hasJDKBinaries( possibleJavaHomes[ i ] ) )
  371. {
  372. return possibleJavaHomes[ i ];
  373. }
  374. }
  375. return null;
  376. }
  377. private static boolean hasJDKBinaries( File javaHome )
  378. {
  379. if ( System.getProperty( "os.name" ).startsWith( "Windows" ) )
  380. {
  381. return new File( javaHome, "bin/javac.exe" ).exists();
  382. }
  383. else
  384. {
  385. return new File( javaHome, "bin/javac" ).exists();
  386. }
  387. }
  388. public static final String getProcessId()
  389. {
  390. File javaHome = StaticEntity.getJDKWorkingDirectory();
  391. if ( javaHome == null )
  392. {
  393. KoLmafia.updateDisplay( "To use this feature, you must run KoLmafia with a JDK instead of a JRE." );
  394. return null;
  395. }
  396. Runtime runtime = Runtime.getRuntime();
  397. String pid = null;
  398. try
  399. {
  400. String[] command = new String[ 2 ];
  401. if ( System.getProperty( "os.name" ).startsWith( "Windows" ) )
  402. {
  403. command[ 0 ] = new File( javaHome, "bin/jps.exe" ).getPath();
  404. }
  405. else
  406. {
  407. command[ 0 ] = new File( javaHome, "bin/jps" ).getPath();
  408. }
  409. command[ 1 ] = "-l";
  410. Process process = runtime.exec( command );
  411. BufferedReader reader = new BufferedReader( new InputStreamReader( process.getInputStream() ) );
  412. String line;
  413. StringBuffer sb = new StringBuffer();
  414. while ( ( pid == null ) && ( line = reader.readLine() ) != null )
  415. {
  416. sb.append( line );
  417. sb.append( KoLConstants.LINE_BREAK );
  418. if ( line.indexOf( "KoLmafia" ) != -1 )
  419. {
  420. pid = line.substring( 0, line.indexOf( ' ' ) );
  421. }
  422. boolean shouldOpenStream = !RequestLogger.isDebugging();
  423. if ( shouldOpenStream )
  424. {
  425. RequestLogger.openDebugLog();
  426. }
  427. RequestLogger.getDebugStream().println( sb.toString() );
  428. if ( shouldOpenStream )
  429. {
  430. RequestLogger.closeDebugLog();
  431. }
  432. }
  433. }
  434. catch ( IOException e )
  435. {
  436. e.printStackTrace();
  437. }
  438. if ( pid != null )
  439. {
  440. return pid;
  441. }
  442. KoLmafia.updateDisplay( "Unable to determine KoLmafia process id." );
  443. return null;
  444. }
  445. public static final void printThreadDump()
  446. {
  447. File javaHome = StaticEntity.getJDKWorkingDirectory();
  448. if ( javaHome == null )
  449. {
  450. KoLmafia.updateDisplay( "To use this feature, you must run KoLmafia with a JDK instead of a JRE." );
  451. return;
  452. }
  453. String pid = StaticEntity.getProcessId();
  454. if ( pid == null )
  455. {
  456. return;
  457. }
  458. KoLmafia.updateDisplay( "Generating thread dump for KoLmafia process id " + pid + "..." );
  459. Runtime runtime = Runtime.getRuntime();
  460. StringBuffer sb = new StringBuffer();
  461. try
  462. {
  463. String[] command = new String[ 2 ];
  464. if ( System.getProperty( "os.name" ).startsWith( "Windows" ) )
  465. {
  466. command[ 0 ] = new File( javaHome, "bin/jstack.exe" ).getPath();
  467. }
  468. else
  469. {
  470. command[ 0 ] = new File( javaHome, "bin/jstack" ).getPath();
  471. }
  472. command[ 1 ] = pid;
  473. Process process = runtime.exec( command );
  474. BufferedReader reader = new BufferedReader( new InputStreamReader( process.getInputStream() ) );
  475. String line;
  476. while ( ( line = reader.readLine() ) != null )
  477. {
  478. sb.append( line );
  479. sb.append( KoLConstants.LINE_BREAK );
  480. }
  481. reader.close();
  482. }
  483. catch ( IOException e )
  484. {
  485. e.printStackTrace();
  486. }
  487. boolean shouldOpenStream = !RequestLogger.isDebugging();
  488. if ( shouldOpenStream )
  489. {
  490. RequestLogger.openDebugLog();
  491. }
  492. RequestLogger.getDebugStream().println( sb.toString() );
  493. if ( shouldOpenStream )
  494. {
  495. RequestLogger.closeDebugLog();
  496. }
  497. }
  498. public static final void generateHeapDump()
  499. {
  500. File javaHome = StaticEntity.getJDKWorkingDirectory();
  501. if ( javaHome == null )
  502. {
  503. KoLmafia.updateDisplay( "To use this feature, you must run KoLmafia with a JDK instead of a JRE." );
  504. return;
  505. }
  506. String pid = StaticEntity.getProcessId();
  507. if ( pid == null )
  508. {
  509. return;
  510. }
  511. KoLmafia.updateDisplay( "Generating heap dump for KoLmafia process id " + pid + "..." );
  512. Runtime runtime = Runtime.getRuntime();
  513. StringBuffer sb = new StringBuffer();
  514. try
  515. {
  516. String[] command = new String[ 3 ];
  517. if ( System.getProperty( "os.name" ).startsWith( "Windows" ) )
  518. {
  519. command[ 0 ] = new File( javaHome, "bin/jmap.exe" ).getPath();
  520. }
  521. else
  522. {
  523. command[ 0 ] = new File( javaHome, "bin/jmap" ).getPath();
  524. }
  525. String javaVersion = System.getProperty( "java.runtime.version" );
  526. if ( javaVersion.contains( "1.5.0_" ) )
  527. {
  528. command[ 1 ] = "-heap:format=b";
  529. }
  530. else
  531. {
  532. int fileIndex = 0;
  533. String jmapFileName = null;
  534. File jmapFile = null;
  535. do
  536. {
  537. ++fileIndex;
  538. jmapFileName = "kolmafia" + fileIndex + ".hprof";
  539. jmapFile = new File( KoLConstants.ROOT_LOCATION, jmapFileName );
  540. }
  541. while ( jmapFile.exists() );
  542. command[ 1 ] = "-dump:format=b,file=" + jmapFileName;
  543. }
  544. command[ 2 ] = pid;
  545. Process process = runtime.exec( command, new String[ 0 ], KoLConstants.ROOT_LOCATION );
  546. BufferedReader reader = new BufferedReader( new InputStreamReader( process.getInputStream() ) );
  547. String line;
  548. while ( ( line = reader.readLine() ) != null )
  549. {
  550. sb.append( line );
  551. sb.append( KoLConstants.LINE_BREAK );
  552. }
  553. reader.close();
  554. }
  555. catch ( IOException e )
  556. {
  557. e.printStackTrace();
  558. }
  559. boolean shouldOpenStream = !RequestLogger.isDebugging();
  560. if ( shouldOpenStream )
  561. {
  562. RequestLogger.openDebugLog();
  563. }
  564. RequestLogger.getDebugStream().println( sb.toString() );
  565. if ( shouldOpenStream )
  566. {
  567. RequestLogger.closeDebugLog();
  568. }
  569. }
  570. public static final String[] getPastUserList()
  571. {
  572. ArrayList<String> pastUserList = new ArrayList<String>();
  573. String user;
  574. File[] files = DataUtilities.listFiles( KoLConstants.SETTINGS_LOCATION );
  575. for ( int i = 0; i < files.length; ++i )
  576. {
  577. user = files[ i ].getName();
  578. if ( user.startsWith( "GLOBAL" ) || !user.endsWith( "_prefs.txt" ) )
  579. {
  580. continue;
  581. }
  582. user = user.substring( 0, user.length() - 10 );
  583. if ( !user.equals( "GLOBAL" ) && !pastUserList.contains( user ) )
  584. {
  585. pastUserList.add( user );
  586. }
  587. }
  588. String[] pastUsers = new String[ pastUserList.size() ];
  589. pastUserList.toArray( pastUsers );
  590. return pastUsers;
  591. }
  592. public static final void disable( final String name )
  593. {
  594. String functionName;
  595. StringTokenizer tokens = new StringTokenizer( name, ", " );
  596. while ( tokens.hasMoreTokens() )
  597. {
  598. functionName = tokens.nextToken();
  599. if ( !KoLConstants.disabledScripts.contains( functionName ) )
  600. {
  601. KoLConstants.disabledScripts.add( functionName );
  602. }
  603. }
  604. }
  605. public static final void enable( final String name )
  606. {
  607. if ( name.equals( "all" ) )
  608. {
  609. KoLConstants.disabledScripts.clear();
  610. return;
  611. }
  612. StringTokenizer tokens = new StringTokenizer( name, ", " );
  613. while ( tokens.hasMoreTokens() )
  614. {
  615. KoLConstants.disabledScripts.remove( tokens.nextToken() );
  616. }
  617. }
  618. public static final boolean isDisabled( final String name )
  619. {
  620. if ( name.equals( "enable" ) || name.equals( "disable" ) )
  621. {
  622. return false;
  623. }
  624. return KoLConstants.disabledScripts.contains( "all" ) || KoLConstants.disabledScripts.contains( name );
  625. }
  626. }