Fresh - JBoss Shell - Getting Started Guide

Version 4

    Installation

     

    Check out sources from http://anonsvn.jboss.org/repos/jbossas/projects/fresh/trunk/

     

    Use maven2 to build:

     

    mvn install

     

    Copy generated deployment archive fresh-jar/target/jboss-fresh.jar to JBoss5 deploy directory.

     

    This will automatically start ssh server on port 2022. Use ssh to connect and start typing commands.

     

     

    System Components

    • VFS
    • ThreadPool
    • SystemShell
    • Shell
    • Executables
    • SSH Service
    • RemoteShell

     

    VFS

    A component that abstracts the file system. There are different implementations available. There is MemVFS which stores
    everything in memory, there is DiskVFS that exposes the native file system. One possible implementation for example is
    DB based that stores the FS content into the database.

     

    The role of the VFS is to provide a familiar way to organize commands and configuration files, and perform command lookup,
    but at the same time avoid the requirement of using the native filesystem for that purpose.

     

    VFS is there to provide a familiar unix shell experience.

     

     

    ThreadPool

    Purely a performance enhancing component, to avoid continuous creation of new threads as commands are executed.

     

     

    SystemShell

    SystemShell is the main component of the system. It controls creation and destruction of shell sessions, processes, executables ...
    It depends on VFS and ThreadPool.

     

    SystemShell provides local programmatic access to shell.

     

     

    Shell

    Shell represents a concepts of a shell session. Every shell instance represents an environment in which all command executions are performed.
    Several executables can run simultaneously within the same shell instance. Shell is responsible for parsing the command line, performing command lookup, setting up and invoking the executables representing the commands, setting up the environment settings, stdin, and stdout buffers, properly channeling inputs and outputs when redirection is used.

     

    Shell instances are created through SystemShell.

     

     

    Executables

    All the commands except some special ones already built into the shell are implemented as Executables.
    Executable interface defines a component that can be instanciated, initialized and invoked by Shell as its container.
    Executable receives command line parameters, it has access to its own stdin, and stdout buffers, it has access to per-process environment ...
    It is very easy to write an executable and then use it through shell.

     

     

    SSH Service

    This component provides remote terminal access to shell through ssh protocol.

     

     

    RemoteShell

    This is an EJB3 stateful session that provides remote programatic access to shell through standard java RMI.

     

    TODO: EJB3 not yet implemented - currently it's a EJB 2.1 (is it commited yet?)

     

     

    Shell Command Line

    Command line syntax and features are a subset of unix bash shell.

    Command line parser understands basic constructs:

     

    • Input redirect

     

      Use '<' to read from VFS file:

     

      cat < /some_file.txt

     


      Use '<<' with EOF marker specification to enter multiline text interactively:

     

      cat << EOF
    Eenie Meenie
    Minee Moe
    EOF

     

     

    • Output redirect

     

      Use '>' to write to a file in VFS, truncating any already existing file:

     

    echo 'Merry Christmas' > some_file.txt

     

      Use '>>' to write to a file in VFS, appending content to any already existing file:

     

    echo ', Ho ho ho ...' >> some_file.txt

     


      Use '|' to redirect the output of one executable as the input of another:

     

    cat < /tmp/cities.txt | grep 'San Francisco' > results.txt

     

    • Pathname Expansion

     

      Shell understands unix style regex based filename wildcards, and automatically expands command parameters using such wildcards into a space separated list of filenames.

     

      Example:

    ls [a-c]*

     

    • Environment Variables

     

    To set a shell scoped environment variable use 'set'. The set value will be visible to all subsequent executions.

     

      Example:


    set PATH=/bin
    echo $PATH

     


    To expand an environment variable in command line use '$' prefix:

     

    echo "The path is set to: $PATH"

     

    Environment variable expansion _does not_ happen when using '$' inside single quoted parameters:

     

    echo 'Use "echo $PATH" to display PATH env variable'

     

     

    Command Lookup

    Lookup mechanism mimics Bash. Every shell contains an environment and within it a special environment variable called PATH, which determines a list of directories used for command lookup. These are VFS directories, not native FS directories (can be native FS directories if filesystem based VFS implementation is mounted as VFS root). Commands are represented as empty files with additional metainfo (called Attributes in VFS terminology). A VFS file attribute named Class has to be present on the file, and contain a full class name of the class that implements Executable interface. If file with the name of the command is not found on the PATH a list of internal command mappings is checked. If command is not
    one of the commands in that list, the final fallback is to try and load a class with command's name.

     

    Therefore, for testing new commands it's not necessary to 'install' them by creating a command file and setting Class attribute on it. You can just type the classname as command name.

     

    Basic commands

    Most of the commands are found and invoked through files inside VFS directory '/bin'. To learn more about a command, call it with '--help'.


    VFS commands

    cd      (org.jboss.fresh.shell.commands.CDExe)
      Changes current directory

     

    ls      (org.jboss.fresh.shell.commands.LsExe)
      List contents of a directory

     

    cat    (org.jboss.fresh.shell.commands.CatExe)
      Streams content of one or more files to stdout

     

    cp      (org.jboss.fresh.shell.commands.CpExe)
      Copies a file

     

    mv      (org.jboss.fresh.shell.commands.MvExe)
      Moves a file

     

    rm      (org.jboss.fresh.shell.commands.RmExe)
      Removes a file

     

    touch  (org.jboss.fresh.shell.commands.TouchExe)
      Creates a new empty file, or changes lastModified of the existing file

     

    mkdir  (org.jboss.fresh.shell.commands.MkDirExe)
      Creates a directory

     

    mount  (org.jboss.fresh.shell.commands.MountExe)
      Mounts a VFS instance to a mount point

     

    ln      (org.jboss.fresh.shell.commands.LnExe)
      Creates a symbolic link

     

    info    (org.jboss.fresh.shell.commands.InfoExe)
      Prints file info

     

    setattr (org.jboss.fresh.shell.commands.SetAttrExe)
      Sets attribute on the file

     

     

    File commands

    bzip2  (org.jboss.fresh.shell.commands.Bzip2Exe)
      Compresses input with bzip2

     

    bunzip2 (org.jboss.fresh.shell.commands.Bunzip2Exe)
      Uncompresses input using bzip2

     

    gzip    (org.jboss.fresh.shell.commands.GzipExe)
      Compresses input using gzip

     

    gunzip  (org.jboss.fresh.shell.commands.GunzipExe)
      Uncompresses input using gzip

     

     

    Shell commands

    set    (org.jboss.fresh.shell.commands.SetCommand)
      Sets shell environment variable, or prints them all

     

    date    (org.jboss.fresh.shell.commands.DateExe)
      Prints current time

     

    echo    (org.jboss.fresh.shell.commands.EchoExe)
      Prints text to stdout

     

    history (org.jboss.fresh.shell.commands.HistoryExe)
      Prints the history of executed commands

     

    ps      (org.jboss.fresh.shell.commands.PsExe)
      Prints a list of running executables

     

    kill    (org.jboss.fresh.shell.commands.PsExe)
      Forces a specific executable to end execution

     

    run      (org.jboss.fresh.shell.commands.RunExe)
      Executes shell commands read frominput

     

    version      (org.jboss.fresh.shell.commands.VersionExe)
      Prints current Fresh version.

     

     

    Util commands

    grep    (org.jboss.fresh.shell.commands.GrepExe)
      Filter input to only display lines that match a search pattern

     

    wget    (org.jboss.fresh.shell.commands.util.WebGetExe)
      Outputs the content of a URL

     

    resize  (org.jboss.fresh.shell.commands.util.ImgResizeExe)
      Reads an image from input, and outputs resized image

     

    diag    (org.jboss.fresh.shell.commands.util.DiagExe)
      Prints out basic information about the server

     

    urlenc  (org.jboss.fresh.shell.commands.util.URLEncExe)
      Performs url encoding on input

     

    jndi    (org.jboss.fresh.shell.commands.JNDIExe)
      Performs JNDI operations - list, lookup, bind, unbind

     

     

    Runtime commands

    mbinvoke    (org.jboss.fresh.shell.commands.MBeanInvokeExe)
      Invoke a mbean; mbinvoke 'jboss.vfs:service=VFSCacheStatistics' listCachedContexts

     

    mbquery    (org.jboss.fresh.shell.commands.MBeanQueryExe)
      Query for mbeans; mbquery 'jboss.vfs:*'

     

    mcinvoke    (org.jboss.fresh.shell.commands.MCBeanInvokeExe)
      Invoke a MC bean; mcinvoke VFSCacheStatistics listCachedContexts

     

     

     

    Usage Examples

    Example 1:


    echo Am bam > /tmp/1
    echo Tra la la > /tmp/2
    cat /tmp/1 /tmp/2

     

     

     

    Example 2:

     

    history | grep echo

     

     

     

    Example 3:

     

    cat > /tmp/3 << EOF
    Lorem Ipsum
    dolor sit amet
    EOF

    cat < /tmp/3

     

     

     

    Example 4:

     

    cat > /tmp/4 << EOF
    ls /bin
    EOF

    run --out /tmp/4

     

     

     

    Example 5:

     

    wget http://rss.slashdot.org/Slashdot/slashdotIT | grep '<title>'

     

     

     

    Example 6:

     

    mbquery 'jboss.jca:*'

     

     

     

    Example 7:

     

    mbinvoke 'jboss:service=JNDIView' listXML

     

     

    Example 8:

     

    mcinvoke MainDeployer getTopLevel

     

     

    Example 9:

     

    set MYVAR=100
    echo $MYVAR
    MYVAR=200 echo $MYVAR
    echo $MYVAR

     

     


    Executable API

     

    Commands are implemented as classes of type Executable.

     

    org.jboss.fresh.shell.Executable interface

     

    This interface defines a contract between executable component (Executable) and its container (Shell - see chapter Shell API).

     

      public void setStdOut(OutBuffer out);
      public OutBuffer getStdOut();
      public void setStdIn(InBuffer in);
      public InBuffer getStdIn();
      public void setShell(Shell shell);
      public Shell getShell();
      public void setProcess(Process proc);
      public Process getProcess();
      public void execute(String exepath, String [] args) throws Exception;
      public void sendMessage(String msg);

     

    The container (shell) sets InBuffer, OutBuffer, Shell, and Process properties on the Executable before executing it by calling its execute() method.

    There is a signalling mechanism that allows clients to send arbitrary signals to a running process in the form of Strings. Method sendMessage() is used for that purpose.

     

    When writing custom executables an abstract class org.jboss.fresh.shell.AbstractExecutable should be used as a base class for your own commands. It's very easy to write your own command.

     

    Example:

     

    public class HelloExe extends AbstractExecutable {

     

    public void process(String exename, String[] params) throws Exception {
        BufferWriter out = new BufferWriter(getStdOut());
        out.println(exename + ": " + Arrays.asList(params));
        out.close();
    }

    }


    For a more serious command we should at least provide a friendly usage message.

    A neat thing about stdout and stdin in Fresh is that they are not streams of bytes, but are general purpose Buffers, that can be used to channel objects. Buffers are not supposed to be used directly. Developer has to decide how to treat input and output and choose a buffer wrapper class accordingly. For stdin one of the following three wrappers can be used:

     

    • BufferInputStream which extends java.io.InputStream
    • BufferedReader which extends java.io.Reader
    • BufferObjectReader which is used to channel objects directly

     

    Analogously there are three wrappers to be used in combination with stdout buffers:

     

    • BufferOutputStream which extends java.io.OutputStream
    • BufferWriter which extends java.io.Writer
    • BufferObjectWriter which is used to channel objects directly


    An executable can support different modes of treating stdin or stdout, and can use command line switches (parameters) to control the mode. For example, an executable that performs an EJBQL query can write results to stdout as entity objects using BufferObjectWriter, or it can format entities in the result as strings and write them out line by line using BufferWriter.

     


    Shell API

    Shell API is used when you want to use shell programatically to execute commands through it.

     

    Shell object represents a session used to execute commands that are implemented as Executables. When using SSH client to connect to SSH Service component, creation of shells is automatically taken care of behind the scene. That's also the case when RemoteShell EJB Session is used for remote programatic shell access. Therefore, if you only want to invoke commands via ssh terminal session, then you don't need Shell API. And in the case of remote programatic access, what you really need is RemoteShell API.

     

    • org.jboss.fresh.shell.Shell interface

     

    Shell commands get invoked through one of the execute() methods on Shell interface. The most basic execute() method is the following:

     

      public ProcessInfo execute(String cmdline) throws ShellException;

     

    This method takes a command line, parses it, identifies commands, performs command lookup, creates processes and executes them. The processes are executed asynchronously - execute() returns immediately. The returned ProcessInfo object is used to communicate with the running process.

     

    When there are several commands in the command line we can talk about a compound command that comprises of several processes. The whole command line outwardly acts as a single process. It has a stdin, which is stdin of the first process, and it has a stdout, which is a stdout of the last process in the command line.

     

    After execute() returns, ProcessInfo can be used to access stdin and stdout of the command line.


    If you want to wait for the command line to finish executing, and retrieve results from it then you can do synchronous invocation by using:

     

      public Object executeAsObject(String cmdline) throws ShellException;


    There are methods for communicating with a running process when you invoke it asynchronously:

     

      public Object read(String id) throws IOException;

      public LinkedList readBuffer(String id, int maxSize) throws IOException;

      public void write(String id, Object obj) throws IOException;

      public void writeBuffer(String id, LinkedList obj) throws IOException;

      public void close(String id, int streamId) throws IOException;


    You don't normally invoke these methods directly. There are helper classes that act as Streams / Readers / Writers that you use as an elegant and familiar abstraction:

     

      ShellInputStream
      ShellReader
      ShellObjectReader

      ShellOutputStream
      ShellWriter
      ShellObjectWriter

     

    These helper classes are analogous to different buffer wrappers in the Executable API. They are the other side of the same coin. Executable uses buffers to read/write data. And this data is channeled through Shell API to clients that use these analogous classes listed above.

     

    The choice of abstraction on the client therefore depends on what the command expects on stdin or outputs to stdout.


    Example:

     

     

     

    RemoteShell API

    Example:

     

    InitialContext ctx = new InitialContext();
    RemoteShellHome home = (RemoteShellHome) ctx.lookup("RemoteShell");
    RemoteShell shell = home.create();

    ProcessInfo inf = shell.execute("cat > /tmp/test");
    ShellOutputStream out = new ShellOutputStream(shell, inf.procId);

    IOUtils.copy(in, out);
    out.close();