The Common Reusable SHell (CRaSH) deploys in a Java runtime and provides interactions with the JVM. Commands are written in Groovy or Java and can be developed at runtime making the extension of the shell very easy with fast development cycle.

Running CRaSH

There are several ways to run CRaSH, as a standalone application it controls its own JVM or as an embedded service in an existing runtime like a web application or a Spring application.

Standalone

Standalone mode

The standalone mode allows you to run CRaSH from the command line directly. It provides the same functionality as the war deployment but does not require a web container as it runs its own virtual machine. The crash directory in the application contains the standalone distribution.

The bin directory /crash/bin can be added to the system path, it contains the crash.sh script that will start the standalone mode, for instance you can set it up this way:

> export PATH=/.../crash/bin:$PATH
> crash.sh
   ______
 .~      ~. |`````````,       .'.                   ..'''' |         |
|           |'''|'''''      .''```.              .''       |_________|
|           |    `.       .'       `.         ..'          |         |
 `.______.' |      `.   .'           `. ....''             |         | 1.3.1

Follow and support the project on http://www.crashub.org
Welcome to jerry + !
It is 2015-02-06 11:09:13 CET now

Let’s review quickly what you can find in standalone crash:

  • The bin directory contains the crash.sh script and the standalone crash jar file

  • The conf directory contains the configuration properties crash.properties and JVM logging configuration logging.properties

  • The cmd directory contains the commands that will be available in crash by default it contains a few example commands

  • The lib directory contains the various libraries used by crash, you should place additional jar files there

Attach mode

The attach mode allows you to attach CRaSH to a JVM located on the same host with the attach API provided by the Hotspot JVM. It is the standalone mode attached to a running JVM specified by a process id. CRaSH will hook into the targetted JVM instead of the JVM started by CRaSH. Let’s see quickly an example of how to use it:

> jps
3165 RemoteMavenServer
20650 Test
20651 Jps

> crash.sh 20650
   ______
 .~      ~. |`````````,       .'.                   ..'''' |         |
|           |'''|'''''      .''```.              .''       |_________|
|           |    `.       .'       `.         ..'          |         |
 `.______.' |      `.   .'           `. ....''             |         | 1.3.1

Follow and support the project on http://vietj.github.com/crash
Welcome to jerry + !
It is 2015-02-06 11:09:13 CET now
%

In this example we attached crash to the Test JVM. We obtained the Test JVM PID thanks to the jps command that belongs to the Java Platform. During this mode the commands are executed in the target JVM.

Configuration

The standalone mode relies on the org.crsh.standalone.CRaSH class main method to configure and run the shell. The startup scripts crash.sh and crash.bar configures this class. You can tweak those scripts to your environment, let’s review the options and arguments of CRaSH:

--cmd option

The --cmd option specifies a directory containing command source files. Such directory contains commands as .groovy files, commands can be in directories for grouping purpose. Several folders can be specified by repeating the option.

--cmd-mode option

