Repository: brooklyn-docs
Updated Branches:
  refs/heads/master f858b171e -> 5676dda50


Update/improve docs for java entities

- In particular, updates the docs to follow the archetype changes
  made in https://github.com/apache/brooklyn-dist/pull/10

Project: http://git-wip-us.apache.org/repos/asf/brooklyn-docs/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-docs/commit/44e812ba
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-docs/tree/44e812ba
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-docs/diff/44e812ba

Branch: refs/heads/master
Commit: 44e812ba782f613f3df28220c82b6831b1ecc19a
Parents: a41e0d7
Author: Aled Sage <aled.s...@gmail.com>
Authored: Mon Mar 7 20:42:00 2016 +0000
Committer: Aled Sage <aled.s...@gmail.com>
Committed: Mon Mar 7 20:42:00 2016 +0000

----------------------------------------------------------------------
 guide/java/archetype.md                         |  62 +++--
 guide/java/common-usage.md                      | 235 ++++++++++++-------
 guide/java/defining-and-deploying.md            | 226 +++++++++++-------
 guide/java/entity.md                            |  26 +-
 guide/java/feeds.md                             | 203 ++++++++++++++++
 guide/java/gist_generator/GistGenerator.java    |  29 +++
 .../java/gist_generator/GistGeneratorImpl.java  |  47 ++++
 .../java/gist_generator/GistGeneratorTest.java  |  20 ++
 .../gist_generator/GistGeneratorYamlTest.java   |  39 +++
 guide/java/gist_generator/gist_create_token.png | Bin 0 -> 390046 bytes
 guide/java/gist_generator/gist_generator.bom    |  15 ++
 guide/java/gist_generator/gist_grant_access.png | Bin 0 -> 411974 bytes
 guide/java/index.md                             |  19 +-
 guide/java/java_app/ExampleWebApp.java          |  30 +++
 guide/java/policies.md                          |  10 +-
 ...topology-dependencies-management-policies.md |  69 ------
 guide/java/topology-dependencies.md             |  49 ++++
 17 files changed, 804 insertions(+), 275 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-docs/blob/44e812ba/guide/java/archetype.md
----------------------------------------------------------------------
diff --git a/guide/java/archetype.md b/guide/java/archetype.md
index ba3bc0e..3bd3426 100644
--- a/guide/java/archetype.md
+++ b/guide/java/archetype.md
@@ -7,9 +7,13 @@ categories: [use, guide, defining-applications]
 
 ### Maven Archetype
 
-Brooklyn includes a maven archetype, which can be used to create the project 
structure for a new application.
+Brooklyn includes a maven archetype, which can be used to create the project 
structure for 
+developing a new Java entity, and generating the OSGi bundle for it.
 
-This can be done interactively using:
+
+#### Generating the Project
+
+The archetype can be used interactively, by running:
 {% highlight bash %}
 $ mvn archetype:generate
 {% endhighlight %}
@@ -33,32 +37,52 @@ $ mvn archetype:generate \
 {% endhighlight %}
 
 This will create a directory with the artifact name (e.g. "autobrick" in the 
example above).
-Note that if run from a directory containing a pom, it will also modify that 
pom to add this as a module!
+Note that if run from a directory containing a pom, it will also modify that 
pom to add this as 
+a module!
+
+The project will contain an example Java entity. You can test this using the 
supplied unit tests,
+and also replace it with your own code.
+
+The `README.md` file within the project gives further guidance.
 
-The project will contain an example app. You can run this, and also replace it 
with your own
-application code.
+
+#### Building
 
 To build, run the commands:
 
 {% highlight bash %}
 $ cd autobrick
-$ mvn clean install assembly:assembly
+$ mvn clean install
 {% endhighlight %}
 
-The assembly command will build a complete standalone distribution archive in 
`target/autobrick-0.1.0-SNAPSHOT-dist.tar.gz`,
-suitable for redistribution and containing `./start.sh` in the root.
 
-An unpacked equivalent is placed in `target/autobrick-0.1.0-SNAPSHOT-dist`,
-thus you can run the single-node sample locally with:
+#### Adding to the Catalog
 
-{% highlight bash %}
-$ cd target/autobrick-0.1.0-SNAPSHOT-dist/autobrick-0.1.0-SNAPSHOT/
-$ ./start.sh launch --single
-{% endhighlight %}
+The build will produce an OSGi bundle in 
`target/autobrick-0.1.0-SNAPSHOT.jar`, suitable for 
+use in the [Brooklyn catalog]({{ site.path.guide }}/ops/catalog/) (using 
`brooklyn.libraries`).
+
+The project comes with a `sample.bom` file, located in `src/test/resources`. 
You will first have 
+to copy the target jar to a suitable location, and update the URL in 
`sample.bom` to point at that 
+jar.
+
+The command below will use the REST api to add this to the catalog of a 
running Brooklyn instance:
+
+    curl -u admin:pa55w0rd http://127.0.0.1:8081/v1/catalog --data-binary 
@src/test/resources/sample.bom
+
+The YAML blueprint below shows an example usage of this blueprint:
+
+    name: my sample
+    services:
+    - type: com.acme.MySampleInCatalog:1.0
+
+
+### Testing Entities
 
-This `start.sh` script has all of the same options as the default `brooklyn` 
script, 
-including `./start.sh help` and the `--location` argument for `launch`,
-with a couple of extra `launch` options for the sample blueprints in the 
archetype project:
+The project comes with unit tests that demonstrate how to test entities, both 
within Java and
+also using YAML-based blueprints.
 
-- `./start.sh launch --single` will launch a single app-server instance
-- `./start.sh launch --cluster` will launch a cluster of app-servers
+A strongly recommended way is to write a YAML test blueprint using the test 
framework, and making  
+this available to anyone who will use your entity. This will allow users to 
easily run the test
+blueprint in their own environment (simply by deploying it to their own 
Brooklyn server) to confirm 
+that the entity is working as expected. An example is contained within the 
project at 
+`src/test/resources/sample-test.yaml`.

http://git-wip-us.apache.org/repos/asf/brooklyn-docs/blob/44e812ba/guide/java/common-usage.md
----------------------------------------------------------------------
diff --git a/guide/java/common-usage.md b/guide/java/common-usage.md
index 8f0ed32..d0f7ec5 100644
--- a/guide/java/common-usage.md
+++ b/guide/java/common-usage.md
@@ -7,134 +7,197 @@ layout: website-normal
 
 ### Entity Class Hierarchy
 
-By convention in Brooklyn the following words have a particular meaning, both 
as types (which extend ``Group``, which extends ``Entity``) and when used as 
words in other entities (such as ``TomcatFabric``):
+By convention in Brooklyn the following words have a particular meaning:
 
-- *Cluster* - a homogeneous collection of entities
-- *Fabric* - a multi-location collection of entities, with one per location; 
often used with a cluster per location
-- *Stack* - heterogeneous (mixed types of children)
-- *Application* - user's entry point
+* *Group* - a homogeneous grouping of entities (which need not all be managed 
by the same parent 
+  entity)
+* *Cluster* - a homogeneous collection of entities (all managed by the 
"cluster" entity)
+* *Fabric* - a multi-location collection of entities, with one per location; 
often used with a cluster per location
+* *Application* - a top-level entity, which can have one or more child 
entities.
 
-<!---
-TODO
--->
+The following constructs are often used for Java entities:
 
