First type module
From ControlTier
This document describes how to create defined commands in a ControlTier type using XML and ProjectBuilder. For a graphical alternative see the Graphical type editor. ProjectBuilder contains a set of commands that let you create, build and stage these. Types are defined in an XML file referred to as a type.xml file. The type.xml file supports a set of XML tags that declare object attributes, defaults, constraints and commands.
Defining new modules with ProjectBuilder is a simple process and follows a typical edit, build, run cycle.
Contents |
Run create-type
ProjectBuilder includes a command called create-type that generates a set of boiler plate files that bootstrap the type and type development process. Without arguments, the create-type command runs interactively. Run the create-type command accepting the defaults:
$ ctl -p aProject -m ProjectBuilder -c create-type Base directory where module source files reside [/tmp/ctier/ctl/src] Target directory where build files are generated [/tmp/ctier/target] Choose a supertype: ([Managed-Entity], Package, Builder, Deployment, Service) Deployment Name of type: poly Description of type: Says hi in different languages Creating module definition files in directory: /tmp/ctier/ctl/src ... Initializing type module from template dir: /tmp/ctier/ctl/projects/default/modules/ProjectBuilder/templates/boilerplate ... Created dir: /tmp/ctier/ctl/src/modules/poly Copying 1 file to /tmp/ctier/ctl/src/modules/poly Creating directory structure... Created dir: /tmp/ctier/ctl/src/modules/poly/bin Created dir: /tmp/ctier/ctl/src/modules/poly/commands Created dir: /tmp/ctier/ctl/src/modules/poly/objects Created dir: /tmp/ctier/ctl/src/modules/poly/templates Copying /tmp/ctier/ctl/projects/default/modules/ProjectBuilder/templates/types/Deployment to /tmp/ctier/ctl/src/modules/poly ... Initializing type module from template dir: /tmp/ctier/ctl/projects/default/modules/ProjectBuilder/templates/types/Deployment ... Copying 2 files to /tmp/ctier/ctl/src/modules/poly Define commands and attributes in this file: /tmp/ctier/ctl/src/modules/poly/type.xml
You might be wondering about the supertype chosen in this example. Deployment is one of the ControlTier core types.
The build-type command generates a set of files that comprise a module. Modules are a piece of software that can be distributed to CTL installations. Once installed the commands in the module are accessible to the command dispatcher.
Modules have the following directory layout:
module_name | |--- commands.properties // file containing command metadata (auto-generated) |--- module.properties // file containing module metadata (auto-generated) |--- type.properties // file containing type metadata (auto-generated) |--- type.xml // file containing command definitions (user created/modified) | +--- bin // optional binaries, shell scripts, etc. | +--- commands // contains generated commands | +--- lib // optional resource files
As mentioned earlier, the type.xml file is used to define all aspects of the type, including its commands. See the type.xml reference document for information about all its tags. In this continuing example, the type.xml file for the "poly" module is $CTL_BASE/src/modules/poly/type.xml.
Define a command named "slither":
<command name="slither" description="Say something with python." command-type="BsfCommand" is-static="true"> <script language="jython">print "python says: %s" % project.getProperty('opts.message')</script> <opts> <opt parameter="message" description="message to print" required="false" property="opts.message" type="string" default="ssss"/> </opts> </command>
This example command was defined as a BsfCommand command-type. Other command-types are shown later in this document.
Run build-type
ProjectBuilder's build-type command processes the type.xml and other module sources and generates a working module. Run the build-type command to generate the module files for your new command (accept the defaults again):
$ ctl -m ProjectBuilder -c build-type -- -type poly -upload -deploy Base directory where module source files reside [/tmp/ctier/ctl/src] Target directory where build files are generated [/tmp/ctier/target] Building type using the buildmodule.xml via classloader converting type.xml for module: poly generating handlers... packaging module: poly Copying 1 file to /tmp/ctier/ctl/src/modules/poly Moving 1 file to /tmp/ctier/ctl/src/modules/poly Building jar: /tmp/ctier/target/modules/poly-1.jar deploying new build of poly module to local installation ... Extracting /tmp/ctier/target/modules/poly-1.jar to: /tmp/ctier/ctl/projects/default/modules/poly Expanding: /tmp/ctier/target/modules/poly-1.jar into /tmp/ctier/ctl/projects/default/modules/poly
The "-upload" flag tells build-type to upload the module to the ControlTier server while the "-deploy" option causes the module to be installed in the local CTL project.
The module was built and deployed and is ready for use.
If you run the ctl shell command without arguments you should see the new module in the listing output:
ctl poly: Says hi in different languages commands: [slither] -- snip --
To see more detail about the commands defined in the new type add "-m poly" as arguments:
$ ctl -m poly poly: Says hi in different languages commands: [slither]
The commands defined in the type will be listed.
Run your command
The general usage for the new module will be: ctl -m poly -c <command> -- [-message <>].
So far the "slither" command has been defined so it supports two ways of being called.
-
ctl -m poly -c slither
- Call it without arguments letting the default message apply
-
ctl -m poly -c slither -- -message message
- Call it with the the -message option
First run it without the -message option to show the default being used.
$ ctl -m poly -c slither python says: ssss
Next, run the command with with the option specified specified:
$ ctl -m poly -c slither -- -message "'some nice mice?'" python says: some nice mice?
Note
- Some Unix users see this error: "can't create package cache dir, '/cachedir/packages'". See python wiki for information about permissions. In most cases, this error won't interefere with this demo example.
You may be curious about the double hyphen (eg, --) in the example. The double hyphen is used to separate the ctl command line arguments from the command-specific ones (in this case "-message"). See CTL Command Reference#Command_Options
The next section describes how to define other command types.
System shell script command
System shellscripts are simple to define and are made up of an "executable" and an "argument string". An easy one to define is an "echo" command.
<command name="echo" description="second command." command-type="Command" is-static="true"> <execution-string>bash</execution-string> <argument-string>echo bash says ${opts.message}</argument-string> <opts> <opt parameter="message" description="option name" required="false" property="opts.message" type="string" default="hi there!"/> </opts> </command>
See more at Shell command.
Ant command
Ant commands are defined using Ant tasks. CTL includes ant-contrib and its own CTL-specific tasks, too. This example uses the "echo" task to print the message.
<command name="emit" description="say something with Ant." command-type="AntCommand" is-static="true"> <implementation> <echo message="ant says ${opts.message}"/> </implementation> <opts> <opt parameter="message" description="option name" required="false" property="opts.message" type="string" default="creepers"/> </opts> </command>
See more at Ant command.
Bean Scripting Framework command
The first example shown here was a BsfCommand type. These commands use the Apache Bean Scripting Framework (BSF) to execute script code of various langauges. Here's another example showing ruby...
<command name="shine" description="ruby BSF command."
command-type="BsfCommand" is-static="true">
<script language="ruby"><![CDATA[
print 'ruby says ', $project.getProperty('opts.message'), "\n"
]]></script>
<opts>
<opt parameter="message" description="option name" required="false"
property="opts.message" type="string" default="dazzle"/>
</opts>
</command>... and yet another this time in groovy:
<command name="groovy" description="groovy BSF command." command-type="BsfCommand" is-static="true"> <script language="groovy"><![CDATA[ println "groovy says ${project.properties['opts.message']} \n" ]]></script> <opts> <opt parameter="message" description="option name" required="false" property="opts.message" type="string" default="peace"/> </opts> </command>
Properties referenced in the command definitions of the type.xml will be replaced before the BSF script is evaluated. In this example, the property opts.message will be replaced by its value.
Note
- You might notice in the examples above that the BSF scripting code was contained in a CDATA section. This is not required but does allow you to use unencoded XML characters.
See more at BSF command.
Programmatic Access to the CTL API
The CTL Java API provides an interface to accessing framework resources via Java. This Java object is accessible to BsfCommands.
A named reference is defined that allows you to look it up as shown below:
com.controltier.ctl.common.Framework framework = project.getReference("com.controltier.ctl.common.Framework.instance")
The Framework provides programmatic access to looking up resources in the framework like project projects, modules, commands, and their properties.
com.controltier.ctl.common.Framework framework = project.getReference("com.controltier.ctl.common.Framework.instance") List projects = framework.getDepotResourceMgr().listDepots()
Here's an example using groovy:
<command name="list-projects" description="List all the project projects." command-type="BsfCommand" is-static="true"> <script language="groovy"><![CDATA[ def framework = project.getReference("com.controltier.ctl.common.Framework.instance") def projects = framework.getDepotResourceMgr().listDepots() projects.each { d -> println "${d.name} \n"; } ]]></script> </command>
Workflow command
You can model a sequence of commands in a command-type called a WorkflowCommand. Here the previously defined commands are called in the order shown below:
<command name="stammer" description="first workflow command" command-type="WorkflowCommand" is-static="true" error-handler-type="FAIL" > <workflow threadcount="1"> <command name="slither"/> <command name="echo"/> <command name="emit"/> <command name="shine"/> <command name="groovy"/> </workflow> <opts> <opt parameter="message" description="option name" required="false" property="opts.message" type="string" default="duh...?"/> </opts> </command>
Run build-type again to regenerate the module:
ctl -m ProjectBuilder -c build-type -- -type poly -upload -deploy
Run the new workflow command:
ctl -m poly -c stammer -- -message cheers Start: "first workflow command" commands: slither,echo,emit,shine,groovy begin workflow command (1/5) -> "slither -message cheers" ... python says: cheers end workflow command (1/5) -> "slither -message cheers" begin workflow command (2/5) -> "echo -message cheers" ... bash says cheers end workflow command (2/5) -> "echo -message cheers" begin workflow command (3/5) -> "emit -message cheers" ... ant says cheers end workflow command (3/5) -> "emit -message cheers" begin workflow command (4/5) -> "shine -message cheers" ... ruby says cheers end workflow command (4/5) -> "shine -message cheers" begin workflow command (5/5) -> "groovy -message cheers" ... groovy says cheers end workflow command (5/5) -> "groovy -message cheers" [command.timer.default.poly.stammer: 16.130 sec] Workflow completed. execution time: 16.130 sec
| ||||||||||||||