The standalone shell search commands in folders (specified with the --cmd option and in the classpath (under the /crash/commands/ folder). The --cmd-mode option defines how to handle the classpath commands:

  • The read option value uses commands from directories and classpath.

  • The copy option value scans the classpath during the startup and copies the commands in the first command folder, then commands are used from the folders. This value requires at least one command directory to be specified for extracting the commands.

--conf option

The --conf option specifies a directory containing configuration files. Several folders can be specified by repeating the option.

--conf-mode option

The standalone shell search configuration files in folders (specified with the --conf option and in the classpath (under the /crash/ folder). The --conf-mode option defines how to handle the classpath configuration:

  • The read option value uses configuration files from directories and classpath.

  • The copy option value scans the classpath during the startup and copies the files in the first configuration folder, then configuration are used from the folders. This value requires at least one conf directory to be specified for extracting the configuration files.

--property option

The --cmd option sets and overrides a shell configuration property, the value follows the pattern a=b, for instance:

crash.sh --property crash.telnet.port=3000

--non-interactive option

The --non-interactive option disable the usage of the JVM input and output.

crash.sh --non-interactive

pid arguments

The org.crsh.standalone.CRaSH main has an optional list of arguments that are JVM process id. When one or several JVM process id are specified, CRaSH will dynamically attach to this virtual machine and will be executed in that machine. By default the two JVM will communicate with a socket unless the non-interactive option is set.

When more than one process id is specified, the non-interactive option must be set because CRaSH will not be able to aggregate two command lines in the same terminal.

Resource extraction

When the options --cmd-mode or --conf-mode are set to the copy, CRaSH will scan the classpath and extract the resources in the corresponding directory.

The default value of these options is copy however no copy happens unless at least one directory for extracting the resources is specified, therefore

  • The org.crsh.standalone.CRaSH does nothing by default

  • The crash.sh or crash.bat extracts the resources in the corresponding directory as the cmd and conf directories are specified

To prevent any resource copying the value read should be used.

Embedded mode

Embedding in a web app

CRaSH can use a standard web archive to be deployed in a web container. The war file is used for its packaging capabilities and triggering the CRaSH life cycle start/stop. In this mode CRaSH has two packaging available:

  • A core war file found under deploy/core/crash.war provides the base CRaSH functionnalities

You have to copy the crash.war in the appropriate server, regardless of the packaging used.

If you want you can embed CRaSH in your own web.xml configuration:

Embedding CRaSH in a web application
<web-app>
  <listener>
    <listener-class>org.crsh.plugin.WebPluginLifeCycle</listener-class>
  </listener>
</web-app>

Embedding in Spring

CRaSH can be easily embedded and configured in a Spring configuration.

Embedding as a Spring bean

Here is an example of embedding crash:

Embedding CRaSH in Spring
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

        <bean class="org.crsh.spring.SpringBootstrap">
    <property name="config">
      <props>
        <!-- VFS configuration -->
        <prop key="crash.vfs.refresh_period">1</prop>

        <!-- SSH configuration -->
        <prop key="crash.ssh.port">2000</prop>

        <!-- Optional SSH timeouts -->
        <prop key="crash.ssh.auth_timeout">300000</prop>
        <prop key="crash.ssh.idle_timeout">300000</prop>

        <!-- Telnet configuration -->
        <prop key="crash.telnet.port">5000</prop>

        <!-- Authentication configuration -->
        <prop key="crash.auth">simple</prop>
        <prop key="crash.auth.simple.username">admin</prop>
        <prop key="crash.auth.simple.password">admin</prop>
      </props>
    </property>
  </bean>

</beans>

The configuration properties are set as properties with the config property of the SpringBootstrap bean.

Any Spring managed beans that extend org.crsh.plugin.CRaSHPlugin will be automatically registered as plugins in addition to those declared in META-INF/services/org.crsh.plugin.CRaSHPlugin.

Embedding in a Spring web app

In case you are embedding CRaSH in a Spring application running with a servlet container, the bean org.crsh.spring.SpringWebBootstrap can be used instead of org.crsh.spring.SpringBootstrap. The SpringWebBootstrap extends the SpringBootstrap class and adds the WEB-INF/crash directory to the command path.

An example packaging comes with the CRaSH distribution, a spring war file found under deploy/spring/crash.war provides the base CRaSH functionnalities bootstrapped by the Spring Framework. It can be used as an example for embedding CRaSH in Spring.

This example is bundled with a spring command that shows how the Spring factory or beans can be accessed within a CRaSH command.

Interacting with the shell

Shell usage

Connection

You need to connect using telnet, SSH or directly to use the shell. The last method is a special mode using the JVM input and output.

Telnet access

Telnet connection is done on port 5000:

(! 520)-> telnet localhost 5000
Trying ::1...
Connected to localhost.
Escape character is '^]'.
   ______
 .~      ~. |`````````,       .'.                   ..'''' |         |
|           |'''|'''''      .''```.              .''       |_________|
|           |    `.       .'       `.         ..'          |         |
 `.______.' |      `.   .'           `. ....''             |         | 1.3.1

Follow and support the project on http://vietj.github.com/crash
Welcome to julien.local + !
It is 2015-02-06 11:09:13 CET now

The bye command disconnect from the shell.

SSH access

SSH connection is done on port 2000 with the password crash:

juliens-macbook-pro:~ julien$ ssh -p 2000 -l root localhost
root@localhost's password:
CRaSH {crash-version} (http://vietj.github.com/crash)
Welcome to juliens-macbook-pro.local!
It is {localdatetime} now.
%

The bye command disconnect from the shell.

Native access

A third mode is available for standalone CRaSH usage where it uses the JVM native input and output. When you run in standalone, CRaSh will be available just after the JVM is launched.

Features

  • Line edition: the current line can be edited via left and right arrow keys

  • History: the key up and key down enable history browsing

  • Quoting: simple quotes or double quotes allow to insert blanks in command options and arguments, for instance "old boy" or old boy. One quote style can quote another, like "hi, it's me".

  • Completion: an advanced completion system is available

Command usage

Getting basic help

The help command will display the list of known commands by the shell.

% help
Try one of these commands with the -h or --help switch:

NAME      DESCRIPTION
help      provides basic help
repl      list the repl or change the current repl
cron      cron management
dashboard a monitoring dashboard
date      show the current time
egrep     search file(s) for lines that match a pattern
env       display the term env
filter    a filter for a stream of map
java      various java language commands
jdbc      JDBC connection
jmx       Java Management Extensions
jndi      Java Naming and Directory Interface
jpa       Java persistance API
jvm       JVM informations
jul       java.util.logging commands
mail      interact with emails
man       format and display the on-line manual pages
shell     shell related command
sleep     sleep for some time
sort      sort a map
system    vm system properties commands
thread    JVM thread commands

Command line usage

The basic CRaSH usage is like any shell, you just type a command with its options and arguments. However it is possible to compose commands and create powerful combinations.

Basic command usage

Typing the command followed by options and arguments will do the job

% ls /
...

Command help display

Any command help can be displayed by using the -h argument:

% help -h
usage: help [-h | --help]

   [-h | --help] this help

In addition of that, commands can have a complete manual that can be displayed thanks to the man command:

% man help
NAME
       help - provides basic help

SYNOPSIS
       help [-h | --help]

PARAMETERS
       [-h | --help]
           Display this help message

Command pipeline

A CRaSH command is able to consume and produce a stream of object, allowing complex interactions between commands where they can exchange stream of compatible objets. Such commands are called pipe commands.

Pipe commands

A pipe commands is a command that can consume and/or produce two type of objects:

  • the consumed type: the type of the object that the command consumes

  • the produced type: the type of the object that the command produces

The Java generic declaration notation is used to denote the command capabilities: <C, P>, for instance the filter is a <Map, Map> pipe.

Non pipe command consumes the java.lang.Void type and produces the java.lang.Object type: <Void, Object> . Such commands will discard any input and can produce any kind of object.

The types consumed and produced by a command are documented in the STREAM section of its manual, let’s read the system propls manual:

% man system propls
NAME
       system propls - list the vm system properties

SYNOPSIS
       system [-h | --help] propls [-f | --filter]

STREAM
       system propls <java.lang.Void, java.util.Map>

PARAMETERS
       [-h | --help]
           Display this help message

       [-f | --filter]
           filter the property with a regular expression on their name

The system propls_ command is a command that:

  • consumes no object (Void)

  • produces system properties as <java.util.Map> objects with two entries NAME and VALUE

Such command is often referred as a producer command as it produces a stream of objects that will either be rendered in the shell or consumed by other commands.

Other pipe commands are usually filters because they consumes and produces objects, for instance the filter command consumes Map objects and produces Map objects:

% man filter
NAME
       filter - a filter for a stream of map

SYNOPSIS
       filter [-p | --pattern] [-h | --help]

STREAM
       filter <java.util.Map, java.util.Map>

PARAMETERS
       [-p | --pattern]
           format <key>:<value>

       [-h | --help]
           Display this help message

This command consumers any map it receives and produces a subset of the maps based on the pattern, providing opportunity for applying other filters down the road.

Creating a pipeline

This operation can be achieved with the pipe operator | and we can combine the system propls and the filter command together:

% system propls | filter -p NAME:*Hosts

NAME               VALUE
---------------------------------------------------------
http.nonProxyHosts local|*.local|169.254/16|*.169.254/16
socksNonProxyHosts local|*.local|169.254/16|*.169.254/16
ftp.nonProxyHosts  local|*.local|169.254/16|*.169.254/16

This work naturally because we have the same type Map shared by the two commands. When the type does not match, several scenarios can happen, depending on the type declared by the piped command:

  • Void : all objects are discarded

  • a super type of the produced type : the objects are consumed since they are acceptable by the command

  • org.crsh.text.Chunk : the chunk is an object representing some textual data. In this case the object toString() method is called and the returning string is transformed into a Chunk object

Pipeline commands

Here is a quick overview of various commands that can interract with the object pipe

Thread

The thread command manipulates java.lang.Thread objects:

  • thread ls : produces threads

  • thread interrupt : interrupts threads

  • thread stop : stop threads

  • thread dump : dump thread stacktrace

Jul command

The Jul command manipulates java.util.logging.Logger objects:

  • jul ls : produces logger objects

  • jul send : consumes logger object and sends a message

  • jul tail : produces log record objects

  • jul set : consumes logger object and sets the log level

  • jul add : create new logger and produces them

JDBC command

The jdbc command manipulates tables as java.util.Map objects:

  • jdbc select : execute a query and produce a stream of map

  • jdbc props : display the connection properties as a single map

  • jdbc info : describe the database as a stream of map

System command

  • system propls : produces a stream of map with the current system properties

Filter command

Filter maps based on value patterns.

Sort command

Buffer a stream and sort it based on keys.

JMX command

todo.

Egrep command

todo.

Jvm command

todo.

Configuration

This chapter explains the configuration of CRaSH, configuration aims to be as simple as possible and is adapted to the mode running CRaSH.

Mount point configuration

CRaSH uses the file system for reading configuration files and discovering command source files. CRaSh uses a virtual file system to be decoupled from the implementation, there are up to three implementations provided out of the box (frameworks embedding CRaSH may add their own VFS implementation):

  • file : the actual file system of the operating system based on the java.io.File API

  • classpath : uses the resources provided by the actual classpath

  • war : the content of the web archive, available only when CRaSH is embedded in a web application

CRaSH can be configured for the conf and cmd mount points with a simple string that describes the VFS to be used. A mount point is configured with a list of mounts, a mount being the name of a file system associated with a path in this file system.

  • file:cmd/ : the cmd directory relative to the file system running the JVM

  • file:/cmd/ : the cmd directory relative to the root of the file system (so /cmd)

  • classpath:/crash/commands/ : any /crash/command/ package found in the classpath

  • war:/WEB-INF/crash/commands/ : the folder /WEB-INF/crash/commands in the war file hosting CRaSH

  • classpath:/crash/commands/;war:/WEB-INF/crash/commands : the aggregates of two entries

By default CRaSH provides an adapted mount point configuration for each mode, but you can customize it according to your needs.

Configuring the web application mode

The servlet context parameters are used for configuring the paths:

<web-app>
  ...
  <context-param>
    <param-name>crash.mountpointconfig.conf</param-name>
    <param-value>war:/WEB-INF/crash/</param-value>
  </context-param>
  <context-param>
    <param-name>crash.mountpointconfig.cmd</param-name>
    <param-value>war:/WEB-INF/crash/commands/</param-value>
  </context-param>
  ...
</web-app>

In this mode, the configs are subject to property interpolation based on the system properties of the JVM:

<web-app>
  ...
  <context-param>
    <param-name>crash.mountpointconfig.conf</param-name>
    <param-value>${myconf}</param-value>
  </context-param>
  ...
</web-app>

The interpolation format allows to specify a default value when the property cannot be resolved using Bash syntax:

<web-app>
  ...
  <context-param>
    <param-name>crash.mountpointconfig.conf</param-name>
    <param-value>${myconf:-war:/WEB-INF/crash/commands/}</param-value>
  </context-param>
  ...
</web-app>

Interpolation is only available for the web application mode.

Configuring the spring mode

The org.crsh.spring.SpringWebBootstrap bean exposes the cmdMountPointConfig and confMountPointConfig properties to configure it:

  <bean class="org.crsh.spring.SpringWebBootstrap">
    <property name="cmdMountPointConfig" value="war:/WEB-INF/crash/commands/"/>
    <property name="confMounPointConfig" value="war:/WEB-INF/crash/"/>
    ...
  </bean>

Configuration properties

Properties play an important role in CRaSH configuration, they are configured differently according to the mode.

Configuring the standalone or attach mode

In standalone or attach mode configuration can be in the /conf/crash.properties file or via the command line directly.

The crash.properties file does not exist by default and it is created at the first run, so you should run CRaSH at least once to extract the file:

% crash

You can also specify properties as a CRaSH command line argument with the -p option:

% crash -p crash.property_name=property_value

Configuring the web application mode

In the war file packaging, the configuration file can be found under /WEB-INF/crash/crash.properties file of the archive. Configuration can be overriden by Java Virtual Machine system properties by using the same property name.

Configuring shell default message

The /crash/commands/base/login.groovy file contains two closures that are evaluated each time a message is required

  • The prompt closure returns the prompt message

  • The welcome closure returns the welcome message

Those closure can be customized to return different messages.

Connectors

Connectors manages the connection of the client to the shell.

JVM connector

The jvm connector is used in the standalone mode and relies on the JVM streams (System.in, System.out and System.err).

The jvm connector uses the default platform encoding provided by the JVM.

The jvm connector uses some parts of the JLine library, since 1.3 it uses the terminal detection and configuration and the key mapping. The JLine library is shaded and included in the crash.shell jar: you don’t need the JLine jar on your classpath and the included jar will not conflict with another existing JLine jar.

JLine can be configured via system properties and the property names should be prefixed with org.crsh.console as the library is shaded.

Terminal detection

By default JLine autodetects the terminal based of the current operating system, the autodetection can be configured to a more specific terminal type with the org.crsh.console.jline.terminal property, see the JLine wiki.

running CRaSH an IDE terminal has limited capabilities and setting the system property org.crsh.console.jline.terminal=none will improve the user experience

JLine logging

JLine logging is useful for troubleshooting the terminal emulation, trace and debug can be activated with the org.crsh.console.jline.internal.Log.debug=true and org.crsh.console.jline.internal.Log.trace=true, see the JLine wiki

SSH connector

Changing the SSH server port

The ports of the server is parameterized by the crash.ssh.port configuration property

crash.ssh.port=2000

Changing SSH server key

The key can be changed by replacing the file WEB-INF/sshd/hostkey.pem. Alternatively you can configure the server to use an external file by using the crash.ssh.keypath parameter in the crash.properties. Uncomment the corresponding property and change the path to the key file.

#crash.ssh.keypath=/path/to/the/key/file

If you specify an external file, you can also configure the server to generate it for you. In this case, the generation will take place when someone first connects through SSH. The default behavior is false, i.e. not to generate.

#crash.ssh.keygen=false

Changing SSH authentication and idle timeouts

Default authentication and idle timeout of the SSH server are set to 10 minutes (600’000 ms). Both timeouts can be configured in milliseconds with the crash.ssh.auth-timeout and crash.ssh.idle-timeout parameters in the crash.properties file.

# SSH configuration 5 minutes = 5 * 60 * 1000 = 300'000
crash.ssh.auth_timeout=300000
crash.ssh.idle_timeout=300000
those properties are named crash.ssh.auth-timeout and crash.ssh.idle-timeout in previous version.

Removing SSH access

To remove the SSH access, remove the jar file crash.connectors.ssh-1.3.1.jar.

Character encoding

By default the SSH connector will uses the LC_CTYPE env value set by the remote client. When this cannot be achieved the SSH connector uses the UTF-8 as default encoding. This default value can be changed using the crash.ssh.default_encoding configuration property.

crash.ssh.default_encoding=UTF-8

Telnet connector

Changing the Telnet server port

The ports of the server is parameterized by the crash.telnet.port configuration property

crash.telnet.port=5000

Removing Telnet access

To remove the Telnet access, remove the jar file crash.connectors.telnet-1.3.1.jar.

Web connector

The websocket provides connectivity from a web browser through WebSockets based on:

  • The jQuery Terminal Emulator Plugin

  • a browser supporting WebSockets

  • a Java web server implementing the JSR 356 API

Client setup

CRaSH.js is the client side part of the connector, it is built on top of the jQuery Terminal Emulator Plugin and uses a client/server protocol for the shell connection.

The web page embedding CRaSH.js requires a few assets:

<script src="js/jquery-1.7.1.min.js"></script>
<script src="js/jquery.mousewheel-min.js"></script>
<script src="js/jquery.terminal-0.7.12.js"></script>
<script src="js/crash.js"></script>
<link href="css/jquery.terminal.css" rel="stylesheet"/>

It can be setup in a few lines of JavaScript:


// Create web socket url
var path = window.location.pathname;
var ctx = path.substring(0, path.indexOf('/', 1));
var protocol;
if (window.location.protocol == 'http:') {
  protocol = 'ws';
} else {
  protocol = 'wss';
}
var url = protocol + '://' + window.location.host + ctx + '/crash';

// Connect to the server
var crash = new CRaSH($('#term_demo'), 1024, 768);
crash.connect(url);

Server setup

Currently the WebSocket server uses the JSR 356 API, the connector is bootstrapped by the org.crashub:crash.connectors.web jar that contains an annotation based endpoint bound to the /crash uri. Therefore the full uri is prefixed by the web application context path in which the connector is deployed.

The org.crashub:crash.connectors.web jar contains also the assets for setting up the client side exposed automatically when the jar is in the WEB-INF/lib of the web application (they are located in the META-INF/resources entry of the jar). To activate the connector the property crash.web.enabled must be set to true.

Step by step setup (recap)

  • put the org.crashub:crash.connectors.web jar in WEB-INF/lib

  • add the crash.web.enabled=true in WEB-INF/crash/crash.properties

  • create a web page in your war file that contains the assets listed previously

  • setup crash.js in the page

Securing the server

todo

Authentication

Authentication configuration

Authentication is used by the SSH server when a user authenticates. Authentication interface is pluggable and has default implementations. The authentication chapter explains how to write a custom authentication plugin, in this section we cover the configuation of the authentication.

The configuration of the authentication plugin is done via property, this is necessary because several plugins can be detected by CRaSH, and the plugin is selected via the property crash.auth that must match the authentication plugin name:

crash.auth=simple

It can also take a comma-separated list of multiple authentication plugins, allowing to mix username/password and key authentication. In this case plugins are tested in the order which they were specified:

crash.auth=simple,key

CRaSH comes out of the box with two authentication plugins.

Simple authentication

Simple authentication provides a simple username/password authentication configured with the crash.auth.simple.username and crash.auth.simple.password properties:

# Authentication configuration
crash.auth=simple
crash.auth.simple.username=admin
crash.auth.simple.password=admin

Jaas authentation

Jaas authentication uses jaas to perform authentication configured with the crash.auth.jaas.domain property to define the jaas domain to use when performing authentication:

# Authentication configuration
crash.auth=jaas
crash.auth.jaas.domain=my-domain

Key authentication

Key authentication relies on a set of authorized public keys to perform authentication configured with the crash.auth.key.path property to specify the path of the keys. The property should point to a valid .pem file. Obviously only a public key is required to be in the file, although it can also contain a private key (that will not be used).

# Authentication configuration
crash.auth=key
crash.auth.key.path=/Users/julien/.ssh/id_dsa.pem

Pluggable authentication

Creating a custom authentication mechanism is done by implementing a CRaSH plugin that provides an implementation of the AuthenticationPlugin interface. Let’s study the simple authentication plugin implementation.

The AuthenticationPlugin is the interface to implement in order to integrate CRaSH with an authentication mechanism:

The integration as a CRaSH plugin mandates to extend the class CRaSHPlugin with the generic type AuthenticationPlugin:

public class SimpleAuthenticationPlugin extends
    CRaSHPlugin<AuthenticationPlugin> implements
    AuthenticationPlugin {


  ...

}
  • The getName() method returns the simple value that matchs the crash.auth configuration property

  • The getImplementation() method returns the object that implements the AuthenticationPlugin class, this method is implemented from the CRaSHPlugin abstract class, but in our case it simply returns this because SimpleAuthenticationPlugin is directly the implementation class.

Now let’s study how the plugin retrieves the configuration properties crash.auth.simple.username and crash.auth.simple.password:

public class SimpleAuthenticationPlugin extends
    CRaSHPlugin<AuthenticationPlugin> implements
    AuthenticationPlugin {


  ...

}
  • The createConfigurationCapabilities() method returns the constants SIMPLE_USERNAME and SIMPLE_PASSWORD that defines the configuration properties that the plugin uses

  • The init() method is invoked by CRaSH before the plugin will be used, at this moment, the configuration properties are retrieved from the plugin context with the method getContext() available in the CRaSHPlugin base class

Finally the plugin needs to provide the authenticate() method that implement the authentication logic:

The logic is straightforward with an equality check of the username and password.

Last but not least we must declare our plugin to make it recognized by CRaSH, this is achieved thanks to the java.util.ServiceLoader class. CRaSH uses the ServiceLoader for loading plugins and the loader needs a file to be present in the jar file containing the class under the name META-INF/services/org.crsh.plugin.CRaSHPlugin containing the class name of the plugin:

org.crsh.auth.SimpleAuthenticationPlugin

When all of this is done, the plugin and its service loader descriptor must be packaged in a jar file and available on the classpath of CRaSH.

You can learn more about the java.util.ServiceLoader by looking at the online javadoc.

Spring authentication

When running in the Spring embedded mode, any Spring bean extending org.crsh.plugin.CRaSHPlugin will be registered as a CRaSH plugin. This can be used for delegating CRaSH authentication to a Spring bean:

Spring managed authentication plugin
package example;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

import javax.sql.DataSource;

import org.crsh.auth.AuthenticationPlugin;
import org.crsh.plugin.CRaSHPlugin;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component("dbCrshAuth")
public class DbCrshAuthPlugin extends CRaSHPlugin<AuthenticationPlugin>
        implements AuthenticationPlugin {

    @Autowired
    private DataSource dataSource;

    @Override
    public AuthenticationPlugin getImplementation() {
        return this;
    }

    @Override
    public boolean authenticate(String username, String password)
            throws Exception {
        Connection conn = dataSource.getConnection();

        PreparedStatement statement = conn
                .prepareStatement("SELECT COUNT(*) FROM users WHERE username = ? AND password = ?");
        statement.setString(1, username);
        statement.setString(2, password);

        ResultSet rs = statement.executeQuery();
        return rs.getInt(1) >= 1;
    }

    @Override
    public String getName() {
        return "dbCrshAuth";
    }

    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
    }
}

The above code uses Spring annotation driven beans, but this works the same with beans configured in XML:

Custom authentication bean in spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

    <bean class="example.DbCrshAuthPlugin">
        <property name="dataSource" ref="dataSource"/>
    </bean>

</beans>

Developers

Developping commands

Early CRaSH versions of CRaSH were targetting Groovy only, since version 1.3, CRaSH has become polyglot and can work potentially with any language supported by the JVM. The Java language is now supported out of the box along with Groovy.

In this section we will describe commands written in the Java or/and Groovy languages. These two JVM languages share a lot and often valid Java code is also valid Groovy code (obviously the converse is not true).

Each command has a corresponding source ending with .java or .groovy file that contains a command class that will be invoked by the shell. The files are usually located in:

  • /crash/commands/ path of jar files

  • cmd directory for the standalone distribution

  • /WEB-INF/crash/commands directory for the web archive deployment

When CRaSH is embedded by a runtime, CRaSH commands can be in other places, please refer to the documentation of your runtime.

Commands can directly be placed in the commands directory; however they can also be placed in a sub directory of the command directory, which is useful to group commands of the same kind.

In addition of that there are two special files called login.groovy and logout.groovy that are executed upon login and logout of a user. They are useful to setup and cleanup things related to the current user session.

Commands are annotated classes, such class can be a simple command or a git-style command. The cli framework provides conventions and a set of annotations for easily writing commands with options and arguments in a very declarative manner.

Simple command

Let’s study a simple class command example:

import org.crsh.cli.Command;
import org.crsh.cli.Usage;
import org.crsh.cli.Option;

class date {
  @Usage("show the current time")
  @Command
  Object main(
     @Usage("the time format")
     @Option(names=["f","format"])
     String format) {
    if (format == null)
      format = "EEE MMM d HH:mm:ss z yyyy";
    def date = new Date();
    return date.format(format);
  }
}

The date command is pretty straightforward to understand:

  • The @Command annotation declares the main method as a command

  • The command takes one optional format option declared by the @Option annotation

  • The @Usage annotation describes the usage of the command and its parameters

% date
Thu Apr 19 15:44:05 CEST 2012
the main name is a convention for simple commands. Another name would create a git-style command instead.

The @Usage annotation is important because it gives a human description of the command to the user:

% date -h
usage: date [-h | --help] [-f | --format]

   [-h | --help]   command usage
   [-f | --format] the time format

Sub commands

A class can hold several commands allowing a single file to group several commands, let’s study the JDBC command structure:

@Usage("JDBC connection")
class jdbc {

  @Usage("connect to database with a JDBC connection string")
  @Command
  public String connect(
          @Usage("The username")
          @Option(names=["u","username"])
          String user,
          @Usage("The password")
          @Option(names=["p","password"])
          String password,
          @Usage("The extra properties")
          @Option(names=["properties"])
          Properties properties,
          @Usage("The connection string")
          @Argument
          String connectionString) {
     ...
  }

  @Usage("close the current connection")
  @Command
  public String close() {
     ...
  }
}

We can see that the class declares two commands connect and close, they are invoked this way:

% jdbc connect jdbc:derby:memory:EmbeddedDB;create=true
Connected to data base : jdbc:derby:memory:EmbeddedDB;create=true
% jdbc close
Connection closed

Java commands

The previous examples focused on the Groovy language, let’s see how we can do the same in Java:

import org.crsh.command.*;
import org.crsh.cli.*;
import java.util.Date;
import java.text.SimpleDateFormat;

public class date extends BaseCommand {
  @Usage("show the current time")
  @Command
  public Object main(@Usage("the time format") @Option(names={"f","format"}) String format) {
    if (format == null)
      format = "EEE MMM d HH:mm:ss z yyyy";
    Date date = new Date();
    SimpleDateFormat formatter = new SimpleDateFormat(format);
    return formatter.format(date);
  }
}

Beside the fact that the Java version is a bit more verbose, let’s outline the noticeable differences:

  • the command must extend the org.crsh.command.BaseCommand class: the main reason is that the BaseCommand class provides contextual state managed by CRaSH, like the context or out fields. A Groovy command doesn’t need to inherit explicitly, but CRaSH will make it extend this class using Groovy annotation processing.

  • the modifier public is required for the class declaration and the command method declarations

  • the option declaration uses curly braces (names={"f","format"}) instead of brackets (names=["f","format"])

if you need a more torough example of a Java command, you can read the source code of the jmx command written in Java

Command line annotations

Let’s study the various annotations the cli framework provides for declaring a command.

@org.crsh.cli.Command

Defines a command method, when using a simple command the method should be named main:

public class sample {

  @Command
  public void main() {
    ...
  }
}

Using this annotation automatically turns a class into a class command. git-style commands simply declares several methods:

public class sample {

  @Command
  public void sub1() {
    ...
  }

  @Command
  public void sub2() {
    ...
  }
}

@org.crsh.cli.Named

Overrides the default command name, the command name must follow these rules:

  • it must not be empty

  • the first letter must be a letter

  • the other letters must be

    • a letter

    • a digit

    • the _ or - character

public class sample {
   @Command
   @Named("bar")
   public void m() {
     ...
   }
}
only sub command can use this annotation as the global command name is provided by the script name of the command

@org.crsh.cli.Option

Declares an option, the names member must be specified: single letter name are turned into posix style option (single hyphen) other names are turned into GNU style option (double hyphen). Several names can specified as aliases of the same option. Options can be declared as method parameters or a class fields.

public class sample {

  @Option(names = ["o", "opt1"])
  private String opt1;

  @Command
  public void sub1(@Option(names = ["opt2"]) String opt2) {
    ...
  }
}
> sample foo
> sample -o foo
> sample --opt1 foo sub1
> sample sub1 --opt2 bar
> sample --opt1 foo foo sub1 --opt2 bar

@org.crsh.cli.Argument

Declares an argument, this annotation should be used as method parameters only.

public class sample {

  @Command
  public void sub1(@Argument String arg) {
    ...
  }
}
> sample sub1
> sample sub1 foo

@org.crsh.cli.Required

By default a parameter is optional, the @Required annotation can be used to force the user to specify a parameter:

public class sample {

  @Command
  public void sub1(@Required @Argument String arg) {
    ...
  }
}

@org.crsh.cli.Usage and @org.crsh.cli.Man

Those annotations are useful for documenting commands help and manual:

@Usage("sample commands")
public class sample {

  @Command
  @Usage("command description, begins with lower case")
  @Man("Verbose descrition of the argument, it should begin with an upper case")
  public void sub1(
    @Usage("argument description, begins with a lower case")
    @Man("Verbose description of the argument, it should begin with an upper case")
    @Argument String arg) {
    ...
  }
}
  • @Usage specifies the usage, a short description, preferably starting with a lower case

  • @Man provides the manual, a verbose description, preferably starting with an upper case

Parameter annotations: Don’t Repeat Yourself

When one or several commands uses the same parameter (option or argument), there is the opportunity to avoid repetition and define a custom annotation that can be used for declaring the parameter:

@Retention(RetentionPolicy.RUNTIME)
@Usage("A color")
@Option(names = "c")
public @interface PathOption {
}

The annotation can then be used instead for declaring an option:

public class mycommand {
  @Command
  public void foo(@ColorOption String color) {
    ...
  }
  @Command
  public void bar(@ColorOption String color) {
    ...
  }
}

Parameter multiplicity

The multiplicity is the number of values expected by a parameter, the multiplicity with simple types is always 1. The arity can also be several when the java.util.List type is used.

public class sample {

  @Command
  public void sub1(@Option(names = ["o"]) List<String> opts) {
    ...
  }
}

The option can now accept several values:

> sample sub1 -o foo -o bar

Parameter types

Option and argument parameters are represented by simple types. The string type is universal and will work with any value provided by the user, other types will require parsing.

Builtin types

CRaSH provides supports a few builtin simple types other than string:

  • Integer type

  • Boolean type

  • java.util.Properties type

  • javax.management.ObjectName type

  • java.io.File type with file completion

  • Enum types

Boolean type is special because it does not need a value when combined with options. The option declaration is enough to set the value to true:

public class sample {

  @Command
  public void sub1(@Option(names = ["o"]) Boolean opt) {
    ...
  }
}

The option will be true with:

> sample sub1 -o

Providing your own type

Providing a custom type is possible, CRaSH uses the ServiceLoader discovery mechanism to discover custom types. Custom types are implemented by a org.crsh.cli.type.ValueType subclass and implement its parse method:

Our custom value type
package my;

public class CustomValueType extends ValueType<Custom> {

  public CustomValueType() {
    super(Custom.class); (1)
  }

  @Override
  public <S extends Custom> S parse(Class<S> type, String s) throws Exception {
    return type.cast(new Custom(s)); (2)
  }
}
1 The custom type is passed to the super class
2 The parse method should reutrn an instance of the type
The parse method uses the <S> generic type because the implementation of enum types has an effective type which is a subclass of the base enum type.

In order to make the custom type discovered by CRaSH, a file named org.crsh.cli.type.ValueType should be placed in the /META-INF/services/ directory of the jar containing the custom value type:

The custom value type declared in META-INF/services/org.crsh.cli.type.ValueType
my.CustomValueType

Adding style

CRaSH adds (since version 1.1) the support for colored text and text decoration. Each portion of text printed has three style attributes:

  • Decoration: bold, underline or blink, as the org.crsh.text.Decoration enum.

  • Foreground color.

  • Background color.

Available colors are grouped as the org.crsh.text.Color enum:

  • black

  • red

  • green

  • yellow

  • blue

  • magenta

  • cyan

  • white

Decoration and colors can be applied with overloaded print and println methods provided by the ShellPrinterWriter. This printer is available as the implicit out attribute or thanks to the context.getWriter() method.

Decorating and coloring text
out.println("hello", red); (1)
out.println("hello", red, blue); (2)
out.println("hello", underline, red, blue); (3)
1 Print hello in red color
2 Print hello in red with a red blue
3 Print hello in red underlined with a red blue

The combination of the decoration, background and foreground colors is a style represented by the org.crsh.text.Style object. Styles can be used like decoration and colors:

Printing styled text
out.println("hello", style(red)); (1)
out.println("hello", style(red, blue)); (2)
out.println("hello", style(underline, red, blue)); (3)
1 Print hello in red color
2 Print hello in red with a red blue
3 Print hello in red underlined with a red blue

When using the print methods, the style will be used for the currently printed object. It is possible to change the style permanently (until it is reset) using Groovy leftshift operator: <<

By default the << operator prints output on the console. The ShellPrintWriter overrides the operator to work with color, decoration and styles:

Styling with the leftshift operator
out << red (1)
out << underline (2)
out << "hello" (3)
out << reset; (4)
1 Set red foreground color
2 Set underline
3 Print hello in underlined red
4 Reset style

Operators can also be combined on the same line providing a more compact syntax:

out << red << underline << "hello" << reset
out << style(underline, red, blue) << "hello" << reset
Throughout the examples we have used decoration, color and styles. CRaSH automatically imports those classes so they can be used out of the box in any CRaSH command without requiring prior import.

Command context

During the execution of a command, CRaSH provides a context for interacting with it:

  • the property context is resolved to an instance of org.crsh.command.InvocationContext

  • the invocation context class extends the org.crsh.command.CommandContext.

Let’s have a look at those types:

The command context

The CommandContext provides access to the shell session as a Map<String, Object>. Session attributes can be accessed using this map, but they are also accessible as Groovy script properties. It means that writing such code will be equivalent:

Using shell session
context.session["foo"] = "bar"; (1)
out.println(bar); (2)
1 Bind the session attribute foo with the value bar
2 The bar is resolved as an session attribute by Groovy

The CommandContext provides also access to the shell attributes as a Map<String, Object>. Context attributes are useful to interact with object shared globally by the CRaSH environment:

  • When embedded in a web application context, attributes resolves to servlet context attributes.

  • When embedded in Spring context, attributes resolve to Spring objects:

    • attributes.factory returns the Spring factory

    • attributes.beans returns Spring beans, for example attribute.beans.telnet returns the telnet bean

  • When attached to a virtual machine, the context attributes has only a single instrumentation entry that is the java.lang.instrument.Instrumentation instance obtained when attaching to a virtual machine.

Obtaining a Spring bean
def bean = context.attributes.beans["TheBean"];

Now let’s examine the InvocationContext that extends the CommandContext:

The invocation context

The PrintWriter object is the command output, it can be used also via the out property in Groovy scripts:

Printing on the shell
context.writer.print("Hello"); (1)
out.print("hello"); (2)
1 Printing using the context writer
2 Printing using the out

The readLine method can be used to get interactive information from the user during the execution of a command.

Reading on the console
def age = context.readLine("How old are you?", false);

Object pipeline

One of the most powerful feature of CRaSH is the object pipeline. CRaSH commands can consume and produce objects allowing the creation of object pipelines by combining commands. Writing such commands is very easy, in fact any CRaSH command can be combined in a pipe. Indeed a command that merely prints text, is a command that produces character data in the pipe.

Producer commands

Until now we have seen how to use annotations of the cli framework to create commands. The logic of this kind of command is executed in @Command annotated methods and it produces character data either by writing text to the output or by returning a string. Such command is called a producer command because it creates a stream of data but does not consume anything. Producer commands can produce other objects than text.

Since CRaSH 1.3 the man page of a command gives details about the object it can consume and produce, let’s look at the man page of the env command:

% man env
NAME
       env - display the term env

SYNOPSIS
       env [-h | --help]

STREAM
       env <java.lang.Void, java.lang.Object>

PARAMETERS
       [-h | --help]
           Display this help message

The STREAM section tells us that the env commands consumes the Void type and produces the Object type. In fact by default any command is a producer command that can produce any object (<java.lang.Object>) and consume none (<java.lang.Void>).

Producing any object is easy, the command just need to return it, let’s see an example

@Command
Map main() {
  return  Thread.currentThread()
}

Let’s print its man page:

% man test
NAME
       test

SYNOPSIS
       test [-h | --help]

STREAM
       test <java.lang.Void, java.lang.Thread>

PARAMETERS
       [-h | --help]
           Display this help message

If you invoke you might expect to read Thread[ppool-1-thread-10,5,main] returned by the Thread#toString() method, the result is actually quite different:

% test
ID      NAME                   GROUP           PRIORI STATE   %CPU    TIME    INTERR DAEMON
37      pool-1-thread-10       main            5      RUNNABL 100     0:0     false  false

The explanation is simple: the thread object is sent in the pipe and hits the end of the pipe. At this moment CRaSH render those objects, it can of course use the toString() method however specific renderers can be used to produce a more visual result for the user. Thread objects have a dedicated render that displays a nice table showing threads.

This example shows that it is easy to produce an object in the pipe, however it produces a single object instance. Producing a stream of object can be achieved via the InvocationContext object. A command method can declare an InvocationContext among its argument list and use the provide method during the invocation of the method

The threads command list all the threads of the virtual machine
class threads {
  @Command
  void main(InvocationContext<Thread> context) { (1)
    for (Thread thread : Thread.getAllStackTraces().keySet()) {
      context.provide(thread); (2)
    }
  }
}
1 declares <Thread> as produced type
2 send a thread object in the pipe

Pipe commands

A pipe command declares a consumed type other than the java.lang.Void type. Developing a pipe command is easy although it is a bit different from producer commands.

Here is an example of a simple pipe:

The daemons command filters the thread stream to retain on the daemons
import org.crsh.command.Pipe;

class daemons {
  @Command
  Pipe<Thread, Thread> main() {
    return new Pipe<Thread, Thread>() {    (1)
      public void provide(Thread thread) { (2)
        if (thread.isDaemon()) {
          context.provide(thread);         (2)
        }
      }
    };
  }
}
1 A pipe command is a factory for org.crsh.command.Pipe objects
2 The provide method is invoked for each object of the stream
3 The context object is an InvocationContext used to produce daemon threads

A pipe command is thus a factory for org.crsh.command.Pipe objects, the pipe declaration specifies the type consumed and produced by the pipe, in this case the daemon command declares Thread for both types.

The provide callback is invoked for each object of the stream, during this invocation, the pipe implementation can invoke the context provide method to produce its objects. As our command filters threads to retain only the daemon threads, this is done only for daemon threads.

Now let’s continue our tour and write a pipe command that counts the number of objects in a pipe. This example is interesting because it demonstrates:

  • different consumed and produced types can be used

  • objects can be produced in the close method of the pipe

import org.crsh.command.Pipe;

class count {
  @Command
  Pipe<Object, Integer> main() {
    return new Pipe<Object, Integer>() {
      int value = 0;
      public void provide(Object o) {
        value++; (1)
      }
      public void close() {
        context.provide(value); (2)
      }
    };
  }
}
1 count the number of consumed objects
2 before closing we produce the count value

Now we can combine those three commands to count the number of daemon threads:

% threads | daemons | count
6

Command interruption

During the execution of a command, sometimes the user wants to interrupt the execution of the command, specially for long lived commands. The ctrl-c keystroke in the shell will trigger a thread interruption during the execution a command.

If you command thread is in the waiting state, an InterruptedException will be thrown otherwise you can check the current thread status with Thread.currentThread.isInterrupted():

class clock {
  @Command
  Object main(InvocationContext<Date> context) {
    while (!Thread.currentThread().isInterrupted()) { (1)
       context.provide(new Date());
       context.flush();
       try {
         Thread.sleep(1000); (2)
       } catch (InterruptedException e) {
         Thread.currentThread().interrupt(); (3)
         break;
       }
    }
  }
}
1 check the thread has not been interrupted
2 sleep for 1 second
3 the command was interrupted while sleeping

This producer command produces the current time in the object stream until the user interrupts it.

% clock
Tue May 06 22:27:55 CEST 2014Tue May 06 22:27:56 CEST 2014Tue May 06 22:27:57 CEST 2014Tue May 06 22:27:58 CEST 2014Tue May 06 22:27:59 CEST 2014Tue May 06 22:28:00 CEST 2014Tue May 06 22:28:01 CEST 2014Tue May 06 22:28:02 CEST 2014Tue May 06 22:28:03 CEST 2014
^C

%
when you are programming a long lived command that will stop upon a signal you should follow the pattern above and never forget to leave the thread in the interrupted state when your thread exits the command. We recommend also to understand well how Java thread interruption works.

Keyboard interactions

A command can interact with the keyboard in two manners, either by reading a line (synchronous api) or by reacting to keyboard events (asynchronous api).

Reading a line

When a command needs to interact with they user to get input, it can use the InvocationContext#readLine() method to prompt the user for a line of text.

String line = context.readLine("tell me something", false);
if (line != null) {
  out.println("You wrote " + line);
}

The returned line may be null sometimes so the command should handle this case properly. For instance, if the user intertupts the command while reading the line, then the line is null. Reading a line is synchronous and blocking until the users hits the enter key or interrupts the command.

Keyboard events

A command can also react to keyboard events by implementing the org.crsh.keyboard.KeyHandler interface. Our previous clock example could be rewritten using this API:

import org.crsh.keyboard.KeyHandler;
import org.crsh.keyboard.KeyType;

class clock implements KeyHandler {

  final AtomicBoolean done = new AtomicBoolean(false);

  @Override
  void handle(KeyType type, int[] sequence) {
    if (type == KeyType.CHARACTER && sequence[0] == 'q') {
      done.set(true);
    }
  }

  @Command
  Object main(InvocationContext<Date> context) {
    while (!done.get()) {
       context.provide(new Date());
       context.flush();
       try {
         Thread.sleep(1000);
       } catch (InterruptedException e) {
       }
    }
  }
}

This command will stream until the user hits the q key. The KeyType allow to distinguish special key sequences whose sequence may vary according to the terminal:

  • KeyType.UP

  • KeyType.DOWN

  • KeyType.LEFT

  • KeyType.RIGHT

  • KeyType.DELETE

  • KeyType.BACKSPACE

  • KeyType.ENTER

Renderers

We studied previously CRaSH object pipe: command push objects into the stream, when an object hits the end of the pipeline, it is printed on the user console. For character data, printing it an obvious operation. For other objects, the renderer api can provide customized textual representation of the object.

The renderer api makes also writing command easier: a command can focus on the business part and just send objects in the pipe, if there is an appropriate renderer for it, it will be displayed nicely:

class developers {
  @Command
  void main(InvocationContext<Map> context) {
    context.provide([firstName:"Julien",lastName:"Viet"]);
    context.provide([firstName:"Alain",lastName:"Defrance"]);
    context.provide([firstName:"Arnaud",lastName:"Heritier"]);
  }
}

The map renderer will format these three maps as a table:

% date
firstName lastName
------------------
Julien    Viet
Alain     Defrance
Arnaud    Heritier

Predefined renderers

CRaSH provides a few renderers out of the box:

  • LoggerRenderer : java.util.logging.Logger objects

  • LogRecordRenderer : java.util.logging.LogRecord objects

  • ThreadRenderer : java.lang.Thread objects

  • MapRenderer : java.util.Map objects

  • MemoryUsageRenderer : java.lang.management.MemoryUsage objects

Implementing a renderer

Renderer implementation is not covered yet.

Groovy guide

This section teaches about advanced Groovy usage in CRaSH.

Commands as a script

The Developers covered how to write a CRaSH command as a Groovy/Java class. The Groovy language also supports simple scripts. A simple script that returns a string is a valid command:

return "Hello World";

The out implicit variable can be used to send a message to the console:

out.println("Hello World");

It can be even Groovier:

out << "Hello World"

Inter command API

Groovy provides powerful support for invoking nested commands, allowing to reuse any CRaSH commands inside your commands, obviously such nested commands don’t have be Groovy commands. Let’s study how a command can reuse existing commands:

dbscript.groovy
jdbc.connect username:root, password:crash, "jdbc:derby:memory:EmbeddedDB;create=true"
jdbc.execute "create table derbyDB(num int, addr varchar(40))"
jdbc.execute "insert into derbyDB values (1956,'Webster St.')"
jdbc.execute "insert into derbyDB values (1910,'Union St.')"
jdbc.execute "select * from derbyDb"
jdbc.close

This script is written in Groovy and use Groovy DSL capabilities, the first statement can be analyzed:

  • the jdbc.connect statement is decomposed into two steps

    • the jdbc is resolved as the command itself

    • the connect invokes the connect command

  • the username and password are considered as command options

  • the SQL statement "jdbc:derby:memory:EmbeddedDB;create=true" is the main argument of the command

This syntax is quite powerful (and explained more in depth in [groovy_repl] section) is equivalent to the command line:

% jdbc connect --username root --password crash jdbc:derby:memory:EmbeddedDB;create=true

The rest of the script is fairly easy to understand, here is the output of the script execution:

% dbscript
Connected to data base : jdbc:derby:memory:EmbeddedDB;create=true
Query executed successfully
Query executed successfully
Query executed successfully
NUM                  ADDR
1956                 Webster St.
1910                 Union St.
Connection closed

The Groovy REPL

The Read–eval–print loop known as REPL is the interactive evaluation of CRaSH. Since CRaSH 1.3, the REPL evaluation can be switch to the Groovy language.

The Groovy REPL is switched via the repl directive:

% repl groovy
Using repl groovy

Evaluating commands

Simple commands are invoked by calling them just like a function:

Invoking a simple command the Groovy way
% repl groovy
Using repl groovy
% help()
Try one of these commands with the -h or --help switch:

NAME          DESCRIPTION
cls           clear screen
egrep         search file(s) for lines that match a pattern
env           display the term env
...

Typing a command name evalutes to a Groovy closure, allowing to call the command just like a function.

to switch back to the script REPL, you need to use the Groovy syntax repl("script") as repl is a command itself
Typing a command evaluates to a closure
% cmd = help
help
% cmd()

Sub commands can be invoked by resolving a new closure from the initial command:

Invoking a sub command the Groovy way
% thread.ls()

Which is equivalent to

Sub commands are also evaluated to closures
% cmd = thread
thread
% cmd2 = cmd.ls
thread.ls
% cmd2()
...

Passing options and arguments

Command options and command arguments are passed as invocation parameters:

  • options are used as a map or named parameters

  • arguments are the other invocation parameters

Passing options as named parameters
% thread(h:true)
usage: thread COMMAND [ARGS]

The most commonly used thread commands are:
   stop             stop vm threads
   interrupt        interrupt vm threads
   top              thread top
   ls               list the vm threads
   dump             dump vm threads

% thread.ls(h:true)
usage: thread ls [-n | --name] [-g | --group] [-s | --state]

   [-n | --name]  Filter the threads with a glob expression on their name
   [-g | --group] Filter the threads with a glob expression on their group
   [-s | --state] Filter the threads by their status (new,runnable,blocked,waiting,timed_waiting,terminated)
Passing an argument
% system.propget("file.encoding")
UTF-8

Passing options and arguments at the same time is easy to do, however the options should be the first method parameters:

Passing an options and arguments
% jul.send(m:"hello", "the.category")
Aug 12, 2013 11:22:50 AM org.codehaus.groovy.reflection.CachedMethod invoke
INFO: hello

Options and arguments binding

Options and arguments can also be bound on a closure:

Binding options to a command
% (thread.ls { h=true })()
...
% cmd = thread.ls { h=true }
thread.ls { h=true }
% cmd();
...
Binding arguments to a command
% (system.propget { "file.encoding" })()
...
% cmd = system.propget { "file.encoding" }
system.propget { ["file.encoding"] }
% cmd();
...

Of course it is possible to bind options and arguments too, the arguments needs to be passed as last parameters:

Passing an options and arguments
% (jul.send { m="hello"; "the category" })()
...
% cmd = jul.send { m="hello"; "the category" }
jul.send { m="hello"; ["the category"] }
% cmd()
...

Command pipeline

The object pipeline can be used in the Groovy REPL using the | (pipe) operator. When a command closure is combined with a pipe, it returns a new closure that will invoke the pipeline construction.

Assembling a command pipe
% (system.propls | egrep { "java.*" })()
java.runtime.name                        Java(TM) SE Runtime Environment
java.vm.version                          23.7-b01
java.vm.vendor                           Oracle Corporation
...
% cmd = system.propls | egrep { "java.*" }
system.propls | egrep { ["java.*"] }
% cmd()
...

A pipeline can also contain Groovy closures in addition of the existing commands

Using a Groovy closure in a pipe
% (thread.ls | { Thread thread -> [id:thread.id, name:thread.name] })()
id name
------------------------------------
2  Reference Handler
3  Finalizer
...
% cmd = thread.ls | { Thread thread -> [id:thread.id, name:thread.name] }
thread.ls | Script14$_run_closure1@47da4d19
% cmd()
...

In this example, the closure takes the threads argument and transforms them to a serie of maps that are displayed then as a table by CRaSH.

Extending CRaSH

Embedding CRaSH

The chapter Running CRaSH explains how to run CRaSH as a standalone or an embedded service. We will study in this section the technical aspect of running application and show how CRaSH can be embedded in specific environments.

The root class for reusing CRaSH is the org.crsh.plugin.PluginLifeCycle class. This class is abstract and it cannot be used directly, instead it should be subclasses for providing specific behavior for running CRaSH. There are several subclasses using it:

  • The standalone bootstrap with the org.crsh.standalone.Bootstrap class : designed for using CRaSH with a real file system (i.e java.io.File). It defines a specific layout for locating resources (libraries, configuration and commands).

  • The embedded approaches

    • org.crsh.plugin.WebPluginLifeCycle : uses a javax.servlet.ServletContext

    • org.crsh.spring.SpringBootstrap : embeds CRaSH as a Spring bean

    • org.crsh.spring.SpringWebBootstrap : extends the SpringBootstrap and uses the existing ServletContext

Standalone bootstrap

The org.crsh.standalone.Bootstrap class is a generic class that can be used to embed the shell in your Java programs Its usage is quite straighforward and configurable. The bootstrap is a coarse grained approach and it needs a bit of configuration for running:

  • The baseLoader properties is the java.lang.ClassLoader used by CRaSH for loading plugins, resources or command sources (under the /crash/commands/ path. This property is not modifiable and must be provided when the bootstrap is instantiated.

  • The config properties provides the contextual properties used by CRaSH configuration such as crash.vfs.refresh_period

  • The attributes property provides the contextual attributes used by CRaSH available at runtime via the org.crsh.command.CommandContext, it is useful for providing objects to commands in a similar fashion to servlet context attributes

  • The cmdPath property is a list of java.io.File scanned by CRaSH for loading additional commands

  • The confPath property is a list of java.io.File scanned by CRaSH for loading configuration files

Let’s see an example on how to use it

Standalone CRaSH

The standalone shell is a Java class configurable and runnable from the command line that is used by the standalone distribution. It is built upon the Standalone bootstrap.

Mail plugin

The mail plugin configures an email client for CRaSH. This email client can be used as a service or via the mail command.

Deployment

The plugin consist of two jars:

  • the JavaMail jar mail-1.4.jar

  • the plugin jar crash.plugins.mail-1.3.1.jar

when the two jars are present in the classpath of CRaSH, they will be detected and the plugin will be present.

Configuration

Configuration is done with CRaSH properties:

Configuring an SMTP server for the CRaSH plugin
crash.mail.smtp.host=smtp.gmail.com
crash.mail.smtp.port=587
crash.mail.smtp.secure=tls
crash.mail.smtp.username=admin
crash.mail.smtp.password=admin
crash.mail.smtp.from=admin@mydomain.org
crash.mail.debug=false

The configuration is pretty obvious and follow the usual JavaMail configuration properties.

Mail command

The mail command can be used to send emails. The command consumes a stream of objects and render them to text before sending the email.

Send an email with a JVM thread dump
% thread ls | thread dump | mail send -s "The thread dump" admin@foo.com

Cron plugin

CRaSH provides a cron plugin for scheduling tasks, the plugin is a thin wrapper of the cron4j library.

Deployment

The plugin consist of two jars:

  • the cron4j jar cron4j-2.2.5.jar

  • the plugin jar crash.plugins.cron-1.3.1.jar

when the two jars are present in the classpath of CRaSH, they will be detected and the plugin will be present.

Configuration file

The plugin is configured mainly through the crontab configuration file. This file looks pretty much like any other crontab configuration file it consists of two parts:

  • a scheduling pattern, for instance * * * * *, this is documented in the cron4j library

  • a command line to execute

Send an mail with a JVM thread dump once every hour, at the begin of the fifth minute (00:05, 01:05, 02:05 etc.).
5 * * * * thread ls | thread dump | mail send -s "the threads" -b admin@gmail.com

Hey, I want to contribute!

Drop me an email. You can find my email on http://www.julienviet.com. Any kind of help is welcome.

Appendix A: Commands reference

cron

NAME
       cron - manages the cron plugin

SYNOPSIS
       cron [-h | --help] COMMAND [ARGS]

PARAMETERS
       [-h | --help]
           Display this help message

COMMANDS
       config
           read or write the cron config path

       history
           display the process history

       spawn
           trigger the cron service now

cron config

NAME
       cron config - read or write the cron config path

SYNOPSIS
       cron [-h | --help] config <path>

STREAM
       cron config <java.lang.Void, java.lang.Object>

PARAMETERS
       [-h | --help]
           Display this help message

       <path>
           the new config path when specified

cron history

NAME
       cron history - display the process history

SYNOPSIS
       cron [-h | --help] history

STREAM
       cron history <java.lang.Void, java.util.Map>

PARAMETERS
       [-h | --help]
           Display this help message

cron spawn

NAME
       cron spawn - trigger the cron service now

SYNOPSIS
       cron [-h | --help] spawn

STREAM
       cron spawn <java.lang.Void, java.lang.Object>

PARAMETERS
       [-h | --help]
           Display this help message

dashboard

NAME
       dashboard - a monitoring dashboard

SYNOPSIS
       dashboard [-h | --help]

STREAM
       dashboard <java.lang.Void, java.lang.Object>

PARAMETERS
       [-h | --help]
           Display this help message

egrep

NAME
       egrep - search file(s) for lines that match a pattern

SYNOPSIS
       egrep [-h | --help] <pattern>

STREAM
       egrep <java.lang.Void, java.lang.Object>

PARAMETERS
       [-h | --help]
           Display this help message

       <pattern>
           the search pattern

env

NAME
       env - display the term env

SYNOPSIS
       env [-h | --help]

STREAM
       env <java.lang.Void, java.lang.Object>

PARAMETERS
       [-h | --help]
           Display this help message

filter

NAME
       filter - a filter for a stream of map

SYNOPSIS
       filter [-p | --pattern] [-h | --help]

STREAM
       filter <java.util.Map, java.util.Map>

PARAMETERS
       [-p | --pattern]
           format <key>:<value>

       [-h | --help]
           Display this help message

java

NAME
       java - various java language commands

SYNOPSIS
       java [-h | --help] COMMAND [ARGS]

PARAMETERS
       [-h | --help]
           Display this help message

COMMANDS
       type
           print information about a java type

java type

NAME
       java type - print information about a java type

SYNOPSIS
       java [-h | --help] type <name>

STREAM
       java type <java.lang.Void, java.lang.Object>

PARAMETERS
       [-h | --help]
           Display this help message

       <name>
           The full qualified type name

jdbc

NAME
       jdbc - JDBC connection

SYNOPSIS
       jdbc [-h | --help] COMMAND [ARGS]

PARAMETERS
       [-h | --help]
           Display this help message

COMMANDS
       props
           show the database properties

       close
           close the current connection

       table
           describe the tables

       open
           open a connection from JNDI bound datasource

       connect
           connect to database with a JDBC connection string

       info
           describe the database

       execute
           execute a SQL statement

       select
           select SQL statement

       tables
           describe the tables

jdbc props

NAME
       jdbc props - show the database properties

SYNOPSIS
       jdbc [-h | --help] props

STREAM
       jdbc props <java.lang.Void, java.util.Map>

PARAMETERS
       [-h | --help]
           Display this help message

jdbc close

NAME
       jdbc close - close the current connection

SYNOPSIS
       jdbc [-h | --help] close

STREAM
       jdbc close <java.lang.Void, java.lang.String>

PARAMETERS
       [-h | --help]
           Display this help message

jdbc table

NAME
       jdbc table - describe the tables

SYNOPSIS
       jdbc [-h | --help] table <tableNames>...

STREAM
       jdbc table <java.lang.Void, java.lang.Object>

PARAMETERS
       [-h | --help]
           Display this help message

       <tableNames>...
           the table names

jdbc open

NAME
       jdbc open - open a connection from JNDI bound datasource

SYNOPSIS
       jdbc [-h | --help] open <globalName>

STREAM
       jdbc open <java.lang.Void, java.lang.String>

PARAMETERS
       [-h | --help]
           Display this help message

       <globalName>
           The datasource JNDI name

jdbc connect

NAME
       jdbc connect - connect to database with a JDBC connection string

SYNOPSIS
       jdbc [-h | --help] connect [-u | --username] [-p | --password] [--properties] <connectionString>

STREAM
       jdbc connect <java.lang.Void, java.lang.String>

PARAMETERS
       [-h | --help]
           Display this help message

       [-u | --username]
           The username

       [-p | --password]
           The password

       [--properties]
           The extra properties

       <connectionString>
           The connection string

jdbc info

NAME
       jdbc info - describe the database

SYNOPSIS
       jdbc [-h | --help] info

STREAM
       jdbc info <java.lang.Void, java.util.Map>

PARAMETERS
       [-h | --help]
           Display this help message

jdbc execute

NAME
       jdbc execute - execute a SQL statement

SYNOPSIS
       jdbc [-h | --help] execute <statement>...

STREAM
       jdbc execute <java.lang.Void, java.lang.String>

PARAMETERS
       [-h | --help]
           Display this help message

       <statement>...
           The statement

jdbc select

NAME
       jdbc select - select SQL statement

SYNOPSIS
       jdbc [-h | --help] select <statement>...

STREAM
       jdbc select <java.lang.Void, java.util.Map>

PARAMETERS
       [-h | --help]
           Display this help message

       <statement>...
           The statement

jdbc tables

NAME
       jdbc tables - describe the tables

SYNOPSIS
       jdbc [-h | --help] tables

STREAM
       jdbc tables <java.lang.Void, java.lang.Object>

PARAMETERS
       [-h | --help]
           Display this help message

jmx

NAME
       jmx - Java Management Extensions

SYNOPSIS
       jmx [-h | --help] COMMAND [ARGS]

DESCRIPTION
       The jmx commands interracts with the JMX registry allowing several kind JMX operations.

PARAMETERS
       [-h | --help]
           Display this help message

COMMANDS
       get
           Retrieves the attributes of a stream of managed beans, this command can be used by specifying managed bean arguments
           % jmx get java.lang:type=ClassLoading
           It also accepts a managed bean stream:
           % jmx query -p java.lang:* | jmx get
           By default all managed bean attributes will be retrieved, the attributes option allow to use a list of attributes:
           % jmx query -p java.lang:* | jmx get -a TotalSwapSpaceSize


       query
           Create a stream of managed beans, by default the stream will contain all the registered managed beans:
           % jmx query
           ...
           The stream can be filtered with the pattern option:
           % jmx query -p java.lang:*
           ...

       info
           Provide the mbean info for a managed bean:
           % jmx info java.lang:type=ClassLoading
           sun.management.ClassLoadingImpl
           +- ClassName   sun.management.ClassLoadingImpl
           |  Description Information on the management interface of the MBean
           +-Descriptor
           | +-immutableInfo      true
           |   interfaceClassName java.lang.management.ClassLoadingMXBean
           |   mxbean             true
           +-Attributes
           | +-NAME                  TYPE                        DESCRIPTION
           |   Verbose               boolean                     Verbose
           |   TotalLoadedClassCount long                        TotalLoadedClassCount
           |   LoadedClassCount      int                         LoadedClassCount
           |   UnloadedClassCount    long                        UnloadedClassCount
           |   ObjectName            javax.management.ObjectName ObjectName
           +-Operations

jmx get

NAME
       jmx get - get attributes of a managed bean

SYNOPSIS
       jmx [-h | --help] get [-s | --silent] [-n | --name] [-a | --attributes] <mbean>...

STREAM
       jmx get <javax.management.ObjectName, java.util.Map>

DESCRIPTION
       Retrieves the attributes of a stream of managed beans, this command can be used by specifying managed bean arguments
       % jmx get java.lang:type=ClassLoading
       It also accepts a managed bean stream:
       % jmx query -p java.lang:* | jmx get
       By default all managed bean attributes will be retrieved, the attributes option allow to use a list of attributes:
       % jmx query -p java.lang:* | jmx get -a TotalSwapSpaceSize


PARAMETERS
       [-h | --help]
           Display this help message

       [-s | --silent]
           silent mode ignores any attribute runtime failures

       [-n | --name]
           add a column  with the option value with the managed bean name

       [-a | --attributes]
           specifies a managed bean attribute name

       <mbean>...
           a managed bean object name

jmx query

NAME
       jmx query - query mbeans

SYNOPSIS
       jmx [-h | --help] query <arg>

STREAM
       jmx query <java.lang.Void, javax.management.ObjectName>

DESCRIPTION
       Create a stream of managed beans, by default the stream will contain all the registered managed beans:
       % jmx query
       ...
       The stream can be filtered with the pattern option:
       % jmx query -p java.lang:*
       ...

PARAMETERS
       [-h | --help]
           Display this help message

       <arg>
           the object name pattern for the query

jmx info

NAME
       jmx info - provide the mbean info of a managed bean

SYNOPSIS
       jmx [-h | --help] info <arg>

STREAM
       jmx info <java.lang.Void, javax.management.MBeanInfo>

DESCRIPTION
       Provide the mbean info for a managed bean:
       % jmx info java.lang:type=ClassLoading
       sun.management.ClassLoadingImpl
       +- ClassName   sun.management.ClassLoadingImpl
       |  Description Information on the management interface of the MBean
       +-Descriptor
       | +-immutableInfo      true
       |   interfaceClassName java.lang.management.ClassLoadingMXBean
       |   mxbean             true
       +-Attributes
       | +-NAME                  TYPE                        DESCRIPTION
       |   Verbose               boolean                     Verbose
       |   TotalLoadedClassCount long                        TotalLoadedClassCount
       |   LoadedClassCount      int                         LoadedClassCount
       |   UnloadedClassCount    long                        UnloadedClassCount
       |   ObjectName            javax.management.ObjectName ObjectName
       +-Operations


PARAMETERS
       [-h | --help]
           Display this help message

       <arg>
           a managed bean object name

jndi

NAME
       jndi - Java Naming and Directory Interface

SYNOPSIS
       jndi [-h | --help] COMMAND [ARGS]

PARAMETERS
       [-h | --help]
           Display this help message

COMMANDS
       find
           List JNDI resources

jndi find

NAME
       jndi find - List JNDI resources

SYNOPSIS
       jndi [-h | --help] find [-f | --filter] [-n | --name] [-v | --verbose] [-d | --datasources] [-e | --emf] [-m | --mail]

STREAM
       jndi find <java.lang.Void, org.crsh.text.renderers.BindingRenderer$BindingData>

PARAMETERS
       [-h | --help]
           Display this help message

       [-f | --filter]
           Filter displayed resources using FQN type'

       [-n | --name]
           Filter displayed resources using name'

       [-v | --verbose]
           Display resource type'

       [-d | --datasources]
           Apply a filter on 'javax.sql.DataSource'

       [-e | --emf]
           Apply a filter on 'javax.persistence.EntityManagerFactory'

       [-m | --mail]
           Apply a filter on 'javax.mail.Session'

jpa

NAME
       jpa - Java persistance API

SYNOPSIS
       jpa [-h | --help] COMMAND [ARGS]

PARAMETERS
       [-h | --help]
           Display this help message

COMMANDS
       close
           Close the current JPA session

       open
           Open a JPA session

       entity
           Display JPA entity

       select
           Execute select JPA query

       entities
           List JPA entities

jpa close

NAME
       jpa close - Close the current JPA session

SYNOPSIS
       jpa [-h | --help] close

STREAM
       jpa close <java.lang.Void, java.lang.Object>

PARAMETERS
       [-h | --help]
           Display this help message

jpa open

NAME
       jpa open - Open a JPA session

SYNOPSIS
       jpa [-h | --help] open <jndiName>

STREAM
       jpa open <java.lang.Void, java.lang.Object>

PARAMETERS
       [-h | --help]
           Display this help message

       <jndiName>

jpa entity

NAME
       jpa entity - Display JPA entity

SYNOPSIS
       jpa [-h | --help] entity <name>

STREAM
       jpa entity <java.lang.Void, org.crsh.text.renderers.EntityTypeRenderer$EntityTypeData>

PARAMETERS
       [-h | --help]
           Display this help message

       <name>

jpa select

NAME
       jpa select - Execute select JPA query

SYNOPSIS
       jpa [-h | --help] select <statements>...

STREAM
       jpa select <java.lang.Void, java.util.Map>

PARAMETERS
       [-h | --help]
           Display this help message

       <statements>...

jpa entities

NAME
       jpa entities - List JPA entities

SYNOPSIS
       jpa [-h | --help] entities

STREAM
       jpa entities <java.lang.Void, org.crsh.text.renderers.EntityTypeRenderer$EntityTypeData>

PARAMETERS
       [-h | --help]
           Display this help message

jul

NAME
       jul - java.util.logging commands

SYNOPSIS
       jul [-h | --help] COMMAND [ARGS]

PARAMETERS
       [-h | --help]
           Display this help message

COMMANDS
       add
           create one or several loggers

       set
           The set command sets the level of a logger. One or several logger names can be specified as
           arguments and the -l option specify the level among the finest, finer, fine, info, warn and
           severe levels. When no level is specified, the level is cleared and the level will be
           inherited from its ancestors.

           % jul set -l trace foo
           % jul set foo

           The logger name can be omitted and instead stream of logger can be consumed as it is a
           <Logger,Void> command. The following set the level warn on all the available loggers:

           % jul ls | jul set -l warn

       send
           The send command log one or several loggers with a specified message. For instance the
           following impersonates the javax.management.mbeanserver class and send a message on its own
           logger.

           #% jul send -m hello javax.management.mbeanserver

           Send is a <Logger, Void> command, it can log messages to consumed log objects:

           % jul ls | jul send -m hello -l warn

       tail
           The tail command provides a tail view of a list of loggers. One or several logger names can
           be specified as argument and the -l option configures the level threshold. When no logger
           name is specified, the root logger will be tailed, when no level is specified, the info
           level will be used:

           % jul tail
           Feb 10, 2014 1:50:36 PM java_util_logging_Logger$log call
           INFO: HELLO

           The tail process will end upon interruption (ctrl-c).

       ls
           The jul ls command list all the available loggers, for instance:

           % jul ls
           org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/].[default]
           org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/eXoGadgetServer].[concat]
           org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/dashboard].[jsp]
           ...

           The -f switch provides filtering with a Java regular expression

           % jul ls -f javax.*
           javax.management.mbeanserver
           javax.management.modelmbean

           The jul ls command is a <Void,Logger> command, therefore any logger produced can be
           consumed.

