
eu.mihosoft.vrl.system.VSysUtil Maven / Gradle / Ivy
/*
* VSysUtil.java
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 2009–2017 Steinbeis Forschungszentrum (STZ Ölbronn),
* Copyright (c) 2006–2017 by Michael Hoffer
*
* This file is part of Visual Reflection Library (VRL).
*
* VRL is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 3
* as published by the Free Software Foundation.
*
* see: http://opensource.org/licenses/LGPL-3.0
* file://path/to/VRL/src/eu/mihosoft/vrl/resources/license/lgplv3.txt
*
* VRL 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 Lesser General Public License for more details.
*
* This version of VRL includes copyright notice and attribution requirements.
* According to the LGPL this information must be displayed even if you modify
* the source code of VRL. Neither the VRL Canvas attribution icon nor any
* copyright statement/attribution may be removed.
*
* Attribution Requirements:
*
* If you create derived work you must do three things regarding copyright
* notice and author attribution.
*
* First, the following text must be displayed on the Canvas:
* "based on VRL source code". In this case the VRL canvas icon must be removed.
*
* Second, the copyright notice must remain. It must be reproduced in any
* program that uses VRL.
*
* Third, add an additional notice, stating that you modified VRL. A suitable
* notice might read
* "VRL source code modified by YourName 2012".
*
* Note, that these requirements are in full accordance with the LGPL v3
* (see 7. Additional Terms, b).
*
* Please cite the publication(s) listed below.
*
* Publications:
*
* M. Hoffer, C. Poliwoda, & G. Wittum. (2013). Visual reflection library:
* a framework for declarative GUI programming on the Java platform.
* Computing and Visualization in Science, 2013, 16(4),
* 181–192. http://doi.org/10.1007/s00791-014-0230-y
*/
package eu.mihosoft.vrl.system;
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.platform.win32.Kernel32;
import eu.mihosoft.vrl.io.IOUtil;
import java.awt.Desktop;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.ClipboardOwner;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.BufferedReader;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.Field;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* This class provides methods for handling platform specific paths,
* compatibility information and other system functionality such as access to
* the system clipboard or loading native libraries.
*
* @author Michael Hoffer <[email protected]>
*/
public class VSysUtil {
public static final String OS_LINUX = "Linux";
public static final String OS_MAC = "Mac OS X";
public static final String OS_WINDOWS = "Windows";
public static final String OS_OTHER = "Other";
public static final String[] SUPPORTED_OPERATING_SYSTEMS = {OS_LINUX, OS_MAC, OS_WINDOWS};
public static final String[] SUPPORTED_ARCHITECTURES = {
"x86", "i386", "i686", // 32 bit (equivalent)
"x86_64", "amd64"}; // 64 bit (equivalent)
private static Boolean fakeLinux;
private static Boolean fakeMacOS;
private static Boolean fakeWindows;
@Deprecated
public static void setFakeLinux(Boolean value) {
fakeLinux = value;
}
@Deprecated
public static void setFakeWindows(Boolean value) {
fakeWindows = value;
}
@Deprecated
public static void setFakeMacOS(Boolean value) {
fakeMacOS = value;
}
// no instanciation allowed
private VSysUtil() {
throw new AssertionError(); // not in this class either!
}
/**
* Returns the architecture name, i.e.,
* x64
or
* x86
or
* generic
.
*
* Note: names returned by this method are compatible with native
* library and resource locations for VRL and VRL plugins.
*
* @return architecture name
*/
public static String getArchName() {
String osArch = System.getProperty("os.arch");
if (!isArchSupported()) {
return "generic";
}
String archName = "x86";
if (osArch.contains("64")) {
archName = "x64";
}
return archName;
}
/**
* Returns the name of the OS, i.e.,
* linux
or
* osx
or
* windows
or
* generic
.
*
* Note: names returned by this method are compatible with native
* library and resource locations for VRL and VRL plugins.
*
* @return architecture name
*/
public static String getOSName() {
String osName = System.getProperty("os.name");
if (osName.contains("Linux")) {
return "linux";
} else if (osName.contains("Mac OS X")) {
return "osx";
} else if (osName.contains("Windows")) {
return "windows";
}
return "generic";
}
/**
* Returns the platform and architecture specific path prefix, e.g.,
* linux/x64
or
* windows/x86
.
*
* @return the platform and architecture specific path prefix
*/
public static String getPlatformSpecificPath() {
String result = "";
String osName = System.getProperty("os.name");
String archFolder = getArchName() + "/";
if (osName.contains("Linux")) {
result += "linux/" + archFolder;
} else if (osName.contains("Mac OS X")) {
result += "osx/";
} else if (osName.contains("Windows")) {
result += "windows/" + archFolder;
} else {
result += "generic/";
}
return result;
}
public static boolean isWindows() {
if(fakeWindows==null) {
return getOS().equals(OS_WINDOWS);
} else {
return fakeWindows;
}
}
public static boolean isMacOSX() {
if(fakeMacOS==null) {
return getOS().equals(OS_MAC);
} else {
return fakeMacOS;
}
}
public static boolean isLinux() {
if(fakeLinux==null) {
return getOS().equals(OS_LINUX);
} else {
return fakeLinux;
}
}
/**
* Returns the platform specific ending for native dynamic libraries.
*
* @param os operatin system
* @return so
on Linux/Unix, dll
on Windows,
* dylib
on Mac OS X and so
for other operating
* system (unsupported)
*/
public static String getPlatformSpecificLibraryEnding(String os) {
VParamUtil.throwIfNull(os);
if (os.equals(OS_MAC)) {
return "dylib";
} else if (os.equals(OS_LINUX)) {
return "so";
} else if (os.equals(OS_WINDOWS)) {
return "dll";
}
// for other assuming posix complient
return "so";
}
/**
* Returns the platform specific ending for native dynamic libraries.
*
* @return so
on Linux/Unix, dll
on Windows,
* dylib
on Mac OS X and so
for other operating
* system (unsupported)
*/
public static String getPlatformSpecificLibraryEnding() {
return getPlatformSpecificLibraryEnding(getOS());
}
/**
* Returns the platform name and architecture.
*
* @return he platform name and architecture
*/
public static String getPlatformInfo() {
String arch = getArchName();
return System.getProperty("os.name")
+ " (" + arch + ")";
}
/**
* Loads all native libraries in the specified folder and optionally all of
* its subfolders. Please ensure that all libraries in the folder are
* compatible with the current os. The folder must contain all library
* dependencies.
*
* @param folder library folder
* @param recursive defines whether recursively load libraries from sub
* folders
*
* @return true
if all native libraries could be loaded;
* false
otherwise
*/
public static boolean loadNativeLibrariesInFolder(File folder, boolean recursive) {
VParamUtil.throwIfNotValid(
VParamUtil.VALIDATOR_EXISTING_FOLDER, folder);
final String dylibEnding = "." + VSysUtil.getPlatformSpecificLibraryEnding();
Collection dynamicLibraries = new ArrayList();
if (recursive) {
dynamicLibraries.addAll(
IOUtil.listFiles(folder, new String[]{dylibEnding}));
} else {
File[] libFiles = folder.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.endsWith(dylibEnding);
}
});
dynamicLibraries.addAll(Arrays.asList(libFiles));
}
System.out.println(">> loading native libraries:");
ArrayList loadedLibraries = new ArrayList();
ArrayList errorLibraries = new ArrayList();
int lastSize = -1;
while (loadedLibraries.size() > lastSize) {
lastSize = loadedLibraries.size();
for (File f : dynamicLibraries) {
String libName = f.getAbsolutePath();
if (!loadedLibraries.contains(libName)) {
// System.out.println(" --> " + f.getName());
try {
System.load(libName);
loadedLibraries.add(libName);
} catch (Exception ex) {
ex.printStackTrace(System.err);
} catch (UnsatisfiedLinkError ex) {
ex.printStackTrace(System.err);
}
}
}
}
boolean errors = loadedLibraries.size() != dynamicLibraries.size();
for (File f : dynamicLibraries) {
if (!loadedLibraries.contains(f.getAbsolutePath())) {
errorLibraries.add(f.getName());
}
}
System.out.println(" --> done.");
if (errors) {
System.err.println(">> Not Loaded:");
for (String loadedLib : errorLibraries) {
System.err.println("--> " + loadedLib);
}
}
return !errors;
}
/**
* Loads all native librarties in the specified folder and all of its
* subfolders. Please ensure that all libraries in the folder are compatible
* with the current os.
*
* @param folder library folder
*
* @return true
if all native libraries could be loaded;
* false
otherwise
*/
public static boolean loadNativeLibrariesInFolder(File folder) {
return loadNativeLibrariesInFolder(folder, true);
}
/**
* Returns the binary path to system executables. The path depends on the OS
* and architecture.
*
* @return the binary path to system executables
*/
public static String getSystemBinaryPath() {
return "bin/" + getPlatformSpecificPath();
}
/**
* Returns the binary path to custom executables. The path depends on the OS
* and architecture.
*
* @return the binary path to custom executables
*/
public static String getCustomBinaryPath() {
return "custom-bin/" + getPlatformSpecificPath();
}
/**
* Indicates whether the current OS is officially supported by VRL.
*
* @return true
if the current OS is officially supported;
* false
otherwise
*/
public static boolean isOsSupported() {
boolean result = false;
String osName = System.getProperty("os.name");
for (String s : SUPPORTED_OPERATING_SYSTEMS) {
if (osName.contains(s)) {
result = true;
break;
}
}
return result;
}
/**
* Returns the OS name. If the OS is not supported, "Other" will be
* returned.
Note: in contrary to
* System.getProperty()
only the base name will be returned.
* See {@link #SUPPORTED_OPERATING_SYSTEMS}.
*
* @return the OS name
*/
public static String getOS() {
String result = OS_OTHER;
String osName = System.getProperty("os.name");
for (String s : SUPPORTED_OPERATING_SYSTEMS) {
if (osName.contains(s)) {
result = s;
break;
}
}
return result;
}
/**
* Indicates whether the current architecture is officially supported by
* VRL.
*
* @return true
if the current architecture is officially
* supported; false
otherwise
*/
public static boolean isArchSupported() {
boolean result = false;
String osArch = System.getProperty("os.arch");
for (String s : SUPPORTED_ARCHITECTURES) {
if (s.equals(osArch)) {
result = true;
break;
}
}
return result;
}
/**
* Copies a string to the system clipboard.
*
* @param s string to copy
*/
public static void copyToClipboard(String s) {
TextTransfer textTransfer = new TextTransfer();
textTransfer.setClipboardContents(s);
}
/**
* Copies a string from the system clipboard.
*
* @return a copy of the string from the sytem clipboard
*/
public static String copyFromClipboard() {
TextTransfer textTransfer = new TextTransfer();
return textTransfer.getClipboardContents();
}
/**
* Clipboard class. Based on a forum entry that I don't remember.
*/
private static class TextTransfer implements ClipboardOwner {
/**
* Empty implementation of the ClipboardOwner interface.
*/
@Override
public void lostOwnership(Clipboard aClipboard,
Transferable aContents) {
//do nothing
}
/**
* Places a string on the clipboard and makes this class the owner of
* the Clipboard's contents.
*/
public void setClipboardContents(String aString) {
StringSelection stringSelection = new StringSelection(aString);
Clipboard clipboard =
Toolkit.getDefaultToolkit().getSystemClipboard();
clipboard.setContents(stringSelection, this);
}
/**
* Returns the current system clipboard string.
*
* @return any text found on the Clipboard; if none found, return an
* empty String.
*/
public String getClipboardContents() {
String result = "";
Clipboard clipboard =
Toolkit.getDefaultToolkit().getSystemClipboard();
//odd: the Object param of getContents is not currently used
Transferable contents = clipboard.getContents(null);
boolean hasTransferableText =
(contents != null)
&& contents.isDataFlavorSupported(DataFlavor.stringFlavor);
if (hasTransferableText) {
try {
result = (String) contents.getTransferData(
DataFlavor.stringFlavor);
} catch (UnsupportedFlavorException ex) {
Logger.getLogger(VSysUtil.class.getName()).
log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(VSysUtil.class.getName()).
log(Level.SEVERE, null, ex);
}
}
return result;
}
}
/**
* Adds a folder path to the native library path.
*
* @param path path to add
* @throws IOException
*/
public static void addNativeLibraryPath(String path) throws IOException {
try {
// This enables the java.library.path to be modified at runtime
// Idea comes from a Sun engineer at
// http://forums.sun.com/thread.jspa?threadID=707176
//
Field field = ClassLoader.class.getDeclaredField("usr_paths");
field.setAccessible(true);
String[] paths = (String[]) field.get(null);
for (int i = 0; i < paths.length; i++) {
if (path.equals(paths[i])) {
return;
}
}
String[] tmp = new String[paths.length + 1];
System.arraycopy(paths, 0, tmp, 0, paths.length);
tmp[paths.length] = path;
field.set(null, tmp);
System.setProperty("java.library.path",
System.getProperty("java.library.path")
+ File.pathSeparator + path);
} catch (IllegalAccessException e) {
throw new IOException("Failed to get permissions to set library path");
} catch (NoSuchFieldException e) {
throw new IOException("Failed to get field handle to set library path");
}
}
/**
* Gives access to native UNIX/POSIX functionality.
*/
private interface CLibrary extends Library {
CLibrary INSTANCE = (CLibrary) Native.loadLibrary("c", CLibrary.class);
int getpid();
int kill(int pid, int signal);
}
/**
* Returns the current process id.
*
* @return the current process id
*/
public static int getPID() {
int result;
if (isWindows()) {
result = Kernel32.INSTANCE.GetCurrentProcessId();
} else if (isLinux() || isMacOSX()) {
return CLibrary.INSTANCE.getpid();
} else {
System.out.println(">> Runing on unsupported OS."
+ " Assuming POSIX compliant OS.");
return CLibrary.INSTANCE.getpid();
}
return result;
}
/**
* Dermines whether the specified process is running.
*
* @param pid process id
* @return true
if the specified process is running;
* false
otherwise
*/
public static boolean isRunning(int pid) {
if (isWindows()) {
// TODO why passing 1 works, 0 does not? the documentation clearly
// states that this value should be set to zero.
return Kernel32.INSTANCE.OpenProcess(1, false, pid) != null;
} else if (isLinux() || isMacOSX()) {
return CLibrary.INSTANCE.kill(pid, 0) == 0;
} else {
System.out.println(">> Runing on unsupported OS."
+ " Assuming POSIX compliant OS.");
return CLibrary.INSTANCE.kill(pid, 0) == 0;
}
}
/**
* Determines whether desktop integration is supported.
*/
public static boolean isDesktopSupported() {
return java.awt.Desktop.isDesktopSupported();
}
/**
* Determines whether desktop integration supports browser actions.
*/
public static boolean isBrowserActionSupported() {
java.awt.Desktop desktop = java.awt.Desktop.getDesktop();
return desktop.isSupported(java.awt.Desktop.Action.BROWSE);
}
/**
* Opens the specified URI in the default browser of the operating system.
*
* @param uri URI to open
*/
public static boolean openURI(URI uri) {
try {
java.awt.Desktop desktop = java.awt.Desktop.getDesktop();
desktop.browse(uri);
return true;
} catch (IOException ex) {
Logger.getLogger(VSysUtil.class.getName()).
log(Level.SEVERE, null, ex);
return false;
}
}
/**
* Indicates whether the specified program is installed and present in the
* execution path.
*
* Note: this method is currently not supported on Windows. It
* requires the Unix program
* which
.
*
* @param program program to check
* @return true
if the program could be found;
* false
otherwise
*/
public static boolean isProgramInstalledOnUnix(String program) {
if (!isWindows()) {
try {
String msg = "";
Process p = new ProcessBuilder("which", program).start();
p.waitFor();
BufferedReader input = new BufferedReader(
new InputStreamReader(p.getErrorStream()));
String line = null;
while ((line = input.readLine()) != null) {
msg += line + "\n";
}
return msg.isEmpty();
} catch (InterruptedException ex) {
Logger.getLogger(VSysUtil.class.getName()).
log(Level.SEVERE, null, ex);
return false;
} catch (IOException ex) {
return false;
}
} else {
throw new IllegalStateException("This command does not support Windows OS!");
}
}
/**
* Opens the specified file in the default file broswer of the operating
* system.
*
* If the default browser cannot be determined the application associated
* with the file type will be opened.
*
* @param f the file to open
*/
public static boolean openFileInDefaultFileBrowser(File f) {
try {
if (VSysUtil.isWindows()) {
Process p = new ProcessBuilder("explorer.exe", "/select," + f.getAbsolutePath()).start();
} else if (VSysUtil.isMacOSX()) {
Process p = new ProcessBuilder("open", "-R", f.getAbsolutePath()).start();
} else if (VSysUtil.isLinux()) {
if (isKDERunning()) {
Process p = new ProcessBuilder("dolphin", "--select", f.getAbsolutePath()).start();
} else if (isProgramInstalledOnUnix("nautilus")) {
Process p = new ProcessBuilder("nautilus", "--browser", f.getAbsolutePath()).start();
} else if (Desktop.isDesktopSupported()) {
Desktop desktop = Desktop.getDesktop();
desktop.open(f);
}
} else if (Desktop.isDesktopSupported()) {
Desktop desktop = Desktop.getDesktop();
desktop.open(f);
}
} catch (IOException ex) {
return false;
}
return true;
}
/**
* Indicates whether KDE 4 is running.
*
* Note: on Windows this method will return
* false
even though KDE running (e.g. through
* Cygwin).
*
* @return true
if KDE 4 is
* running;false
otherwise
*/
public static boolean isKDERunning() {
if (isWindows()) {
return false;
}
Runtime rt = Runtime.getRuntime();
try {
String msg = "";
Process pr = rt.exec("sh -c ps aux");
pr.waitFor();
BufferedReader input = new BufferedReader(
new InputStreamReader(pr.getInputStream()));
String line = null;
while ((line = input.readLine()) != null) {
msg += line + "\n";
}
return msg.contains("kdeinit4");
} catch (InterruptedException ex) {
Logger.getLogger(VSysUtil.class.getName()).
log(Level.SEVERE, null, ex);
return false;
} catch (IOException ex) {
Logger.getLogger(VSysUtil.class.getName()).
log(Level.SEVERE, null, ex);
return false;
}
}
/**
* Indicates whether Gnome or Unity is running.
*
* Note: on Windows this method will return
* false
even though Gnome or Unity is running (e.g. through
* Cygwin).
*
* @return true
if Gnome or Unity is
* running;false
otherwise
*/
public static boolean isGnomeOrUnityRunning() {
if (isWindows()) {
return false;
}
Runtime rt = Runtime.getRuntime();
try {
String msg = "";
Process pr = rt.exec("sh -c ps aux");
pr.waitFor();
BufferedReader input = new BufferedReader(
new InputStreamReader(pr.getErrorStream()));
String line = null;
while ((line = input.readLine()) != null) {
msg += line + "\n";
}
return msg.contains("gnome-session");
} catch (InterruptedException ex) {
Logger.getLogger(VSysUtil.class.getName()).
log(Level.SEVERE, null, ex);
return false;
} catch (IOException ex) {
return false;
}
}
/**
* Runs the specified command with administrator privileges.
*
* Note: be careful. Using this method can do serious damage to
* the users data! Before considering the use of this method be sure you
* really need it.
*
* @param cmd the full command to execute (including arguments)
* @return true
if the command could be executed;
* false
otherwise
*/
public static boolean runWithAdminPrivileges(String cmd) {
throw new UnsupportedOperationException(
"Unfortunately, this is feature not implemented yet!");
// Runtime rt = Runtime.getRuntime();
//
// try {
//
// String msg = "";
//
// Process pr = rt.exec("sh -c ps aux");
//
// pr.waitFor();
//
// BufferedReader input = new BufferedReader(
// new InputStreamReader(pr.getErrorStream()));
//
// String line = null;
//
// while ((line = input.readLine()) != null) {
// msg += line + "\n";
// }
//
// return msg.contains("gnome-session");
//
// } catch (InterruptedException ex) {
// Logger.getLogger(VSysUtil.class.getName()).
// log(Level.SEVERE, null, ex);
// return false;
// } catch (IOException ex) {
// return false;
// }
}
}