SocketChannel createClient()

in maven-resolver-named-locks-ipc/src/main/java/org/eclipse/aether/named/ipc/IpcClient.java [112:256]


    SocketChannel createClient() throws IOException {
        String familyProp = System.getProperty(IpcServer.SYSTEM_PROP_FAMILY, IpcServer.DEFAULT_FAMILY);
        SocketFamily family = familyProp != null ? SocketFamily.valueOf(familyProp) : SocketFamily.inet;

        Path lockPath = this.lockPath.toAbsolutePath().normalize();
        Path lockFile =
                lockPath.resolve(".maven-resolver-ipc-lock-" + family.name().toLowerCase(Locale.ENGLISH));
        if (!Files.isRegularFile(lockFile)) {
            if (!Files.isDirectory(lockFile.getParent())) {
                Files.createDirectories(lockFile.getParent());
            }
        }

        try (RandomAccessFile raf = new RandomAccessFile(lockFile.toFile(), "rw")) {
            try (FileLock lock = raf.getChannel().lock()) {
                String line = raf.readLine();
                if (line != null) {
                    try {
                        SocketAddress address = SocketFamily.fromString(line);
                        return SocketChannel.open(address);
                    } catch (IOException e) {
                        // ignore
                    }
                }

                ServerSocketChannel ss = family.openServerSocket();
                String tmpaddr = SocketFamily.toString(ss.getLocalAddress());
                String rand = Long.toHexString(new Random().nextLong());
                String nativeName =
                        System.getProperty(IpcServer.SYSTEM_PROP_NATIVE_NAME, IpcServer.DEFAULT_NATIVE_NAME);
                String syncCmd = IS_WINDOWS ? nativeName + ".exe" : nativeName;

                boolean debug = Boolean.parseBoolean(
                        System.getProperty(IpcServer.SYSTEM_PROP_DEBUG, Boolean.toString(IpcServer.DEFAULT_DEBUG)));
                boolean noNative = Boolean.parseBoolean(System.getProperty(
                        IpcServer.SYSTEM_PROP_NO_NATIVE, Boolean.toString(IpcServer.DEFAULT_NO_NATIVE)));
                if (!noNative) {
                    noNative = !Files.isExecutable(syncPath.resolve(syncCmd));
                }
                Closeable close;
                Path logFile = logPath.resolve("resolver-ipcsync-" + rand + ".log");
                List<String> args = new ArrayList<>();
                if (noNative) {
                    boolean noFork = Boolean.parseBoolean(System.getProperty(
                            IpcServer.SYSTEM_PROP_NO_FORK, Boolean.toString(IpcServer.DEFAULT_NO_FORK)));
                    if (noFork) {
                        IpcServer server = IpcServer.runServer(family, tmpaddr, rand);
                        close = server::close;
                    } else {
                        String javaHome = System.getenv("JAVA_HOME");
                        if (javaHome == null) {
                            javaHome = System.getProperty("java.home");
                        }
                        String javaCmd = IS_WINDOWS ? "bin\\java.exe" : "bin/java";
                        String java = Paths.get(javaHome)
                                .resolve(javaCmd)
                                .toAbsolutePath()
                                .toString();
                        args.add(java);
                        String classpath = getJarPath(getClass()) + File.pathSeparator + getJarPath(IpcServer.class);
                        args.add("-cp");
                        args.add(classpath);
                        String timeout = System.getProperty(IpcServer.SYSTEM_PROP_IDLE_TIMEOUT);
                        if (timeout != null) {
                            args.add("-D" + IpcServer.SYSTEM_PROP_IDLE_TIMEOUT + "=" + timeout);
                        }
                        args.add("-D" + IpcServer.SYSTEM_PROP_DEBUG + "=" + debug);
                        args.add(IpcServer.class.getName());
                        args.add(family.name());
                        args.add(tmpaddr);
                        args.add(rand);
                        ProcessBuilder processBuilder = new ProcessBuilder();
                        ProcessBuilder.Redirect discard = ProcessBuilder.Redirect.to(logFile.toFile());
                        Files.createDirectories(logPath);
                        Process process = processBuilder
                                .directory(lockFile.getParent().toFile())
                                .command(args)
                                .redirectOutput(discard)
                                .redirectError(discard)
                                .start();
                        close = process::destroyForcibly;
                    }
                } else {
                    args.add(syncPath.resolve(syncCmd).toString());
                    String timeout = System.getProperty(IpcServer.SYSTEM_PROP_IDLE_TIMEOUT);
                    if (timeout != null) {
                        args.add("-D" + IpcServer.SYSTEM_PROP_IDLE_TIMEOUT + "=" + timeout);
                    }
                    args.add("-D" + IpcServer.SYSTEM_PROP_DEBUG + "=" + debug);
                    args.add(family.name());
                    args.add(tmpaddr);
                    args.add(rand);
                    ProcessBuilder processBuilder = new ProcessBuilder();
                    ProcessBuilder.Redirect discard = ProcessBuilder.Redirect.to(logFile.toFile());
                    Files.createDirectories(logPath);
                    Process process = processBuilder
                            .directory(lockFile.getParent().toFile())
                            .command(args)
                            .redirectOutput(discard)
                            .redirectError(discard)
                            .start();
                    close = process::destroyForcibly;
                }

                ExecutorService es = Executors.newSingleThreadExecutor();
                Future<String[]> future = es.submit(() -> {
                    SocketChannel s = ss.accept();
                    DataInputStream dis = new DataInputStream(Channels.newInputStream(s));
                    String rand2 = dis.readUTF();
                    String addr2 = dis.readUTF();
                    return new String[] {rand2, addr2};
                });
                String[] res;
                try {
                    res = future.get(5, TimeUnit.SECONDS);
                } catch (Exception e) {
                    try (PrintWriter writer = new PrintWriter(new FileWriter(logFile.toFile(), true))) {
                        writer.println("Arguments:");
                        args.forEach(writer::println);
                        writer.println();
                        writer.println("Exception:");
                        e.printStackTrace(writer);
                    }
                    close.close();
                    throw e;
                } finally {
                    es.shutdownNow();
                    ss.close();
                }
                if (!Objects.equals(rand, res[0])) {
                    close.close();
                    throw new IllegalStateException("IpcServer did not respond with the correct random");
                }

                SocketAddress addr = SocketFamily.fromString(res[1]);
                SocketChannel socket = SocketChannel.open(addr);

                raf.seek(0);
                raf.writeBytes(res[1] + "\n");
                return socket;
            } catch (Exception e) {
                throw new RuntimeException("Unable to create and connect to lock server", e);
            }
        }
    }