jul add

NAME
       jul add - create one or several loggers

SYNOPSIS
       jul [-h | --help] add <name>...

STREAM
       jul add <java.lang.Void, java.util.logging.Logger>

PARAMETERS
       [-h | --help]
           Display this help message

       <name>...
           The name of the logger

jul set

NAME
       jul set - configures the level of one of several loggers

SYNOPSIS
       jul [-h | --help] set [-l | --level] <name>...

STREAM
       jul set <java.util.logging.Logger, java.lang.Object>

DESCRIPTION
       The set command sets the level of a logger. One or several logger names can be specified as
       arguments and the -l option specify the level among the finest, finer, fine, info, warn and
       severe levels. When no level is specified, the level is cleared and the level will be
       inherited from its ancestors.

       % jul set -l trace foo
       % jul set foo

       The logger name can be omitted and instead stream of logger can be consumed as it is a
       <Logger,Void> command. The following set the level warn on all the available loggers:

       % jul ls | jul set -l warn

PARAMETERS
       [-h | --help]
           Display this help message

       [-l | --level]
           The logger level to assign among {trace, debug, info, warn, error}

       <name>...
           The name of the logger

jul send

NAME
       jul send - send a message to a jul logger

SYNOPSIS
       jul [-h | --help] send [-m | --message] [-l | --level] <name>

