PageRenderTime 68ms CodeModel.GetById 33ms RepoModel.GetById 0ms app.codeStats 1ms

/src/org/opengts/util/OSTools.java

https://github.com/neeph/OpenGTSFull
Java | 593 lines | 342 code | 54 blank | 197 comment | 53 complexity | c194f231f2c0900fa0cc4956bcd1dd51 MD5 | raw file
  1. // ----------------------------------------------------------------------------
  2. // Copyright 2006-2010, GeoTelematic Solutions, Inc.
  3. // All rights reserved
  4. // ----------------------------------------------------------------------------
  5. //
  6. // Licensed under the Apache License, Version 2.0 (the "License");
  7. // you may not use this file except in compliance with the License.
  8. // You may obtain a copy of the License at
  9. //
  10. // http://www.apache.org/licenses/LICENSE-2.0
  11. //
  12. // Unless required by applicable law or agreed to in writing, software
  13. // distributed under the License is distributed on an "AS IS" BASIS,
  14. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. // See the License for the specific language governing permissions and
  16. // limitations under the License.
  17. //
  18. // ----------------------------------------------------------------------------
  19. // Description:
  20. // General OS specific tools
  21. // ----------------------------------------------------------------------------
  22. // Change History:
  23. // 2006/03/26 Martin D. Flynn
  24. // -Initial release
  25. // 2006/06/30 Martin D. Flynn
  26. // -Repackaged
  27. // 2008/06/20 Martin D. Flynn
  28. // -Added method 'getProcessID()'
  29. // 2010/05/24 Martin D. Flynn
  30. // -Added "getMemoryUsage", "printMemoryUsage"
  31. // ----------------------------------------------------------------------------
  32. package org.opengts.util;
  33. import java.lang.management.*;
  34. import java.util.*;
  35. import java.io.*;
  36. public class OSTools
  37. {
  38. // ------------------------------------------------------------------------
  39. private static final Object LockObject = new Object();
  40. // ------------------------------------------------------------------------
  41. // OS and JVM specific tools
  42. // ------------------------------------------------------------------------
  43. private static final int OS_INITIALIZE = -1;
  44. public static final int OS_TYPE_MASK = 0x00FF00;
  45. public static final int OS_SUBTYPE_MASK = 0x0000FF;
  46. public static final int OS_UNKNOWN = 0x000000;
  47. public static final int OS_LINUX = 0x000100;
  48. public static final int OS_MACOSX = 0x000200;
  49. public static final int OS_WINDOWS = 0x000300;
  50. public static final int OS_WINDOWS_XP = 0x000001;
  51. public static final int OS_WINDOWS_9X = 0x000002;
  52. public static final int OS_WINDOWS_CYGWIN = 0x000010;
  53. private static int OSType = OS_INITIALIZE;
  54. /**
  55. *** Returns the known OS type as an integer bitmask
  56. *** @return The OS type
  57. **/
  58. public static int getOSType()
  59. {
  60. if (OSType == OS_INITIALIZE) {
  61. String osName = System.getProperty("os.name").toLowerCase();
  62. //Print.logInfo("OS: " + osName);
  63. if (osName.startsWith("windows")) {
  64. OSType = OS_WINDOWS;
  65. if (osName.startsWith("windows xp")) {
  66. OSType |= OS_WINDOWS_XP;
  67. } else
  68. if (osName.startsWith("windows 9") || osName.startsWith("windows m")) {
  69. OSType |= OS_WINDOWS_9X;
  70. }
  71. } else
  72. if (osName.startsWith("mac")) {
  73. // "Max OS X"
  74. OSType = OS_MACOSX;
  75. } else
  76. if (File.separatorChar == '/') {
  77. // "Linux"
  78. OSType = OS_LINUX;
  79. } else {
  80. OSType = OS_UNKNOWN;
  81. }
  82. }
  83. return OSType;
  84. }
  85. // ------------------------------------------------------------------------
  86. // ------------------------------------------------------------------------
  87. /**
  88. *** Returns true if the OS is unknown
  89. *** @return True if the OS is unknown
  90. **/
  91. public static boolean isUnknown()
  92. {
  93. return (getOSType() == OS_UNKNOWN);
  94. }
  95. /**
  96. *** Returns true if the OS is the specified type
  97. *** @return True if the OS is the specified type
  98. **/
  99. public static boolean isOSType(int type)
  100. {
  101. int osType = getOSType();
  102. return ((osType & OS_TYPE_MASK) == type);
  103. }
  104. /**
  105. *** Returns true if the OS is the specified type
  106. *** @return True if the OS is the specified type
  107. **/
  108. public static boolean isOSType(int type, int subType)
  109. {
  110. int osType = getOSType();
  111. if ((osType & OS_TYPE_MASK) != type) {
  112. return false;
  113. } else {
  114. return ((osType & OS_SUBTYPE_MASK & subType) != 0);
  115. }
  116. }
  117. /**
  118. *** Returns true if the OS is a flavor of Windows
  119. *** @return True if the OS is a flavor of Windows
  120. **/
  121. public static boolean isWindows()
  122. {
  123. return isOSType(OS_WINDOWS);
  124. }
  125. /**
  126. *** Returns true if the OS is Windows XP
  127. *** @return True if the OS is Windows XP
  128. **/
  129. public static boolean isWindowsXP()
  130. {
  131. return isOSType(OS_WINDOWS, OS_WINDOWS_XP);
  132. }
  133. /**
  134. *** Returns true if the OS is Windows 95/98
  135. *** @return True if the OS is Windows 95/98
  136. **/
  137. public static boolean isWindows9X()
  138. {
  139. return isOSType(OS_WINDOWS, OS_WINDOWS_9X);
  140. }
  141. /**
  142. *** Returns true if the OS is Unix/Linux
  143. *** @return True if the OS is Unix/Linux
  144. **/
  145. public static boolean isLinux()
  146. {
  147. return isOSType(OS_LINUX);
  148. }
  149. /**
  150. *** Returns true if the OS is Apple Mac OS X
  151. *** @return True if the OS is Apple Mac OS X
  152. **/
  153. public static boolean isMacOSX()
  154. {
  155. return isOSType(OS_MACOSX);
  156. }
  157. // ------------------------------------------------------------------------
  158. // ------------------------------------------------------------------------
  159. /**
  160. *** Get the current memory usage (in number of bytes)
  161. *** @param L The long array where the memory values will be placed. If 'null',
  162. *** is specified, or if the array has fewer than 3 elements, a new
  163. *** long array will be returned.
  164. *** then the array must be
  165. *** @return The current memory usage as an array of 3 long values indicating
  166. *** { MaxMemory, TotalMemory, FreeMemory } (in that order).
  167. **/
  168. public static long[] getMemoryUsage(long L[])
  169. {
  170. long mem[] = ((L != null) && (L.length >= 3))? L : new long[3];
  171. Runtime rt = Runtime.getRuntime();
  172. synchronized (OSTools.LockObject) {
  173. mem[0] = rt.maxMemory();
  174. mem[1] = rt.totalMemory();
  175. mem[2] = rt.freeMemory();
  176. }
  177. return mem;
  178. }
  179. /**
  180. *** Prints the current memory usage to the log file
  181. **/
  182. public static void printMemoryUsage()
  183. {
  184. long mem[] = OSTools.getMemoryUsage(null);
  185. long maxK = mem[0] / 1024L;
  186. long totK = mem[1] / 1024L;
  187. long freK = mem[2] / 1024L;
  188. Print.logInfo("Memory-K: max=%d, total=%d, free=%d, used=%d", maxK, totK, freK, (totK - freK));
  189. //OSTools.printMemoryUsageMXBean();
  190. }
  191. /**
  192. *** Prints the current memory usage to the log file
  193. **/
  194. public static void printMemoryUsageMXBean()
  195. {
  196. /* Heap/Non-Heap */
  197. MemoryMXBean memory = ManagementFactory.getMemoryMXBean();
  198. MemoryUsage heapUsage = memory.getHeapMemoryUsage();
  199. MemoryUsage nonHeapUsage = memory.getNonHeapMemoryUsage();
  200. Print.logInfo("Heap Memory Usage : " + formatMemoryUsage(heapUsage ));
  201. Print.logInfo("Non-Heap Memory Usage: " + formatMemoryUsage(nonHeapUsage));
  202. /* Pools */
  203. java.util.List<MemoryPoolMXBean> memPool = ManagementFactory.getMemoryPoolMXBeans();
  204. for (MemoryPoolMXBean mp : memPool) {
  205. String name = mp.getName();
  206. MemoryType type = mp.getType();
  207. MemoryUsage estUsage = mp.getUsage();
  208. MemoryUsage peakUsage = mp.getPeakUsage();
  209. MemoryUsage collUsage = mp.getCollectionUsage();
  210. Print.logInfo("Pool Usage: " + name + " [" + type + "]");
  211. Print.logInfo(" Estimate : " + formatMemoryUsage(estUsage ));
  212. Print.logInfo(" Peak : " + formatMemoryUsage(peakUsage));
  213. Print.logInfo(" Collection: " + formatMemoryUsage(collUsage));
  214. }
  215. }
  216. /**
  217. *** Formats a MemoryUsage instance
  218. **/
  219. private static String formatMemoryUsage(MemoryUsage u)
  220. {
  221. if (u != null) {
  222. long comm = u.getCommitted() / 1024L;
  223. long init = u.getInit() / 1024L;
  224. long max = u.getMax() / 1024L;
  225. long used = u.getUsed() / 1024L;
  226. StringBuffer sb = new StringBuffer();
  227. sb.append("[K]");
  228. sb.append(" Committed=").append(comm);
  229. sb.append(" Init=").append(init);
  230. sb.append(" Max=").append(max);
  231. sb.append(" Used=").append(used);
  232. return sb.toString();
  233. } else {
  234. return "";
  235. }
  236. }
  237. // ------------------------------------------------------------------------
  238. // ------------------------------------------------------------------------
  239. private static Object memoryCheckLock = new Object();
  240. private static long firstMem_maxB = 0L;
  241. private static long firstMem_usedB = 0L;
  242. private static long firstMem_time = 0L;
  243. private static long memoryCheckCount = 0L;
  244. private static long averMem_usedB = 0L;
  245. private static long lastMem_usedB = 0L;
  246. /**
  247. *** Analyzes/Prints the current memory usage.<br>
  248. *** (This method only analyzes/prints memory usage if the current usage is less than
  249. *** the previous usage, implying that a garbage collection has recently occured)<br>
  250. *** Useful for determining <b>IF</b> there are memory leaks, and how much it is leaking,
  251. *** but useless for determining <b>WHERE</b> the leak is occurring.
  252. *** @param reset True to reset the memory growth-rate checks.
  253. **/
  254. public static void checkMemoryUsage(boolean reset)
  255. {
  256. // http://olex.openlogic.com/wazi/2009/how-to-fix-memory-leaks-in-java/
  257. // http://java.sun.com/docs/hotspot/gc1.4.2/faq.html
  258. // http://java.dzone.com/articles/letting-garbage-collector-do-c
  259. /* memory check enabled? */
  260. if (!RTConfig.getBoolean(RTKey.OSTOOLS_MEMORY_CHECK_ENABLE)) {
  261. return;
  262. }
  263. /* get current memory usage */
  264. long nowTime = DateTime.getCurrentTimeSec();
  265. long maxB, usedB;
  266. long averUsedB = 0L, firstUsedB = 0L, firstTime = 0L;
  267. long count = 0L;
  268. Runtime rt = Runtime.getRuntime();
  269. synchronized (OSTools.memoryCheckLock) {
  270. // reset?
  271. if (reset) {
  272. // start over
  273. OSTools.firstMem_maxB = 0L;
  274. OSTools.firstMem_usedB = 0L;
  275. OSTools.firstMem_time = 0L;
  276. OSTools.memoryCheckCount = 0L;
  277. OSTools.averMem_usedB = 0L;
  278. OSTools.lastMem_usedB = 0L;
  279. }
  280. // get memory usage
  281. maxB = rt.maxMemory();
  282. usedB = rt.totalMemory() - rt.freeMemory();
  283. if (usedB <= 0L) {
  284. // unlikely, but we need to check anyway
  285. Print.logWarn("Memory usage <= 0? " + usedB + " bytes");
  286. } else {
  287. if (usedB < OSTools.lastMem_usedB) {
  288. // garbage collection has occurred
  289. if ((OSTools.firstMem_time <= 0L) || (usedB < OSTools.firstMem_usedB)) {
  290. // store results after first garbage collection
  291. OSTools.firstMem_maxB = maxB; // should never change
  292. OSTools.firstMem_usedB = usedB;
  293. OSTools.firstMem_time = nowTime;
  294. OSTools.memoryCheckCount = 0L;
  295. OSTools.averMem_usedB = 0L;
  296. }
  297. firstUsedB = OSTools.firstMem_usedB; // cache for use outside synchronized section
  298. firstTime = OSTools.firstMem_time; // cache for use outside synchronized section
  299. // average "trend"
  300. if (OSTools.averMem_usedB <= 0L) {
  301. // initialize average
  302. OSTools.averMem_usedB = usedB;
  303. } else
  304. if (usedB <= OSTools.averMem_usedB) {
  305. // always reset to minimum used (ie. 100% downward trend)
  306. OSTools.averMem_usedB = usedB;
  307. } else {
  308. // upward "trend" determined by weighting factor
  309. double trendWeight = RTConfig.getDouble(RTKey.OSTOOLS_MEMORY_TREND_WEIGHT);
  310. OSTools.averMem_usedB = OSTools.averMem_usedB + (long)((double)(usedB - OSTools.averMem_usedB) * trendWeight);
  311. }
  312. averUsedB = OSTools.averMem_usedB; // cache for use outside synchronized section
  313. // count
  314. count = ++OSTools.memoryCheckCount; // increment and cache count for use outside synchronized section
  315. }
  316. OSTools.lastMem_usedB = usedB; // save last used
  317. }
  318. } // synchronized
  319. /* return if a garbage collection has not just occurred */
  320. if (count <= 0L) {
  321. return;
  322. }
  323. /* analyze */
  324. double deltaHours = (double)(nowTime - firstTime) / 3600.0;
  325. long deltaUsedB = averUsedB - firstUsedB; // could be <= 0
  326. long grwBPH = (deltaHours > 0.0)? (long)(deltaUsedB / deltaHours) : 0L; // bytes/hour
  327. long grwBPC = deltaUsedB / count; // bytes/hour
  328. /* message */
  329. long maxK = maxB / 1024;
  330. long usedK = usedB / 1024;
  331. long averK = averUsedB / 1024;
  332. String s = "["+count+"] Memory-K max "+maxK+ ", used "+usedK+ " (trend "+averK+ " K "+grwBPH+" b/h "+ grwBPC+" b/c)";
  333. /* display */
  334. double maxPercent = RTConfig.getDouble(RTKey.OSTOOLS_MEMORY_USAGE_WARN);
  335. if (usedB >= (long)((double)maxB * maxPercent)) {
  336. Print.logWarn("**** More than "+(maxPercent*100.0)+"% of max memory has been used!! ****");
  337. Print.logWarn(s);
  338. } else {
  339. Print.logInfo(s);
  340. }
  341. }
  342. // ------------------------------------------------------------------------
  343. // ------------------------------------------------------------------------
  344. /**
  345. *** Returns true if this implementation has a broken 'toFront' Swing implementation.<br>
  346. *** (may only be applicable on Java v1.4.2)
  347. *** @return True if this implementation has a broken 'toFront' Swing implementation.
  348. **/
  349. public static boolean isBrokenToFront()
  350. {
  351. return isWindows();
  352. }
  353. // ------------------------------------------------------------------------
  354. // ------------------------------------------------------------------------
  355. public static final String PROPERTY_JAVA_HOME = "java.home";
  356. public static final String PROPERTY_JAVA_VENDOR = "java.vendor";
  357. public static final String PROPERTY_JAVA_SPECIFICATION_VERSION = "java.specification.version";
  358. /**
  359. *** Returns true if executed from a Sun Microsystems JVM.
  360. *** @return True is executed from a Sun Microsystems JVM.
  361. **/
  362. public static boolean isSunJava()
  363. {
  364. String propVal = System.getProperty(PROPERTY_JAVA_VENDOR); // "Sun Microsystems Inc."
  365. if ((propVal == null) || (propVal.indexOf("Sun Microsystems") < 0)) {
  366. return false;
  367. } else {
  368. return true;
  369. }
  370. }
  371. // ------------------------------------------------------------------------
  372. // ------------------------------------------------------------------------
  373. /**
  374. *** Gets the class of the caller at the specified frame index
  375. *** @param frame The frame index
  376. *** @return The calling class
  377. **/
  378. @SuppressWarnings("proprietary") // <-- does not work to supress the "Sun proprietary API" warning
  379. private static Class _getCallerClass(int frame)
  380. throws Throwable
  381. {
  382. return sun.reflect.Reflection.getCallerClass(frame + 1); // <== ignore any warnings
  383. }
  384. /**
  385. *** Gets the class of the caller at the specified frame index
  386. *** @param frame The frame index
  387. *** @return The calling class
  388. **/
  389. public static Class getCallerClass(int frame)
  390. {
  391. try {
  392. // sun.reflect.Reflection.getCallerClass(0) == sun.reflect.Reflection
  393. // sun.reflect.Reflection.getCallerClass(1) == OSTools
  394. Class clz = OSTools._getCallerClass(frame + 1);
  395. //Print._println("" + (frame + 1) + "] class " + StringTools.className(clz));
  396. return clz;
  397. } catch (Throwable th) { // ClassNotFoundException
  398. // This can occur when the code has been compiled with the Sun Microsystems version
  399. // of Java, but is executed with the GNU version of Java (or other non-Sun version).
  400. Print.logException("Sun Microsystems version of Java is not in use", th);
  401. return null;
  402. }
  403. }
  404. /**
  405. *** Returns true if 'sun.reflect.Reflection' is present in the runtime libraries.<br>
  406. *** (will return true when running with the Sun Microsystems version of Java)
  407. *** @return True if 'getCallerClass' is available.
  408. **/
  409. public static boolean hasGetCallerClass()
  410. {
  411. try {
  412. OSTools._getCallerClass(0);
  413. return true;
  414. } catch (Throwable th) {
  415. return false;
  416. }
  417. }
  418. /**
  419. *** Prints the class of the caller (debug purposes only)
  420. **/
  421. public static void printCallerClasses()
  422. {
  423. try {
  424. for (int i = 0;; i++) {
  425. Class clz = OSTools._getCallerClass(i);
  426. Print.logInfo("" + i + "] class " + StringTools.className(clz));
  427. if (clz == null) { break; }
  428. }
  429. } catch (Throwable th) { // ClassNotFoundException
  430. // This can occur when the code has been compiled with the Sun Microsystems version
  431. // of Java, but is executed with the GNU version of Java.
  432. Print.logException("Sun Microsystems version of Java is not in use", th);
  433. }
  434. }
  435. // ------------------------------------------------------------------------
  436. // ------------------------------------------------------------------------
  437. /**
  438. *** Gets the Process-ID of this JVM invocation.<br>
  439. *** IMPORTANT: This implementation relies on a "convention", rather that a documented method
  440. *** of obtaining the process-id of this JVM within the OS. <b>Caveat Emptor!</b><br>
  441. *** (On Windows, this returns the 'WINPID' which is probably useless anyway)
  442. *** @return The Process-ID
  443. **/
  444. public static int getProcessID()
  445. {
  446. // References:
  447. // - http://blog.igorminar.com/2007/03/how-java-application-can-discover-its.html
  448. if (OSTools.isSunJava()) {
  449. try {
  450. // by convention, returns "<PID>@<host>" (until something changes, and it doesn't)
  451. String n = java.lang.management.ManagementFactory.getRuntimeMXBean().getName();
  452. int pid = StringTools.parseInt(n,-1); // parse PID
  453. return pid;
  454. } catch (Throwable th) {
  455. Print.logException("Unable to obtain Process ID", th);
  456. return -1;
  457. }
  458. } else {
  459. return -1;
  460. }
  461. }
  462. /* this does not work on Windows (and seems to return the wrong parent PID on Linux) */
  463. private static int _getProcessID()
  464. {
  465. try {
  466. String cmd[] = new String[] { "bash", "-c", "echo $PPID" };
  467. Process ppidExec = Runtime.getRuntime().exec(cmd);
  468. BufferedReader ppidReader = new BufferedReader(new InputStreamReader(ppidExec.getInputStream()));
  469. StringBuffer sb = new StringBuffer();
  470. for (;;) {
  471. String line = ppidReader.readLine();
  472. if (line == null) { break; }
  473. sb.append(StringTools.trim(line));
  474. }
  475. int pid = StringTools.parseInt(sb.toString(),-1);
  476. int exitVal = ppidExec.waitFor();
  477. Print.logInfo("Exit value: %d [%s]", exitVal, sb.toString());
  478. ppidReader.close();
  479. return pid;
  480. } catch (Throwable th) {
  481. Print.logException("Unable to obtain PID", th);
  482. return -1;
  483. }
  484. }
  485. // ------------------------------------------------------------------------
  486. // ------------------------------------------------------------------------
  487. /**
  488. *** Returns a Java command set up to be executed by Runtime.getRuntime().exec(...)
  489. *** @param classpath The classpath
  490. *** @param className The main Java class name
  491. *** @param args The command line arguments
  492. *** @return A command to call and it's arguments
  493. **/
  494. public static String[] createJavaCommand(String classpath[], String className, String args[])
  495. {
  496. java.util.List<String> execCmd = new Vector<String>();
  497. execCmd.add(System.getProperty("java.home") + File.separator + "bin" + File.separator + "java");
  498. execCmd.add("-classpath");
  499. if (ListTools.isEmpty(classpath)) {
  500. execCmd.add(System.getProperty("java.class.path"));
  501. } else {
  502. StringBuffer sb = new StringBuffer();
  503. for (String p : classpath) {
  504. if (sb.length() > 0) { sb.append(File.pathSeparator); }
  505. sb.append(p);
  506. }
  507. execCmd.add(sb.toString());
  508. }
  509. execCmd.add(className);
  510. if (!ListTools.isEmpty(args)) {
  511. for (String a : args) {
  512. execCmd.add(a);
  513. }
  514. }
  515. return execCmd.toArray(new String[execCmd.size()]);
  516. }
  517. // ------------------------------------------------------------------------
  518. // ------------------------------------------------------------------------
  519. /**
  520. *** Main entry point for testing/debugging
  521. *** @param argv Comand-line arguments
  522. **/
  523. public static void main(String argv[])
  524. {
  525. RTConfig.setCommandLineArgs(argv);
  526. System.out.println("OS Type ...");
  527. Print.sysPrintln("Is Windows : " + isWindows());
  528. Print.sysPrintln("Is Windows9X: " + isWindows9X());
  529. Print.sysPrintln("Is WindowsXP: " + isWindowsXP());
  530. Print.sysPrintln("Is Linux : " + isLinux());
  531. Print.sysPrintln("Is MacOSX : " + isMacOSX());
  532. Print.sysPrintln("PID #1 : " + getProcessID());
  533. Print.sysPrintln("PID #2 : " + _getProcessID());
  534. Runtime rt = Runtime.getRuntime();
  535. Print.sysPrintln("Total Mem : " + rt.totalMemory()/(1024.0*1024.0));
  536. Print.sysPrintln("Max Mem : " + rt.maxMemory()/(1024.0*1024.0));
  537. Print.sysPrintln("Free Mem : " + rt.freeMemory()/(1024.0*1024.0));
  538. }
  539. }