/*
* Copyright 2010-2015 Institut Pasteur.
*
* This file is part of Icy.
*
* Icy is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Icy is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Icy. If not, see <http://www.gnu.org/licenses/>.
*/
package icy.system;
import icy.file.FileUtil;
import icy.main.Icy;
import icy.type.collection.CollectionUtil;
import icy.util.ReflectionUtil;
import icy.util.StringUtil;
import java.awt.BufferCapabilities;
import java.awt.Desktop;
import java.awt.Desktop.Action;
import java.awt.DisplayMode;
import java.awt.Event;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.HeadlessException;
import java.awt.ImageCapabilities;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.Transparency;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.VolatileImage;
import java.io.File;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import com.sun.management.OperatingSystemMXBean;
/**
* @author stephane
*/
public class SystemUtil
{
public static final String SYSTEM_WINDOWS = "win";
public static final String SYSTEM_MAC_OS = "mac";
public static final String SYSTEM_UNIX = "unix";
/**
* internals
*/
private static Properties props = System.getProperties();
private static long lastNano = 0;
private static long lastCpu = 0;
private static int lastCpuLoad = 0;
/**
* Launch specified jar file.
*
* @param jarPath
* jar file path.
* @param vmArgs
* arguments for the java virtual machine.
* @param appArgs
* arguments for jar application.
* @param workDir
* working directory.
*/
public static Process execJAR(String jarPath, String vmArgs, String appArgs, String workDir)
{
return exec("java " + vmArgs + " -jar " + jarPath + " " + appArgs, workDir);
}
/**
* Launch specified jar file.
*
* @param jarPath
* jar file path.
* @param vmArgs
* arguments for the java virtual machine.
* @param appArgs
* arguments for jar application.
*/
public static Process execJAR(String jarPath, String vmArgs, String appArgs)
{
return exec("java " + vmArgs + " -jar " + jarPath + " " + appArgs);
}
/**
* Launch specified jar file.
*
* @param jarPath
* jar file path.
* @param appArgs
* arguments for jar application.
*/
public static Process execJAR(String jarPath, String appArgs)
{
return execJAR(jarPath, "", appArgs);
}
/**
* Launch specified jar file.
*
* @param jarPath
* jar file path.
*/
public static Process execJAR(String jarPath)
{
return execJAR(jarPath, "", "");
}
/**
* Execute a system command and return the attached process.
*
* @param cmd
* system command to execute.
*/
public static Process exec(String cmd)
{
return exec(cmd, ".");
}
/**
* Execute a system command and return the attached process.
*
* @param cmd
* system command to execute.
* @param dir
* the working directory of the subprocess, or null if the subprocess should inherit the
* working directory of the current process.
*/
public static Process exec(String cmd, String dir)
{
try
{
return Runtime.getRuntime().exec(cmd, null, new File(dir));
}
catch (Exception e)
{
System.err.println("SystemUtil.exec(" + cmd + ") error :");
IcyExceptionHandler.showErrorMessage(e, false);
return null;
}
}
public static BufferedImage createCompatibleImage(int width, int height)
{
final GraphicsConfiguration defaultGC = getDefaultGraphicsConfiguration();
if (defaultGC == null)
return new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
return defaultGC.createCompatibleImage(width, height);
}
public static BufferedImage createCompatibleImage(int width, int height, int transparency)
{
final GraphicsConfiguration defaultGC = getDefaultGraphicsConfiguration();
if (defaultGC == null)
{
if (transparency == Transparency.OPAQUE)
return new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
return new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
}
return defaultGC.createCompatibleImage(width, height, transparency);
}
public static VolatileImage createCompatibleVolatileImage(int width, int height)
{
final GraphicsConfiguration defaultGC = getDefaultGraphicsConfiguration();
if (defaultGC == null)
return null;
return defaultGC.createCompatibleVolatileImage(width, height);
}
public static VolatileImage createCompatibleVolatileImage(int width, int height, int transparency)
{
final GraphicsConfiguration defaultGC = getDefaultGraphicsConfiguration();
if (defaultGC == null)
return null;
return defaultGC.createCompatibleVolatileImage(width, height, transparency);
}
public static Desktop getDesktop()
{
if (Desktop.isDesktopSupported())
return Desktop.getDesktop();
return null;
}
/**
* Launch the system file manager on specified folder (if supported)
*
* @throws IOException
*/
public static boolean openFolder(String folder) throws IOException
{
final Desktop desktop = getDesktop();
if ((desktop != null) && desktop.isSupported(Action.OPEN))
{
desktop.open(new File(folder));
return true;
}
return false;
}
/**
* @see System#getProperty(String)
*/
public static String getProperty(String name)
{
return props.getProperty(name);
}
/**
* @see System#getProperty(String, String)
*/
public static String getProperty(String name, String defaultValue)
{
return props.getProperty(name, defaultValue);
}
/**
* @see System#setProperty(String, String)
*/
public static String setProperty(String name, String value)
{
return (String) props.setProperty(name, value);
}
/**
* @deprecated Use {@link #getMenuCtrlMask()} instead.
*/
@Deprecated
public static int getCtrlMask()
{
return getMenuCtrlMask();
}
/**
* Return the CTRL key mask used for Menu shortcut.
*/
public static int getMenuCtrlMask()
{
try
{
return Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
}
catch (HeadlessException e)
{
// headless mode, use default Ctrl Mask
return Event.CTRL_MASK;
}
}
/**
* @deprecated Use {@link #getMenuCtrlMask()} instead
*/
@Deprecated
public static int getSystemCtrlMask()
{
return getMenuCtrlMask();
}
public static GraphicsEnvironment getLocalGraphicsEnvironment()
{
return GraphicsEnvironment.getLocalGraphicsEnvironment();
}
/**
* Return the default screen device.
*/
public static GraphicsDevice getDefaultScreenDevice()
{
if (Icy.getMainInterface().isHeadLess())
return null;
return getLocalGraphicsEnvironment().getDefaultScreenDevice();
}
/**
* Return the default graphics configuration.
*/
public static GraphicsConfiguration getDefaultGraphicsConfiguration()
{
final GraphicsDevice screenDevice = getDefaultScreenDevice();
if (screenDevice != null)
return screenDevice.getDefaultConfiguration();
return null;
}
/**
* @deprecated Use {@link #getDefaultGraphicsConfiguration()} instead.
*/
@Deprecated
public static GraphicsConfiguration getSystemGraphicsConfiguration()
{
return getDefaultGraphicsConfiguration();
}
/**
* Return all available screen devices.
*/
public static List<GraphicsDevice> getScreenDevices()
{
final List<GraphicsDevice> result = new ArrayList<GraphicsDevice>();
if (Icy.getMainInterface().isHeadLess())
return result;
try
{
return CollectionUtil.asList(getLocalGraphicsEnvironment().getScreenDevices());
}
catch (HeadlessException e)
{
return result;
}
}
/**
* Return the number of screen device.
*/
public static int getScreenDeviceCount()
{
if (Icy.getMainInterface().isHeadLess())
return 0;
try
{
return getLocalGraphicsEnvironment().getScreenDevices().length;
}
catch (HeadlessException e)
{
return 0;
}
}
/**
* Return the screen device corresponding to specified index.
*/
public static GraphicsDevice getScreenDevice(int index)
{
if (Icy.getMainInterface().isHeadLess())
return null;
try
{
return getLocalGraphicsEnvironment().getScreenDevices()[index];
}
catch (HeadlessException e)
{
return null;
}
}
/**
* Returns all screen device intersecting the given region.<br>
* Can return an empty list if given region do not intersect any screen device.
*/
public static List<GraphicsDevice> getScreenDevices(Rectangle region)
{
final List<GraphicsDevice> result = new ArrayList<GraphicsDevice>();
if (Icy.getMainInterface().isHeadLess())
return result;
for (GraphicsDevice gd : getLocalGraphicsEnvironment().getScreenDevices())
if (getScreenBounds(gd, true).intersects(region))
result.add(gd);
return result;
}
/**
* Returns the main screen device corresponding to the given region.<br>
* If the given region intersect multiple screen, it return screen containing the largest area.<br>
* Can return <code>null</code> if given region do not intersect any screen device.
*/
public static GraphicsDevice getScreenDevice(Rectangle region)
{
if (Icy.getMainInterface().isHeadLess())
return null;
GraphicsDevice result = null;
Rectangle2D largest = null;
for (GraphicsDevice gd : getLocalGraphicsEnvironment().getScreenDevices())
{
final Rectangle2D intersection = getScreenBounds(gd, true).createIntersection(region);
if (!intersection.isEmpty())
{
// bigger intersection ?
if ((largest == null)
|| ((intersection.getWidth() * intersection.getHeight()) > (largest.getWidth() * largest
.getHeight())))
{
largest = intersection;
result = gd;
}
}
}
return result;
}
/**
* Returns the screen device corresponding to the given position.<br>
* Can return <code>null</code> if given position is not located in any screen device.
*/
public static GraphicsDevice getScreenDevice(Point position)
{
if (Icy.getMainInterface().isHeadLess())
return null;
for (GraphicsDevice gd : getLocalGraphicsEnvironment().getScreenDevices())
if (getScreenBounds(gd, false).contains(position))
return gd;
return null;
}
/**
* Returns true if current system is "head less" (no screen output device).
*/
public static boolean isHeadLess()
{
return GraphicsEnvironment.isHeadless();
}
public static ClassLoader getContextClassLoader()
{
return Thread.currentThread().getContextClassLoader();
}
public static ClassLoader getSystemClassLoader()
{
return ClassLoader.getSystemClassLoader();
}
public static BufferCapabilities getSystemBufferCapabilities()
{
final GraphicsConfiguration defaultGC = getDefaultGraphicsConfiguration();
if (defaultGC == null)
return null;
return defaultGC.getBufferCapabilities();
}
public static ImageCapabilities getSystemImageCapabilities()
{
final GraphicsConfiguration defaultGC = getDefaultGraphicsConfiguration();
if (defaultGC == null)
return null;
return defaultGC.getImageCapabilities();
}
public static ColorModel getSystemColorModel()
{
final GraphicsConfiguration defaultGC = getDefaultGraphicsConfiguration();
if (defaultGC == null)
return null;
return defaultGC.getColorModel();
}
public static ColorModel getSystemColorModel(int transparency)
{
final GraphicsConfiguration defaultGC = getDefaultGraphicsConfiguration();
if (defaultGC == null)
return null;
return defaultGC.getColorModel(transparency);
}
/**
* Return bounds for specified screen.
*
* @param removeInsets
* remove any existing taskbars and menubars from the result
*/
public static Rectangle getScreenBounds(GraphicsDevice graphicsDevice, boolean removeInsets)
{
if (graphicsDevice == null)
return new Rectangle();
final GraphicsConfiguration graphicsConfiguration = graphicsDevice.getDefaultConfiguration();
final Rectangle bounds = graphicsConfiguration.getBounds();
final Insets insets = Toolkit.getDefaultToolkit().getScreenInsets(graphicsConfiguration);
bounds.x += insets.left;
bounds.y += insets.top;
bounds.width -= (insets.left + insets.right);
bounds.height -= (insets.top + insets.bottom);
return bounds;
}
/**
* Return the entire desktop bounds (take multi screens in account).
*
* @param removeInsets
* remove any existing taskbars and menubars from the result
*/
public static Rectangle getDesktopBounds(boolean removeInsets)
{
Rectangle result = new Rectangle();
if (Icy.getMainInterface().isHeadLess())
return result;
final GraphicsDevice[] gs = getLocalGraphicsEnvironment().getScreenDevices();
for (int j = 0; j < gs.length; j++)
result = result.union(getScreenBounds(gs[j], removeInsets));
return result;
}
/**
* Return the entire desktop bounds (take multi screens in account)
*
* @see #getDesktopBounds(boolean)
*/
public static Rectangle getDesktopBounds()
{
return getDesktopBounds(true);
}
/**
* {@link GraphicsEnvironment#getMaximumWindowBounds()}
*/
public static Rectangle getMaximumWindowBounds()
{
if (Icy.getMainInterface().isHeadLess())
return new Rectangle();
return getLocalGraphicsEnvironment().getMaximumWindowBounds();
}
/**
* {@link GraphicsDevice#getDisplayMode()}
*/
public static DisplayMode getSystemDisplayMode()
{
final GraphicsDevice screenDevice = getDefaultScreenDevice();
if (screenDevice != null)
return screenDevice.getDisplayMode();
return null;
}
/**
* @deprecated Use {@link #getNumberOfCPUs()} instead
*/
@Deprecated
public static int getAvailableProcessors()
{
return Runtime.getRuntime().availableProcessors();
}
/**
* Return total number of processors or cores available to the JVM (same as system)
*/
public static int getNumberOfCPUs()
{
return Runtime.getRuntime().availableProcessors();
}
/**
* Return total amount of free memory available to the JVM (in bytes)
*/
public static long getJavaFreeMemory()
{
return getJavaMaxMemory() - getJavaUsedMemory();
}
/**
* Return maximum amount of memory the JVM will attempt to use (in bytes)
*/
public static long getJavaMaxMemory()
{
return Runtime.getRuntime().maxMemory();
}
/**
* @deprecated Use {@link #getJavaAllocatedMemory()} instead.
*/
@Deprecated
public static long getJavaTotalMemory()
{
return getJavaAllocatedMemory();
}
/**
* Return memory currently allocated by the JVM (in bytes)
*/
public static long getJavaAllocatedMemory()
{
return Runtime.getRuntime().totalMemory();
}
/**
* Return actual memory used by the JVM (in bytes)
*/
public static long getJavaUsedMemory()
{
return getJavaAllocatedMemory() - Runtime.getRuntime().freeMemory();
}
private static OperatingSystemMXBean getOSMXBean()
{
final java.lang.management.OperatingSystemMXBean bean = ManagementFactory.getOperatingSystemMXBean();
if (bean instanceof OperatingSystemMXBean)
return (OperatingSystemMXBean) bean;
// for (Method method : bean.getClass().getDeclaredMethods())
// {
// final int modifiers=method.getModifiers();
//
// method.setAccessible(true);
// if (method.getName().startsWith("get")
// && Modifier.isPublic(modifiers)) {
// Object value;
// try {
// value = method.invoke(bean);
// } catch (Exception e) {
// value = e;
// } // try
// System.out.println(method.getName() + " = " + value);
// } // if
// } // for
return null;
}
/**
* Return total physic memory of system (in bytes)
*/
public static long getTotalMemory()
{
final OperatingSystemMXBean bean = getOSMXBean();
if (bean != null)
return bean.getTotalPhysicalMemorySize();
return -1L;
}
/**
* @deprecated Use {@link #getTotalMemory()} instead
*/
@Deprecated
public static long getSystemTotalMemory()
{
return getTotalMemory();
}
/**
* Return free physic memory of system (in bytes)
*/
public static long getFreeMemory()
{
final OperatingSystemMXBean bean = getOSMXBean();
if (bean != null)
return bean.getFreePhysicalMemorySize();
return -1L;
}
/**
* @deprecated Use {@link #getFreeMemory()} instead
*/
@Deprecated
public static long getSystemFreeMemory()
{
return getFreeMemory();
}
/**
* Return system process CPU time
*/
public static long getProcessCpuTime()
{
final OperatingSystemMXBean bean = getOSMXBean();
if (bean != null)
return bean.getProcessCpuTime();
return -1L;
}
/**
* @deprecated Use {@link #getProcessCpuTime()} instead
*/
@Deprecated
public static long getSystemProcessCpuTime()
{
return getProcessCpuTime();
}
/**
* Return average CPU load of the application processes from the last call<br>
* (-1 if no available)
*/
public static int getCpuLoad()
{
final OperatingSystemMXBean bean = getOSMXBean();
if (bean != null)
{
// first call
if (lastNano == 0)
{
lastNano = System.nanoTime();
lastCpu = bean.getProcessCpuTime();
}
else
{
final long nanoAfter = System.nanoTime();
final long cpuAfter = bean.getProcessCpuTime();
final long dNano = nanoAfter - lastNano;
final long dCpu = cpuAfter - lastCpu;
// below 0.5s the reported value isn't very significant
if (dNano > 500000000L)
{
lastCpuLoad = (int) ((dCpu * 100L) / (dNano * getNumberOfCPUs()));
lastNano = nanoAfter;
lastCpu = cpuAfter;
}
}
return lastCpuLoad;
}
return -1;
}
/**
* @deprecated Use {@link #getCpuLoad()} instead
*/
@Deprecated
public static int getSystemCpuLoad()
{
return getCpuLoad();
}
/**
* Returns the user name.
*/
public static String getUserName()
{
return getProperty("user.name");
}
/**
* Returns the JVM name.
*/
public static String getJavaName()
{
return getProperty("java.runtime.name");
}
/**
* Returns the JVM version.
*/
public static String getJavaVersion()
{
String result = getProperty("java.runtime.version");
if (result.equals("unknow"))
result = getProperty("java.version");
return result;
}
/**
* Returns the JVM version in number format (ex: 1.6091)
*/
public static double getJavaVersionAsNumber()
{
String version = getJavaVersion().replaceAll("[^\\d.]", "");
final int firstSepInd = version.indexOf('.');
if (firstSepInd >= 0)
{
int lastSepInd = version.lastIndexOf('.');
while (lastSepInd != firstSepInd)
{
version = version.substring(0, lastSepInd) + version.substring(lastSepInd + 1);
lastSepInd = version.lastIndexOf('.');
}
}
return StringUtil.parseDouble(version, 0);
}
/**
* Returns the JVM data architecture model.
*/
public static int getJavaArchDataModel()
{
return Integer.parseInt(getProperty("sun.arch.data.model"));
}
/**
* Returns the Operating System name.
*/
public static String getOSName()
{
return getProperty("os.name");
}
/**
* Returns the Operating System architecture name.
*/
public static String getOSArch()
{
return getProperty("os.arch");
}
/**
* Returns the Operating System version.
*/
public static String getOSVersion()
{
return getProperty("os.version");
}
/**
* Return an id OS string :<br>
* <br>
* Windows system return <code>SystemUtil.SYSTEM_WINDOWS</code><br>
* MAC OS return <code>SystemUtil.SYSTEM_MAC_OS</code><br>
* Unix system return <code>SystemUtil.SYSTEM_UNIX</code><br>
* <br>
* An empty string is returned is OS is unknown.
*/
public static String getOSNameId()
{
if (isWindows())
return SYSTEM_WINDOWS;
if (isMac())
return SYSTEM_MAC_OS;
if (isUnix())
return SYSTEM_UNIX;
return "";
}
/**
* Return an id OS architecture string<br>
* example : "win32", "win64", "mac32", "mac64", "unix32"...<br>
* The bits number depends only from current installed JVM (32 or 64 bit)
* and not directly from host OS.<br>
* An empty string is returned if OS is unknown.
*/
public static String getOSArchIdString()
{
final String javaBit = Integer.toString(getJavaArchDataModel());
if (isWindows())
return SYSTEM_WINDOWS + javaBit;
if (isMac())
return SYSTEM_MAC_OS + javaBit;
if (isUnix())
return SYSTEM_UNIX + javaBit;
return "";
}
/**
* Returns true is the operating system support link (symbolic or not).
*/
public static boolean isLinkSupported()
{
return isMac() || isUnix();
}
/**
* Returns true is the JVM is 32 bits.
*/
public static boolean is32bits()
{
return getJavaArchDataModel() == 32;
}
/**
* Returns true is the JVM is 64 bits.
*/
public static boolean is64bits()
{
return getJavaArchDataModel() == 64;
}
/**
* @deprecated Use {@link #isWindows()} instead.
*/
@Deprecated
public static boolean isWindow()
{
return isWindows();
}
/**
* Returns true is the Operating System is Windows based.
*/
public static boolean isWindows()
{
return (getOSName().toLowerCase().indexOf("win") >= 0);
}
/**
* Returns true is the Operating System is Mac OS based.
*/
public static boolean isMac()
{
return (getOSName().toLowerCase().indexOf("mac") >= 0);
}
/**
* Returns true is the Operating System is Unix / Linux based.
*/
public static boolean isUnix()
{
final String os = getOSName().toLowerCase();
return (os.indexOf("nix") >= 0) || (os.indexOf("nux") >= 0);
}
/**
* Returns true is the Operating System is Windows 64 bits whatever is the JVM installed (32 or 64 bits).
*/
public static boolean isWindows64()
{
if (!isWindows())
return false;
final String wow64Arch = System.getenv("PROCESSOR_ARCHITEW6432");
if ((wow64Arch != null) && wow64Arch.endsWith("64"))
return true;
final String arch = System.getenv("PROCESSOR_ARCHITECTURE");
if ((arch != null) && arch.endsWith("64"))
return true;
return false;
}
/**
* Returns default temporary directory.<br>
* ex:<br>
* <code>c:/temp</code><br>
* <code>/tmp</code><br>
* Same as {@link FileUtil#getTempDirectory()}
*/
public static String getTempDirectory()
{
return FileUtil.getTempDirectory();
}
/**
* Returns temporary native library path (used to load native libraries from plugin)
*/
public static String getTempLibraryDirectory()
{
return FileUtil.getTempDirectory() + "/lib";
}
public static boolean addToJavaLibraryPath(String directories[])
{
try
{
final String path_separator = System.getProperty("path.separator");
// patch user library paths...
final Field pathsField = ReflectionUtil.getField(ClassLoader.class, "usr_paths", true);
// get current user paths
final ArrayList<String> userPaths = CollectionUtil.asArrayList((String[]) pathsField.get(null));
// get current system paths
String sysPaths = System.getProperty("java.library.path");
for (String dir : directories)
{
if (!userPaths.contains(dir))
userPaths.add(dir);
if (!sysPaths.contains(dir))
sysPaths += path_separator + dir;
}
// set back user library path
pathsField.set(null, userPaths.toArray(new String[userPaths.size()]));
// set back system library path
System.setProperty("java.library.path", sysPaths);
return true;
}
catch (Exception e)
{
System.err.println(e.getMessage());
System.err.println("Cannot patch Java Library Path.");
return false;
}
}
/**
* Load the specified native library.
*
* @param dir
* directory from where we want to load the native library.
* @param name
* name of the library.<br/>
* The filename of the library is automatically built depending the operating system.
*/
public static void loadLibrary(String dir, String name)
{
final File libPath = new File(dir, System.mapLibraryName(name));
if (libPath.exists())
System.load(libPath.getAbsolutePath());
else
System.loadLibrary(name);
}
/**
* Load the specified native library.
*
* @param pathname
* complete path or name of the library we want to load
*/
public static void loadLibrary(String pathname)
{
final File file = new File(pathname);
if (file.exists())
System.load(file.getAbsolutePath());
else
System.loadLibrary(pathname);
}
}