STREAM
       jul send <java.util.logging.Logger, java.lang.Object>

DESCRIPTION
       The send command log one or several loggers with a specified message. For instance the
       following impersonates the javax.management.mbeanserver class and send a message on its own
       logger.

       #% jul send -m hello javax.management.mbeanserver

       Send is a <Logger, Void> command, it can log messages to consumed log objects:

       % jul ls | jul send -m hello -l warn

PARAMETERS
       [-h | --help]
           Display this help message

       [-m | --message]
           The message to log

       [-l | --level]
           The logger level to assign among {trace, debug, info, warn, error}

       <name>
           The name of the logger

jul tail

NAME
       jul tail - tail loggers

SYNOPSIS
       jul [-h | --help] tail [-l | --level] <name>...

STREAM
       jul tail <java.lang.Void, java.util.logging.LogRecord>

DESCRIPTION
       The tail command provides a tail view of a list of loggers. One or several logger names can
       be specified as argument and the -l option configures the level threshold. When no logger
       name is specified, the root logger will be tailed, when no level is specified, the info
       level will be used:

       % jul tail
       Feb 10, 2014 1:50:36 PM java_util_logging_Logger$log call
       INFO: HELLO

       The tail process will end upon interruption (ctrl-c).

PARAMETERS
       [-h | --help]
           Display this help message

       [-l | --level]
           The logger level to assign among {trace, debug, info, warn, error}

       <name>...
           The name of the logger