-- *entity spec* defines an entity, so that one or more such entities can be 
created; often used by clusters/groups to define how to instantiate new 
children.
-- *entity factories* are often used by clusters/groups to define how to 
instantiate new children.
-- *traits* (mixins) providing certain capabilities, such as Resizable and 
Balanceable
-- *Resizable* entities can re-sized dynamically, to increase/decrease the 
number of child entities.
-- *Movable* entities can be migrated between *balanceable containers*.
-- *Balanceable containers* can contain *movable* entities, where each 
contained entity is normally associated with
-    a piece of work within that container.
+* *entity spec* defines an entity to be created; used to define a child 
entity, or often to 
+  define the type of entity in a cluster.
+* *traits* (mixins) providing certain capabilities, such as *Resizable* and 
*Startable*.
+* *Resizable* entities can re-sized dynamically, to increase/decrease the 
number of child entities.
+  For example, scaling up or down a cluster. It could similarly be used to 
vertically scale a VM,
+  or to resize a disk.
+* *Startable* indicates the effector to be executed on initial deployment 
(`start()`) and on 
+  tear down (`stop()`).
 
-### Off-the-Shelf Entities
 
-brooklyn includes a selection of entities already available for use in 
applications,
-including appropriate sensors and effectors, and in some cases include Cluster 
and Fabric variants.
-(These are also useful as templates for writing new entities.)
- 
-These include:
+### Configuration
 
-- **Web**: Tomcat, JBoss, Jetty (external), Play (external); nginx; GeoScaling
-- **Data**: MySQL, Redis, MongoDB, Infinispan, GemFire (external)
-- **Containers**: Karaf
-- **Messaging**: ActiveMQ, Qpid, Rabbit MQ
-- **PaaS**: Cloud Foundry, Stackato; OpenShift
+Configuration keys are typically defined as static named fields on the Entity 
interface. These
+define the configuration values that can be passed to the entity during 
construction. For
+example:
 
+{% highlight java %}
+public static final ConfigKey<String> ROOT_WAR = new 
ConfigKeys.newStringConfigKey(
+        "wars.root",
+        "WAR file to deploy as the ROOT, as URL (supporting file: and 
classpath: prefixes)");
+{% endhighlight %}
 
-### Sensors
+One can optional define a `@SetFromFlag("war")`. This defines a short-hand for 
configuring the
+entity. However, it should be used with caution - the long form defined in the 
constructor should
+be meaningful and sufficient. Its use may be deprecated in a future release.
 
-Sensors are typically defined as static named fields on the Entity subclass. 
These define the channels of events and activity that interested parties can 
track remotely. For example:
-{% highlight java %}
-/** a sensor for saying hi (illustrative), carrying a String value 
-    which is typically the name of the person to whom we are saying hi */
-public static final Sensor<String> HELLO_SENSOR = ...
+The type `AttributeSensorAndConfigKey<?>` can be used to indicate that a 
config key should be resolved,
+and its value set as a sensor on the entity (when 
`ConfigToAttributes.apply(entity)` is called).
+
+A special case of this is `PortAttributeSensorAndConfigKey`. This is resolved 
to find an available 
+port (by querying the target location). For example, the value `8081+` means 
that then next available
+port starting from 8081 will be used.
+
+
+### Declaring Sensors
+
+Sensors are typically defined as static named fields on the Entity interface. 
These define 
+the events published by the entity, which interested parties can subscribe to. 
For example:
 
+{% highlight java %}
+AttributeSensor<String> MANAGEMENT_URL = Sensors.newStringSensor(
+        "crate.managementUri",
+        "The address at which the Crate server listens");
 {% endhighlight %}
 
-If the entity is local (e.g. to a policy) these can be looked up using 
``get(Sensor)``. If it may be remote, you can subscribe to it through various 
APIs.
 
-Sensors are used by operators and policies to monitor health and know when to 
invoke the effectors. The sensor data forms a nested map (i.e. JSON), which can 
be subscribed to through the ``ManagementContext``.
+### Declaring Effectors
 
-Often ``Policy`` instances will subscribe to sensor events on their associated 
entity or its children; these events might be an ``AttributeValueEvent`` – an 
attribute value being reported on change or periodically – or something 
transient such as ``LogMessage`` or a custom ``Event`` such as "TOO_HOT".
+Effectors are the operations that an entity supports. There are multiple ways 
that an entity can 
+be defined. Examples of each are given below.
 
-<!---
-TODO check classes above; is this much detail needed here?
--->
+#### Effector Annotation
+
+A method on the entity interface can be annotated to indicate it is an 
effector, and to provide
+metadata about the effector and its parameters.
+
+{% highlight java %}
+@org.apache.brooklyn.core.annotation.Effector(description="Retrieve a Gist")
+public String getGist(@EffectorParam(name="id", description="Gist id") String 
id);
+{% endhighlight %}
 
-Sensor values form a map-of-maps. An example of some simple sensor information 
is shown below in JSON:
-        
-    {
-      config : {
-        url : "jdbc:mysql://ec2-50-17-19-65.compute-1.amazonaws.com:3306/mysql"
-        status : "running"
-      }
-      workrate : {
-        msgsPerSec : 432
-      }
-    }
 
-Sensor values are defined as statics, which can be used to programmatically 
drive the subscription.
+#### Static Field Effector Declaration
 
-A range of `Feed` instances are available to simplify reading sensor 
information.
+A static field can be defined on the entity to define an effector, giving 
metadata about that effector.
+
+{% highlight java %}
+public static final Effector<String> EXECUTE_SCRIPT = 
Effectors.effector(String.class, "executeScript")
+        .description("invokes a script")
+        .parameter(ExecuteScriptEffectorBody.SCRIPT)
+        .impl(new ExecuteScriptEffectorBody())
+        .build();
+{% endhighlight %}
+
+In this example, the implementation of the effector is an instance of 
`ExecuteScriptEffectorBody`. 
+This implements `EffectorBody`. It will be invoked whenever the effector is 
called.
 
 
-### Effectors
+#### Dynamically Added Effectors
 
-Like sensors and config info, effectors are also static fields on the Entity 
class. These describe actions available on the entity, similar to methods. 
Their implementation includes details of how to invoke them, typically this is 
done by calling a method on the entity. Effectors are typically defined as 
follows:
+An effector can be added to an entity dynamically - either as part of the 
entity's `init()`
+or as separate initialization code. This allows the implementation of the 
effector to be shared
+amongst multiple entities, without sub-classing. For example:
 
 {% highlight java %}
-/** an effector which returns no value,
-    but which causes the entity to emit a HELLO sensor event */
-public static Effector<Void> SAY_HI = ...
+Effector<Void> GET_GIST = Effectors.effector(Void.class, "createGist")
+        .description("Create a Gist")
+        .parameter(String.class, "id", "Gist id")
+        .buildAbstract();
+
+public static void CreateGistEffectorBody implements EffectorBody<Void>() {
+    @Override
+    public Void call(ConfigBag parameters) {
+        // impl
+        return null;
+    }
+}
 
+@Override
+public void init() {
+    getMutableEntityType().addEffector(CREATE_GIST, new 
CreateGistEffectorBody());
+}
 {% endhighlight %}
 
-Effectors are invoked by calling ``invoke(SAY_HI, name:"Bob")`` or similar. 
The method may take an entity if context is not clear, and it takes parameters 
as named parameters or a Map.
 
-Invocation returns a ``Task`` object (extending ``Future``). This allows the 
caller to understand progress and errors on the task, as well as ``Task.get()`` 
the return value. Be aware that ``task.get()`` is a blocking function that will 
wait until a value is available before returning.
+### Effector Invocation
+
+There are several ways to invoke an effector programmatically:
+
+* Where there is an annotated method, simply call the method on the interface.
 
