Dépôt officiel du code source de l'ERP OpenConcerto
/trunk/OpenConcerto/src/org/openconcerto/utils/Platform.java |
---|
14,6 → 14,7 |
package org.openconcerto.utils; |
import static org.openconcerto.utils.DesktopEnvironment.cmdSubstitution; |
import org.openconcerto.utils.cc.ITransformer; |
import java.io.BufferedReader; |
23,6 → 24,8 |
import java.math.BigDecimal; |
import java.net.InetAddress; |
import java.net.SocketException; |
import java.nio.file.Files; |
import java.nio.file.Paths; |
import java.util.ArrayList; |
import java.util.List; |
import java.util.logging.Level; |
43,8 → 46,10 |
final OSFamily os = OSFamily.getInstance(); |
if (os == OSFamily.Windows) { |
return CYGWIN; |
} else if (os == OSFamily.FreeBSD || os == OSFamily.Mac) { |
} else if (os == OSFamily.FreeBSD) { |
return FREEBSD; |
} else if (os == OSFamily.Mac) { |
return MACOS; |
} else { |
return LINUX; |
} |
57,12 → 62,23 |
public abstract String getPath(final File f); |
public final String getPID() throws IOException { |
// TODO remove reflection and getPreJava9PID() once on java 11 |
try { |
final Class<?> phClass = Class.forName("java.lang.ProcessHandle"); |
final Object ph = phClass.getMethod("current").invoke(null); |
return ((Number) phClass.getMethod("pid").invoke(ph)).toString(); |
} catch (ClassNotFoundException e) { |
// fall back |
} catch (Exception e) { |
throw new IOException("Couldn't get PID", e); |
} |
return getPreJava9PID(); |
} |
protected String getPreJava9PID() throws IOException { |
final Process p = this.eval("echo -n $PPID"); |
final BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream())); |
try { |
try (final BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()))) { |
return reader.readLine(); |
} finally { |
reader.close(); |
} |
} |
102,12 → 118,8 |
public final void append(File f1, File f2) throws IOException { |
final String c = "cat '" + f1.getAbsolutePath() + "' >> '" + f2.getAbsolutePath() + "'"; |
try { |
this.eval(c).waitFor(); |
} catch (InterruptedException e) { |
throw new IllegalStateException(e); |
this.waitForSuccess(this.eval(c), "append"); |
} |
} |
public Process cp_l(File src, File dest) throws IOException { |
return Runtime.getRuntime().exec(new String[] { "cp", "-prl", src.getAbsolutePath(), dest.getAbsolutePath() }); |
138,14 → 150,23 |
protected final PingResult ping(final String command, final int totalCount, int requiredCount) throws IOException { |
if (requiredCount <= 0) |
requiredCount = totalCount; |
final List<String> countAndLastLine = StringUtils.splitIntoLines(cmdSubstitution(eval(command))); |
// Keep errors out of cmdSubstitution() (e.g. "ping: sendto: Message too long" when |
// setDontFragment(true)) |
final Process proc = evalPB(command).redirectErrorStream(false).start(); |
final String output = cmdSubstitution(proc); |
try { |
this.waitForSuccess(proc, "ping"); |
final List<String> countAndLastLine = StringUtils.splitIntoLines(output); |
if (countAndLastLine.size() != 2) |
throw new IllegalStateException("Not 2 lines in " + countAndLastLine); |
final int replied = Integer.parseInt(countAndLastLine.get(0)); |
assert replied <= totalCount; |
final PingResult res = new PingResult(totalCount, replied, requiredCount, replied == 0 ? null : parsePingAverageRT(countAndLastLine.get(1).trim())); |
return res; |
final BigDecimal averageRTT = replied == 0 ? null : parsePingAverageRT(countAndLastLine.get(1).trim()); |
return new PingResult(totalCount, replied, requiredCount, averageRTT); |
} catch (Exception e) { |
throw new IllegalStateException("Couldn't use output :<<<\n" + output + "\n<<<", e); |
} |
} |
/** |
* Eval the passed string with bash. |
155,17 → 176,31 |
* @throws IOException If an I/O error occurs. |
*/ |
public final Process eval(String s) throws IOException { |
return Runtime.getRuntime().exec(new String[] { this.getBash(), "-c", s }); |
return evalPB(s).start(); |
} |
public final ProcessBuilder evalPB(String s) throws IOException { |
return new ProcessBuilder(this.getBash(), "-c", s); |
} |
public final int exitStatus(Process p) { |
return this.exitStatus(p, null); |
} |
public final int exitStatus(Process p, final String name) { |
try { |
return p.waitFor(); |
} catch (InterruptedException e) { |
throw new IllegalStateException(e); |
throw new RTInterruptedException("Interrupted while waiting for" + (name == null ? "" : " '" + name + "'") + " process", e); |
} |
} |
public final void waitForSuccess(final Process p, final String name) { |
final int exitStatus = exitStatus(p, name); |
if (exitStatus != 0) |
throw new IllegalStateException(name + " unsuccessful : " + exitStatus); |
} |
public abstract boolean isAdmin() throws IOException; |
private static abstract class UnixPlatform extends Platform { |
175,6 → 210,20 |
return true; |
} |
@Override |
public final String getPreJava9PID() throws IOException { |
final String symlink = getSelfProcessSymlink(); |
if (symlink == null) |
return super.getPreJava9PID(); |
// readSymbolicLink() seems to faster than getCanonicalFile() or toRealPath(). |
// Another way is using reflection for |
// ManagementFactory.getRuntimeMXBean().jvm.getProcessId() |
return Files.readSymbolicLink(Paths.get(symlink)).getFileName().toString(); |
} |
protected abstract String getSelfProcessSymlink(); |
public final boolean isRunning(final int pid) throws IOException { |
// --pid only works on Linux, -p also on Nexenta |
final Process p = Runtime.getRuntime().exec(new String[] { "ps", "-p", String.valueOf(pid) }); |
220,7 → 269,7 |
protected BigDecimal parsePingAverageRT(String statsLine) { |
final Matcher m = PING_STATS_PATTERN.matcher(statsLine); |
if (!m.matches()) |
throw new IllegalArgumentException("Not matching " + PING_STATS_PATTERN + " : " + statsLine); |
throw new IllegalArgumentException("Not matching " + PING_STATS_PATTERN + " :\n" + statsLine); |
return new BigDecimal(m.group(2)); |
} |
232,7 → 281,13 |
} |
private static final Platform LINUX = new UnixPlatform() { |
@Override |
protected String getSelfProcessSymlink() { |
return "/proc/self"; |
} |
@Override |
public PingResult ping(final InetAddress host, final PingBuilder pingBuilder, final int routingTableIndex) throws IOException { |
if (routingTableIndex > 0) |
throw new UnsupportedOperationException("On Linux, choosing a different routing table requires changing the system policy"); |
271,7 → 326,13 |
}; |
private static final Platform FREEBSD = new UnixPlatform() { |
@Override |
protected String getSelfProcessSymlink() { |
return "/proc/curproc"; |
} |
@Override |
public PingResult ping(final InetAddress host, final PingBuilder pingBuilder, final int routingTableIndex) throws IOException { |
final List<String> command = new ArrayList<String>(16); |
command.add("setfib"); |
308,6 → 369,18 |
} |
}; |
private static final Platform MACOS = new UnixPlatform() { |
@Override |
protected String getSelfProcessSymlink() { |
return null; |
} |
@Override |
protected PingResult ping(InetAddress host, PingBuilder pingBuilder, int routingTableIndex) throws IOException { |
return FREEBSD.ping(host, pingBuilder, routingTableIndex); |
} |
}; |
private static final class CygwinPlatform extends Platform { |
@Override |
347,13 → 420,9 |
public boolean ping(InetAddress host, final int timeout) throws IOException { |
// windows implem of isReachable() is buggy |
// see http://bordet.blogspot.com/2006/07/icmp-and-inetaddressisreachable.html |
try { |
final int exit = Runtime.getRuntime().exec("ping -n 1 -w " + timeout + " " + host.getHostAddress()).waitFor(); |
final int exit = this.exitStatus(Runtime.getRuntime().exec("ping -n 1 -w " + timeout + " " + host.getHostAddress()), "ping"); |
return exit == 0; |
} catch (InterruptedException e) { |
throw new IllegalStateException(e); |
} |
} |
@Override |
public PingResult ping(final InetAddress host, final PingBuilder pingBuilder, final int routingTableIndex) throws IOException { |