jul ls

NAME
       jul ls - list the available loggers

SYNOPSIS
       jul [-h | --help] ls [-f | --filter]

STREAM
       jul ls <java.lang.Void, java.util.logging.Logger>

DESCRIPTION
       The jul ls command list all the available loggers, for instance:

       % jul ls
       org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/].[default]
       org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/eXoGadgetServer].[concat]
       org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/dashboard].[jsp]
       ...

       The -f switch provides filtering with a Java regular expression

       % jul ls -f javax.*
       javax.management.mbeanserver
       javax.management.modelmbean

       The jul ls command is a <Void,Logger> command, therefore any logger produced can be
       consumed.

PARAMETERS
       [-h | --help]
           Display this help message

       [-f | --filter]
           A regular expressions used to filter the loggers

jvm

NAME
       jvm - JVM informations

SYNOPSIS
       jvm [-h | --help] COMMAND [ARGS]

PARAMETERS
       [-h | --help]
           Display this help message

COMMANDS
       gc
           Show JVM garbage collection

       system
           Show JVM operating system

       pool
           Show JVM memory pool

       runtime
           Show JVM runtime

       top

       heap
           Show JVM memory heap

       pools
           Show JVM memory pools

       classloading
           Show JVM classloding

       compilation
           Show JVM compilation

       nonheap
           Show JVM memory non heap