-The management framework ensures that execution occurs on the machine where 
the ``Entity`` is mastered, with progress, result, and/or any errors reported 
back to the caller. It does this through the ``ExecutionManager`` which, where 
necessary, creates proxy ``Task`` instances. The ``ExecutionManager`` 
associates ``Tasks`` with the corresponding ``Entity`` so that these can be 
tracked externally (and relocated if the Entity is remastered to a different 
location).
+* Call the `invoke` method on the entity, using the static effector 
declaration. For example:  
+  `entity.invoke(CREATE_GIST, ImmutableMap.of("id", id));`.
 
-It is worth noting that where a method corresponds to an effector, direct 
invocation of that method on an ``Entity`` will implicitly generate the 
``Task`` object as though the effector had been invoked. For example, invoking 
``Cluster.resize(int)``, where ``resize`` provides an ``Effector RESIZE``, will 
generate a ``Task`` which can be observed remotely.
+* Call the utility method 
`org.apache.brooklyn.core.entity.Entities.invokeEffector`. For example:  
+  `Entities.invokeEffector(this, targetEntity, CREATE_GIST, 
ImmutableMap.of("id", id));`.
 
+When an effector is invoked, the call is intercepted to wrap it in a task. In 
this way, the 
+effector invocation is tracked - it is shown in the Activity view.
 
-### Tasks and the Execution Manager
+When `invoke` or `invokeEffector` is used, the call returns a `Task` object 
(which extends 
+`Future`). This allows the caller to understand progress and errors on the 
task, as well as 
+calling `task.get()` to retrieve the return value. Be aware that `task.get()` 
is a blocking 
+function that will wait until a value is available before returning.
 
-The ``ExecutionManager`` is responsible for tracking simultaneous executing 
tasks and associating these with given **tags**.
-Arbitrary tasks can be run by calling ``Task submit(Runnable)`` (similarly to 
the standard ``Executor``, although it also supports ``Callable`` arguments 
including Groovy closures, and can even be passed ``Task`` instances which have 
not been started). ``submit`` also accepts a few other named parameters, 
including ``description``, which allow additional metadata to be kept on the 
``Task``. The main benefit then is to have rich metadata for executing tasks, 
which can be inspected through methods on the ``Task`` interface.
 
-By using the ``tag`` or ``tags`` named parameters on ``submit`` (or setting 
``tags`` in a ``Task`` that is submitted), execution can be associated with 
various categories. This allows easy viewing can be examined by calling
-``ExecutionManager.getTasksWithTag(...)``.
+### Tasks
 
-The following example uses Groovy, with time delays abused for readability. 
brooklyn's test cases check this using mutexes, which is recommended.
-    
-    ExecutionManager em = []
-    em.submit(tag:"a", description:"One Mississippi", { Thread.sleep(1000) })
-    em.submit(tags:["a","b"], description:"Two Mississippi", { 
Thread.sleep(1000) })
-    assert em.getTasksWithTag("a").size()==2
-    assert em.getTasksWithTag("a").every { Task t -> !t.isDone() }
-    Thread.sleep(1500)
-    assert em.getTasksWithTag("a").size()==2
-    assert em.getTasksWithTag("a").every { Task t -> t.isDone() }
+_Warning: the task API may be changed in a future release. However, backwards 
compatibility
+will be maintained where possible._
 
