This walkthrough will set up a simple entity, add it to the catalog, and provision it.
For illustration purposes, we will write an integration with Github Gist, with an effector to create new gists.
Follow the instructions to create a new Java project using the archetype, and import it into your [favorite IDE]({{ site.path.guide }}/dev/env/ide/). This example assumes you used the groupId com.acme
and artifact id autobrick
.
First ensure you can build this project at the command line, using mvn clean install
.
For this particular example, we will use a third party Gist library, so will need to add that as a dependency. Add the following to your pom.xml
inside the <dependencies>
section (see Maven for more details):
{% highlight xml %} org.eclipse.mylyn.github org.eclipse.egit.github.core 2.1.5 {% endhighlight %}
Create a new Java interface, GistGenerator
, to describe the entity's interface (i.e. the configuration options, sensors, and effectors). The code below assumes you have created this in the package com.acme
for src/main/java
.
{% highlight java %} {% readj gist_generator/GistGenerator.java %} {% endhighlight %}
To describe each part of this:
@ImplementedBy
indicates the implementation class for this entity type - i.e. the class to instantiate when an entity of this type is created.Entity
, we indicate that this interface is an Entity type. We could alternatively have extended one of the other sub-types of Entity.OAUTH_KEY
is a configuration key - it is configuration that can be set on the entity when it is being instantiated.@Effector
annotation indicates that the given method is an effector, so should be presented and tracked as such. Execution of the effector is intercepted, to track it as a task and show its execution in the Activity view.@EffectorParam
annotations give metadata about the effector's parameters. This metadata, such as the parameter description, is available to those using the client CLI, rest API and web-console.Note there is an alternative way of defining effectors - adding them to the entity dynamically, discussed in the section Dynamically Added Effectors.
Next lets add the implementation. Create a new Java class named GistGeneratorImpl
.
{% highlight java %} {% readj gist_generator/GistGeneratorImpl.java %} {% endhighlight %}
To describe each part of this:
AbstractEntity
- all entity implementations should extend this, or one of its sub-types.GistGenerator
: this is the Entity type definition, so must be implemented. Users of the entity will only refer to the interface; they will never be given an instance of the concrete class - instead a dynamic proxy is used (to allow remoting).org.slf4j.Logger
is the logger used throughout Apache Brooklyn.createGist
effector - we do not need to re-declare all the annotations.oath.key
parameter was passed in, then use the configuration set on the entity.First, create a github.com account, if you do not already have one.
Before running the blueprint, we'll need to generate an access token that has permissions to create a gist programmatically.
First create a new access token that our blueprint will use to create a gist:
Next, grant the token rights to create gists:
The archetype project comes with example unit tests that demonstrate how to test entities, both within Java and also using YAML-based blueprints.
We will create a similar Java-based test for this blueprint. Create a new Java class named GistGeneratorTest
in the package com.acme
, inside src/test/java
.
You will need to substitute the github access token you generated in the previous section for the placeholder text xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
.
{% highlight java %} {% readj gist_generator/GistGeneratorTest.java %} {% endhighlight %}
Similarly, we can write a test that uses the GistGenerator
from a YAML blueprint. Create a new Java class named GistGeneratorYamlTest
in the package com.acme
, inside src/test/java
.
Again you will need to substitute the github access token you generated in the previous section for the placeholder text xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
. See the section on [externalised configuration]({{ site.path.guide }}/ops/externalized-configuration.html) for how to store these credentials more securely.
{% highlight java %} {% readj gist_generator/GistGeneratorYamlTest.java %} {% endhighlight %}
Next we will build this example as an OSGi Bundle so that it can be added to the Apache Brooklyn server at runtime, and so multiple versions of the
blueprint can be managed.
The mvn clean install
will automatically do this, creating a jar inside the target/
sub-directory of the project. This works by using the Maven Bundle Plugin which we get automatically by declaring the pom.xml
's parent as brooklyn-downstream-parent
.
Similar to the sample.bom
entity that ships with the archetype, we will define a .bom
file to add our GistGenerator
to the catalog. Substitute the URL below for your own newly built artifact (which will be in the target
sub-directory after running mvn clean install
).
{% highlight yaml %} {% readj gist_generator/gist_generator.bom %} {% endhighlight %}
Unfortunately the file org.eclipse.egit.github.core-2.1.5.jar (available on maven central) was generated incorrectly as an OSGi bundle (there is a missing quotation mark from the manfest file, making it invalid). The above YAML references a corrected version of this OSGi bundle, made available for test purposes.
The command below will use the REST api to add this to the catalog of a running Brooklyn instance. Substitute the credentials, URL and port for those of your server.
{% highlight bash %} $ curl -u admin:pa55w0rd https://127.0.0.1:8443/v1/catalog --data-binary @gist_generator.bom {% endhighlight %}
The YAML blueprint below shows an example usage of this blueprint:
name: my sample services: - type: example.GistGenerator:1.0 brooklyn.config: oauth.key: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Note the type name matches the id and version defined in the .bom
file.
You can now call the effector by any of the standard means - [web console]({{ site.path.guide }}/ops/gui/), [REST api]({{ site.path.guide }}/ops/rest.html), or [Client CLI]({{ site.path.guide }}/ops/cli/).