jvm gc

NAME
       jvm gc - Show JVM garbage collection

SYNOPSIS
       jvm [-h | --help] gc

STREAM
       jvm gc <java.lang.Void, java.lang.Object>

PARAMETERS
       [-h | --help]
           Display this help message

jvm system

NAME
       jvm system - Show JVM operating system

SYNOPSIS
       jvm [-h | --help] system

STREAM
       jvm system <java.lang.Void, java.util.Map>

PARAMETERS
       [-h | --help]
           Display this help message

jvm pool

NAME
       jvm pool - Show JVM memory pool

SYNOPSIS
       jvm [-h | --help] pool <pools>...

STREAM
       jvm pool <java.lang.String, java.lang.management.MemoryUsage>

PARAMETERS
       [-h | --help]
           Display this help message

       <pools>...

jvm runtime

NAME
       jvm runtime - Show JVM runtime

SYNOPSIS
       jvm [-h | --help] runtime

STREAM
       jvm runtime <java.lang.Void, java.lang.Object>

PARAMETERS
       [-h | --help]
           Display this help message

jvm top

NAME
       jvm top

SYNOPSIS
       jvm [-h | --help] top

STREAM
       jvm top <java.lang.Void, java.lang.management.MemoryUsage>

PARAMETERS
       [-h | --help]
           Display this help message