-It is possible to define `ParallelTask` and sequential `Task` instancess 
-and to specify inter-task relationships with `TaskPreprocessor` instances. 
-This allows building quite sophisticated workflows relatively easily.
+When implementing entities and policies, all work done within Brooklyn is 
executed as Tasks.
+This makes it trackable and visible to administrators. For the activity list 
to show a break-down 
+of an effector's work (in real-time, and also after completion), tasks and 
sub-tasks must be 
+created.
+
+In common situations, tasks are implicitly created and executed. For example, 
when implementing
+an effector using the `@Effector` annotation on a method, the method 
invocation is automatically
+wrapped as a task. Similarly, when a subscription is passed an event (e.g. 
when using 
+`SensorEventListener.onEvent(SensorEvent<T> event)`, that call is done inside 
a task.
+
+Within a task, it is possible to create and execute sub-tasks. A common way to 
do this is to 
+use `DynamicTasks.queue`. If called from within a a "task queuing context" 
(e.g. from inside an
+effector implementation), it will add the task to be executed. By default, the 
outer task will not be
+marked as done until its queued sub-tasks are complete.
+
+When creating tasks, the `TaskBuilder` can be used to create simple tasks or 
to create compound tasks
+whose sub-tasks are to be executed either sequentially or in parallel. For 
example:
+
+{% highlight java %}
+TaskBuilder.<Integer>builder()
+        .displayName("stdout-example")
+        .body(new Callable<Integer>() { public Integer call() { 
System.out.println("example"; } })
+        .build();
+{% endhighlight %}
 
-Continuing the example above, submitting a `SequentialTask` 
-or specifying ``em.setTaskPreprocessorForTag("a", 
SingleThreadedExecution.class)`` 
-will cause ``Two Mississippi`` to run after ``One Mississippi`` completes.
+There are also builder and factory utilities for common types of operation, 
such as executing SSH 
+commands using `SshTasks`.
 
-It is also possible to register `ScheduledTask` instances which run 
periodically.
+A lower level way to submit tasks within an entity is to call 
`getExecutionContext().submit(...)`.
+This automatically tags the task to indicate that its context is the given 
entity.
 
-**The `Tasks` factory supplies a number of conveniences including builders to 
make working with tasks easier
-and should be the entry point in most cases.**
+An even lower level way to execute tasks (to be ignored except for 
power-users) is to go straight  
+to the `getManagementContext().getExecutionManager().submit(...)`. This is 
similar to the standard
+Java `Executor`, but also supports more metadata about tasks such as 
descriptions and tags.
+It also supports querying for tasks. There is also support for submitting 
`ScheduledTask` 
+instances which run periodically.
 
+The `Tasks` and `BrooklynTaskTags` classes supply a number of conveniences 
including builders to 
+make working with tasks easier.
 
 
 ### Subscriptions and the Subscription Manager
 
-In addition to scheduled tasks, tasks can triggered by subscriptions on other 
events including sensors.
+Entities, locations, policies and enrichers can subscribe to events. These 
events could be
+attribute-change events from other entities, or other events explicitly 
published by the entities.
 
-To register low-level listeners to events, use the `SubscriptionManager` API.
+A subscription is created by calling `subscriptions().subscribe(entity, 
sensorType, sensorEventListener)`.
+The `sensorEventListener` will be called with the event whenever the given 
entity emits a sensor of
+the given type. If `null` is used for either the entity or sensor type, this 
is treated as a 
+wildcard.
 
+It is very common for a policy or enricher to subscribe to events, to kick off 
actions or to 
+publish other aggregated attributes or events. 

http://git-wip-us.apache.org/repos/asf/brooklyn-docs/blob/44e812ba/guide/java/defining-and-deploying.md
----------------------------------------------------------------------
diff --git a/guide/java/defining-and-deploying.md 
b/guide/java/defining-and-deploying.md
index 59c0947..fda711b 100644
--- a/guide/java/defining-and-deploying.md
+++ b/guide/java/defining-and-deploying.md
@@ -5,121 +5,171 @@ layout: website-normal
 
 ## Intro
 
-This walkthrough will set up a sample application which you can use as 
foundation for creating your own applications.
+This walkthrough will set up a simple entity, add it to the catalog, and 
provision it.
 
-The sample application is a three tier web service, composed of:
+For illustration purposes, we will write an integration with [Github 
Gist](https://gist.github.com/), 
+with an effector to create new gists.
 
-* an Nginx load-balancer
-* a cluster of JBoss appservers
-* a MySQL database
 
-## Define your Application Blueprint
+## Project Setup
 
-An application blueprint is defined as a Java class, as follows:
+Follow the instructions to create a new Java project using the 
[archetype](archetype.html), 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`.
+
+
+## Java Entity Classes
+
+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](https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html)
 
+for more details):
+
+{% highlight xml %}
+<dependency>
+  <groupId>org.eclipse.mylyn.github</groupId>
+  <artifactId>org.eclipse.egit.github.core</artifactId>
+  <version>2.1.5</version>
+</dependency>
+{% 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 %}
-public class ClusterWebServerDatabaseSample extends AbstractApplication {
-    @Override
-    public void init() {
-        MySqlNode mysql = addChild(EntitySpec.create(MySqlNode.class));
-        ControlledDynamicWebAppCluster web = 
addChild(EntitySpec.create(ControlledDynamicWebAppCluster.class));
-    }
-}
+{% readj gist_generator/GistGenerator.java %}
 {% endhighlight %}
 
-The file `ClusterWebServerDatabaseSample.java` in 
`src/main/java/com/acme/sample/brooklyn/sample/app/` 
-provides a template to follow.
+To describe each part of this:
 
+* The `@ImplementedBy` indicates the implementation class for this entity type 
- i.e. the class 
+  to instantiate when an entity of this type is created.
+* By extending `Entity`, we indicate that this interface is an Entity type. We 
could alternatively
+  have extended one of the other sub-types of Entity.
+* The `OAUTH_KEY` is a configuration key - it is configuration that can be set 
on the entity when 
+  it is being instantiated.
+* The `@Effector` annotation indicates the 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.
+* The `@EffectorParam` annotations give metadata about the effector's 
parameters. These will be  
+  presented in users of the entity, e.g. when invoking the effector via the 
web-console.
 
-## Deploying the Application
+Note there is an alternative way of defining effectors - adding them to the 
entity dynamically, 
+discussed in the section [Dynamic Effectors](dynamic_effectors.html).
 
-If you have not already done so, follow the instructions 
-[here]({{site.path.guide}}/ops/locations/) to create a `brooklyn.properties` 
-file containing credentials for your preferred cloud provider. 
+Next lets add the implementation. Create a new Java class named 
`GistGeneratorImpl`.
 
-To launch this application, build the project and run the `start.sh` script in 
the resulting assembly:
+{% highlight java %}
+{% readj gist_generator/GistGeneratorImpl.java %}
+{% endhighlight %}
 
-{% highlight bash %}
-$ mvn clean assembly:assembly
+To describe each part of this:
 
-$ cd target/brooklyn-sample-0.1.0-SNAPSHOT-dist/brooklyn-sample-0.1.0-SNAPSHOT/
+* Extends `AbstractEntity` - all entity implementations should extend this, or 
one of its 
+  sub-types.
+* Implements `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](https://docs.oracle.com/javase/7/docs/api/java/lang/reflect/Proxy.html) 
+  is used (to allow remoting).
+* `org.slf4j.Logger` is the logger used throughout Apache Brooklyn.
+* Implements the `createGist` effector - we do not need to re-declare all the 
annotations.
+* If no `oath.key` parameter was passed in, then use the configuration set on 
the entity.
+* Use the third party library to create the gist.
 
-$ ./start.sh launch \
-    --app com.acme.sample.brooklyn.sample.app.ClusterWebServerDatabaseSample \
-    --location jclouds:aws-ec2:eu-west-1
-{% endhighlight %}
 
-(Amazon is used in this walkthrough, but lots of targets are supported,
-including `--location localhost`, fixed IP addresses, and 
-everything supported by [jclouds](http://jclouds.org), from OpenStack to 
Google Compute.)
+### Configuring GitHub
+
+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](https://help.github.com/articles/creating-an-access-token-for-command-line-use/)
 
+that our blueprint will use to create a gist:
 
-Your console will inform you that it has started a Brooklyn console at 
[http://localhost:8081](http://localhost:8081)
+[![Create a new access key.](gist_generator/gist_create_token.png "Create a 
new access key")](gist_generator/gist_create_token.png)
 
-[![Web Console]({{ page.url_basedir }}wt-starting-700.png "Web 
Console")](wt-starting.png) 
+Next, grant the token rights to create gists:
 
-The management console provides a view on to the entities that launched,
-including the hierarchy (appservers grouped into a cluster) and their 
locations. 
+[![Grant access.](gist_generator/gist_grant_access.png "Grant 
access")](gist_generator/gist_grant_access.png)
 
-Brooklyn collects information from these entities ("sensors"), 
-aggregates these for clusters and other groups (using "enrichers"),
-and exposes operations ("effectors") that can be performed on entities.
 
-[![Web Console Details]({{ page.url_basedir }}wt-tree-jboss-sensors-700.png 
"Web Console Details")](wt-tree-jboss-sensors.png) 
+### Testing
 
-## What Next?
- 
-In addition to the sample project created by the archetype, with its README and
-`assembly` build, you can find additional code related to this example 
included with Brooklyn as the ``simple-web-cluster`` example.
-{% comment %}
-described [in detail here]({{site.path.guide}}/use/examples/webcluster).
-{% endcomment %}
+The archetype project comes with example unit tests that demonstrate how to 
test entities, 
+both within Java and also using YAML-based blueprints. 
 
-For your applications, you might want to mix in other data stores, messaging 
systems, or on-line services including PaaS.
-Brooklyn supports some of these out-of-the-box, including a wide-range of 
tools which it can use Whirr to provision, such as Hadoop.
-But if you have something you don't see, 
-[let us know]({{site.path.website}}/community/) -- 
-we want to work with you to 
-[write a new entity]({{site.path.guide}}/java/entity.html) or
-[policy]({{site.path.guide}}/java/policy.html) 
-and [contribute it]({{site.path.website}}/developers/how-to-contribute.html).
+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 %}
 
-Alternatively you can just add a ``main`` method to the application class as 
follows:
+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 %}
-    public static void main(String[] argv) {
-        List<String> args = Lists.newArrayList(argv);
-        String port =  CommandLineUtil.getCommandLineOption(args, "--port", 
"8081+");
-        String location = CommandLineUtil.getCommandLineOption(args, 
"--location", DEFAULT_LOCATION);
-
-        BrooklynServerDetails server = BrooklynLauncher.newLauncher()
-                .webconsolePort(port)
-                .launch();
-
-        Location loc = 
server.getManagementContext().getLocationRegistry().resolve(location);
-
-        StartableApplication app = new WebClusterDatabaseExample()
-                .appDisplayName("Brooklyn WebApp Cluster with Database 
example")
-                .manage(server.getManagementContext());
-        
-        app.start(ImmutableList.of(loc));
-        
-        Entities.dumpInfo(app);
-    }
+{% readj gist_generator/GistGeneratorYamlTest.java %}
 {% endhighlight %}
 
-Compile and run this with the [``brooklyn-all`` 
jar]({{site.path.guide}}/start/download.html) on the classpath,
-pointing at your favourite WAR on your filesystem. 
-(If the ``import`` packages aren't picked up correctly,
-you can cheat by looking at [the file in 
Github](https://github.com/apache/brooklyn-library/blob/master/examples/simple-web-cluster/src/main/java/org/apache/brooklyn/demo/WebClusterDatabaseExample.java);
-and you'll find a sample WAR which uses the database as configured above 
-[here](http://search.maven.org/remotecontent?filepath=org/apache/brooklyn/example/brooklyn-example-hello-world-sql-webapp/0.8.0-incubating/brooklyn-example-hello-world-sql-webapp-0.8.0-incubating.war).)
- TODO example webapp url 
- 
-If you want to adventure beyond ``localhost`` (the default),
-simply supply the your favourite cloud (e.g. ``aws-ec2:eu-west-1``)
-with credentials set up as described [here]({{ site.path.guide 
}}/use/guide/management/index.html#startup-config).
-
--->
+
+## Building the OSGi Bundle
+
+We will build this as an [OSGi 
Bundle](https://www.osgi.org/developer/architecture/) 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](http://felix.apache.org/documentation/subprojects/apache-felix-maven-bundle-plugin-bnd.html)
+which we get automatically by declaring the `pom.xml`'s parent as 
`brooklyn-downstream-parent`.
+
+
+## Adding to the catalog
+
+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.
+
+    curl -u admin:pa55w0rd https://127.0.0.1:8443/v1/catalog --data-binary 
@gist_generator.bom
+
+
+## Using the blueprint
+
+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/).

http://git-wip-us.apache.org/repos/asf/brooklyn-docs/blob/44e812ba/guide/java/entity.md
----------------------------------------------------------------------
diff --git a/guide/java/entity.md b/guide/java/entity.md
index ec06347..d3ed881 100644
--- a/guide/java/entity.md
+++ b/guide/java/entity.md
@@ -7,10 +7,23 @@ title: Writing an Entity
 
 There are several ways to write a new entity:
 
-* Write pure-java, extending existing base-classes and using utilities such as 
`HttpTool` and `BashCommands`.
-* Write scripts, and configure (e.g. using YAML) a 
**`VanillaSoftwareProcess`**.
-* Use Chef recipes, and wire these into the entity by using `ChefConfig` and 
`ChefLifecycleEffectorTasks`.
-* Use an equivalent of Chef (e.g. Salt or Puppet; support for these is 
currently less mature than for Chef)
+* For Unix/Linux, write YAML blueprints, for example using a 
**`VanillaSoftwareProcess`** and 
+  configuring it with your scripts.
+* For Windows, write YAML blueprints using **`VanillaWindowsProcess`** and 
configure the PowerShell
+  scripts.
+* For composite entities, use YAML to compose exiting types of entities 
(potentially overwriting
+  parts of their configuration), and wire them together.
+* Use **[Chef recipes]({{site.path.guide}}/yaml/chef)**.
+* Use **[Salt formulas]({{site.path.guide}}/yaml/salt)**.
+* Use **[Ansible playbooks]({{site.path.guide}}/yaml/ansible)**.
+* Write pure-java, extending existing base-classes. For example, the 
`GistGenerator` 
+  [example](defining-and-deploying.html). These can use utilities such as 
`HttpTool` and 
+  `BashCommands`.
+* Write pure-Java blueprints that extend `SoftwareProcess`. However, the YAML 
approach is strongly
+  recommended over this approach.
+* Write pure-Java blueprints that compose together existing entities, for 
example to manage
+  a cluster. Often this is possible in YAML and that approach is strongly 
recommended. However,
+  sometimes the management logic may be so complex that it is easier to use 
Java.
 
 The rest of this section covers writing an entity in pure-java (or other JVM 
languages).
 
@@ -24,8 +37,7 @@ Entities are created through the management context (rather 
than calling the
 constructor directly). This returns a proxy for the entity rather than the 
real 
 instance, which is important in a distributed management plane.
 
-All entity implementations inherit from `AbstractEntity`, 
-often through one of the following:
+All entity implementations inherit from `AbstractEntity`, often through one of 
the following:
 
 * **`SoftwareProcessImpl`**:  if it's a software process
 * **`VanillaJavaAppImpl`**:  if it's a plain-old-java app
@@ -48,6 +60,8 @@ Choose one (or more) as appropriate.
 
 ## Key Steps
 
+*NOTE: Consider instead writing a YAML blueprint for your entity.*
+
 So to get started:
 
 1. Create your entity interface, extending the appropriate selection from 
above,

http://git-wip-us.apache.org/repos/asf/brooklyn-docs/blob/44e812ba/guide/java/feeds.md
----------------------------------------------------------------------
diff --git a/guide/java/feeds.md b/guide/java/feeds.md
new file mode 100644
index 0000000..88e005d
--- /dev/null
+++ b/guide/java/feeds.md
@@ -0,0 +1,203 @@
+---
+title: Feeds
+layout: website-normal
+---
+
+<!-- TODO old, needs work (refactoring!) and use of java_link -->
+
+### Feeds
+
+A `Feed` is used to populate an entity's sensors. A variety of feed types are 
available.
+
+
+#### Persistence
+
+There are two ways to associate a feed with an entity. The recommended way is 
(within the
+entity) to call `feeds().addFeed(...)`. This persists the feed: the feed will 
be automatically
+added to the entity when the Brooklyn server restarts. It is important that 
all configuration
+of the feed is persistable (e.g. not using any in-line anonymous inner classes 
to define
+functions).
+
+The feed builders can be passed a `uniqueTag(...)`, which will be used to 
ensure that on
+rebind there will not be multiple copied of the feed (e.g. if `rebind()` had 
already re-created
+the feed).
+
+The second way is to just pass to the feed's builder the entity. When using 
this mechanism, 
+the feed will be wired up to the entity but it will not be persisted. In this 
case, it is
+important that the entity's `rebind()` method recreates the feed.
+
+
+#### Types of Feed
+
+##### HTTP Feed
+
+An `HttpFeed` polls over http(s). An example is shown below:
+
+{% highlight java %}
+private HttpFeed feed;
+
+//@Override
+protected void connectSensors() {
+  super.connectSensors();
+  
+  feed = feeds().addFeed(HttpFeed.builder()
+      .period(200)
+      
.baseUri(String.format("http://%s:%s/management/subsystem/web/connector/http/read-resource";,
 host, port))
+      .baseUriVars(ImmutableMap.of("include-runtime","true"))
+      .poll(new HttpPollConfig(SERVICE_UP)
+          .onSuccess(HttpValueFunctions.responseCodeEquals(200))
+          .onError(Functions.constant(false)))
+      .poll(new HttpPollConfig(REQUEST_COUNT)
+          .onSuccess(HttpValueFunctions.jsonContents("requestCount", 
Integer.class)))
+      .build());
+}
+
+@Override
+protected void disconnectSensors() {
+  super.disconnectSensors();
+  if (feed != null) feed.stop();
+}
+{% endhighlight %}
+
+
+##### SSH Feed
+
+An SSH feed executes a command over ssh periodically. An example is shown 
below:
+
+{% highlight java %}
+private SshFeed feed;
+
+//@Override
+protected void connectSensors() {
+  super.connectSensors();
+
+  feed = feeds.addFeed(SshFeed.builder()
+      .machine(mySshMachineLachine)
+      .poll(new SshPollConfig(SERVICE_UP)
+          .command("rabbitmqctl -q status")
+          .onSuccess(new Function() {
+              public Boolean apply(SshPollValue input) {
+                return (input.getExitStatus() == 0);
+              }}))
+      .build());
+}
+
+@Override
+protected void disconnectSensors() {
+  super.disconnectSensors();
+  if (feed != null) feed.stop();
+}
+{% endhighlight %}
+
+
+##### Windows Performance Counter Feed
+
+This type of feed retrieves performance counters from a Windows host, and 
posts the values to sensors.
+
+One must supply a collection of mappings between Windows performance counter 
names and Brooklyn 
+attribute sensors.
+
+This feed uses WinRM to invoke the windows utility <tt>typeperf</tt> to query 
for a specific set 
+of performance counters, by name. The values are extracted from the response, 
and published to the
+entity's sensors. An example is shown below:
+
+{% highlight java %}
+private WindowsPerformanceCounterFeed feed;
+
+@Override
+protected void connectSensors() {
+  feed = feeds.addFeed(WindowsPerformanceCounterFeed.builder()
+      .addSensor("\\Processor(_total)\\% Idle Time", CPU_IDLE_TIME)
+      .addSensor("\\Memory\\Available MBytes", AVAILABLE_MEMORY)
+      .build());
+}
+
+@Override
+protected void disconnectSensors() {
+  super.disconnectSensors();
+  if (feed != null) feed.stop();
+}
+{% endhighlight %}
+
+
+##### JMX Feed
+
+This type of feed queries over JMX to retrieve sensor values. This can query 
attribute
+values or call operations.
+
+The JMX connection details can be automatically inferred from the entity's 
standard attributes,
+or it can be explicitly supplied.
+
+An example is shown below:
+
+{% highlight java %}
+private JmxFeed feed;
+
+@Override
+protected void connectSensors() {
+  super.connectSensors();
+
+  feed = feeds().addFeed(JmxFeed.builder()
+      .period(5, TimeUnit.SECONDS)
+      .pollAttribute(new JmxAttributePollConfig<Integer>(ERROR_COUNT)
+          .objectName(requestProcessorMbeanName)
+          .attributeName("errorCount"))
+      .pollAttribute(new JmxAttributePollConfig<Boolean>(SERVICE_UP)
+          .objectName(serverMbeanName)
+          .attributeName("Started")
+          .onError(Functions.constant(false)))
+      .build());
+}
+
+Override
+protected void disconnectSensors() {
+  super.disconnectSensors();
+  if (feed != null) feed.stop();
+}
+{% endhighlight %}
+
+
+
+##### Function Feed
+
+This type of feed periodically executes something to compute the attribute 
values. This 
+can be a `Callable`, `Supplier` or Groovy `Closure`. It must be persistable 
(e.g. not use 
+an in-line anonymous inner classes).
+
+An example is shown below:
+
+{% highlight java %}
+public static class ErrorCountRetriever implements Callable<Integer> {
+  private final Entity entity;
+  
+  public ErrorCountRetriever(Entity entity) {
+    this.entity = entity;
+  }
+  
+  @Override
+  public Integer call() throws Exception {
+    // TODO your implementation...
+    return 0;
+  }
+}
+
+private FunctionFeed feed;
+
+@Override
+protected void connectSensors() {
+  super.connectSensors();
+
+  feed = feeds().addFeed(FunctionFeed.builder()
+    .poll(new FunctionPollConfig<Object, Integer>(ERROR_COUNT)
+        .period(500, TimeUnit.MILLISECONDS)
+        .callable(new ErrorCountRetriever(this))
+        .onExceptionOrFailure(Functions.<Integer>constant(null))
+    .build());
+}
+ 
+@Override
+protected void disconnectSensors() {
+  super.disconnectSensors();
+  if (feed != null) feed.stop();
+}
+{% endhighlight %}

http://git-wip-us.apache.org/repos/asf/brooklyn-docs/blob/44e812ba/guide/java/gist_generator/GistGenerator.java
----------------------------------------------------------------------
diff --git a/guide/java/gist_generator/GistGenerator.java 
b/guide/java/gist_generator/GistGenerator.java
new file mode 100644
index 0000000..678d1e0
--- /dev/null
+++ b/guide/java/gist_generator/GistGenerator.java
@@ -0,0 +1,29 @@
+package com.acme;
+
+import java.io.IOException;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.entity.ImplementedBy;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.annotation.Effector;
+import org.apache.brooklyn.core.annotation.EffectorParam;
+import org.apache.brooklyn.core.config.ConfigKeys;
+
+@ImplementedBy(GistGeneratorImpl.class)
+public interface GistGenerator extends Entity {
+
+    ConfigKey<String> OAUTH_KEY = ConfigKeys.newStringConfigKey("oauth.key", 
"OAuth key for creating a gist",
+            "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+
+    @Effector(description="Create a Gist")
+    String createGist(
+            @EffectorParam(name="gistName", description="Gist Name", 
defaultValue="Demo Gist") String gistName,
+            @EffectorParam(name="fileName", description="File Name", 
defaultValue="Hello.java") String fileName,
+            @EffectorParam(name="gistContents", description="Gist Contents", 
defaultValue="System.out.println(\"Hello World\");") String gistContents,
+            @EffectorParam(name="oauth.key", description="OAuth key for 
creating a gist", defaultValue="") String oauthKey) throws IOException;
+
+    @Effector(description="Retrieve a Gist")
+    public String getGist(
+            @EffectorParam(name="id", description="Gist id") String id,
+            @EffectorParam(name="oauth.key", description="OAuth key for 
creating a gist", defaultValue="") String oauthKey) throws IOException;
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/brooklyn-docs/blob/44e812ba/guide/java/gist_generator/GistGeneratorImpl.java
----------------------------------------------------------------------
diff --git a/guide/java/gist_generator/GistGeneratorImpl.java 
b/guide/java/gist_generator/GistGeneratorImpl.java
new file mode 100644
index 0000000..db1ecdb
--- /dev/null
+++ b/guide/java/gist_generator/GistGeneratorImpl.java
@@ -0,0 +1,47 @@
+package com.acme;
+
+import java.io.IOException;
+import java.util.Collections;
+
+import org.apache.brooklyn.core.entity.AbstractEntity;
+import org.apache.brooklyn.util.text.Strings;
+import org.eclipse.egit.github.core.Gist;
+import org.eclipse.egit.github.core.GistFile;
+import org.eclipse.egit.github.core.service.GistService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Iterables;
+
+public class GistGeneratorImpl extends AbstractEntity implements GistGenerator 
{
+
+    private static final Logger LOG = 
LoggerFactory.getLogger(GistGeneratorImpl.class);
+
+    @Override
+    public String createGist(String gistName, String fileName, String 
gistContents, String oathToken) throws IOException {
+        if (Strings.isBlank(oathToken)) oathToken = config().get(OAUTH_KEY);
+
+        GistFile file = new GistFile();
+        file.setContent(gistContents);
+        Gist gist = new Gist();
+        gist.setDescription(gistName);
+        gist.setFiles(Collections.singletonMap(fileName, file));
+        gist.setPublic(true);
+        
+        GistService service = new GistService();
+        service.getClient().setOAuth2Token(oathToken);
+        LOG.info("Creating Gist: " +  gistName);
+        Gist result = service.createGist(gist);
+        return result.getId();
+    }
+    
+    @Override
+    public String getGist(String id, String oathToken) throws IOException {
+        if (Strings.isBlank(oathToken)) oathToken = config().get(OAUTH_KEY);
+
+        GistService service = new GistService();
+        service.getClient().setOAuth2Token(oathToken);
+        Gist gist = service.getGist(id);
+        return Iterables.getOnlyElement(gist.getFiles().values()).getContent();
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/brooklyn-docs/blob/44e812ba/guide/java/gist_generator/GistGeneratorTest.java
----------------------------------------------------------------------
diff --git a/guide/java/gist_generator/GistGeneratorTest.java 
b/guide/java/gist_generator/GistGeneratorTest.java
new file mode 100644
index 0000000..9f5cc1a
--- /dev/null
+++ b/guide/java/gist_generator/GistGeneratorTest.java
@@ -0,0 +1,20 @@
+package com.acme;
+
+import static org.testng.Assert.assertEquals;
+
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
+import org.testng.annotations.Test;
+
+public class GistGeneratorTest extends BrooklynAppUnitTestSupport {
+
+    @Test
+    public void testEntity() throws Exception {
+        String oathKey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
+        GistGenerator entity = 
app.createAndManageChild(EntitySpec.create(GistGenerator.class));
+        String id = entity.createGist("myGistName", "myFileName", 
"myGistContents", oathKey);
+        
+        String contents = entity.getGist(id, oathKey);
+        assertEquals(contents, "myGistContents");
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/brooklyn-docs/blob/44e812ba/guide/java/gist_generator/GistGeneratorYamlTest.java
----------------------------------------------------------------------
diff --git a/guide/java/gist_generator/GistGeneratorYamlTest.java 
b/guide/java/gist_generator/GistGeneratorYamlTest.java
new file mode 100644
index 0000000..2051993
--- /dev/null
+++ b/guide/java/gist_generator/GistGeneratorYamlTest.java
@@ -0,0 +1,39 @@
+package com.acme;
+
+import static org.testng.Assert.assertEquals;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.camp.brooklyn.AbstractYamlTest;
+import org.apache.brooklyn.core.entity.Entities;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.Iterables;
+
+public class GistGeneratorYamlTest extends AbstractYamlTest {
+
+    private String contents;
+
+    @Test
+    public void testEntity() throws Exception {
+        String oathKey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
+        
+        String yaml = Joiner.on("\n").join(
+            "name: my test",
+            "services:",
+            "- type: com.acme.GistGenerator",
+            "  brooklyn.config:",
+            "    oauth.key: "+oathKey);
+        
+        Entity app = createAndStartApplication(yaml);
+        waitForApplicationTasks(app);
+
+        Entities.dumpInfo(app);
+
+        GistGenerator entity = (GistGenerator) 
Iterables.getOnlyElement(app.getChildren());
+        String id = entity.createGist("myGistName", "myFileName", 
"myGistContents", null);
+        
+        contents = entity.getGist(id, null);
+        assertEquals(contents, "myGistContents");
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/brooklyn-docs/blob/44e812ba/guide/java/gist_generator/gist_create_token.png
----------------------------------------------------------------------
diff --git a/guide/java/gist_generator/gist_create_token.png 
b/guide/java/gist_generator/gist_create_token.png
new file mode 100644
index 0000000..2a9f621
Binary files /dev/null and b/guide/java/gist_generator/gist_create_token.png 
differ

http://git-wip-us.apache.org/repos/asf/brooklyn-docs/blob/44e812ba/guide/java/gist_generator/gist_generator.bom
----------------------------------------------------------------------
diff --git a/guide/java/gist_generator/gist_generator.bom 
b/guide/java/gist_generator/gist_generator.bom
new file mode 100644
index 0000000..5be6b50
--- /dev/null
+++ b/guide/java/gist_generator/gist_generator.bom
@@ -0,0 +1,15 @@
+brooklyn.catalog:
+  id: example.GistGenerator
+  version: 1.0
+  description: For programmatically generating GitHub Gists
+  displayName: Gist Generator
+  iconUrl: classpath:///sample-icon.png
+  itemType: template
+  libraries:
+  - 
http://search.maven.org/remotecontent?filepath=com/google/code/gson/gson/2.2.2/gson-2.2.2.jar
+  - 
http:/.developers.cloudsoftcorp.com/brooklyn/guide/java/gist_generator/org.eclipse.egit.github.core-2.1.5.jar
+  - 
http://developers.cloudsoftcorp.com/brooklyn/guide/java/gist_generator/autobrick-0.1.0-SNAPSHOT.jar
+
+  item:
+    services:
+    - type: com.acme.GistGenerator

http://git-wip-us.apache.org/repos/asf/brooklyn-docs/blob/44e812ba/guide/java/gist_generator/gist_grant_access.png
----------------------------------------------------------------------
diff --git a/guide/java/gist_generator/gist_grant_access.png 
b/guide/java/gist_generator/gist_grant_access.png
new file mode 100644
index 0000000..48cc669
Binary files /dev/null and b/guide/java/gist_generator/gist_grant_access.png 
differ

http://git-wip-us.apache.org/repos/asf/brooklyn-docs/blob/44e812ba/guide/java/index.md
----------------------------------------------------------------------
diff --git a/guide/java/index.md b/guide/java/index.md
index e2b7984..0dce159 100644
--- a/guide/java/index.md
+++ b/guide/java/index.md
@@ -6,8 +6,9 @@ started-pdf-exclude: true
 children:
 - archetype.md
 - defining-and-deploying.md
-- topology-dependencies-management-policies.md
+- topology-dependencies.md
 - common-usage.md
+- feeds.md
 - entity.md
 - entities.md
 - policies.md
@@ -16,9 +17,21 @@ children:
 - entitlements.md
 ---
 
-Java blueprints are much more powerful than YAML but is also rather more 
difficult.
+Java blueprints are powerful, but also rather more difficult to write than 
YAML.
 Advanced Java skills are required.
 
 {% include list-children.html %}
 
-Brooklyn makes it easy to describe the structure and management of 
sophisticated distributed applications, and then it makes it easy to launch 
them in a cloud, with on-going automated management.
+The main uses of Java-based blueprints are:
+
+* Integration with a service's API (e.g. for an on-line DNS service). This 
could take advantage of 
+  existing Java-based clients, or of Java's flexibility to chain together 
multiple calls.
+* Complex management logic, for example when the best practices for 
adding/removing nodes from a 
+  cluster is fiddly and has many conditionals.
+* Where the developer has a strong preference for Java. Anything that can be 
done in YAML can be done in 
+  the Java API. Once the blueprint is added to the catalog, the use of Java 
will be entirely hidden
+  from users of that blueprint.
+
+The Apache Brooklyn community is striving to make YAML-based blueprints as 
simple as possible - 
+if you come across a use-case that is hard to do in YAML then please let the 
community know.
+

http://git-wip-us.apache.org/repos/asf/brooklyn-docs/blob/44e812ba/guide/java/java_app/ExampleWebApp.java
----------------------------------------------------------------------
diff --git a/guide/java/java_app/ExampleWebApp.java 
b/guide/java/java_app/ExampleWebApp.java
new file mode 100644
index 0000000..97b6910
--- /dev/null
+++ b/guide/java/java_app/ExampleWebApp.java
@@ -0,0 +1,30 @@
+package com.acme.autobrick;
+
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.core.entity.AbstractApplication;
+import org.apache.brooklyn.core.sensor.DependentConfiguration;
+import org.apache.brooklyn.entity.database.mysql.MySqlNode;
+import org.apache.brooklyn.entity.group.DynamicCluster;
+import org.apache.brooklyn.entity.proxy.nginx.NginxController;
+import org.apache.brooklyn.entity.webapp.tomcat.TomcatServer;
+
+public class ExampleWebApp extends AbstractApplication {
+
+    @Override
+    public void init() {
+        MySqlNode db = addChild(EntitySpec.create(MySqlNode.class)
+                .configure(MySqlNode.CREATION_SCRIPT_URL, 
"https://bit.ly/brooklyn-visitors-creation-script";));
+
+        DynamicCluster cluster = 
addChild(EntitySpec.create(DynamicCluster.class)
+                .configure(DynamicCluster.MEMBER_SPEC, 
EntitySpec.create(TomcatServer.class)
+                        .configure(TomcatServer.ROOT_WAR, 
+                                "wars.root: 
http://search.maven.org/remotecontent?filepath=org/apache/brooklyn/example/brooklyn-example-hello-world-sql-webapp/0.8.0-incubating/brooklyn-example-hello-world-sql-webapp-0.8.0-incubating.war";)
+                        
.configure(TomcatServer.JAVA_SYSPROPS.subKey("brooklyn.example.db.url"),
+                                
DependentConfiguration.formatString("jdbc:%s%s?user=%s&password=%s",
+                                        
DependentConfiguration.attributeWhenReady(db, MySqlNode.DATASTORE_URL),
+                                        "visitors", "brooklyn", "br00k11n"))));
+        
+        addChild(EntitySpec.create(NginxController.class)
+                .configure(NginxController.SERVER_POOL, cluster));
+    }
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-docs/blob/44e812ba/guide/java/policies.md
----------------------------------------------------------------------
diff --git a/guide/java/policies.md b/guide/java/policies.md
index 4eb50fb..9781d6e 100644
--- a/guide/java/policies.md
+++ b/guide/java/policies.md
@@ -5,14 +5,16 @@ layout: website-normal
 ---
 
 Policies perform the active management enabled by Brooklyn.  
-They can subscribe to entity sensors and be triggered by them or they can run 
periodically.
+They can subscribe to entity sensors and be triggered by them (or they can run 
periodically,
+or be triggered by external systems).
 
 <!---
-TODO, clarify below, memebers of what?
+TODO, clarify below, members of what?
 -->
-Policies can add subscriptions to sensors on any entity. Normally a policy 
will subscribe to its related entity, to the child entities, and/or those 
entities which are members.
+Policies can add subscriptions to sensors on any entity. Normally a policy 
will subscribe to its 
+associated entity, to the child entities, and/or to the members of a "group" 
entity.
 
-When a policy runs it can:
+Common uses of a policy include the following:
 
 *      perform calculations,
 *      look up other values,

http://git-wip-us.apache.org/repos/asf/brooklyn-docs/blob/44e812ba/guide/java/topology-dependencies-management-policies.md
----------------------------------------------------------------------
diff --git a/guide/java/topology-dependencies-management-policies.md 
b/guide/java/topology-dependencies-management-policies.md
deleted file mode 100644
index 249c99a..0000000
--- a/guide/java/topology-dependencies-management-policies.md
+++ /dev/null
@@ -1,69 +0,0 @@
----
-layout: website-normal
-title: Topology, Dependencies, and Management Policies
-title_in_menu: Topology, Dependencies, and Management Policies
---- 
-Of course in the real world, application deployments are more interesting;
-they do things and need configuration.  For instance you might need to:
-
-* specify a WAR file
-* initialize the database
-* tell the webapp servers where to find the database
-
-Let's show how these are done using Brooklyn.
-We assume the WAR file and the database init script are accessible
-on the classpath, but a range of URL formats is supported.
-The "dependent inter-process configuration" -- giving the database's URL
-to the webapps -- we'll do here with a JVM system property,
-but you're free to use any mechanism you wish.
-
-Under the covers, ``attributeWhenReady`` is monitoring a sensor from MySQL
-and generating a string to pass to the webapp software processes; 
``formatString``
-is a similar utility that returns a string once all of its parts have been 
resolved.
-Due to the use of futures, the Brooklyn webapp entities will automatically
-block "at the last moment" when the value is needed
-(but after e.g. the VMs have been provisioned, to speed things up).
-
-{% highlight java %}
-public class ClusterWebServerDatabaseSample extends AbstractApplication {
-    @Override
-    public void init() {
-        MySqlNode mysql = addChild(EntitySpec.create(MySqlNode.class)
-                .configure(MySqlNode.CREATION_SCRIPT_URL, 
"classpath://visitors-database-setup.sql"));
-        
-        ControlledDynamicWebAppCluster web = 
addChild(EntitySpec.create(ControlledDynamicWebAppCluster.class)
-                .configure("memberSpec", EntitySpec.create(JBoss7Server.class)
-                        .configure("httpPort", "8080+")
-                        .configure("war", WAR_PATH)
-                        
.configure(JavaEntityMethods.javaSysProp("brooklyn.example.db.url"), 
-                                
formatString("jdbc:%s%s?user=%s\\&password=%s", 
-                                        attributeWhenReady(mysql, 
MySqlNode.MYSQL_URL), DB_TABLE, DB_USERNAME, DB_PASSWORD))));
-    }
-}
-{% endhighlight %}
-
-We now see our app at the Nginx URL:
-
-[![Our Web App]({{ page.url_basedir }}wt-deployed-application-700.png 
"Screenshot of our Web App")](wt-deployed-application.png) 
-
-Finally, we'll bring in some active management: we're going to monitor 
requests per second,
-and scale out if this exceeds 100 up to a maximum of 5 servers.
-This is a naively simple policy, but it shows Brooklyn's real metier,
-running management policies for applications whose topology it knows. 
-
-{% highlight java %}
-        web.getCluster().addPolicy(AutoScalerPolicy.builder().
-                        
metric(DynamicWebAppCluster.AVERAGE_REQUESTS_PER_SECOND).
-                        sizeRange(1, 5).
-                        metricRange(10, 100).
-                        build());
-{% endhighlight %}
-        
-*Policies* in Brooklyn typically subscribe to sensors,  perform some 
computation, and if necessary invoke effectors on entities.  This is where the 
ability to group entities
-becomes very useful -- policies can be attached to group entities, and groups 
themselves can be hierarchical. It's also handy that often Brooklyn creates the 
entities,
-so it knows what the hierarchy is.
-
-Under the covers, this ``AutoScalerPolicy`` attaches to any ``Resizable`` 
entity (exposing a ``resize`` effector), and monitors a specified sensor (or 
function) attempting to keep it within healthy limits. A separate policy 
operates at the ``Controlled`` cluster to ensure the load-balancer is updated 
as the pool of web servers expands and contracts.
-
-Fire up a JMeter session (or other load testing tool) and blast the Nginx 
address. The auto-scaler policy will scale up the cluster.
-

http://git-wip-us.apache.org/repos/asf/brooklyn-docs/blob/44e812ba/guide/java/topology-dependencies.md
----------------------------------------------------------------------
diff --git a/guide/java/topology-dependencies.md 
b/guide/java/topology-dependencies.md
new file mode 100644
index 0000000..a1b86ca
--- /dev/null
+++ b/guide/java/topology-dependencies.md
@@ -0,0 +1,49 @@
+---
+layout: website-normal
+title: Topology, Dependencies, and Management Policies
+title_in_menu: Topology, Dependencies, and Management Policies
+---
+
+Applications written in YAML can similarly be written in Java. However, the 
YAML approach is 
+recommended.
+
+## Define your Application Blueprint
+
+The example below creates a three tier web service, composed of an Nginx 
load-balancer, 
+a cluster of Tomcat app-servers, and a MySQL database:
+
+{% highlight java %}
+{% readj java_app/ExampleWebApp.java %}
+{% endhighlight %}
+
+To describe each part of this:
+
+* The application extends `AbstractApplication`.
+* It implements `init()`, to add its child entities. The `init` method is 
called only once, when
+  instantiating the entity instance.
+* The `addChild` method takes an `EntitySpec`. This describes the entity to be 
created, defining
+  its type and its configuration.
+* The `brooklyn.example.db.url` is a system property that will be passed to 
each `TomcatServer` 
+  instance. Its value is the database's URL (discussed below).
+* The `NginxController` is the load-balancer and reverse-proxy: by default, it 
round-robins to 
+  the ip:port of each member of the cluster configured as the `SERVER_POOL`.
+  
+
+## Dependent Configuration
+
+Often a component of an application will depend on another component, where 
the dependency
+information is only available at runtime (e.g. it requires the IP of a 
dynamically provisioned
+component). For example, the app-servers in the example above require the 
database URL to be 
+injected.
+
+The "DependentConfiguration" methods returns a return a future (or a "promise" 
in the language of 
+some other programming languages): when the  value is needed, the caller will 
block to wait for  
+the future to resolve. It will block only "at the last moment" when the value 
is needed (e.g. 
+after the VMs have been provisioned and the software is installed, thus 
optimising the 
+provisioning time). It will automatically monitor the given entity's sensor, 
and generate the 
+value when the sensor is populated.
+
+The `attributeWhenReady` is used to generate a configuration value that 
depends on the dynamic 
+sensor value of another entity - in the example above, it will not be 
available until that 
+`MySqlNode.DATASTORE_URL` sensor is populated. At that point, the JDBC URL 
will be constructed 
+(as defined in the `formatString` method, which also returns a future).

Reply via email to