SHL-23 - Create docbook based reference guide
This commit is contained in:
BIN
docs/src/reference/docbook/images/shell-example-enum.jpg
Normal file
BIN
docs/src/reference/docbook/images/shell-example-enum.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 22 KiB |
BIN
docs/src/reference/docbook/images/shell-example.jpg
Normal file
BIN
docs/src/reference/docbook/images/shell-example.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 124 KiB |
@@ -16,16 +16,16 @@
|
|||||||
<surname>Pollack</surname>
|
<surname>Pollack</surname>
|
||||||
<affiliation>SpringSource</affiliation>
|
<affiliation>SpringSource</affiliation>
|
||||||
</author>
|
</author>
|
||||||
<author>
|
|
||||||
<firstname>Jarred</firstname>
|
|
||||||
<surname>Li</surname>
|
|
||||||
<affiliation>VMware</affiliation>
|
|
||||||
</author>
|
|
||||||
<author>
|
<author>
|
||||||
<firstname>Costin</firstname>
|
<firstname>Costin</firstname>
|
||||||
<surname>Leau</surname>
|
<surname>Leau</surname>
|
||||||
<affiliation>SpringSource</affiliation>
|
<affiliation>SpringSource</affiliation>
|
||||||
</author>
|
</author>
|
||||||
|
<author>
|
||||||
|
<firstname>Jarred</firstname>
|
||||||
|
<surname>Li</surname>
|
||||||
|
<affiliation>VMware</affiliation>
|
||||||
|
</author>
|
||||||
</authorgroup>
|
</authorgroup>
|
||||||
|
|
||||||
<legalnotice>
|
<legalnotice>
|
||||||
@@ -63,7 +63,7 @@
|
|||||||
<part id="samples">
|
<part id="samples">
|
||||||
<title>Spring Shell Sample application</title>
|
<title>Spring Shell Sample application</title>
|
||||||
<xi:include href="samples/introduction.xml"/>
|
<xi:include href="samples/introduction.xml"/>
|
||||||
<xi:include href="samples/sample-application.xml"/>
|
<xi:include href="samples/simple-application.xml"/>
|
||||||
</part>
|
</part>
|
||||||
|
|
||||||
</book>
|
</book>
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
xmlns:ns2="http://www.w3.org/1999/xlink"
|
xmlns:ns2="http://www.w3.org/1999/xlink"
|
||||||
xmlns:ns="http://docbook.org/ns/docbook">
|
xmlns:ns="http://docbook.org/ns/docbook">
|
||||||
<para>The Spring Shell provides an interactive shell that lets you
|
<para>The Spring Shell provides an interactive shell that lets you
|
||||||
contribute commands using a simple POJO based programming model.</para>
|
contribute commands using a simple Spring based programming model.</para>
|
||||||
|
|
||||||
<para>This document is the reference guide for the Spring Shell and covers
|
<para>This document is the reference guide for the Spring Shell and covers
|
||||||
the key classes that are part of the Shell infrastructure, the plugin model,
|
the key classes that are part of the Shell infrastructure, the plugin model,
|
||||||
|
|||||||
@@ -8,11 +8,7 @@
|
|||||||
xmlns:ns="http://docbook.org/ns/docbook">
|
xmlns:ns="http://docbook.org/ns/docbook">
|
||||||
<title>Requirements</title>
|
<title>Requirements</title>
|
||||||
|
|
||||||
<para>The Spring Shell requires JDK level 6.0 (just like Hadoop) and above
|
<para>The Spring Shell requires JDK level 6.0 and above as well as the
|
||||||
and the Spring <ulink
|
Spring <ulink url="http://www.springsource.org/about">Framework</ulink> 3.0
|
||||||
url="http://www.springsource.org/about">Framework</ulink> 3.0 (3.1
|
(3.1 recommended) and above.</para>
|
||||||
recommended) and above.<ulink
|
|
||||||
url="http://www.gemstone.com/products/gemfire"/><ulink
|
|
||||||
url="http://hbase.apache.org/"/><ulink url="http://hive.apache.org/"/><ulink
|
|
||||||
url="http://pig.apache.org/"/></para>
|
|
||||||
</chapter>
|
</chapter>
|
||||||
|
|||||||
@@ -8,45 +8,40 @@
|
|||||||
<title>Preface</title>
|
<title>Preface</title>
|
||||||
|
|
||||||
<para>The Spring Shell provides an interactive shell that allows you to
|
<para>The Spring Shell provides an interactive shell that allows you to
|
||||||
plugin your own custom commands using a Spring based POJO programming
|
plugin your own custom commands using a Spring based programming
|
||||||
model.</para>
|
model.</para>
|
||||||
|
|
||||||
<para>The shell has been extracted from the Spring Roo project, giving it a
|
<para>The shell has been extracted from the <link
|
||||||
strong foundation and rich feature set. One significant change from Spring
|
ns2:href="http://www.springsource.org/spring-roo/">Spring Roo
|
||||||
Roo is that the plugin model is no longer based on OSGi but instead uses
|
project</link>, giving it a strong foundation and rich feature set. One
|
||||||
Spring IoC container to discover commands through classpath scanning. There
|
significant change from Spring Roo is that the plugin model is no longer
|
||||||
is currently no classloader isolation between plugins, however that maybe
|
based on OSGi but instead uses Spring IoC container to discover commands
|
||||||
added in future versions.</para>
|
through classpath scanning. There is currently no classloader isolation
|
||||||
|
between plugins, however that maybe added in future versions.</para>
|
||||||
|
|
||||||
<para>Spring Shell's features include</para>
|
<para>Spring Shell's features include</para>
|
||||||
|
|
||||||
<itemizedlist>
|
<itemizedlist>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>A POJO based programming model to contribute custom
|
<para>A simple, annotation driven, programming model to contribute
|
||||||
commands</para>
|
custom commands</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
|
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>Use Spring's classpath scanning functionality as a basis for a
|
<para>Use of Spring's classpath scanning functionality asthe basis for a
|
||||||
command plugin strategy</para>
|
command plugin strategy and command develoment</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
|
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>Inheritance of the <link
|
<para>Inheritance of the <link
|
||||||
ns2:href="http://static.springsource.org/spring-roo/reference/html-single/index.html#usage-shell">Roo
|
ns2:href="http://static.springsource.org/spring-roo/reference/html-single/index.html#usage-shell">Roo
|
||||||
Shell features</link></para>
|
Shell features</link>, most notably tab completion, colorization, and
|
||||||
|
script execution.</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
|
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>Tab completion</para>
|
<para>Customizatin of command prompt, banner, shell history file
|
||||||
</listitem>
|
name.</para>
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<para>Scripting and Script recording</para>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<para>Customize command prompt, banner, shell history file name.</para>
|
|
||||||
</listitem>
|
</listitem>
|
||||||
</itemizedlist>
|
</itemizedlist>
|
||||||
|
|
||||||
|
|||||||
@@ -10,35 +10,151 @@
|
|||||||
<title>Developing Spring Shell Applications</title>
|
<title>Developing Spring Shell Applications</title>
|
||||||
|
|
||||||
<para>Contributing commands to the shell is very easy. There are only a few
|
<para>Contributing commands to the shell is very easy. There are only a few
|
||||||
annotations you need to learn. The implementation style of the command is in
|
annotations you need to learn. The implementation style of the command is
|
||||||
the style of developing an application that uses dependency injection as you
|
the same as developing classes in for application that uses dependency
|
||||||
can leverage all the features of the Spring container.</para>
|
injection. You can leverage all the features of the Spring container to
|
||||||
|
implement your command classes.</para>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
<title>Marker Interface</title>
|
<title>Marker Interface</title>
|
||||||
|
|
||||||
<para>The first step to creating a command is to implement the market
|
<para>The first step to creating a command is to implement the marker
|
||||||
interface CommandMarker and to annotate your class with Spring's
|
interface <interfacename>CommandMarker</interfacename> and to annotate
|
||||||
@Component annotation. (Note there is an open JIRA issue to provide a
|
your class with Spring's <classname>@Component </classname>annotation.
|
||||||
@CliCommand meta-annotation to avoid having to use a market interface)
|
(Note there is an open JIRA issue to provide a
|
||||||
Taking the </para>
|
<classname>@CliCommand</classname> meta-annotation to avoid having to use
|
||||||
</section>
|
a marker interface). Using the code from the helloworld sample
|
||||||
|
application, the shell of a <classname>HelloWorldCommands</classname>
|
||||||
|
class is shown below </para>
|
||||||
|
|
||||||
<section>
|
<programlisting>@Component
|
||||||
<title>CLI Annotations</title>
|
public class HelloWorldCommands implements CommandMarker {
|
||||||
|
|
||||||
<para>annotations</para>
|
// use any Spring annotations for Dependency Injection or other Spring interfaces as required.
|
||||||
|
|
||||||
|
// methods with @Cli annotations go here
|
||||||
|
|
||||||
|
}</programlisting>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
<title>Logging</title>
|
<title>Logging</title>
|
||||||
|
|
||||||
<para/>
|
<para>Logging is done using JDK logging. Simply add a LOG declaration as
|
||||||
|
shown below to use a logger.</para>
|
||||||
|
|
||||||
|
<programlisting>@Component
|
||||||
|
public class HelloWorldCommands implements CommandMarker {
|
||||||
|
|
||||||
|
protected final Logger LOG = Logger.getLogger(getClass().getName());
|
||||||
|
|
||||||
|
// methods with @Cli annotations go here
|
||||||
|
|
||||||
|
}</programlisting>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<title>CLI Annotations</title>
|
||||||
|
|
||||||
|
<para>There are three annotations used on methods and method arguments
|
||||||
|
that define main contract for interacting with the shell. These are</para>
|
||||||
|
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem>
|
||||||
|
<para><classname>CliAvailabilityIndicator</classname> - Placed on a
|
||||||
|
method that returns a boolean value and indicates if a particular
|
||||||
|
command can be presented in the shell. This decision is usually based
|
||||||
|
on the history of commands that have been executed previously. It
|
||||||
|
prevents extraneous commands being presented until some preconditions
|
||||||
|
are met, for example the execution of a 'configuration'
|
||||||
|
command.</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para><classname>CliCommand</classname> - Placed on a method that
|
||||||
|
provides a command to the shell. Its value provides one or more
|
||||||
|
strings that serve as the start of a particular command name. These
|
||||||
|
must be unique within the entire application, across all
|
||||||
|
plugins.</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para><classname>CliOptions</classname> - Placed on the arguments of a
|
||||||
|
command methods, allowing it to declare the argument value as
|
||||||
|
mandatory or optional with a default value.</para>
|
||||||
|
</listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
|
||||||
|
<para>Here is a simple use of these annotations in a command class </para>
|
||||||
|
|
||||||
|
<programlisting language="java">@Component
|
||||||
|
public class HelloWorldCommands implements CommandMarker {
|
||||||
|
|
||||||
|
protected final Logger LOG = Logger.getLogger(getClass().getName());
|
||||||
|
|
||||||
|
@CliAvailabilityIndicator({"hw simple"})
|
||||||
|
public boolean isCommandAvailable() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@CliCommand(value = "hw simple", help = "Print a simple hello world message")
|
||||||
|
public void simple(
|
||||||
|
@CliOption(key = { "message" }, mandatory = true, help = "The hello world message") final String message,
|
||||||
|
@CliOption(key = { "location" }, mandatory = false, help = "Where you are saying hello", specifiedDefaultValue="At work") final String location) {
|
||||||
|
|
||||||
|
LOG.info("Message = [" + message + "] Location = [" + location + "]");
|
||||||
|
|
||||||
|
}
|
||||||
|
}</programlisting>
|
||||||
|
|
||||||
|
<para>The method annotated with <classname>@CliAvailabilityIndicator
|
||||||
|
</classname>is returning true so that the one and only command in this
|
||||||
|
class is exposed to the shell to be invoked. If there were more commands
|
||||||
|
in the class, you would list them as comma separated value.</para>
|
||||||
|
|
||||||
|
<para>The <classname>@CliCommand</classname> annotation is creating the
|
||||||
|
command '<literal>hw simple</literal>' in the shell. The help message is
|
||||||
|
what will be printed if you use the build in <literal>help</literal>
|
||||||
|
command. The method name is '<methodname>simple</methodname>' but it could
|
||||||
|
just have well been any other name.</para>
|
||||||
|
|
||||||
|
<para>The <classname>@CliOption</classname> annotation on each of the
|
||||||
|
command arguments is where you will spend most of your time authoring
|
||||||
|
commands. You need to decide which arguments are required, which are
|
||||||
|
optional, and if they are optional is there a default value. In this case
|
||||||
|
there are two arguments or keys to the command, message and location. The
|
||||||
|
key message is required and a help message is provided to give guidance to
|
||||||
|
the user when tabbing to get completion for the command. </para>
|
||||||
|
|
||||||
|
<para>The implementation of the 'simple' method is trivial, just a log
|
||||||
|
statement, but this is where you would typically call other collaborating
|
||||||
|
objects that were injected into the class via Spring.</para>
|
||||||
|
|
||||||
|
<para>The method argument types in this example are
|
||||||
|
<classname>String</classname>, which doesn't present any issue with type
|
||||||
|
conversion. You can specify methods with any rich object type including
|
||||||
|
basic primitive types such as int, float etc. For all types other than
|
||||||
|
those handled by the shell by default (basic types,
|
||||||
|
<classname>Date</classname>, <classname>File</classname>) you will need to
|
||||||
|
register your own implementation of the
|
||||||
|
<interfacename>org.springframework.shell.core.Converter</interfacename>
|
||||||
|
interface with the container in your plugin.</para>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
<title>Building and running the shell</title>
|
<title>Building and running the shell</title>
|
||||||
|
|
||||||
<para/>
|
<para>In our opinion, the easiest way to build an execute the shell is to
|
||||||
|
cut-n-paste the gradle script in the example application. This uses the
|
||||||
|
application plugin from gradle to create a bin directory with a startup
|
||||||
|
script for windows and Unix and places all dependent jars in a lib
|
||||||
|
directory. Maven has a similar plugin - the <link
|
||||||
|
xlink:href="http://mojo.codehaus.org/appassembler/appassembler-maven-plugin/">AppAssembler</link>
|
||||||
|
plugin.</para>
|
||||||
|
|
||||||
|
<para>The main class of the shell is
|
||||||
|
<classname>org.springframework.shell.Bootstrap</classname>. As long as you
|
||||||
|
place other plugins, perhaps developed independently, on the classpath,
|
||||||
|
the Bootstrap class will incorporate them into the shell.</para>
|
||||||
</section>
|
</section>
|
||||||
</chapter>
|
</chapter>
|
||||||
|
|||||||
@@ -23,8 +23,8 @@
|
|||||||
looks like this<programlisting>new ClassPathXmlApplicationContext("classpath*:/META-INF/spring/spring-shell-plugin.xml");</programlisting></para>
|
looks like this<programlisting>new ClassPathXmlApplicationContext("classpath*:/META-INF/spring/spring-shell-plugin.xml");</programlisting></para>
|
||||||
|
|
||||||
<para>In the <literal>spring-shell-plugin.xml</literal> file you should
|
<para>In the <literal>spring-shell-plugin.xml</literal> file you should
|
||||||
define the command classes and any other collaboration objects that
|
define the command classes and any other collaborating objects that
|
||||||
support the commands actions. The plugin model is depicted in the
|
support the command's actions. The plugin model is depicted in the
|
||||||
following diagram</para>
|
following diagram</para>
|
||||||
|
|
||||||
<mediaobject>
|
<mediaobject>
|
||||||
@@ -41,7 +41,7 @@
|
|||||||
<title>Commands</title>
|
<title>Commands</title>
|
||||||
|
|
||||||
<para>An easy way to declare the commands is to use Spring's component
|
<para>An easy way to declare the commands is to use Spring's component
|
||||||
scanning functionality.Here is an example
|
scanning functionality. Here is an example
|
||||||
<literal>spring-shell-plugin.xml </literal>that from the sample
|
<literal>spring-shell-plugin.xml </literal>that from the sample
|
||||||
application.</para>
|
application.</para>
|
||||||
|
|
||||||
@@ -56,7 +56,7 @@
|
|||||||
</beans></programlisting>
|
</beans></programlisting>
|
||||||
|
|
||||||
<para>The commands are Spring components, demarcated as such using the
|
<para>The commands are Spring components, demarcated as such using the
|
||||||
<literal>@Component</literal> annotation. For example, the
|
<literal>@Component</literal> annotation. For example, the shell of the
|
||||||
<classname>HelloWorldCommands</classname> class from the sample
|
<classname>HelloWorldCommands</classname> class from the sample
|
||||||
application looks like this</para>
|
application looks like this</para>
|
||||||
|
|
||||||
@@ -82,7 +82,7 @@ public class HelloWorldCommands implements CommandMarker {
|
|||||||
<para>The
|
<para>The
|
||||||
<interfacename>org.springframework.shell.core.Converter</interfacename>
|
<interfacename>org.springframework.shell.core.Converter</interfacename>
|
||||||
interface provides the contract to convert the strings that are entered
|
interface provides the contract to convert the strings that are entered
|
||||||
in the command to rich Java types passed into the arguments of
|
on the command line to rich Java types passed into the arguments of
|
||||||
<classname>@Cli</classname>-annotated methods.</para>
|
<classname>@Cli</classname>-annotated methods.</para>
|
||||||
|
|
||||||
<para>By default converters for common types are registered. These cover
|
<para>By default converters for common types are registered. These cover
|
||||||
@@ -122,6 +122,30 @@ public class HelloWorldCommands implements CommandMarker {
|
|||||||
executed.</para>
|
executed.</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</itemizedlist>
|
</itemizedlist>
|
||||||
|
|
||||||
|
<para>There are also a few commands that are provided by the
|
||||||
|
<classname>AbstractShell</classname> class, these are</para>
|
||||||
|
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem>
|
||||||
|
<para><literal>date</literal> - Displays the local date and
|
||||||
|
time</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para><literal>script</literal> - Parses the specified resource file
|
||||||
|
and executes its commands</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para><literal>system properties</literal> - Shows the shell's
|
||||||
|
properties</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para><literal>version</literal> - Displays current CLI version</para>
|
||||||
|
</listitem>
|
||||||
|
</itemizedlist>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
@@ -133,13 +157,14 @@ public class HelloWorldCommands implements CommandMarker {
|
|||||||
<itemizedlist>
|
<itemizedlist>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para><interfacename>BannerProvider</interfacename> - Specifies the
|
<para><interfacename>BannerProvider</interfacename> - Specifies the
|
||||||
banner text , welcome message, and version number that will be
|
banner text, welcome message, and version number that will be
|
||||||
displayed when the shell is started</para>
|
displayed when the shell is started</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
|
|
||||||
<listitem>
|
<listitem>
|
||||||
<para><interfacename>PromptProvider</interfacename> - Specifies the
|
<para><interfacename>PromptProvider</interfacename> - Specifies the
|
||||||
command prompt text</para>
|
command prompt text, eg. "<literal>shell></literal>" or
|
||||||
|
"<literal>#</literal>" or "<literal>$</literal>"</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
|
|
||||||
<listitem>
|
<listitem>
|
||||||
@@ -176,10 +201,10 @@ public class HelloWorldCommands implements CommandMarker {
|
|||||||
<para>It has shown to be useful to provide a simple form of interception
|
<para>It has shown to be useful to provide a simple form of interception
|
||||||
around the invocation of a command method. This enables the command class
|
around the invocation of a command method. This enables the command class
|
||||||
to check for updates to state, such as configuration information modified
|
to check for updates to state, such as configuration information modified
|
||||||
by other plugins, before the command is executed. The interface
|
by other plugins, before the command method is executed. The interface
|
||||||
<interfacename>ExecutionProcess</interfacename> should be implemented
|
<interfacename>ExecutionProcess</interfacename> should be implemented
|
||||||
instead of <interfacename>CommandMarker</interfacename> to access this
|
instead of <interfacename>CommandMarker</interfacename> to access this
|
||||||
functionlatiy. The <interfacename>ExecutionProcess</interfacename>
|
functionality. The <interfacename>ExecutionProcess</interfacename>
|
||||||
interface is shown below</para>
|
interface is shown below</para>
|
||||||
|
|
||||||
<programlisting>public interface ExecutionProcessor extends CommandMarker {
|
<programlisting>public interface ExecutionProcessor extends CommandMarker {
|
||||||
@@ -212,4 +237,43 @@ public class HelloWorldCommands implements CommandMarker {
|
|||||||
|
|
||||||
}</programlisting>
|
}</programlisting>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<title>Command line options</title>
|
||||||
|
|
||||||
|
<para>There are a few command line options that can be specified when
|
||||||
|
starting the shell. They are </para>
|
||||||
|
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem>
|
||||||
|
<para><literal>--profiles</literal> - Specifies values for the system
|
||||||
|
property spring.profiles.active so that Spring 3.1 and greater <link
|
||||||
|
xlink:href="http://blog.springsource.com/2011/02/11/spring-framework-3-1-m1-released/">profile
|
||||||
|
support </link>is enabled.</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para><literal>--cmdfile</literal> - Specifies a file to read that
|
||||||
|
contains shell commands</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para><literal>--histsize</literal> - Specifies the maximum number of
|
||||||
|
lines to store in the command history file. Default value is
|
||||||
|
3000.</para>
|
||||||
|
</listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<title>Scripts and comments</title>
|
||||||
|
|
||||||
|
<para>Scripts can be executed either by passing in the
|
||||||
|
<literal>--cmdfile</literal> argument at startup or by executing the
|
||||||
|
<literal>script</literal> command inside the shell. When using scripts it
|
||||||
|
helps to add comments and this can be done using block comments that start
|
||||||
|
and end with <literal>/*</literal> and <literal>*/</literal> or an inline
|
||||||
|
one line command using <literal>//</literal> or <literal>;</literal>
|
||||||
|
characters.</para>
|
||||||
|
</section>
|
||||||
</chapter>
|
</chapter>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<chapter version="5.0" xml:id="simple-application" xmlns="http://docbook.org/ns/docbook"
|
<chapter version="5.0" xml:id="simple-application"
|
||||||
|
xmlns="http://docbook.org/ns/docbook"
|
||||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||||
xmlns:ns5="http://www.w3.org/1998/Math/MathML"
|
xmlns:ns5="http://www.w3.org/1998/Math/MathML"
|
||||||
@@ -8,12 +9,127 @@
|
|||||||
xmlns:ns="http://docbook.org/ns/docbook">
|
xmlns:ns="http://docbook.org/ns/docbook">
|
||||||
<title>Simple sample application using the Spring Shell</title>
|
<title>Simple sample application using the Spring Shell</title>
|
||||||
|
|
||||||
<section id="shell:simple-application">
|
<section>
|
||||||
<title>Introduction</title>
|
<title>Introduction</title>
|
||||||
|
|
||||||
This sample demonstrates how to execute a MapReduce application and a script that interacts with HDFS inside a Spring based application. It does not use spring Batch or Spring Integration.
|
<para>The sample application named 'helloworld' contains three
|
||||||
|
'<literal>hw</literal>' commands, they are '<literal>hw simple</literal>',
|
||||||
|
'<literal>hw complex</literal>' and '<literal>hw enum</literal>' and
|
||||||
|
demonstrate simple to intermediate level usage of the
|
||||||
|
<literal>@Cli</literal> annotation classes for creating commands.</para>
|
||||||
|
|
||||||
<para>The example code is located in the distribution directory
|
<para>The example code is located in the distribution directory
|
||||||
<literal><spring-hadoop-install-dir>/samples/wordcount</literal>.</para>
|
<literal><spring-shell-install-dir>/samples/helloworld</literal>.</para>
|
||||||
|
|
||||||
|
<para>To build the example cd to the helloworld directory and execute
|
||||||
|
<literal>..\..\gradlew installApp</literal>. To run the application cd to
|
||||||
|
<literal>build\install\helloworld\bin</literal> and execute the helloworld
|
||||||
|
script.</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<title>HelloWorldCommands</title>
|
||||||
|
|
||||||
|
<para>The <classname>HelloWorldCommands</classname> class is show
|
||||||
|
below</para>
|
||||||
|
|
||||||
|
<programlisting language="java">package org.springframework.shell.samples.helloworld.commands;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import org.springframework.shell.core.CommandMarker;
|
||||||
|
import org.springframework.shell.core.annotation.CliAvailabilityIndicator;
|
||||||
|
import org.springframework.shell.core.annotation.CliCommand;
|
||||||
|
import org.springframework.shell.core.annotation.CliOption;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class HelloWorldCommands implements CommandMarker {
|
||||||
|
|
||||||
|
protected final Logger LOG = Logger.getLogger(getClass().getName());
|
||||||
|
|
||||||
|
private boolean simpleCommandExecuted = false;
|
||||||
|
|
||||||
|
@CliAvailabilityIndicator({"hw simple"})
|
||||||
|
public boolean isSimpleAvailable() {
|
||||||
|
//always available
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@CliAvailabilityIndicator({"hw complex", "hw enum"})
|
||||||
|
public boolean isComplexAvailable() {
|
||||||
|
if (simpleCommandExecuted) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@CliCommand(value = "hw simple", help = "Print a simple hello world message")
|
||||||
|
public void simple(
|
||||||
|
@CliOption(key = { "message" }, mandatory = true, help = "The hello world message") final String message,
|
||||||
|
@CliOption(key = { "location" }, mandatory = false, help = "Where you are saying hello", specifiedDefaultValue="At work") final String location) {
|
||||||
|
LOG.info("Message = [" + message + "] Location = [" + location + "]");
|
||||||
|
simpleCommandExecuted = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@CliCommand(value = "hw complex", help = "Print a complex hello world message")
|
||||||
|
public void hello(
|
||||||
|
@CliOption(key = { "message" }, mandatory = true, help = "The hello world message") final String message,
|
||||||
|
@CliOption(key = { "name1"}, mandatory = true, help = "Say hello to the first name") final String name1,
|
||||||
|
@CliOption(key = { "name2" }, mandatory = true, help = "Say hello to a second name") final String name2,
|
||||||
|
@CliOption(key = { "time" }, mandatory = false, specifiedDefaultValue="now", help = "When you are saying hello") final String time,
|
||||||
|
@CliOption(key = { "location" }, mandatory = false, help = "Where you are saying hello") final String location) {
|
||||||
|
LOG.info("Hello " + name1 + " and " + name2 + ". Your special message is " + message + ". time=[" + time + "] location=[" + location + "]");
|
||||||
|
}
|
||||||
|
|
||||||
|
@CliCommand(value = "hw enum", help = "Print a simple hello world message from an enumerated value")
|
||||||
|
public void eenum(
|
||||||
|
@CliOption(key = { "message" }, mandatory = true, help = "The hello world message") final MessageType message){
|
||||||
|
LOG.info("Hello. You special enumerated message is " + message);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum MessageType {
|
||||||
|
Type1("type1"),
|
||||||
|
Type2("type2"),
|
||||||
|
Type3("type3");
|
||||||
|
|
||||||
|
private String type;
|
||||||
|
|
||||||
|
private MessageType(String type){
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getType(){
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</programlisting>
|
||||||
|
|
||||||
|
<para>The use of the <classname>@CliAvailabilityIndicator</classname>
|
||||||
|
annotation on two methods, <methodname>isSimpleAvailable</methodname> and
|
||||||
|
<methodname>isComplexAvailable</methodname> shows how you can enable the
|
||||||
|
presence of the '<literal>hw complex</literal>' and '<literal>hw
|
||||||
|
enum</literal>' commands only if the '<literal>hw simple</literal>'
|
||||||
|
command was executed.</para>
|
||||||
|
|
||||||
|
<para>Here is an example session showing the behavior.</para>
|
||||||
|
|
||||||
|
<mediaobject>
|
||||||
|
<imageobject>
|
||||||
|
<imagedata fileref="../images/shell-example.jpg"/>
|
||||||
|
</imageobject>
|
||||||
|
</mediaobject>
|
||||||
|
|
||||||
|
<para>The '<literal>hw enum</literal>' command shows how the shell
|
||||||
|
supports the use of Enumeration as command method arguments.</para>
|
||||||
|
|
||||||
|
<mediaobject>
|
||||||
|
<imageobject>
|
||||||
|
<imagedata fileref="../images/shell-example-enum.jpg"/>
|
||||||
|
</imageobject>
|
||||||
|
</mediaobject>
|
||||||
</section>
|
</section>
|
||||||
</chapter>
|
</chapter>
|
||||||
|
|||||||
2
samples/helloworld/.gitignore
vendored
2
samples/helloworld/.gitignore
vendored
@@ -5,4 +5,4 @@ target/
|
|||||||
/log.roo
|
/log.roo
|
||||||
*.log
|
*.log
|
||||||
|
|
||||||
|
/bin/
|
||||||
|
|||||||
@@ -12,14 +12,33 @@ import org.springframework.stereotype.Component;
|
|||||||
@Component
|
@Component
|
||||||
public class HelloWorldCommands implements CommandMarker {
|
public class HelloWorldCommands implements CommandMarker {
|
||||||
|
|
||||||
|
|
||||||
protected final Logger LOG = Logger.getLogger(getClass().getName());
|
protected final Logger LOG = Logger.getLogger(getClass().getName());
|
||||||
|
|
||||||
@CliAvailabilityIndicator({"hw echo"})
|
private boolean simpleCommandExecuted = false;
|
||||||
public boolean isCommandAvailable() {
|
|
||||||
|
@CliAvailabilityIndicator({"hw simple"})
|
||||||
|
public boolean isSimpleAvailable() {
|
||||||
|
//always available
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@CliAvailabilityIndicator({"hw complex", "hw enum"})
|
||||||
|
public boolean isComplexCommandAvailable() {
|
||||||
|
if (simpleCommandExecuted) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@CliCommand(value = "hw simple", help = "Print a simple hello world message")
|
||||||
|
public void simple(
|
||||||
|
@CliOption(key = { "message" }, mandatory = true, help = "The hello world message") final String message,
|
||||||
|
@CliOption(key = { "location" }, mandatory = false, help = "Where you are saying hello", specifiedDefaultValue="At work") final String location) {
|
||||||
|
LOG.info("Message = [" + message + "] Location = [" + location + "]");
|
||||||
|
simpleCommandExecuted = true;
|
||||||
|
}
|
||||||
|
|
||||||
@CliCommand(value = "hw complex", help = "Print a complex hello world message")
|
@CliCommand(value = "hw complex", help = "Print a complex hello world message")
|
||||||
public void hello(
|
public void hello(
|
||||||
@CliOption(key = { "message" }, mandatory = true, help = "The hello world message") final String message,
|
@CliOption(key = { "message" }, mandatory = true, help = "The hello world message") final String message,
|
||||||
|
|||||||
@@ -20,6 +20,14 @@ import java.lang.annotation.Retention;
|
|||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
import java.lang.annotation.Target;
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Annotates a method that provides a command to the shell.
|
||||||
|
*
|
||||||
|
* @author Ben Alex
|
||||||
|
* @since 1.0
|
||||||
|
*
|
||||||
|
*/
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@Target(ElementType.METHOD)
|
@Target(ElementType.METHOD)
|
||||||
public @interface CliCommand {
|
public @interface CliCommand {
|
||||||
|
|||||||
@@ -22,7 +22,13 @@ import java.lang.annotation.Target;
|
|||||||
|
|
||||||
import org.springframework.shell.core.Converter;
|
import org.springframework.shell.core.Converter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Annotates the arguments of a command methods, allowing it to declare the argument value as mandatory or optional with a default value.
|
||||||
|
*
|
||||||
|
* @author Ben Alex
|
||||||
|
* @since 1.0
|
||||||
|
*
|
||||||
|
*/
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@Target(ElementType.PARAMETER)
|
@Target(ElementType.PARAMETER)
|
||||||
public @interface CliOption {
|
public @interface CliOption {
|
||||||
|
|||||||
Reference in New Issue
Block a user