jvm heap

NAME
       jvm heap - Show JVM memory heap

SYNOPSIS
       jvm [-h | --help] heap

STREAM
       jvm heap <java.lang.Void, java.lang.management.MemoryUsage>

PARAMETERS
       [-h | --help]
           Display this help message

jvm pools

NAME
       jvm pools - Show JVM memory pools

SYNOPSIS
       jvm [-h | --help] pools

STREAM
       jvm pools <java.lang.Void, java.lang.String>

PARAMETERS
       [-h | --help]
           Display this help message

jvm classloading

NAME
       jvm classloading - Show JVM classloding

SYNOPSIS
       jvm [-h | --help] classloading

STREAM
       jvm classloading <java.lang.Void, java.lang.Object>

PARAMETERS
       [-h | --help]
           Display this help message

jvm compilation

NAME
       jvm compilation - Show JVM compilation

SYNOPSIS
       jvm [-h | --help] compilation

STREAM
       jvm compilation <java.lang.Void, java.lang.Object>

PARAMETERS
       [-h | --help]
           Display this help message

jvm nonheap

NAME
       jvm nonheap - Show JVM memory non heap

SYNOPSIS
       jvm [-h | --help] nonheap

STREAM
       jvm nonheap <java.lang.Void, java.lang.management.MemoryUsage>

