From IcedTea

Jump to: navigation, search

Thermostat Home


1 Extending Thermostat

Note: This page is a draft and may change frequently. These are instructions for Thermostat users who are also developers and would like to extend Thermostat.

1.1 Building Thermostat and the Thermostat Maven Archetypes

Thermostat sources include a Maven archetype which can be used to generate a basic scaffold for developing a new thermostat extension bundle. Also, in order to be able to compile your Thermostat extension bundle it is easiest to get the sources for the thermostat version you are using, compile them locally and install them into your local maven repo.

 $ hg clone<VERSION>
 $ cd thermostat-<VERSION>
 $ mvn clean install

Say, you'd want to develop an extension for Thermostat 1.0 then the above hg clone command would become:

 $ hg clone

After the mvn clean install step above you should have the thermostat maven archetypes installed and should be able to use it.

Some plug-ins are developed in-tree and could be used for inspiration of developing your own. Every subfolder in distribution/target/image/plugins comprises a separate Thermostat plugin. See respective thermostat-plugin.xml for details as to what they provide.

1.2 Scaffolding

With version 1.0.2 and better Thermostat comes with two maven archetypes which are useful for scaffolding the general structure of a new thermostat plugin. The first artifact is fairly simple and generates a scaffold for a Thermostat plug-in which consists of a single Maven module. The coordinates (archetypeGroupId:archetypeArtifactId) of this archetype are com.redhat.thermostat:thermostat-maven-archetype-ext. The second archetype generates a complete Hello-World style Thermostat plugin consisting of multiple Maven modules. The coordinates to this archetype are com.redhat.thermostat:thermostat-maven-archetype-multimodule. Note that you can remove the -B switch from the below maven commands and you can enter required parameters interactively.

1.2.1 Single-Maven-Module Plug-in Scaffold

Say we'd like to write a new Thermostat command available via the thermostat shell. We'll develop this new command in folder "helloworld". In order to speed things up we'll use the maven archetype in order to get a basic structure which we can work with. Also suppose we want to develop against Thermostat 1.0.0. Note that the version should match the one you've cloned and installed above.

 $ mvn archetype:generate -B -DarchetypeGroupId=com.redhat.thermostat \
                          -DarchetypeArtifactId=thermostat-maven-archetype-ext \
                          -DbundleSymbolicName=org.jerboaa.thermostat.helloworld \
                          -Dpackage=org.jerboaa.thermostat \
                          -DgroupId=org.jerboaa.thermostat \
                          -DartifactId=helloworld \
                          -Dversion=0.0.1-SNAPSHOT \
                          -DthermostatVersion=1.0.0 \
                          -DmoduleName="Thermostat Hello World Extension Command"

Let's now look at the details of each property passed to achetype:generate. As mentioned before archetypeGroupId and archetypeArtifactId comprise the unique coordinates to this archetype.

The Bundle-SymbolicName to be used in the generated OSGi metadata. Since Thermostat uses OSGi, every plug-in JAR requires OSGi metadata. See MANIFEST.MF files of existing thermostat JARs.
The package for the generated Maven module. The package should include the groupId prepended. E.g. if groupId is example.groupId then the package should start with example.groupId (ex. example.groupId.expackage)
The groupId of the generated Maven module (pom.xml only) The groupId should be unique.
The artifactId of the generated Maven module (pom.xml only) This determines the name of the jar file without version and also determines the name of the folder that the module will be generated in.
The description of this plug-in (pom.xml only)
The version to use for this Maven module (pom.xml only)
The Thermostat version for which you are about to develop a plug-in for
The Maven module name to use (pom.xml only)

See for more information.

1.2.2 Multi-Maven-Module Plug-in Scaffold

mvn archetype:generate -B \
 -DarchetypeGroupId=com.redhat.thermostat \
 -DarchetypeArtifactId=thermostat-maven-archetype-multimodule \
 -DgroupId=org.jerboaa.thermostat.plugins \
 -DartifactId=thermostat-foo-plugin \
 -DpluginDescription="Thermostat foo plug-in" \
 -DhelloMessage='Hello World!' \ \
 -Dversion=0.0.1-SNAPSHOT \
 -DpluginDeployDir=foo-plugin \

Once you've run this command have a look at the generated README file. Let's now look at the details of each property passed to achetype:generate. As mentioned before archetypeGroupId and archetypeArtifactId comprise the unique coordinates to this archetype.

The groupId of the generated Maven module (pom.xml only)
The artifactId of the generated Maven module (pom.xml only)
The description of this plug-in (pom.xml only)
The message to use in generated Java code classes.
The Java base package to use. Sub-modules will use ${package}.storage, ${package}.agent etc. as package name.
The version to use for Maven modules (pom.xml only) a.k.a plug-in version number.
The Thermostat version for which you are about to develop a plug-in for
The directory name to use inside $THERMOSTAT_HOME/plugins. See also after you've run the achetype:generate command.

The above command should have generated a folder called thermostat-foo-plugin. Again this folder will contain a README file with further information on this Hello-World plugin. The generated scaffold should also compile and deploy properly if all went well. You can import the thermostat-foo-plugin folder into Eclipse and start hacking on your first Thermostat plug-in as well.

1.3 Adding Plugins to Thermostat

Thermostat picks up plugins under $THERMOSTAT_HOME/plugins/ (which the rest of this documentation will refer to as $PLUGIN_ROOT) automatically. These plugins are first-class citizens in thermostat. They have access to everything that built-in bundles in thermostat do.

A thermostat install directory (trimmed for clarity) looks like the following:

├── libs
│   ├── thermostat-agent-cli-0.6.0-SNAPSHOT.jar
│   ├── thermostat-agent-command-0.6.0-SNAPSHOT.jar
│   ├── thermostat-agent-core-0.6.0-SNAPSHOT.jar
│   ├── thermostat-client-cli-0.6.0-SNAPSHOT.jar
│   ├── thermostat-client-command-0.6.0-SNAPSHOT.jar
│   ├── thermostat-client-core-0.6.0-SNAPSHOT.jar
│   ├── thermostat-client-swing-0.6.0-SNAPSHOT.jar
│   ├── thermostat-common-command-0.6.0-SNAPSHOT.jar
│   ├── thermostat-common-core-0.6.0-SNAPSHOT.jar
│   ├── thermostat-launcher-0.6.0-SNAPSHOT.jar
│   └── thermostat-main-0.6.0-SNAPSHOT.jar
└── plugins (aka ${PLUGIN_ROOT})
    ├── plugin1 (aka ${PLUGIN_HOME})
    │   ├── plugin.xml
    │   ├── plugin-agent.jar
    │   └── plugin-client.jar
    └── plugin2
        ├── plugin.xml
        ├── plugin-agent.jar
        ├── plugin-client-core.jar
        ├── plugin-client-swing.jar
        └── plugin-common.jar

Each plugin must be installed under $THERMOSTAT_HOME/plugins/$PLUGIN_NAME/ (which the rest of this documentation will refer to as $PLUGIN_HOME). All the files provided by the plugin must be placed under there. The top-level $PLUGIN_HOME directory must contain a thermostat-plugin.xml file that describes the plugin and tells thermostat how to use it. Other files in the plugin can be located anywhere under $PLUGIN_HOME. All jars that are part of a plugin must be valid OSGi bundles. The activators of these OSGi bundles will be used (as expected) when the bundle changes its lifecycle state.

Here's how a simple thermostat-plugin.xml file might look like

<?xml version="1.0" ?>
      <description>print hello</description>
          <description>write hello to the file</description>

This file describes that the plugin is only used for two commands: a new command hello and the existing command gui. Thermostat will ignore this plugin for all other other commands.

For the gui command (a command that's part of thermostat which starts the default gui client), thermostat should load the bundle with the symbolic name com.plugin.hello.gui and version 0.1, which is provided by this plugin.

For the hello command (a new command specified by this plugin), thermostat should load the bundle with symbolic-name of com.plugin.hello.cli and a version of 0.1, which is provided by this plugin, as well as the bundle with symbolic-name of com.redhat.thermostat.client.core and the version 0.13, which is part of thermostat itself. The activator of the com.plugin.hello.cli bundle must, at a minimum, register an implementation of a "hello" command that are specified in the plugin.xml file.

Each plugin contains commands and extensions</command> elements. The <code>commands element contains new commands provided by the plugin. The extensions element indicates that the plugin wishes to extend existing commands.

The <commands> element should contain multiple of <command> elements. Each <command> element should contain one <bundles> element and a <dependencies> element. The <bundles> element contains multiple <bundle> elements. Each <bundle> specifies the path to one bundle that should be loaded and activated when the command is invoked. The path of a specified in the <bundle> element is relative to the $PLUGIN_HOME. The <dependencies> element contains one or more <dependency> elements. Each <dependency> element specifies bundles that are part of thermostat (not the plugin!) that should be loaded and activated. The path of of a dependency is relative to $THERMOSTAT_HOME/libs/.

See the Plugin Schema Guide for more information. Alternatively look at thermostat-plugin.xsd located in distribution/docs/ for the schema. This can be accessed online through

1.3.1 Thermostat Plugin Configuration Files

Thermostat (HEAD revision or 1.1.0-SNAPSHOT and better) supports loading of plugin configuration files through a pluginID specification in the plugin's thermostat-plugin.xml. The configuration files must be acceptable by the Java Properties.load(Inputstream) function. See for more information. For example, plain text documents containing key=value pairs separated by new lines are accepted.



The default locations for plugin configurations is $USER_THERMOSTAT_HOME/etc/plugins.d/$PLUGIN_ID/ and $THERMOSTAT_HOME/etc/plugins.d/$PLUGIN_ID/. Configuration files placed here will be loaded by Thermostat during launch so that the plugin may acquire it through the ConfigurationInfoSource OSGi Service. If the configuration file is located in both the user and system directories, the user configuration overrides the system configuration. Plugin's can also specify an absolute path through their thermostat-plugin.xml with the <configuration> tag. This will also be loaded by Thermostat and can be accessed in the same way as configurations located in the default directories.

An example thermostat-plugin.xml with an absolute path:

 <plugin xmlns=""
         xsi:schemaLocation=" thermostat-plugin.xsd">

Sample code that acquires the configuration file example.conf from plugin with id example-plugin :

   public void example(BundleContext context) {
       ServiceReference ref = context.getServiceReference(ConfigurationInfoSource.class.getName());
       ConfigurationInfoSource configurationInfoSource = (ConfigurationInfoSource) context.getService(ref);
       Map<String, String> configuration = configurationInfoSource.getConfiguration("example-plugin", "example.conf");

1.3.2 Thermostat Eclipse Plugin Tool

For those developing in Eclipse, there is a plugin that aids in developing Thermostat plugins. The tool provides a base project structure from which to build off of, similar to the Maven multi-module archetype. It also allows you to build the plugin within Eclipse directly into Thermostat.

Repository located at: Readme located within the repository.

1.3.3 Examples

In order of date last changed (newest first):

1.4 Statement Descriptors

Thermostat uses prepared statements for reading and writing data from storage. You can find more information on their format on the statement descriptor wiki page.

Personal tools