public Integer create()

in brooklyn-server/core/src/main/java/org/apache/brooklyn/util/core/internal/ssh/sshj/SshjTool.java [960:1058]


        public Integer create() throws Exception {
            try {
                session = acquire(newSessionAction());
                
                shell = session.startShell();
                
                if (out != null) {
                    InputStream outstream = shell.getInputStream();
                    outgobbler = new StreamGobbler(outstream, out, (Logger)null);
                    outgobbler.start();
                }
                if (err != null) {
                    InputStream errstream = shell.getErrorStream();
                    errgobbler = new StreamGobbler(errstream, err, (Logger)null);
                    errgobbler.start();
                }
                
                OutputStream output = shell.getOutputStream();

                for (CharSequence cmd : commands) {
                    try {
                        output.write(toUTF8ByteArray(cmd+"\n"));
                        output.flush();
                    } catch (ConnectionException e) {
                        if (!shell.isOpen()) {
                            // shell is closed; presumably the user command did `exit`
                            if (LOG.isDebugEnabled()) LOG.debug("Shell closed to {} when executing {}", SshjTool.this.toString(), commands);
                            break;
                        } else {
                            throw e;
                        }
                    }
                }
                // workaround attempt for SSHJ deadlock - https://github.com/shikhar/sshj/issues/105
                synchronized (shell.getOutputStream()) {
                    shell.sendEOF();
                }
                closeWhispering(output, this);
                
                boolean timedOut = false;
                try {
                    long timeoutMillis = Math.min(timeout.toMilliseconds(), Integer.MAX_VALUE);
                    long timeoutEnd = System.currentTimeMillis() + timeoutMillis;
                    Exception last = null;
                    do {
                        if (!shell.isOpen() && ((SessionChannel)session).getExitStatus()!=null)
                            // shell closed, and exit status returned
                            break;
                        boolean endBecauseReturned =
                            // if either condition is satisfied, then wait 1s in hopes the other does, then return
                            (!shell.isOpen() || ((SessionChannel)session).getExitStatus()!=null);
                        try {
                            shell.join(1000, TimeUnit.MILLISECONDS);
                        } catch (ConnectionException e) {
                            last = e;
                        }
                        if (endBecauseReturned) {
                            // shell is still open, ie some process is running
                            // but we have a result code, so main shell is finished
                            // we waited one second extra to allow any background process 
                            // which is nohupped to really be in the background (#162)
                            // now let's bail out
                            break;
                        }
                    } while (System.currentTimeMillis() < timeoutEnd);
                    if (shell.isOpen() && ((SessionChannel)session).getExitStatus()==null) {
                        LOG.debug("Timeout ({}) in SSH shell to {}", timeout, this);
                        // we timed out, or other problem -- reproduce the error.
                        // The shell.join should always have thrown ConnectionExceptoin (looking at code of
                        // AbstractChannel), but javadoc of Channel doesn't explicity say that so play it safe.
                        timedOut = true;
                        throw (last != null) ? last : new TimeoutException("Timeout after "+timeout+" executing "+this);
                    }
                    return ((SessionChannel)session).getExitStatus();
                } finally {
                    // wait for all stdout/stderr to have been re-directed
                    closeWhispering(shell, this);
                    shell = null;
                    try {
                        // Don't use forever (i.e. 0) because BROOKLYN-106: ssh hangs
                        long joinTimeout = (timedOut) ? 1000 : 10*1000;
                        if (outgobbler != null) {
                            outgobbler.join(joinTimeout);
                            outgobbler.close();
                        }
                        if (errgobbler != null) {
                            errgobbler.join(joinTimeout);
                            errgobbler.close();
                        }
                    } catch (InterruptedException e) {
                        LOG.warn("Interrupted gobbling streams from ssh: "+commands, e);
                        Thread.currentThread().interrupt();
                    }
                }
                
            } finally {
                clear();
            }
        }