Coverage Report - com.jcabi.ssh.Shell
 
Classes in this File Line Coverage Branch Coverage Complexity
Shell
N/A
N/A
1.222
Shell$Empty
0%
0/6
0%
0/10
1.222
Shell$Plain
75%
6/8
0%
0/10
1.222
Shell$Safe
66%
6/9
8%
1/12
1.222
Shell$Verbose
66%
4/6
0%
0/10
1.222
 
 1  
 /**
 2  
  * Copyright (c) 2014-2015, jcabi.com
 3  
  * All rights reserved.
 4  
  *
 5  
  * Redistribution and use in source and binary forms, with or without
 6  
  * modification, are permitted provided that the following conditions
 7  
  * are met: 1) Redistributions of source code must retain the above
 8  
  * copyright notice, this list of conditions and the following
 9  
  * disclaimer. 2) Redistributions in binary form must reproduce the above
 10  
  * copyright notice, this list of conditions and the following
 11  
  * disclaimer in the documentation and/or other materials provided
 12  
  * with the distribution. 3) Neither the name of the jcabi.com nor
 13  
  * the names of its contributors may be used to endorse or promote
 14  
  * products derived from this software without specific prior written
 15  
  * permission.
 16  
  *
 17  
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 18  
  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
 19  
  * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 20  
  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
 21  
  * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 22  
  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 23  
  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 24  
  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 25  
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 26  
  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 27  
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 28  
  * OF THE POSSIBILITY OF SUCH DAMAGE.
 29  
  */
 30  
 package com.jcabi.ssh;
 31  
 
 32  
 import com.jcabi.aspects.Immutable;
 33  
 import com.jcabi.log.Logger;
 34  
 import java.io.ByteArrayOutputStream;
 35  
 import java.io.IOException;
 36  
 import java.io.InputStream;
 37  
 import java.io.OutputStream;
 38  
 import java.util.logging.Level;
 39  
 import lombok.EqualsAndHashCode;
 40  
 import lombok.ToString;
 41  
 import org.apache.commons.io.input.NullInputStream;
 42  
 import org.apache.commons.io.output.TeeOutputStream;
 43  
 import org.apache.commons.lang3.CharEncoding;
 44  
 
 45  
 /**
 46  
  * Shell.
 47  
  *
 48  
  * <p>This interface is implemented by {@link SSH} class. In order to use
 49  
  * it, just make an instance and call
 50  
  * {@link #exec(String,InputStream,OutputStream,OutputStream)} exec()}:
 51  
  *
 52  
  * <pre> String hello = new Shell.Plain(
 53  
  *   new SSH(
 54  
  *     "ssh.example.com", 22,
 55  
  *     "yegor", "-----BEGIN RSA PRIVATE KEY-----..."
 56  
  *   )
 57  
  * ).exec("echo 'Hello, world!'");</pre>
 58  
  *
 59  
  * @author Yegor Bugayenko (yegor@teamed.io)
 60  
  * @version $Id: 14bca8299c3ed783beaa6b0bf4b9e24ae3380cae $
 61  
  * @since 1.0
 62  
  * @see <a href="http://www.yegor256.com/2014/09/02/java-ssh-client.html">article by Yegor Bugayenko</a>
 63  
  */
 64  
 @Immutable
 65  
 public interface Shell {
 66  
 
 67  
     /**
 68  
      * Execute and return exit code.
 69  
      * @param command Command
 70  
      * @param stdin Stdin (will be closed)
 71  
      * @param stdout Stdout (will be closed)
 72  
      * @param stderr Stderr (will be closed)
 73  
      * @return Exit code
 74  
      * @throws IOException If fails
 75  
      * @checkstyle ParameterNumberCheck (5 line)
 76  
      */
 77  
     int exec(String command, InputStream stdin,
 78  
         OutputStream stdout, OutputStream stderr) throws IOException;
 79  
 
 80  
     /**
 81  
      * Safe run (throws if exit code is not zero).
 82  
      */
 83  
     @Immutable
 84  0
     @ToString
 85  0
     @EqualsAndHashCode(of = "origin")
 86  
     final class Safe implements Shell {
 87  
         /**
 88  
          * Original.
 89  
          */
 90  
         private final transient Shell origin;
 91  
         /**
 92  
          * Ctor.
 93  
          * @param shell Original shell
 94  
          */
 95  2
         public Safe(final Shell shell) {
 96  2
             this.origin = shell;
 97  2
         }
 98  
         // @checkstyle ParameterNumberCheck (5 line)
 99  
         @Override
 100  
         public int exec(final String command, final InputStream stdin,
 101  
             final OutputStream stdout, final OutputStream stderr)
 102  
             throws IOException {
 103  2
             final int exit = this.origin.exec(command, stdin, stdout, stderr);
 104  2
             if (exit != 0) {
 105  0
                 throw new IllegalArgumentException(
 106  
                     String.format("non-zero exit code #%d: %s", exit, command)
 107  
                 );
 108  
             }
 109  2
             return exit;
 110  
         }
 111  
     }
 112  
 
 113  
     /**
 114  
      * Without input and output.
 115  
      */
 116  
     @Immutable
 117  0
     @ToString
 118  0
     @EqualsAndHashCode(of = "origin")
 119  
     final class Empty {
 120  
         /**
 121  
          * Original.
 122  
          */
 123  
         private final transient Shell origin;
 124  
         /**
 125  
          * Ctor.
 126  
          * @param shell Original shell
 127  
          */
 128  0
         public Empty(final Shell shell) {
 129  0
             this.origin = shell;
 130  0
         }
 131  
         /**
 132  
          * Just exec.
 133  
          * @param cmd Command
 134  
          * @return Exit code
 135  
          * @throws IOException If fails
 136  
          */
 137  
         public int exec(final String cmd) throws IOException {
 138  0
             return this.origin.exec(
 139  
                 cmd, new NullInputStream(0L),
 140  
                 Logger.stream(Level.INFO, this),
 141  
                 Logger.stream(Level.WARNING, this)
 142  
             );
 143  
         }
 144  
     }
 145  
 
 146  
     /**
 147  
      * With output only.
 148  
      */
 149  
     @Immutable
 150  0
     @ToString
 151  0
     @EqualsAndHashCode(of = "origin")
 152  
     final class Plain {
 153  
         /**
 154  
          * Original.
 155  
          */
 156  
         private final transient Shell origin;
 157  
         /**
 158  
          * Ctor.
 159  
          * @param shell Original shell
 160  
          */
 161  2
         public Plain(final Shell shell) {
 162  2
             this.origin = shell;
 163  2
         }
 164  
         /**
 165  
          * Just exec.
 166  
          * @param cmd Command
 167  
          * @return Stdout
 168  
          * @throws IOException If fails
 169  
          */
 170  
         public String exec(final String cmd) throws IOException {
 171  2
             final ByteArrayOutputStream baos = new ByteArrayOutputStream();
 172  2
             this.origin.exec(
 173  
                 cmd, new NullInputStream(0L),
 174  
                 baos, baos
 175  
             );
 176  2
             return baos.toString(CharEncoding.UTF_8);
 177  
         }
 178  
     }
 179  
 
 180  
     /**
 181  
      * Verbose run.
 182  
      */
 183  
     @Immutable
 184  0
     @ToString
 185  0
     @EqualsAndHashCode(of = "orgn")
 186  
     final class Verbose implements Shell {
 187  
         /**
 188  
          * Original.
 189  
          */
 190  
         private final transient Shell orgn;
 191  
         /**
 192  
          * Ctor.
 193  
          * @param shell Original shell
 194  
          */
 195  2
         public Verbose(final Shell shell) {
 196  2
             this.orgn = shell;
 197  2
         }
 198  
         // @checkstyle ParameterNumberCheck (5 line)
 199  
         @Override
 200  
         public int exec(final String command, final InputStream stdin,
 201  
             final OutputStream stdout, final OutputStream stderr)
 202  
             throws IOException {
 203  2
             return this.orgn.exec(
 204  
                 command, stdin,
 205  
                 new TeeOutputStream(stdout, Logger.stream(Level.INFO, this)),
 206  
                 new TeeOutputStream(stderr, Logger.stream(Level.WARNING, this))
 207  
             );
 208  
         }
 209  
     }
 210  
 }