PARAMETERS
       [-h | --help]
           Display this help message

less

NAME
       less - opposite of more

SYNOPSIS
       less [-h | --help]

STREAM
       less <java.lang.CharSequence, java.lang.Object>

DESCRIPTION
       Less  is a program similar to more, but which allows backward movement in the file as well as forward movement.

       The following commands are available while less is running:

       SPACE - Scroll forward one page
       UP    - Scroll forward one line
       DOWN  - Scroll backward one line
       q     - Quit

PARAMETERS
       [-h | --help]
           Display this help message

mail

NAME
       mail - interact with emails

SYNOPSIS
       mail [-h | --help] COMMAND [ARGS]

PARAMETERS
       [-h | --help]
           Display this help message

COMMANDS
       send
           Send an mail to a list of recipients.

           The body of the mail is the input stream of the command. For example, the output of the "thread ls | thread dump" command
           can be piped into the mail command: an email with the list of current JVM thread is sent to the admin:

           % thread ls | thread dump | mail send -s "The thread dump" admin@foo.com

mail send

NAME
       mail send - send an mail to a list of recipients, the body of the mail is the input stream of the command.

SYNOPSIS
       mail [-h | --help] send [-b | --block] [-s | --subject] [--width] [--height] <recipients>...

STREAM
       mail send <java.lang.Object, java.lang.Object>

DESCRIPTION
       Send an mail to a list of recipients.

       The body of the mail is the input stream of the command. For example, the output of the "thread ls | thread dump" command
       can be piped into the mail command: an email with the list of current JVM thread is sent to the admin:

       % thread ls | thread dump | mail send -s "The thread dump" admin@foo.com


PARAMETERS
       [-h | --help]
           Display this help message

       [-b | --block]
           block until the mails are delivered

       [-s | --subject]
           mail subject

       [--width]
           override the screen width

       [--height]
           override the screen height

       <recipients>...
           mail recipients

man

NAME
       man - format and display the on-line manual pages

SYNOPSIS
       man [-h | --help] <command>

STREAM
       man <java.lang.Void, java.lang.Object>

PARAMETERS
       [-h | --help]
           Display this help message

       <command>
           the command

shell

NAME
       shell - shell related command

SYNOPSIS
       shell [-h | --help] COMMAND [ARGS]

PARAMETERS
       [-h | --help]
           Display this help message

COMMANDS
       properties
           list the configuration properties and their description

       plugins
           list the loaded plugins and their configuration

shell properties

NAME
       shell properties - list the configuration properties and their description

SYNOPSIS
       shell [-h | --help] properties

STREAM
       shell properties <java.lang.Void, java.lang.Object>

PARAMETERS
       [-h | --help]
           Display this help message

shell plugins

NAME
       shell plugins - list the loaded plugins and their configuration

SYNOPSIS
       shell [-h | --help] plugins

STREAM
       shell plugins <java.lang.Void, java.lang.Object>

PARAMETERS
       [-h | --help]
           Display this help message

sleep

NAME
       sleep - sleep for some time

SYNOPSIS
       sleep [-h | --help] <time>

STREAM
       sleep <java.lang.Void, java.lang.Object>

PARAMETERS
       [-h | --help]
           Display this help message

       <time>
           sleep time in seconds

sort

NAME
       sort - sort a map

SYNOPSIS
       sort [-f | --fields] [-h | --help]

STREAM
       sort <java.util.Map, java.util.Map>

PARAMETERS
       [-f | --fields]
           Filed used to sort

       [-h | --help]
           Display this help message

system

NAME
       system - vm system properties commands

SYNOPSIS
       system [-h | --help] COMMAND [ARGS]

PARAMETERS
       [-h | --help]
           Display this help message

COMMANDS
       gc
           call garbage collector

       propls
           list the vm system properties

       propset
           set a system property

       propget
           get a system property

       proprm
           remove a system property

       freemem
           show free memory

       totalmem
           show total memory

system gc

NAME
       system gc - call garbage collector

SYNOPSIS
       system [-h | --help] gc

STREAM
       system gc <java.lang.Void, java.lang.Object>

PARAMETERS
       [-h | --help]
           Display this help message

system propls

NAME
       system propls - list the vm system properties

SYNOPSIS
       system [-h | --help] propls [-f | --filter]

STREAM
       system propls <java.lang.Void, java.util.Map>

PARAMETERS
       [-h | --help]
           Display this help message

       [-f | --filter]
           filter the property with a regular expression on their name

system propset

NAME
       system propset - set a system property

SYNOPSIS
       system [-h | --help] propset <name> <value>

STREAM
       system propset <java.lang.Void, java.lang.Object>

PARAMETERS
       [-h | --help]
           Display this help message

       <name>
           The name of the property

       <value>
           The value of the property

system propget

NAME
       system propget - get a system property

SYNOPSIS
       system [-h | --help] propget <name>

STREAM
       system propget <java.lang.Void, java.lang.String>

PARAMETERS
       [-h | --help]
           Display this help message

       <name>
           The name of the property

system proprm

NAME
       system proprm - remove a system property

SYNOPSIS
       system [-h | --help] proprm <name>

STREAM
       system proprm <java.lang.Void, java.lang.Object>

PARAMETERS
       [-h | --help]
           Display this help message

       <name>
           The name of the property

system freemem

NAME
       system freemem - show free memory

SYNOPSIS
       system [-h | --help] freemem [-u | --unit] [-d | --decimal]

STREAM
       system freemem <java.lang.Void, java.lang.String>

PARAMETERS
       [-h | --help]
           Display this help message

       [-u | --unit]
           The unit of the memory space size {(B)yte, (O)ctet, (M)egaOctet, (G)igaOctet}

       [-d | --decimal]
           The number of decimal (default 0)

system totalmem

NAME
       system totalmem - show total memory

SYNOPSIS
       system [-h | --help] totalmem [-u | --unit] [-d | --decimal]

STREAM
       system totalmem <java.lang.Void, java.lang.String>

PARAMETERS
       [-h | --help]
           Display this help message

       [-u | --unit]
           The unit of the memory space size {(B)yte, (O)ctet, (M)egaOctet, (G)igaOctet}

       [-d | --decimal]
           The number of decimal (default 0)

thread

NAME
       thread - JVM thread commands

SYNOPSIS
       thread [-h | --help] COMMAND [ARGS]

DESCRIPTION
       The thread command provides introspection and control over JVM threads:

       % thread ls
       ID   PRIORITY  STATE          INTERRUPTED  DAEMON  NAME
       2    10        WAITING        false        true    Reference Handler
       3    8         WAITING        false        true    Finalizer
       6    9         RUNNABLE       false        true    Signal Dispatcher
       1    5         WAITING        false        false   main
       13   1         TIMED_WAITING  false        true    Poller SunPKCS11-Darwin
       14   5         WAITING        false        false   pool-1-thread-1
       15   5         WAITING        false        false   pool-1-thread-2
       16   5         WAITING        false        false   pool-1-thread-3
       17   5         WAITING        false        false   pool-1-thread-4
       27   5         WAITING        false        false   pool-1-thread-6
       19   5         RUNNABLE       false        false   org.crsh.standalone.CRaSH.main()

       % thread stop 14
       Stopped thread Thread[pool-1-thread-1,5,main]

       % thread interrupt 17
       Interrupted thread Thread[pool-1-thread-1,5,main]

       In addition of the classical usage, the various commands (ls, stop, interrupt) can be
       combined with a pipe, the most common operation is to combine the ls command with the stop,
       interrupt or dump command, for instance the following command will interrupt all the thread
       having a name starting with the 'pool' prefix:

       % thread ls --filter pool.* | thread interrupt
       Interrupted thread Thread[pool-1-thread-1,5,main]
       Interrupted thread Thread[pool-1-thread-2,5,main]
       Interrupted thread Thread[pool-1-thread-3,5,main]
       Interrupted thread Thread[pool-1-thread-4,5,main]
       Interrupted thread Thread[pool-1-thread-5,5,main]

PARAMETERS
       [-h | --help]
           Display this help message

COMMANDS
       stop
           Stop VM threads.

       interrupt
           Interrup VM threads.

       ls
           list the vm threads

       top
           thread top

       dump
           Dump VM threads.

thread stop

NAME
       thread stop - stop vm threads

SYNOPSIS
       thread [-h | --help] stop <threads>...

STREAM
       thread stop <java.lang.Thread, java.lang.Thread>

DESCRIPTION
       Stop VM threads.

PARAMETERS
       [-h | --help]
           Display this help message

       <threads>...
           the thread ids to stop

thread interrupt

NAME
       thread interrupt - interrupt vm threads

SYNOPSIS
       thread [-h | --help] interrupt <threads>...

STREAM
       thread interrupt <java.lang.Thread, java.lang.Thread>

DESCRIPTION
       Interrup VM threads.

PARAMETERS
       [-h | --help]
           Display this help message

       <threads>...
           the thread ids to interrupt

thread ls

NAME
       thread ls - list the vm threads

SYNOPSIS
       thread [-h | --help] ls [-n | --name] [-g | --group] [-s | --state]

STREAM
       thread ls <java.lang.Void, java.lang.Thread>

PARAMETERS
       [-h | --help]
           Display this help message

       [-n | --name]
           Filter the threads with a glob expression on their name

       [-g | --group]
           Filter the threads with a glob expression on their group

       [-s | --state]
           Filter the threads by their status (new,runnable,blocked,waiting,timed_waiting,terminated)

thread top

NAME
       thread top - thread top

SYNOPSIS
       thread [-h | --help] top [-n | --name] [-g | --group] [-s | --state]

STREAM
       thread top <java.lang.Void, java.lang.Object>

PARAMETERS
       [-h | --help]
           Display this help message

       [-n | --name]
           Filter the threads with a glob expression on their name

       [-g | --group]
           Filter the threads with a glob expression on their group

       [-s | --state]
           Filter the threads by their status (new,runnable,blocked,waiting,timed_waiting,terminated)

thread dump

NAME
       thread dump - dump vm threads

SYNOPSIS
       thread [-h | --help] dump <threads>...

STREAM
       thread dump <java.lang.Thread, java.lang.Object>

DESCRIPTION
       Dump VM threads.

PARAMETERS
       [-h | --help]
           Display this help message

       <threads>...
           the thread ids to dump

help

NAME
       help - provides basic help

SYNOPSIS
       help [-h | --help]

STREAM
       help <java.lang.Void, java.lang.Object>

PARAMETERS
       [-h | --help]
           Display this help message

repl

NAME
       repl - list the repl or change the current repl

SYNOPSIS
       repl [-h | --help] <arg>

STREAM
       repl <java.lang.Void, java.lang.Object>

PARAMETERS
       [-h | --help]
           Display this help message

       <arg>
           the optional repl name