http://git-wip-us.apache.org/repos/asf/incubator-edgent-website/blob/ca854973/content/algolia_search.json
----------------------------------------------------------------------
diff --git a/content/algolia_search.json b/content/algolia_search.json
index 9214db2..3619ed0 100644
--- a/content/algolia_search.json
+++ b/content/algolia_search.json
@@ -52,7 +52,7 @@
 "keywords": "",
 "url": "../docs/console",
 "summary": "",
-"body": "## Visualizing and monitoring your applicationThe Edgent application 
console is a web application that enables you to visualize your application 
topology and monitor the tuples flowing through your application. The kind of 
oplets used in the topology, as well as the stream tags included in the 
topology, are also visible in the console.## Adding the console web app to your 
applicationTo use the console, you must use the Edgent classes that provide the 
service to access the console web application or directly call the `HttpServer` 
class itself, start the server and then obtain the console URL.The easiest way 
to include the console in your application is to use the the 
`DevelopmentProvider` class. `DevelopmentProvider` is a subclass of 
`DirectProvider` and adds services such as access to the console web 
application and counter oplets used to determine tuple counts. You can get the 
URL for the console from the `DevelopmentProvider` using the `getService` 
method as shown in a hy
 pothetical application shown below:```javaimport 
java.util.concurrent.TimeUnit;import 
org.apache.edgent.console.server.HttpServer;import 
org.apache.edgent.providers.development.DevelopmentProvider;import 
org.apache.edgent.topology.TStream;import 
org.apache.edgent.topology.Topology;public class TempSensorApplication {    
public static void main(String[] args) throws Exception {        TempSensor 
sensor = new TempSensor();        DevelopmentProvider dp = new 
DevelopmentProvider();        Topology topology = dp.newTopology();        
TStream tempReadings = topology.poll(sensor, 1, TimeUnit.MILLISECONDS);        
TStream filteredReadings = tempReadings.filter(reading -> reading  80);        
filteredReadings.print();        
System.out.println(dp.getServices().getService(HttpServer.class).getConsoleUrl());
        dp.submit(topology);    }}```Note that the console URL is being printed 
to `System.out`. The `filteredReadings` are as well, since 
`filteredReadings.print()` is being called in the
  application. You may need to scroll your terminal window up to see the output 
for the console URL.Optionally, you can modify the above code in the 
application to have a timeout before submitting the topology, which would allow 
you to see the console URL before any other output is shown. The modification 
would look like this:```java// Print the console URL and wait for 10 seconds 
before submitting the 
topologySystem.out.println(dp.getServices().getService(HttpServer.class).getConsoleUrl());try
 {    TimeUnit.SECONDS.sleep(10);} catch (InterruptedException e) {    // Do 
nothing}dp.submit(topology);```The other way to embed the console in your 
application is shown in the `HttpServerSample.java` example (on [GitHub]({{ 
site.data.project.source_repository_mirror 
}}/blob/master/samples/console/src/main/java/{{ site.data.project.unix_name 
}}/samples/console/HttpServerSample.java)). It gets the `HttpServer` instance, 
starts it, and prints out the console URL. Note that it does not submit a 
 job, so when the console is displayed in the browser, there are no running 
jobs and therefore no topology graph. The example is meant to show how to get 
the `HttpServer` instance, start the console web app and get the URL of the 
console.## Accessing the consoleThe console URL has the following 
format:`http://host_name:port_number/console`Once it is obtained from 
`System.out`, enter it in a browser window.If you cannot access the console at 
this URL, ensure there is a `console.war` file in the `webapps` directory. If 
the `console.war` file cannot be found, an exception will be thrown (in 
`std.out`) indicating `console.war` was not found.## ConsoleWaterDetector 
sampleTo see the features of the console in action and as a way to demonstrate 
how to monitor a topology in the console, let's look at the 
`ConsoleWaterDetector` sample (on [GitHub]({{ 
site.data.project.source_repository_mirror 
}}/blob/master/samples/console/src/main/java/{{ site.data.project.unix_name 
}}/samples/console/Consol
 eWaterDetector.java)).Prior to running any console applications, the 
`console.war` file must be built as mentioned above. If you are building Edgent 
from a Git repository, go to the top level Edgent directory and run `ant`.Here 
is an example in my environment:```Susans-MacBook-Pro-247:edgent susancline$ 
pwd/Users/susancline/git/edgentSusans-MacBook-Pro-247:edgent susancline$ 
antBuildfile: 
/Users/susancline/git/edgent/build.xmlsetcommitversion:init:suball:init:project.component:compile:...[javadoc]
 Constructing Javadoc information...[javadoc] Standard Doclet version 
1.8.0_71[javadoc] Building tree for all the packages and classes...[javadoc] 
Generating 
/Users/susancline/git/edgent/target/docs/javadoc/edgent/analytics/sensors/package-summary.html...[javadoc]
 Copying file 
/Users/susancline/git/edgent/analytics/sensors/src/main/java/edgent/analytics/sensors/doc-files/deadband.png
 to directory 
/Users/susancline/git/edgent/target/docs/javadoc/edgent/analytics/sensors/doc-files...[javadoc]
  Generating 
/Users/susancline/git/edgent/target/docs/javadoc/edgent/topology/package-summary.html...[javadoc]
 Copying file 
/Users/susancline/git/edgent/api/topology/src/main/java/edgent/topology/doc-files/sources.html
 to directory 
/Users/susancline/git/edgent/target/docs/javadoc/edgent/topology/doc-files...[javadoc]
 Building index for all the packages and classes...[javadoc] Building index for 
all classes...all:BUILD SUCCESSFULTotal time: 3 seconds```This command will let 
you know that `console.war` was built and is in the correct place, under the 
`webapps` directory.```Susans-MacBook-Pro-247:edgent susancline$ find . -name 
console.war -print./target/java8/console/webapps/console.war```Now we know we 
have built `console.war`, so we're good to go. To run this sample from the 
command line:```Susans-MacBook-Pro-247:edgent susancline$ 
pwd/Users/susancline/git/edgentSusans-MacBook-Pro-247:edgent susancline$ java 
-cp target/java8/samples/lib/edgent.samples.console.jar:. edgent.samples.con
 sole.ConsoleWaterDetector```If everything is successful, you'll start seeing 
output. You may have to scroll back up to get the URL of the 
console:```Susans-MacBook-Pro-247:edgent susancline$ java -cp 
target/java8/samples/lib/edgent.samples.console.jar:. 
edgent.samples.console.ConsoleWaterDetectorMar 07, 2016 12:04:52 PM 
org.eclipse.jetty.util.log.Log initializedINFO: Logging initialized @176msMar 
07, 2016 12:04:53 PM org.eclipse.jetty.server.Server doStartINFO: 
jetty-9.3.6.v20151106Mar 07, 2016 12:04:53 PM 
org.eclipse.jetty.server.handler.ContextHandler doStartINFO: Started 
o.e.j.s.ServletContextHandler@614c5515{/jobs,null,AVAILABLE}Mar 07, 2016 
12:04:53 PM org.eclipse.jetty.server.handler.ContextHandler doStartINFO: 
Started o.e.j.s.ServletContextHandler@77b52d12{/metrics,null,AVAILABLE}Mar 07, 
2016 12:04:53 PM org.eclipse.jetty.webapp.StandardDescriptorProcessor 
visitServletINFO: NO JSP Support for /console, did not find 
org.eclipse.jetty.jsp.JettyJspServletMar 07, 2016 12:04:53 PM
  org.eclipse.jetty.server.handler.ContextHandler doStartINFO: Started 
o.e.j.w.WebAppContext@2d554825{/console,file:///private/var/folders/0c/pb4rznhj7sbc886t30w4vpxh0000gn/T/jetty-0.0.0.0-0-console.war-_console-any-3101338829524954950.dir/webapp/,AVAILABLE}{/console.war}Mar
 07, 2016 12:04:53 PM org.eclipse.jetty.server.AbstractConnector doStartINFO: 
Started ServerConnector@66480dd7{HTTP/1.1,[http/1.1]}{0.0.0.0:57964}Mar 07, 
2016 12:04:53 PM org.eclipse.jetty.server.Server doStartINFO: Started 
@426mshttp://localhost:57964/consoleWell1 alert, ecoli value is 1Well1 alert, 
temp value is 48Well3 alert, ecoli value is 1```Now point your browser to the 
URL displayed above in the output from running the Java command to launch the 
`ConsoleWaterDetector` application. In this case, the URL is 
`http://localhost:57964/console`.Below is a screen shot of what you should see 
if everything is working properly:## ConsoleWaterDetector application 
scenarioThe application is now running in your browser.
  Let's discuss the scenario for the application.A county agency is responsible 
for ensuring the safety of residents well water. Each well they monitor has 
four different sensor types:* Temperature* Acidity* Ecoli* LeadThe sample 
application topology monitors 3 wells:* For the hypothetical scenario, Well1 
and Well3 produce 'unhealthy' values from their sensors on occasion. Well2 
always produces 'healthy' values.* Each well that is to be measured is added to 
the topology. The topology polls each sensor (temp, ecoli, etc.) for each well 
as a unit. A `TStream` is returned from polling the toplogy and represents a 
sensor reading. Each sensor reading for the well has a tag added to it with the 
reading type i.e, \"temp\", and the well id. Once all of the sensor readings 
are obtained and the tags added, each sensor reading is 'unioned' into a single 
`TStream`. Look at the `waterDetector` method for details on this.* Now, each 
well has a single stream with each of the sensors readings as a p
 roperty with a name and value in the `TStream`. Next the `alertFilter` method 
is called on the `TStream` representing each well. This method checks the 
values for each well's sensors to determine if they are 'out of range' for 
healthy values. The `filter` oplet is used to do this. If any of the sensor's 
readings are out of the acceptable range the tuple is passed along. Those that 
are within an acceptable range are discarded.* Next the applications' 
`splitAlert` method is called on each well's stream that contains the union of 
all the sensor readings that are out of range. The `splitAlert` method uses the 
`split` oplet to split the incoming stream into 5 different streams. Only those 
tuples that are out of range for each stream, which represents each sensor 
type, will be returned. The object returned from `splitAlert` is a list of 
`TStream` objects. The `splitAlert` method is shown below:    ```java    public 
static List> splitAlert(TStream alertStream, int wellId) {        List> al
 lStreams = alertStream.split(5, tuple -> {            if (tuple.get(\"temp\") 
!= null) {                JsonObject tempObj = new JsonObject();                
int temp = tuple.get(\"temp\").getAsInt();                if (temp = 
TEMP_ALERT_MAX) {                    tempObj.addProperty(\"temp\", temp);       
             return 0;                } else {                    return -1;    
            }            } else if (tuple.get(\"acidity\") != null){            
    JsonObject acidObj = new JsonObject();                int acid = 
tuple.get(\"acidity\").getAsInt();                if (acid = ACIDITY_ALERT_MAX) 
{                    acidObj.addProperty(\"acidity\", acid);                    
return 1;                } else {                    return -1;                
}            } else if (tuple.get(\"ecoli\") != null) {                
JsonObject ecoliObj = new JsonObject();                int ecoli = 
tuple.get(\"ecoli\").getAsInt();                if (ecoli >= ECOLI_ALERT) {     
    
            ecoliObj.addProperty(\"ecoli\", ecoli);                    return 
2;                } else {                    return -1;                }       
     } else if (tuple.get(\"lead\") != null) {                JsonObject 
leadObj = new JsonObject();                int lead = 
tuple.get(\"lead\").getAsInt();                if (lead >= LEAD_ALERT_MAX) {    
                leadObj.addProperty(\"lead\", lead);                    return 
3;                } else {                    return -1;                }       
     } else {                 return -1;            }        });        return 
allStreams;    }    ```* Next we want to get the temperature stream from the 
first well and put a rate meter on it to determine the rate at which the out of 
range values are flowing in the stream    ```java    List> individualAlerts1 = 
splitAlert(filteredReadings1, 1);    // Put a rate meter on well1's temperature 
sensor output    Metrics.rateMeter(individualAlerts1.get(0));    ```* Next all 
 the sensors for well 1 have tags added to the stream indicating the stream is 
out of range for that sensor and the well id. Next a sink is added, passing the 
tuple to a `Consumer` that formats a string to `System.out` containing the well 
id, alert type (sensor type) and value of the sensor.    ```java    // Put a 
rate meter on well1's temperature sensor output    
Metrics.rateMeter(individualAlerts1.get(0));    
individualAlerts1.get(0).tag(TEMP_ALERT_TAG, \"well1\").sink(tuple -> 
System.out.println(\"\\n\" + formatAlertOutput(tuple, \"1\", \"temp\")));    
individualAlerts1.get(1).tag(ACIDITY_ALERT_TAG, \"well1\").sink(tuple -> 
System.out.println(formatAlertOutput(tuple, \"1\", \"acidity\")));    
individualAlerts1.get(2).tag(ECOLI_ALERT_TAG, \"well1\").sink(tuple -> 
System.out.println(formatAlertOutput(tuple, \"1\", \"ecoli\")));    
individualAlerts1.get(3).tag(LEAD_ALERT_TAG, \"well1\").sink(tuple -> 
System.out.println(formatAlertOutput(tuple, \"1\", \"lead\")));    ```Output in 
the 
 terminal window from the `formatAlertOutput` method will look like 
this:```Well1 alert, temp value is 86Well3 alert, ecoli value is 2Well1 alert, 
ecoli value is 1Well3 alert, acidity value is 1Well1 alert, lead value is 
12Well1 alert, ecoli value is 2Well3 alert, lead value is 10Well3 alert, 
acidity value is 10```Notice how only those streams that are out of range for 
the temperature sensor type show output.## Detecting zero tuple countsAt the 
end of the `ConsoleWaterDetector` application is this snippet of code, added 
after the topology has been submitted:```javadp.submit(wellTopology);while 
(true) {    MetricRegistry metricRegistry = 
dp.getServices().getService(MetricRegistry.class);    SortedMap counters = 
metricRegistry.getCounters();    Set> values = counters.entrySet();    for 
(Entry e : values) {        if (e.getValue().getCount() == 0) {            
System.out.println(\"Counter Op:\" + e.getKey() + \" tuple count: \" + 
e.getValue().getCount());        }    }    Thread.sleep(2
 000);}```What this does is get all the counters in the `MetricRegistry` class 
and print out the name of the counter oplet they are monitoring along with the 
tuple count if it is zero. Here is some sample output:```Counter 
Op:TupleCounter.edgent.oplet.JOB_0.OP_44 has a tuple count of zero!Counter 
Op:TupleCounter.edgent.oplet.JOB_0.OP_45 has a tuple count of zero!Counter 
Op:TupleCounter.edgent.oplet.JOB_0.OP_46 has a tuple count of zero!Counter 
Op:TupleCounter.edgent.oplet.JOB_0.OP_47 has a tuple count of zero!Counter 
Op:TupleCounter.edgent.oplet.JOB_0.OP_89 has a tuple count of zero!Counter 
Op:TupleCounter.edgent.oplet.JOB_0.OP_95 has a tuple count of zero!Counter 
Op:TupleCounter.edgent.oplet.JOB_0.OP_96 has a tuple count of zero!Counter 
Op:TupleCounter.edgent.oplet.JOB_0.OP_97 has a tuple count of zero!Counter 
Op:TupleCounter.edgent.oplet.JOB_0.OP_98 has a tuple count of zero!```To 
summarize what the application is doing:* Unions all sensor type readings for a 
single well* Filters a
 ll sensor type readings for a single well, passing on an object that only 
contains tuples for the object that have at least one sensor type with out of 
range values* Splits the object that contained name/value pairs for sensor type 
and readings into individual sensor types returning only those streams that 
contain out of range values* Outputs to the command line the well id, sensor 
type and value that is out of range* Tags are added at various points in the 
topology for easier identification of either the well or some out of range 
condition* The topology contains counters to measure tuple counts since 
`DevelopmentProvider` was used* Individual rate meters were placed on `well1` 
and `well3`'s temperature sensors to determine the rate of 'unhealthy' values* 
Prints out the name of the counter oplets whose tuple counts are zero## 
Topology graph controlsNow that you have an understanding of what the 
application is doing, let's look at some of the controls in the console, so we 
can learn 
 how to monitor the application. Below is a screen shot of the top controls: 
the controls that affect the Topology Graph.* **Job**: A drop down to select 
which job is being displayed in the Topology Graph. An application can contain 
multiple jobs.* **State**: Hovering over the 'State' icon shows information 
about the selected job. The current and next states of the job, the job id and 
the job name.* **View by**: This select is used to change how the topology 
graph is displayed. The three options for this select are:  - Static flow  - 
Tuple count  - Oplet kind  - Currently it is set to 'Static flow'. This means 
the oplets (represented as circles in the topology graph) do not change size, 
nor do the lines or links (representing the edges of the topology graph) change 
width or position. The graph is not being refreshed when it is in 'Static flow' 
mode.* **Refresh interval**: Allows the user to select an interval between 3 - 
20 seconds to refresh the tuple count values in the graph. Ever
 y X seconds the metrics for the topology graph are refreshed. More about 
metrics a little bit later.* **Pause graph**: Stops the refresh interval timer. 
Once the 'Pause graph' button is clicked, the user must push 'Resume graph' for 
the graph to be updated, and then refreshed at the interval set in the 'Refresh 
interval' timer. It can be helpful to pause the graph if multiple oplets are 
occupying the same area on the graph, and their names become unreadable. Once 
the graph is paused, the user can drag an oplet off of another oplet to better 
view the name and see the edge(s) that connect them.* **Show tags**: If the 
checkbox appears in the top controls, it means:  - The 'View by' layer is 
capable of displaying stream tags  - The topology currently shown in the 
topology graph has stream tags associated with it* **Show all tags**: Selecting 
this checkbox shows all the tags present in the topology. If you want to see 
only certain tags, uncheck this box and select the button labeled 'Sel
 ect individual tags ...'. A dialog will appear, and you can select one or all 
of the tags listed in the dialog which are present in the topology.    The next 
aspect of the console we'll look at are the popups available when selecting 
'View all oplet properties', hovering over an oplet and hovering over an edge 
(link).The screen shot below shows the output from clicking on the 'View all 
oplet properties' link directly below the job selector:Looking at the sixth 
line in the table, where the Name is 'OP_5', we can see that the Oplet kind is 
a `Map`, a `edgent.oplet.functional.Map`, the Tuple count is 0 (this is because 
the view is in Static flow mode - the graph does not show the number of tuples 
flowing in it), the source oplet is 'OP_55', the target oplet is 'OP_60', and 
there are no stream tags coming from the source or target streams. 
Relationships for all oplets can be viewed in this manner.Now, looking at the 
graph, if we want to see the relationships for a single oplet, we can h
 over over it. The image below shows the hover when we are over 'OP_5'.You can 
also hover over the edges of the topology graph to get information. Hover over 
the edge (link) between 'OP_0' and 'OP_55'. The image shows the name and kind 
of the oplet as the source, and the name and kind of oplet as the target. Again 
the tuple count is 0 since this is the 'Static flow' view. The last item of 
information in the tooltip is the tags on the stream.One or many tags can be 
added to a stream. In this case we see the tags 'temperature' and 'well1'.The 
section of the code that adds the tags 'temperature' and 'well1' is in the 
`waterDetector` method of the `ConsoleWaterDetector` class.```javapublic static 
TStream waterDetector(Topology topology, int wellId) {    Random rNum = new 
Random();    TStream temp = topology.poll(() -> rNum.nextInt(TEMP_RANDOM_HIGH - 
TEMP_RANDOM_LOW) + TEMP_RANDOM_LOW, 1, TimeUnit.SECONDS);    TStream acidity = 
topology.poll(() -> rNum.nextInt(ACIDITY_RANDOM_HIGH - ACIDIT
 Y_RANDOM_LOW) + ACIDITY_RANDOM_LOW, 1, TimeUnit.SECONDS);    TStream ecoli = 
topology.poll(() -> rNum.nextInt(ECOLI_RANDOM_HIGH - ECOLI_RANDOM_LOW) + 
ECOLI_RANDOM_LOW, 1, TimeUnit.SECONDS);    TStream lead = topology.poll(() -> 
rNum.nextInt(LEAD_RANDOM_HIGH - LEAD_RANDOM_LOW) + LEAD_RANDOM_LOW, 1, 
TimeUnit.SECONDS);    TStream id = topology.poll(() -> wellId, 1, 
TimeUnit.SECONDS);    // add tags to each sensor    temp.tag(\"temperature\", 
\"well\" + wellId);```### LegendThe legend(s) that appear in the console depend 
on the view currently displayed. In the static flow mode, if no stream tags are 
present, there is no legend. In this example we have stream tags in the 
topology, so the static flow mode gives us the option to select 'Show tags'. If 
selected, the result is the addition of the stream tags legend:This legend 
shows all the tags that have been added to the topology, regardless of whether 
or not 'Show all tags' is checked or specific tags have been selected from the 
dialog th
 at appears when the 'Select individual tags ...' button is clicked.### 
Topology graphNow that we've covered most of the ways to modify the view of the 
topology graph and discussed the application, let's look at the topology graph 
as a way to understand our application.When analyzing what is happening in your 
application, here are some ways you might use the console to help you 
understand it:* Topology of the application - how the edges and vertices of the 
graph are related* Tuple flow - tuple counts since the application was started* 
The affect of filters or maps on the downstream streams* Stream tags - if tags 
are added dynamically based on a condition, where the streams with tags are 
displayed in the topologyLet's start with the static flow view of the topology. 
We can look at the graph, and we can also hover over any of the oplets or 
streams to better understand the connections. Also, we can click 'View all 
oplet properties' and see the relationships in a tabular format.The other
  thing to notice in the static flow view are the tags. Look for any colored 
edges (the links between the oplets). All of the left-most oplets have streams 
with tags. Most of them have the color that corresponds to 'Multiple tags'. If 
you hover over the edges, you can see the tags. It's obvious that we have 
tagged each sensor with the sensor type and the well id.Now, if you look to the 
far right, you can see more tags on streams coming out of a `split` oplet. They 
also have multiple tags, and hovering over them you can determine that they 
represent out of range values for each sensor type for the well. Notice how the 
`split` oplet, OP_43, has no tags in the streams coming out of it. If you 
follow that split oplet back, you can determine from the first tags that it is 
part of the well 2 stream.If you refer back to the `ConsoleWaterDetector` 
source, you can see that no tags were placed on the streams coming out of 
`well2`'s split because they contained no out of range values.Let's swit
 ch the view to Oplet kind now. It will make more clear which oplets are 
producing the streams with the tags on them. Below is an image of how the graph 
looks after switching to the Oplet kind view.In the Oplet kind view the links 
are all the same width, but the circles representing the oplets are sized 
according to tuple flow. Notice how the circles representing OP_10, OP_32 and 
OP_21 are large in relation to OP_80, OP_88 and OP_89. As a matter of fact, we 
can't even see the circle representing OP_89. Looking at OP_35 and then the 
Oplet kind legend, you can see by the color that it is a Filter oplet. This is 
because the filter that we used against `well2`, which is the stream that OP_35 
is part of returned no tuples. This is a bit difficult to see. Let's look at 
the Tuple count view.The Tuple count view will make it more clear that no 
tuples are following out of OP_35, which represents the filter for `well2` and 
only returns out of range values. You may recall that in this example `
 well2` returned no out of range values. Below is the screen shot of the graph 
in 'Tuple count' view mode.The topology graph oplets can sometimes sit on top 
of each other. If this is the case, pause the refresh and use your mouse to 
pull down on the oplets that are in the same position. This will allow you to 
see their name. Alternately, you can use the 'View all properties' table to see 
the relationships between oplets.### MetricsIf you scroll the browser window 
down, you can see a Metrics section. This section appears when the application 
contains the following:* A `DevelopmentProvider` is used; this automatically 
inserts counters on the streams of the topology* A 
`edgent.metrics.Metric.Counter` or `edgent.metrics.Metric.RateMeter` is added 
to an individual stream## CountersIn the `ConsoleWaterDetector` application we 
used a `DevelopmentProvider`. Therefore, counters were added to most streams 
(edges) with the following exceptions (from the [Javadoc]({{ site.docsurl 
}}/latest/{{ si
 te.data.project.unix_name }}/metrics/Metrics.html#counter-{{ 
site.data.project.unix_name }}.topology.TStream-) for 
`edgent.metrics.Metrics`):*Oplets are only inserted upstream from a FanOut 
oplet.**If a chain of Peek oplets exists between oplets A and B, a Metric oplet 
is inserted after the last Peek, right upstream from oplet B.**If a chain of 
Peek oplets is followed by a FanOut, a metric oplet is inserted between the 
last Peek and the FanOut oplet.The implementation is not idempotent; previously 
inserted metric oplets are treated as regular graph vertices. Calling the 
method twice will insert a new set of metric oplets into the graph.*Also, the 
application inserts counters on `well2`'s streams after the streams from the 
individual sensors were unioned and then split:```javaList> individualAlerts2 = 
splitAlert(filteredReadings2, 2);TStream alert0Well2 = 
individualAlerts2.get(0);alert0Well2  = 
Metrics.counter(alert0Well2);alert0Well2.tag(\"well2\", \"temp\");TStream 
alert1Well2 = in
 dividualAlerts2.get(1);alert1Well2  = 
Metrics.counter(alert1Well2);alert1Well2.tag(\"well2\", \"acidity\");TStream 
alert2Well2 = individualAlerts2.get(2);alert2Well2  = 
Metrics.counter(alert2Well2);alert2Well2.tag(\"well2\", \"ecoli\");TStream 
alert3Well2 = individualAlerts2.get(3);alert3Well2  = 
Metrics.counter(alert3Well2);alert3Well2.tag(\"well2\", \"lead\");```When 
looking at the select next to the label 'Metrics', make sure the 'Count, oplets 
OP_37, OP_49 ...' is selected.  This select compares all of the counters in the 
topology visualized as a bar graph.  An image is shown below:Hover over 
individual bars to get the value of the number of tuples flowing through that 
oplet since the application was started. You can also see the oplet name. You 
can see that some of the oplets have zero tuples flowing through them.The bars 
that are the tallest and therefore have the highest tuple count are OP_76, 
OP_67 and OP_65.  If you look back up to the topology graph, in the Tuple count 
vie
 w, you can see that the edges (streams) surrounding these oplets have the 
color that corresponds to the highest tuple count (in the pictures above that 
color is bright orange in the Tuple count legend).### Rate metersThe other type 
of metric we can look at are rate meter metrics. In the `ConsoleWaterDetector` 
application we added two rate meters here with the objective of comparing the 
rate of out of range readings between `well1` and `well3`:```List> 
individualAlerts1 = splitAlert(filteredReadings1, 1);// Put a rate meter on 
well1's temperature sensor 
outputMetrics.rateMeter(individualAlerts1.get(0));...List> individualAlerts3 = 
splitAlert(filteredReadings3, 3);// Put a rate meter on well3's temperature 
sensor outputMetrics.rateMeter(individualAlerts3.get(0));```Rate meters contain 
the following metrics for each stream they are added to:  * Tuple count  * The 
rate of change in the tuple count. The following rates are available for a 
single stream:    - 1 minute rate change    - 5 m
 inute rate change    - 15 minute rate change    - Mean rate changeNow change 
the Metrics select to the 'MeanRate'. In our example these correspond to oplets 
OP_37 and OP_49:Hovering over the slightly larger bar, the one to the right, 
the name is OP_49. Looking at the topology graph and changing the view to 
'Static flow', follow the edges back from OP_49 until you can see an edge with 
a tag on it. You can see that OP_49's source is OP_51, whose source is OP_99.  
The edge between OP_99 and it's source OP_48 has multiple tags. Hovering over 
this stream, the tags are 'TEMP out of range' and 'well3'.If a single rate 
meter is placed on a stream, in addition to plotting a bar chart, a line chart 
over the last 20 measures can be viewed. For example, if I comment out the 
addition of the rate meter for `well1` and then rerun the application, the 
Metrics section will look like the image below. I selected the 'OneMinuteRate' 
and 'Line chart' for Chart type:## SummaryThe intent of the informatio
 n on this page is to help you understand the following:* How to add the 
console application to an Edgent application* How to run the 
`ConsoleWaterDetector` sample* The design/architecture in the 
`ConsoleWaterDetector` application* The controls for the Topology graph are and 
what they do, including the different views of the graph* The legend for the 
graph* How to interpret the graph and use the tooltips over the edges and 
vertices, as well as the 'View all properties' link* How to add counters and 
rate meters to a topology* How to use the metrics section to understand tuple 
counters and rate meters* How to correlate values from the metrics section with 
the topology graphThe Edgent console will continue to evolve and improve. 
Please open an issue if you see a problem with the existing console, but more 
importantly add an issue if you have an idea of how to make the console 
better.The more folks write Edgent applications and view them in the console, 
the more information we can gather
  from the community about what is needed in the console. Please consider 
making a contribution if there is a feature in the console that would really 
help you and others!"
+"body": "## Visualizing and monitoring your applicationThe Edgent application 
console is a web application that enables you to visualize your application 
topology and monitor the tuples flowing through your application. The kind of 
oplets used in the topology, as well as the stream tags included in the 
topology, are also visible in the console.## Adding the console web app to your 
applicationTo use the console, you must use the Edgent classes that provide the 
service to access the console web application or directly call the `HttpServer` 
class itself, start the server and then obtain the console URL.The easiest way 
to include the console in your application is to use the the 
`DevelopmentProvider` class. `DevelopmentProvider` is a subclass of 
`DirectProvider` and adds services such as access to the console web 
application and counter oplets used to determine tuple counts. You can get the 
URL for the console from the `DevelopmentProvider` using the `getService` 
method as shown in a hy
 pothetical application shown below:```javaimport 
java.util.concurrent.TimeUnit;import 
org.apache.edgent.console.server.HttpServer;import 
org.apache.edgent.providers.development.DevelopmentProvider;import 
org.apache.edgent.topology.TStream;import 
org.apache.edgent.topology.Topology;public class TempSensorApplication {    
public static void main(String[] args) throws Exception {        TempSensor 
sensor = new TempSensor();        DevelopmentProvider dp = new 
DevelopmentProvider();        Topology topology = dp.newTopology();        
TStream tempReadings = topology.poll(sensor, 1, TimeUnit.MILLISECONDS);        
TStream filteredReadings = tempReadings.filter(reading -> reading  80);        
filteredReadings.print();        
System.out.println(dp.getServices().getService(HttpServer.class).getConsoleUrl());
        dp.submit(topology);    }}```Note that the console URL is being printed 
to `System.out`. The `filteredReadings` are as well, since 
`filteredReadings.print()` is being called in the
  application. You may need to scroll your terminal window up to see the output 
for the console URL.Optionally, you can modify the above code in the 
application to have a timeout before submitting the topology, which would allow 
you to see the console URL before any other output is shown. The modification 
would look like this:```java// Print the console URL and wait for 10 seconds 
before submitting the 
topologySystem.out.println(dp.getServices().getService(HttpServer.class).getConsoleUrl());try
 {    TimeUnit.SECONDS.sleep(10);} catch (InterruptedException e) {    // Do 
nothing}dp.submit(topology);```The other way to embed the console in your 
application is shown in the `HttpServerSample.java` example (on [GitHub]({{ 
site.data.project.source_repository_mirror 
}}/blob/master/samples/console/src/main/java/org/apache/{{ 
site.data.project.unix_name }}/samples/console/HttpServerSample.java)). It gets 
the `HttpServer` instance, starts it, and prints out the console URL. Note that 
it does no
 t submit a job, so when the console is displayed in the browser, there are no 
running jobs and therefore no topology graph. The example is meant to show how 
to get the `HttpServer` instance, start the console web app and get the URL of 
the console.## Accessing the consoleThe console URL has the following 
format:`http://host_name:port_number/console`Once it is obtained from 
`System.out`, enter it in a browser window.If you cannot access the console at 
this URL, ensure there is a `console.war` file in the `webapps` directory. If 
the `console.war` file cannot be found, an exception will be thrown (in 
`std.out`) indicating `console.war` was not found.## ConsoleWaterDetector 
sampleTo see the features of the console in action and as a way to demonstrate 
how to monitor a topology in the console, let's look at the 
`ConsoleWaterDetector` sample (on [GitHub]({{ 
site.data.project.source_repository_mirror 
}}/blob/master/samples/console/src/main/java/org/apache/{{ 
site.data.project.unix_name }}/
 samples/console/ConsoleWaterDetector.java)).Prior to running any console 
applications, the `console.war` file must be built as mentioned above. If you 
are building Edgent from a Git repository, go to the top level Edgent directory 
and run `ant`.Here is an example in my 
environment:```Susans-MacBook-Pro-247:edgent susancline$ 
pwd/Users/susancline/git/edgentSusans-MacBook-Pro-247:edgent susancline$ 
antBuildfile: 
/Users/susancline/git/edgent/build.xmlsetcommitversion:init:suball:init:project.component:compile:...[javadoc]
 Constructing Javadoc information...[javadoc] Standard Doclet version 
1.8.0_71[javadoc] Building tree for all the packages and classes...[javadoc] 
Generating 
/Users/susancline/git/edgent/target/docs/javadoc/edgent/analytics/sensors/package-summary.html...[javadoc]
 Copying file 
/Users/susancline/git/edgent/analytics/sensors/src/main/java/edgent/analytics/sensors/doc-files/deadband.png
 to directory 
/Users/susancline/git/edgent/target/docs/javadoc/edgent/analytics/sensors
 /doc-files...[javadoc] Generating 
/Users/susancline/git/edgent/target/docs/javadoc/edgent/topology/package-summary.html...[javadoc]
 Copying file 
/Users/susancline/git/edgent/api/topology/src/main/java/edgent/topology/doc-files/sources.html
 to directory 
/Users/susancline/git/edgent/target/docs/javadoc/edgent/topology/doc-files...[javadoc]
 Building index for all the packages and classes...[javadoc] Building index for 
all classes...all:BUILD SUCCESSFULTotal time: 3 seconds```This command will let 
you know that `console.war` was built and is in the correct place, under the 
`webapps` directory.```Susans-MacBook-Pro-247:edgent susancline$ find . -name 
console.war -print./target/java8/console/webapps/console.war```Now we know we 
have built `console.war`, so we're good to go. To run this sample from the 
command line:```Susans-MacBook-Pro-247:edgent susancline$ 
pwd/Users/susancline/git/edgentSusans-MacBook-Pro-247:edgent susancline$ java 
-cp target/java8/samples/lib/edgent.samples.console.ja
 r:. edgent.samples.console.ConsoleWaterDetector```If everything is successful, 
you'll start seeing output. You may have to scroll back up to get the URL of 
the console:```Susans-MacBook-Pro-247:edgent susancline$ java -cp 
target/java8/samples/lib/edgent.samples.console.jar:. 
edgent.samples.console.ConsoleWaterDetectorMar 07, 2016 12:04:52 PM 
org.eclipse.jetty.util.log.Log initializedINFO: Logging initialized @176msMar 
07, 2016 12:04:53 PM org.eclipse.jetty.server.Server doStartINFO: 
jetty-9.3.6.v20151106Mar 07, 2016 12:04:53 PM 
org.eclipse.jetty.server.handler.ContextHandler doStartINFO: Started 
o.e.j.s.ServletContextHandler@614c5515{/jobs,null,AVAILABLE}Mar 07, 2016 
12:04:53 PM org.eclipse.jetty.server.handler.ContextHandler doStartINFO: 
Started o.e.j.s.ServletContextHandler@77b52d12{/metrics,null,AVAILABLE}Mar 07, 
2016 12:04:53 PM org.eclipse.jetty.webapp.StandardDescriptorProcessor 
visitServletINFO: NO JSP Support for /console, did not find 
org.eclipse.jetty.jsp.JettyJspServletMa
 r 07, 2016 12:04:53 PM org.eclipse.jetty.server.handler.ContextHandler 
doStartINFO: Started 
o.e.j.w.WebAppContext@2d554825{/console,file:///private/var/folders/0c/pb4rznhj7sbc886t30w4vpxh0000gn/T/jetty-0.0.0.0-0-console.war-_console-any-3101338829524954950.dir/webapp/,AVAILABLE}{/console.war}Mar
 07, 2016 12:04:53 PM org.eclipse.jetty.server.AbstractConnector doStartINFO: 
Started ServerConnector@66480dd7{HTTP/1.1,[http/1.1]}{0.0.0.0:57964}Mar 07, 
2016 12:04:53 PM org.eclipse.jetty.server.Server doStartINFO: Started 
@426mshttp://localhost:57964/consoleWell1 alert, ecoli value is 1Well1 alert, 
temp value is 48Well3 alert, ecoli value is 1```Now point your browser to the 
URL displayed above in the output from running the Java command to launch the 
`ConsoleWaterDetector` application. In this case, the URL is 
`http://localhost:57964/console`.Below is a screen shot of what you should see 
if everything is working properly:## ConsoleWaterDetector application 
scenarioThe application is now ru
 nning in your browser. Let's discuss the scenario for the application.A county 
agency is responsible for ensuring the safety of residents well water. Each 
well they monitor has four different sensor types:* Temperature* Acidity* 
Ecoli* LeadThe sample application topology monitors 3 wells:* For the 
hypothetical scenario, Well1 and Well3 produce 'unhealthy' values from their 
sensors on occasion. Well2 always produces 'healthy' values.* Each well that is 
to be measured is added to the topology. The topology polls each sensor (temp, 
ecoli, etc.) for each well as a unit. A `TStream` is returned from polling the 
toplogy and represents a sensor reading. Each sensor reading for the well has a 
tag added to it with the reading type i.e, \"temp\", and the well id. Once all 
of the sensor readings are obtained and the tags added, each sensor reading is 
'unioned' into a single `TStream`. Look at the `waterDetector` method for 
details on this.* Now, each well has a single stream with each of the s
 ensors readings as a property with a name and value in the `TStream`. Next the 
`alertFilter` method is called on the `TStream` representing each well. This 
method checks the values for each well's sensors to determine if they are 'out 
of range' for healthy values. The `filter` oplet is used to do this. If any of 
the sensor's readings are out of the acceptable range the tuple is passed 
along. Those that are within an acceptable range are discarded.* Next the 
applications' `splitAlert` method is called on each well's stream that contains 
the union of all the sensor readings that are out of range. The `splitAlert` 
method uses the `split` oplet to split the incoming stream into 5 different 
streams. Only those tuples that are out of range for each stream, which 
represents each sensor type, will be returned. The object returned from 
`splitAlert` is a list of `TStream` objects. The `splitAlert` method is shown 
below:    ```java    public static List> splitAlert(TStream alertStream, int wel
 lId) {        List> allStreams = alertStream.split(5, tuple -> {            if 
(tuple.get(\"temp\") != null) {                JsonObject tempObj = new 
JsonObject();                int temp = tuple.get(\"temp\").getAsInt();         
       if (temp = TEMP_ALERT_MAX) {                    
tempObj.addProperty(\"temp\", temp);                    return 0;               
 } else {                    return -1;                }            } else if 
(tuple.get(\"acidity\") != null){                JsonObject acidObj = new 
JsonObject();                int acid = tuple.get(\"acidity\").getAsInt();      
          if (acid = ACIDITY_ALERT_MAX) {                    
acidObj.addProperty(\"acidity\", acid);                    return 1;            
    } else {                    return -1;                }            } else 
if (tuple.get(\"ecoli\") != null) {                JsonObject ecoliObj = new 
JsonObject();                int ecoli = tuple.get(\"ecoli\").getAsInt();       
         if (ecoli >= E
 COLI_ALERT) {                    ecoliObj.addProperty(\"ecoli\", ecoli);       
             return 2;                } else {                    return -1;    
            }            } else if (tuple.get(\"lead\") != null) {              
  JsonObject leadObj = new JsonObject();                int lead = 
tuple.get(\"lead\").getAsInt();                if (lead >= LEAD_ALERT_MAX) {    
                leadObj.addProperty(\"lead\", lead);                    return 
3;                } else {                    return -1;                }       
     } else {                 return -1;            }        });        return 
allStreams;    }    ```* Next we want to get the temperature stream from the 
first well and put a rate meter on it to determine the rate at which the out of 
range values are flowing in the stream    ```java    List> individualAlerts1 = 
splitAlert(filteredReadings1, 1);    // Put a rate meter on well1's temperature 
sensor output    Metrics.rateMeter(individualAlerts1.get(
 0));    ```* Next all the sensors for well 1 have tags added to the stream 
indicating the stream is out of range for that sensor and the well id. Next a 
sink is added, passing the tuple to a `Consumer` that formats a string to 
`System.out` containing the well id, alert type (sensor type) and value of the 
sensor.    ```java    // Put a rate meter on well1's temperature sensor output  
  Metrics.rateMeter(individualAlerts1.get(0));    
individualAlerts1.get(0).tag(TEMP_ALERT_TAG, \"well1\").sink(tuple -> 
System.out.println(\"\\n\" + formatAlertOutput(tuple, \"1\", \"temp\")));    
individualAlerts1.get(1).tag(ACIDITY_ALERT_TAG, \"well1\").sink(tuple -> 
System.out.println(formatAlertOutput(tuple, \"1\", \"acidity\")));    
individualAlerts1.get(2).tag(ECOLI_ALERT_TAG, \"well1\").sink(tuple -> 
System.out.println(formatAlertOutput(tuple, \"1\", \"ecoli\")));    
individualAlerts1.get(3).tag(LEAD_ALERT_TAG, \"well1\").sink(tuple -> 
System.out.println(formatAlertOutput(tuple, \"1\", \"lead\")))
 ;    ```Output in the terminal window from the `formatAlertOutput` method will 
look like this:```Well1 alert, temp value is 86Well3 alert, ecoli value is 
2Well1 alert, ecoli value is 1Well3 alert, acidity value is 1Well1 alert, lead 
value is 12Well1 alert, ecoli value is 2Well3 alert, lead value is 10Well3 
alert, acidity value is 10```Notice how only those streams that are out of 
range for the temperature sensor type show output.## Detecting zero tuple 
countsAt the end of the `ConsoleWaterDetector` application is this snippet of 
code, added after the topology has been 
submitted:```javadp.submit(wellTopology);while (true) {    MetricRegistry 
metricRegistry = dp.getServices().getService(MetricRegistry.class);    
SortedMap counters = metricRegistry.getCounters();    Set> values = 
counters.entrySet();    for (Entry e : values) {        if 
(e.getValue().getCount() == 0) {            System.out.println(\"Counter Op:\" 
+ e.getKey() + \" tuple count: \" + e.getValue().getCount());        } 
    }    Thread.sleep(2000);}```What this does is get all the counters in the 
`MetricRegistry` class and print out the name of the counter oplet they are 
monitoring along with the tuple count if it is zero. Here is some sample 
output:```Counter Op:TupleCounter.edgent.oplet.JOB_0.OP_44 has a tuple count of 
zero!Counter Op:TupleCounter.edgent.oplet.JOB_0.OP_45 has a tuple count of 
zero!Counter Op:TupleCounter.edgent.oplet.JOB_0.OP_46 has a tuple count of 
zero!Counter Op:TupleCounter.edgent.oplet.JOB_0.OP_47 has a tuple count of 
zero!Counter Op:TupleCounter.edgent.oplet.JOB_0.OP_89 has a tuple count of 
zero!Counter Op:TupleCounter.edgent.oplet.JOB_0.OP_95 has a tuple count of 
zero!Counter Op:TupleCounter.edgent.oplet.JOB_0.OP_96 has a tuple count of 
zero!Counter Op:TupleCounter.edgent.oplet.JOB_0.OP_97 has a tuple count of 
zero!Counter Op:TupleCounter.edgent.oplet.JOB_0.OP_98 has a tuple count of 
zero!```To summarize what the application is doing:* Unions all sensor type 
readings for a 
 single well* Filters all sensor type readings for a single well, passing on an 
object that only contains tuples for the object that have at least one sensor 
type with out of range values* Splits the object that contained name/value 
pairs for sensor type and readings into individual sensor types returning only 
those streams that contain out of range values* Outputs to the command line the 
well id, sensor type and value that is out of range* Tags are added at various 
points in the topology for easier identification of either the well or some out 
of range condition* The topology contains counters to measure tuple counts 
since `DevelopmentProvider` was used* Individual rate meters were placed on 
`well1` and `well3`'s temperature sensors to determine the rate of 'unhealthy' 
values* Prints out the name of the counter oplets whose tuple counts are zero## 
Topology graph controlsNow that you have an understanding of what the 
application is doing, let's look at some of the controls in the con
 sole, so we can learn how to monitor the application. Below is a screen shot 
of the top controls: the controls that affect the Topology Graph.* **Job**: A 
drop down to select which job is being displayed in the Topology Graph. An 
application can contain multiple jobs.* **State**: Hovering over the 'State' 
icon shows information about the selected job. The current and next states of 
the job, the job id and the job name.* **View by**: This select is used to 
change how the topology graph is displayed. The three options for this select 
are:  - Static flow  - Tuple count  - Oplet kind  - Currently it is set to 
'Static flow'. This means the oplets (represented as circles in the topology 
graph) do not change size, nor do the lines or links (representing the edges of 
the topology graph) change width or position. The graph is not being refreshed 
when it is in 'Static flow' mode.* **Refresh interval**: Allows the user to 
select an interval between 3 - 20 seconds to refresh the tuple count val
 ues in the graph. Every X seconds the metrics for the topology graph are 
refreshed. More about metrics a little bit later.* **Pause graph**: Stops the 
refresh interval timer. Once the 'Pause graph' button is clicked, the user must 
push 'Resume graph' for the graph to be updated, and then refreshed at the 
interval set in the 'Refresh interval' timer. It can be helpful to pause the 
graph if multiple oplets are occupying the same area on the graph, and their 
names become unreadable. Once the graph is paused, the user can drag an oplet 
off of another oplet to better view the name and see the edge(s) that connect 
them.* **Show tags**: If the checkbox appears in the top controls, it means:  - 
The 'View by' layer is capable of displaying stream tags  - The topology 
currently shown in the topology graph has stream tags associated with it* 
**Show all tags**: Selecting this checkbox shows all the tags present in the 
topology. If you want to see only certain tags, uncheck this box and select t
 he button labeled 'Select individual tags ...'. A dialog will appear, and you 
can select one or all of the tags listed in the dialog which are present in the 
topology.    The next aspect of the console we'll look at are the popups 
available when selecting 'View all oplet properties', hovering over an oplet 
and hovering over an edge (link).The screen shot below shows the output from 
clicking on the 'View all oplet properties' link directly below the job 
selector:Looking at the sixth line in the table, where the Name is 'OP_5', we 
can see that the Oplet kind is a `Map`, a `edgent.oplet.functional.Map`, the 
Tuple count is 0 (this is because the view is in Static flow mode - the graph 
does not show the number of tuples flowing in it), the source oplet is 'OP_55', 
the target oplet is 'OP_60', and there are no stream tags coming from the 
source or target streams. Relationships for all oplets can be viewed in this 
manner.Now, looking at the graph, if we want to see the relationships for a 
 single oplet, we can hover over it. The image below shows the hover when we 
are over 'OP_5'.You can also hover over the edges of the topology graph to get 
information. Hover over the edge (link) between 'OP_0' and 'OP_55'. The image 
shows the name and kind of the oplet as the source, and the name and kind of 
oplet as the target. Again the tuple count is 0 since this is the 'Static flow' 
view. The last item of information in the tooltip is the tags on the stream.One 
or many tags can be added to a stream. In this case we see the tags 
'temperature' and 'well1'.The section of the code that adds the tags 
'temperature' and 'well1' is in the `waterDetector` method of the 
`ConsoleWaterDetector` class.```javapublic static TStream 
waterDetector(Topology topology, int wellId) {    Random rNum = new Random();   
 TStream temp = topology.poll(() -> rNum.nextInt(TEMP_RANDOM_HIGH - 
TEMP_RANDOM_LOW) + TEMP_RANDOM_LOW, 1, TimeUnit.SECONDS);    TStream acidity = 
topology.poll(() -> rNum.nextInt(ACIDIT
 Y_RANDOM_HIGH - ACIDITY_RANDOM_LOW) + ACIDITY_RANDOM_LOW, 1, 
TimeUnit.SECONDS);    TStream ecoli = topology.poll(() -> 
rNum.nextInt(ECOLI_RANDOM_HIGH - ECOLI_RANDOM_LOW) + ECOLI_RANDOM_LOW, 1, 
TimeUnit.SECONDS);    TStream lead = topology.poll(() -> 
rNum.nextInt(LEAD_RANDOM_HIGH - LEAD_RANDOM_LOW) + LEAD_RANDOM_LOW, 1, 
TimeUnit.SECONDS);    TStream id = topology.poll(() -> wellId, 1, 
TimeUnit.SECONDS);    // add tags to each sensor    temp.tag(\"temperature\", 
\"well\" + wellId);```### LegendThe legend(s) that appear in the console depend 
on the view currently displayed. In the static flow mode, if no stream tags are 
present, there is no legend. In this example we have stream tags in the 
topology, so the static flow mode gives us the option to select 'Show tags'. If 
selected, the result is the addition of the stream tags legend:This legend 
shows all the tags that have been added to the topology, regardless of whether 
or not 'Show all tags' is checked or specific tags have been selec
 ted from the dialog that appears when the 'Select individual tags ...' button 
is clicked.### Topology graphNow that we've covered most of the ways to modify 
the view of the topology graph and discussed the application, let's look at the 
topology graph as a way to understand our application.When analyzing what is 
happening in your application, here are some ways you might use the console to 
help you understand it:* Topology of the application - how the edges and 
vertices of the graph are related* Tuple flow - tuple counts since the 
application was started* The affect of filters or maps on the downstream 
streams* Stream tags - if tags are added dynamically based on a condition, 
where the streams with tags are displayed in the topologyLet's start with the 
static flow view of the topology. We can look at the graph, and we can also 
hover over any of the oplets or streams to better understand the connections. 
Also, we can click 'View all oplet properties' and see the relationships in a ta
 bular format.The other thing to notice in the static flow view are the tags. 
Look for any colored edges (the links between the oplets). All of the left-most 
oplets have streams with tags. Most of them have the color that corresponds to 
'Multiple tags'. If you hover over the edges, you can see the tags. It's 
obvious that we have tagged each sensor with the sensor type and the well 
id.Now, if you look to the far right, you can see more tags on streams coming 
out of a `split` oplet. They also have multiple tags, and hovering over them 
you can determine that they represent out of range values for each sensor type 
for the well. Notice how the `split` oplet, OP_43, has no tags in the streams 
coming out of it. If you follow that split oplet back, you can determine from 
the first tags that it is part of the well 2 stream.If you refer back to the 
`ConsoleWaterDetector` source, you can see that no tags were placed on the 
streams coming out of `well2`'s split because they contained no out of r
 ange values.Let's switch the view to Oplet kind now. It will make more clear 
which oplets are producing the streams with the tags on them. Below is an image 
of how the graph looks after switching to the Oplet kind view.In the Oplet kind 
view the links are all the same width, but the circles representing the oplets 
are sized according to tuple flow. Notice how the circles representing OP_10, 
OP_32 and OP_21 are large in relation to OP_80, OP_88 and OP_89. As a matter of 
fact, we can't even see the circle representing OP_89. Looking at OP_35 and 
then the Oplet kind legend, you can see by the color that it is a Filter oplet. 
This is because the filter that we used against `well2`, which is the stream 
that OP_35 is part of returned no tuples. This is a bit difficult to see. Let's 
look at the Tuple count view.The Tuple count view will make it more clear that 
no tuples are following out of OP_35, which represents the filter for `well2` 
and only returns out of range values. You may recall 
 that in this example `well2` returned no out of range values. Below is the 
screen shot of the graph in 'Tuple count' view mode.The topology graph oplets 
can sometimes sit on top of each other. If this is the case, pause the refresh 
and use your mouse to pull down on the oplets that are in the same position. 
This will allow you to see their name. Alternately, you can use the 'View all 
properties' table to see the relationships between oplets.### MetricsIf you 
scroll the browser window down, you can see a Metrics section. This section 
appears when the application contains the following:* A `DevelopmentProvider` 
is used; this automatically inserts counters on the streams of the topology* A 
`edgent.metrics.Metric.Counter` or `edgent.metrics.Metric.RateMeter` is added 
to an individual stream## CountersIn the `ConsoleWaterDetector` application we 
used a `DevelopmentProvider`. Therefore, counters were added to most streams 
(edges) with the following exceptions (from the [Javadoc]({{ site.d
 ocsurl }}/org/apache/{{ site.data.project.unix_name 
}}/metrics/Metrics.html#counter-org.apache.{{ site.data.project.unix_name 
}}.topology.TStream-) for `edgent.metrics.Metrics`):*Oplets are only inserted 
upstream from a FanOut oplet.**If a chain of Peek oplets exists between oplets 
A and B, a Metric oplet is inserted after the last Peek, right upstream from 
oplet B.**If a chain of Peek oplets is followed by a FanOut, a metric oplet is 
inserted between the last Peek and the FanOut oplet.The implementation is not 
idempotent; previously inserted metric oplets are treated as regular graph 
vertices. Calling the method twice will insert a new set of metric oplets into 
the graph.*Also, the application inserts counters on `well2`'s streams after 
the streams from the individual sensors were unioned and then 
split:```javaList> individualAlerts2 = splitAlert(filteredReadings2, 2);TStream 
alert0Well2 = individualAlerts2.get(0);alert0Well2  = 
Metrics.counter(alert0Well2);alert0Well2.tag(\"well2\
 ", \"temp\");TStream alert1Well2 = individualAlerts2.get(1);alert1Well2  = 
Metrics.counter(alert1Well2);alert1Well2.tag(\"well2\", \"acidity\");TStream 
alert2Well2 = individualAlerts2.get(2);alert2Well2  = 
Metrics.counter(alert2Well2);alert2Well2.tag(\"well2\", \"ecoli\");TStream 
alert3Well2 = individualAlerts2.get(3);alert3Well2  = 
Metrics.counter(alert3Well2);alert3Well2.tag(\"well2\", \"lead\");```When 
looking at the select next to the label 'Metrics', make sure the 'Count, oplets 
OP_37, OP_49 ...' is selected.  This select compares all of the counters in the 
topology visualized as a bar graph.  An image is shown below:Hover over 
individual bars to get the value of the number of tuples flowing through that 
oplet since the application was started. You can also see the oplet name. You 
can see that some of the oplets have zero tuples flowing through them.The bars 
that are the tallest and therefore have the highest tuple count are OP_76, 
OP_67 and OP_65.  If you look back up to the t
 opology graph, in the Tuple count view, you can see that the edges (streams) 
surrounding these oplets have the color that corresponds to the highest tuple 
count (in the pictures above that color is bright orange in the Tuple count 
legend).### Rate metersThe other type of metric we can look at are rate meter 
metrics. In the `ConsoleWaterDetector` application we added two rate meters 
here with the objective of comparing the rate of out of range readings between 
`well1` and `well3`:```List> individualAlerts1 = splitAlert(filteredReadings1, 
1);// Put a rate meter on well1's temperature sensor 
outputMetrics.rateMeter(individualAlerts1.get(0));...List> individualAlerts3 = 
splitAlert(filteredReadings3, 3);// Put a rate meter on well3's temperature 
sensor outputMetrics.rateMeter(individualAlerts3.get(0));```Rate meters contain 
the following metrics for each stream they are added to:  * Tuple count  * The 
rate of change in the tuple count. The following rates are available for a 
single strea
 m:    - 1 minute rate change    - 5 minute rate change    - 15 minute rate 
change    - Mean rate changeNow change the Metrics select to the 'MeanRate'. In 
our example these correspond to oplets OP_37 and OP_49:Hovering over the 
slightly larger bar, the one to the right, the name is OP_49. Looking at the 
topology graph and changing the view to 'Static flow', follow the edges back 
from OP_49 until you can see an edge with a tag on it. You can see that OP_49's 
source is OP_51, whose source is OP_99.  The edge between OP_99 and it's source 
OP_48 has multiple tags. Hovering over this stream, the tags are 'TEMP out of 
range' and 'well3'.If a single rate meter is placed on a stream, in addition to 
plotting a bar chart, a line chart over the last 20 measures can be viewed. For 
example, if I comment out the addition of the rate meter for `well1` and then 
rerun the application, the Metrics section will look like the image below. I 
selected the 'OneMinuteRate' and 'Line chart' for Chart type:#
 # SummaryThe intent of the information on this page is to help you understand 
the following:* How to add the console application to an Edgent application* 
How to run the `ConsoleWaterDetector` sample* The design/architecture in the 
`ConsoleWaterDetector` application* The controls for the Topology graph are and 
what they do, including the different views of the graph* The legend for the 
graph* How to interpret the graph and use the tooltips over the edges and 
vertices, as well as the 'View all properties' link* How to add counters and 
rate meters to a topology* How to use the metrics section to understand tuple 
counters and rate meters* How to correlate values from the metrics section with 
the topology graphThe Edgent console will continue to evolve and improve. 
Please open an issue if you see a problem with the existing console, but more 
importantly add an issue if you have an idea of how to make the console 
better.The more folks write Edgent applications and view them in the consol
 e, the more information we can gather from the community about what is needed 
in the console. Please consider making a contribution if there is a feature in 
the console that would really help you and others!"
 
 },
 
@@ -65,7 +65,7 @@
 "keywords": "",
 "url": "../docs/edgent-getting-started",
 "summary": "",
-"body": "## What is Apache Edgent?Edgent is an open source programming model 
and runtime for edge devices that enables you to analyze streaming data on your 
edge devices. When you analyze on the edge, you can:* Reduce the amount of data 
that you transmit to your analytics server* Reduce the amount of data that you 
storeFor more information, see the [Edgent overview](home).### Apache Edgent 
and streaming analyticsThe fundamental building block of an Edgent application 
is a **stream**: a continuous sequence of tuples (messages, events, sensor 
readings, and so on).The Edgent API provides the ability to process or analyze 
each tuple as it appears on a stream, resulting in a derived stream.Source 
streams are streams that originate data for analysis, such as readings from a 
device's temperature sensor.Streams are terminated using sink functions that 
can perform local device control or send information to centralized analytic 
systems through a message hub.Edgent's primary API is functional
  where streams are sourced, transformed, analyzed or sinked though functions, 
typically represented as lambda expressions, such as `reading -> reading  80` 
to filter temperature readings in Fahrenheit.### Downloading Apache EdgentTo 
use Edgent, access the source code and build it. You can read more about 
building Edgent [here]({{ site.data.project.source_repository_mirror 
}}/blob/master/DEVELOPMENT.md).After you build the Edgent package, you can set 
up your environment.### Setting up your environmentEnsure that you are running 
a supported environment. For more information, see the [Edgent overview](home). 
This guide assumes you're running Java 8.The Edgent Java 8 JAR files are 
located in the `edgent/java8/lib` directory.1. Create a new Java project in 
Eclipse, and specify Java 8 as the execution environment JRE:    2. Modify the 
Java build path to include all of the JAR files in the `edgent\\java8\\lib` 
directory:    Your environment is set up! You can start writing your first Edgen
 t application.## Creating a simple applicationIf you're new to Edgent or to 
writing streaming applications, the best way to get started is to write a 
simple program.Edgent is a framework that pushes data analytics and machine 
learning to *edge devices*. (Edge devices include things like routers, 
gateways, machines, equipment, sensors, appliances, or vehicles that are 
connected to a network.) Edgent enables you to process data locally—such 
as, in a car engine, on an Android phone, or Raspberry Pi—before you send 
data over a network.For example, if your device takes temperature readings from 
a sensor 1,000 times per second, it is more efficient to process the data 
locally and send only interesting or unexpected results over the network. To 
simulate this, let's define a (simulated) TempSensor class:```javaimport 
java.util.Random;import org.apache.edgent.function.Supplier;/** * Every time 
get() is called, TempSensor generates a temperature reading. */public class 
TempSensor 
 implements Supplier {    double currentTemp = 65.0;    Random rand;    
TempSensor(){        rand = new Random();    }    @Override    public Double 
get() {        // Change the current temperature some random amount        
double newTemp = rand.nextGaussian() + currentTemp;        currentTemp = 
newTemp;        return currentTemp;    }}```Every time you call 
`TempSensor.get()`, it returns a new temperature reading. The continuous 
temperature readings are a stream of data that an Edgent application can 
process.Our sample Edgent application processes this stream by filtering the 
data and printing the results. Let's define a TempSensorApplication class for 
the application:```javaimport java.util.concurrent.TimeUnit;import 
org.apache.edgent.providers.direct.DirectProvider;import 
org.apache.edgent.topology.TStream;import 
org.apache.edgent.topology.Topology;public class TempSensorApplication {    
public static void main(String[] args) throws Exception {        TempSensor 
sensor = new TempS
 ensor();        DirectProvider dp = new DirectProvider();        Topology 
topology = dp.newTopology();        TStream tempReadings = 
topology.poll(sensor, 1, TimeUnit.MILLISECONDS);        TStream 
filteredReadings = tempReadings.filter(reading -> reading  80);        
filteredReadings.print();        dp.submit(topology);    }}```To understand how 
the application processes the stream, let's review each line.### Specifying a 
providerYour first step when you write an Edgent application is to create a 
[`DirectProvider`]({{ site.docsurl 
}}/latest/index.html?edgent/providers/direct/DirectProvider.html):```javaDirectProvider
 dp = new DirectProvider();```A `Provider` is an object that contains 
information on how and where your Edgent application will run. A 
`DirectProvider` is a type of Provider that runs your application directly 
within the current virtual machine when its `submit()` method is called.### 
Creating a topologyAdditionally a Provider is used to create a [`Topology`]({{ 
site.doc
 surl }}/latest/index.html?edgent/topology/Topology.html) 
instance:```javaTopology topology = dp.newTopology();```In Edgent, `Topology` 
is a container that describes the structure of your application:* Where the 
streams in the application come from* How the data in the stream is modifiedIn 
the TempSensor application above, we have exactly one data source: the 
`TempSensor` object. We define the source stream by calling `topology.poll()`, 
which takes both a `Supplier` function and a time parameter to indicate how 
frequently readings should be taken. In our case, we read from the sensor every 
millisecond:```javaTStream tempReadings = topology.poll(sensor, 1, 
TimeUnit.MILLISECONDS);```### Defining the `TStream` objectCalling 
`topology.poll()` to define a source stream creates a `TStream` instance, which 
represents the series of readings taken from the temperature sensor.A streaming 
application can run indefinitely, so the `TStream` might see an arbitrarily 
large number of readings pass t
 hrough it. Because a `TStream` represents the flow of your data, it supports a 
number of operations which allow you to modify your data.### Filtering a 
`TStream`In our example, we want to filter the stream of temperature readings, 
and remove any \"uninteresting\" or expected readings—specifically 
readings which are above 50 degrees and below 80 degrees. To do this, we call 
the `TStream`'s `filter` method and pass in a function that returns *true* if 
the data is interesting and *false* if the data is uninteresting:```javaTStream 
filteredReadings = tempReadings.filter(reading -> reading  80);```As you can 
see, the function that is passed to `filter` operates on each tuple 
individually. Unlike data streaming frameworks like [Apache 
Spark](https://spark.apache.org/), which operate on a collection of data in 
batch mode, Edgent achieves low latency processing by manipulating each piece 
of data as soon as it becomes available. Filtering a `TStream` produces another 
`TStream` that con
 tains only the filtered tuples; for example, the `filteredReadings` stream.### 
Printing to outputWhen our application detects interesting data (data outside 
of the expected parameters), we want to print results. You can do this by 
calling the `TStream.print()` method, which prints using  `.toString()` on each 
tuple that passes through the stream:```javafilteredReadings.print();```Unlike 
`TStream.filter()`, `TStream.print()` does not produce another `TStream`. This 
is because `TStream.print()` is a **sink**, which represents the terminus of a 
stream.In addition to `TStream.print()` there are other sink operations that 
send tuples to an MQTT server, JDBC connection, file, or Kafka cluster. 
Additionally, you can define your own sink by invoking `TStream.sink()` and 
passing in your own function.### Submitting your applicationNow that your 
application has been completely declared, the final step is to run your 
application.`DirectProvider` contains a `submit()` method, which runs your app
 lication directly within the current virtual 
machine:```javadp.submit(topology);```After you run your program, you should 
see output containing only \"interesting\" data coming from your 
sensor:```49.90403231177259647.9783750403908446.5927233630903146.68154455165293447.400819234155236...```As
 you can see, all temperatures are outside the 50-80 degree range. In terms of 
a real-world application, this would prevent a device from sending superfluous 
data over a network, thereby reducing communication costs.## Further 
examplesThis example demonstrates a small piece of Edgent's functionality. 
Edgent supports more complicated topologies, such as topologies that require 
merging and splitting data streams, or perform operations which aggregate the 
last *N* seconds of data (for example, calculating a moving average).For more 
complex examples, see:* [Edgent sample programs](samples)* [Common Edgent 
operations](common-edgent-operations)"
+"body": "## What is Apache Edgent?Edgent is an open source programming model 
and runtime for edge devices that enables you to analyze streaming data on your 
edge devices. When you analyze on the edge, you can:* Reduce the amount of data 
that you transmit to your analytics server* Reduce the amount of data that you 
storeFor more information, see the [Edgent overview](home).### Apache Edgent 
and streaming analyticsThe fundamental building block of an Edgent application 
is a **stream**: a continuous sequence of tuples (messages, events, sensor 
readings, and so on).The Edgent API provides the ability to process or analyze 
each tuple as it appears on a stream, resulting in a derived stream.Source 
streams are streams that originate data for analysis, such as readings from a 
device's temperature sensor.Streams are terminated using sink functions that 
can perform local device control or send information to centralized analytic 
systems through a message hub.Edgent's primary API is functional
  where streams are sourced, transformed, analyzed or sinked though functions, 
typically represented as lambda expressions, such as `reading -> reading  80` 
to filter temperature readings in Fahrenheit.### Downloading Apache EdgentTo 
use Edgent, access the source code and build it. You can read more about 
building Edgent [here]({{ site.data.project.source_repository_mirror 
}}/blob/master/DEVELOPMENT.md).After you build the Edgent package, you can set 
up your environment.### Setting up your environmentEnsure that you are running 
a supported environment. For more information, see the [Edgent overview](home). 
This guide assumes you're running Java 8.The Edgent Java 8 JAR files are 
located in the `edgent/java8/lib` directory.1. Create a new Java project in 
Eclipse, and specify Java 8 as the execution environment JRE:    2. Modify the 
Java build path to include all of the JAR files in the `edgent\\java8\\lib` 
directory:    Your environment is set up! You can start writing your first Edgen
 t application.## Creating a simple applicationIf you're new to Edgent or to 
writing streaming applications, the best way to get started is to write a 
simple program.Edgent is a framework that pushes data analytics and machine 
learning to *edge devices*. (Edge devices include things like routers, 
gateways, machines, equipment, sensors, appliances, or vehicles that are 
connected to a network.) Edgent enables you to process data locally—such 
as, in a car engine, on an Android phone, or Raspberry Pi—before you send 
data over a network.For example, if your device takes temperature readings from 
a sensor 1,000 times per second, it is more efficient to process the data 
locally and send only interesting or unexpected results over the network. To 
simulate this, let's define a (simulated) TempSensor class:```javaimport 
java.util.Random;import org.apache.edgent.function.Supplier;/** * Every time 
get() is called, TempSensor generates a temperature reading. */public class 
TempSensor 
 implements Supplier {    double currentTemp = 65.0;    Random rand;    
TempSensor(){        rand = new Random();    }    @Override    public Double 
get() {        // Change the current temperature some random amount        
double newTemp = rand.nextGaussian() + currentTemp;        currentTemp = 
newTemp;        return currentTemp;    }}```Every time you call 
`TempSensor.get()`, it returns a new temperature reading. The continuous 
temperature readings are a stream of data that an Edgent application can 
process.Our sample Edgent application processes this stream by filtering the 
data and printing the results. Let's define a TempSensorApplication class for 
the application:```javaimport java.util.concurrent.TimeUnit;import 
org.apache.edgent.providers.direct.DirectProvider;import 
org.apache.edgent.topology.TStream;import 
org.apache.edgent.topology.Topology;public class TempSensorApplication {    
public static void main(String[] args) throws Exception {        TempSensor 
sensor = new TempS
 ensor();        DirectProvider dp = new DirectProvider();        Topology 
topology = dp.newTopology();        TStream tempReadings = 
topology.poll(sensor, 1, TimeUnit.MILLISECONDS);        TStream 
filteredReadings = tempReadings.filter(reading -> reading  80);        
filteredReadings.print();        dp.submit(topology);    }}```To understand how 
the application processes the stream, let's review each line.### Specifying a 
providerYour first step when you write an Edgent application is to create a 
[`DirectProvider`]({{ site.docsurl }}/index.html?org/apache/{{ 
site.data.project.unix_name 
}}/providers/direct/DirectProvider.html):```javaDirectProvider dp = new 
DirectProvider();```A `Provider` is an object that contains information on how 
and where your Edgent application will run. A `DirectProvider` is a type of 
Provider that runs your application directly within the current virtual machine 
when its `submit()` method is called.### Creating a topologyAdditionally a 
Provider is used to cr
 eate a [`Topology`]({{ site.docsurl }}/index.html?org/apache/{{ 
site.data.project.unix_name }}/topology/Topology.html) instance:```javaTopology 
topology = dp.newTopology();```In Edgent, `Topology` is a container that 
describes the structure of your application:* Where the streams in the 
application come from* How the data in the stream is modifiedIn the TempSensor 
application above, we have exactly one data source: the `TempSensor` object. We 
define the source stream by calling `topology.poll()`, which takes both a 
`Supplier` function and a time parameter to indicate how frequently readings 
should be taken. In our case, we read from the sensor every 
millisecond:```javaTStream tempReadings = topology.poll(sensor, 1, 
TimeUnit.MILLISECONDS);```### Defining the `TStream` objectCalling 
`topology.poll()` to define a source stream creates a `TStream` instance, which 
represents the series of readings taken from the temperature sensor.A streaming 
application can run indefinitely, so the `TSt
 ream` might see an arbitrarily large number of readings pass through it. 
Because a `TStream` represents the flow of your data, it supports a number of 
operations which allow you to modify your data.### Filtering a `TStream`In our 
example, we want to filter the stream of temperature readings, and remove any 
\"uninteresting\" or expected readings—specifically readings which are 
above 50 degrees and below 80 degrees. To do this, we call the `TStream`'s 
`filter` method and pass in a function that returns *true* if the data is 
interesting and *false* if the data is uninteresting:```javaTStream 
filteredReadings = tempReadings.filter(reading -> reading  80);```As you can 
see, the function that is passed to `filter` operates on each tuple 
individually. Unlike data streaming frameworks like [Apache 
Spark](https://spark.apache.org/), which operate on a collection of data in 
batch mode, Edgent achieves low latency processing by manipulating each piece 
of data as soon as it becomes availa
 ble. Filtering a `TStream` produces another `TStream` that contains only the 
filtered tuples; for example, the `filteredReadings` stream.### Printing to 
outputWhen our application detects interesting data (data outside of the 
expected parameters), we want to print results. You can do this by calling the 
`TStream.print()` method, which prints using  `.toString()` on each tuple that 
passes through the stream:```javafilteredReadings.print();```Unlike 
`TStream.filter()`, `TStream.print()` does not produce another `TStream`. This 
is because `TStream.print()` is a **sink**, which represents the terminus of a 
stream.In addition to `TStream.print()` there are other sink operations that 
send tuples to an MQTT server, JDBC connection, file, or Kafka cluster. 
Additionally, you can define your own sink by invoking `TStream.sink()` and 
passing in your own function.### Submitting your applicationNow that your 
application has been completely declared, the final step is to run your 
application.`Dir
 ectProvider` contains a `submit()` method, which runs your application 
directly within the current virtual machine:```javadp.submit(topology);```After 
you run your program, you should see output containing only \"interesting\" 
data coming from your 
sensor:```49.90403231177259647.9783750403908446.5927233630903146.68154455165293447.400819234155236...```As
 you can see, all temperatures are outside the 50-80 degree range. In terms of 
a real-world application, this would prevent a device from sending superfluous 
data over a network, thereby reducing communication costs.## Further 
examplesThis example demonstrates a small piece of Edgent's functionality. 
Edgent supports more complicated topologies, such as topologies that require 
merging and splitting data streams, or perform operations which aggregate the 
last *N* seconds of data (for example, calculating a moving average).For more 
complex examples, see:* [Edgent sample programs](samples)* [Common Edgent 
operations](common-edgent-operati
 ons)"
 
 },
 
@@ -146,7 +146,7 @@
 "keywords": "",
 "url": "../docs/quickstart",
 "summary": "",
-"body": "## Edgent to Quickstart quickly!IoT devices running Edgent 
applications typically connect to back-end analytic systems through a message 
hub. Message hubs are used to isolate the back-end system from having to handle 
connections from thousands to millions of devices.An example of such a message 
hub designed for the Internet of Things is [IBM Watson IoT 
Platform](https://internetofthings.ibmcloud.com/). This cloud service runs on 
IBM's Bluemix cloud platformand Edgent provides a [connector]({{ site.docsurl 
}}/latest/index.html?{{ site.data.project.unix_name 
}}/connectors/iotf/IotfDevice.html).You can test out the service without any 
registration by using its Quickstart service and the Edgent sample application: 
[code]({{ site.data.project.source_repository_mirror 
}}/blob/master/samples/connectors/src/main/java/{{ site.data.project.unix_name 
}}/samples/connectors/iotf/IotfQuickstart.java), [Javadoc]({{ site.docsurl 
}}/latest/index.html?{{ site.data.project.unix_name }}/sample
 s/connectors/iotf/IotfQuickstart.html).You can execute the class directly from 
Eclipse, or using the script: 
[`edgent/java8/scripts/connectors/iotf/runiotfquickstart.sh`]({{ 
site.data.project.source_repository_mirror 
}}/blob/master/scripts/connectors/iotf/runiotfquickstart.sh)When run it 
produces output like this, with a URL as the third line.Pointing any browser on 
any machine to that URL takes you to a view of the data coming from the sample 
application. This view is executing in Bluemix, thus the device events from 
this sample are being sent over the public internet to the Quickstart Bluemix 
service.Here's an example view:## Edgent codeThe full source is at: 
[IotfQuickstart.java]({{ site.data.project.source_repository_mirror 
}}/blob/master/samples/connectors/src/main/java/{{ site.data.project.unix_name 
}}/samples/connectors/iotf/IotfQuickstart.java).The first step to is to create 
a `IotDevice` instance that represents the connection to IBM Watson IoT 
Platform Quickstart service.`
 ``java// Declare a connection to IoTF Quickstart serviceString deviceId = 
\"qs\" + Long.toHexString(new Random().nextLong());IotDevice device = 
IotfDevice.quickstart(topology, deviceId);```Now any stream can send device 
events to the Quickstart service by simply calling its `events()` method. Here 
we map a stream of random numbers into JSON as the payload for a device event 
is typically JSON.```javaTStream json = raw.map(v -> {    JsonObject j = new 
JsonObject();    j.addProperty(\"temp\", v[0]);    j.addProperty(\"humidity\", 
v[1]);    j.addProperty(\"objectTemp\", v[2]);    return j;});```Now we have a 
stream of simulated sensor reading events as JSON tuples (`json`) we send them 
as events with event identifer (type) `sensors`  using 
`device`.```javadevice.events(json, \"sensors\", QoS.FIRE_AND_FORGET);```It's 
that simple to send tuples on an Edgent stream to IBM Watson IoT Platform as 
device events."
+"body": "## Edgent to Quickstart quickly!IoT devices running Edgent 
applications typically connect to back-end analytic systems through a message 
hub. Message hubs are used to isolate the back-end system from having to handle 
connections from thousands to millions of devices.An example of such a message 
hub designed for the Internet of Things is [IBM Watson IoT 
Platform](https://internetofthings.ibmcloud.com/). This cloud service runs on 
IBM's Bluemix cloud platformand Edgent provides a [connector]({{ site.docsurl 
}}/index.html?org/apache/{{ site.data.project.unix_name 
}}/connectors/iotp/IotpDevice.html).You can test out the service without any 
registration by using its Quickstart service and the Edgent sample application: 
[code]({{ site.data.project.source_repository_mirror 
}}/blob/master/samples/connectors/src/main/java/org/apache/{{ 
site.data.project.unix_name }}/samples/connectors/iotp/IotpQuickstart.java), 
[Javadoc]({{ site.docsurl }}/index.html?org/apache/{{ site.data.project.
 unix_name }}/samples/connectors/iotp/IotpQuickstart.html).You can execute the 
class directly from Eclipse, or using the script: 
[`edgent/java8/scripts/connectors/iotp/runiotpquickstart.sh`]({{ 
site.data.project.source_repository_mirror 
}}/blob/master/scripts/connectors/iotp/runiotpquickstart.sh)When run it 
produces output like this, with a URL as the third line.Pointing any browser on 
any machine to that URL takes you to a view of the data coming from the sample 
application. This view is executing in Bluemix, thus the device events from 
this sample are being sent over the public internet to the Quickstart Bluemix 
service.Here's an example view:## Edgent codeThe full source is at: 
[IotpQuickstart.java]({{ site.data.project.source_repository_mirror 
}}/blob/master/samples/connectors/src/main/java/org/apache/{{ 
site.data.project.unix_name }}/samples/connectors/iotp/IotpQuickstart.java).The 
first step to is to create a `IotDevice` instance that represents the 
connection to IBM Watson IoT
  Platform Quickstart service.```java// Declare a connection to IoTP Quickstart 
serviceString deviceId = \"qs\" + Long.toHexString(new 
Random().nextLong());IotDevice device = IotpDevice.quickstart(topology, 
deviceId);```Now any stream can send device events to the Quickstart service by 
simply calling its `events()` method. Here we map a stream of random numbers 
into JSON as the payload for a device event is typically JSON.```javaTStream 
json = raw.map(v -> {    JsonObject j = new JsonObject();    
j.addProperty(\"temp\", v[0]);    j.addProperty(\"humidity\", v[1]);    
j.addProperty(\"objectTemp\", v[2]);    return j;});```Now we have a stream of 
simulated sensor reading events as JSON tuples (`json`) we send them as events 
with event identifer (type) `sensors`  using 
`device`.```javadevice.events(json, \"sensors\", QoS.FIRE_AND_FORGET);```It's 
that simple to send tuples on an Edgent stream to IBM Watson IoT Platform as 
device events."
 
 },
 
@@ -159,7 +159,7 @@
 "keywords": "",
 "url": "../recipes/recipe_adaptable_deadtime_filter",
 "summary": "",
-"body": "Oftentimes, an application wants to control the frequency that 
continuously generated analytic results are made available to other parts of 
the application or published to other applications or an event hub.For example, 
an application polls an engine temperature sensor every second and performs 
various analytics on each reading — an analytic result is generated every 
second. By default, the application only wants to publish a (healthy) analytic 
result every 30 minutes. However, under certain conditions, the desire is to 
publish every per-second analytic result.Such a condition may be locally 
detected, such as detecting a sudden rise in the engine temperature or it may 
be as a result of receiving some external command to change the publishing 
frequency.Note this is a different case than simply changing the polling 
frequency for the sensor as doing that would disable local continuous 
monitoring and analysis of the engine temperature.This case needs a *deadtime 
filter* a
 nd Edgent provides one for your use! In contrast to a *deadband filter*, which 
skips tuples based on a deadband value range, a deadtime filter skips tuples 
based on a *deadtime period* following a tuple that is allowed to pass through. 
For example, if the deadtime period is 30 minutes, after allowing a tuple to 
pass, the filter skips any tuples received for the next 30 minutes. The next 
tuple received after that is allowed to pass through, and a new deadtime period 
is begun.See `edgent.analytics.sensors.Filters.deadtime()` (on [GitHub]({{ 
site.data.project.source_repository_mirror 
}}/blob/master/analytics/sensors/src/main/java/{{ site.data.project.unix_name 
}}/analytics/sensors/Filters.java)) and `edgent.analytics.sensors.Deadtime` (on 
[GitHub]({{ site.data.project.source_repository_mirror 
}}/blob/master/analytics/sensors/src/main/java/{{ site.data.project.unix_name 
}}/analytics/sensors/Deadtime.java)).This recipe demonstrates how to use an 
adaptable deadtime filter.An Edgent `IotPr
 ovider` ad `IoTDevice` with its command streams would be a natural way to 
control the application. In this recipe we will just simulate a \"set deadtime 
period\" command stream.## Create a polled sensor readings 
stream```javaTopology top = ...;SimulatedTemperatureSensor tempSensor = new 
SimulatedTemperatureSensor();TStream engineTemp = top.poll(tempSensor, 1, 
TimeUnit.SECONDS)                              .tag(\"engineTemp\");```It's 
also a good practice to add tags to streams to improve the usability of the 
development mode Edgent console.## Create a deadtime filtered 
stream—initially no deadtimeIn this recipe we'll just filter the direct 
``engineTemp`` sensor reading stream. In practice this filtering would be 
performed after some analytics stages and used as the input to 
``IotDevice.event()`` or some other connector publish operation.```javaDeadtime 
deadtime = new Deadtime();TStream deadtimeFilteredEngineTemp = 
engineTemp.filter(deadtime)                              .tag(\
 "deadtimeFilteredEngineTemp\");```## Define a \"set deadtime period\" 
method```javastatic  void setDeadtimePeriod(Deadtime deadtime, long period, 
TimeUnit unit) {    System.out.println(\"Setting deadtime period=\"+period+\" 
\"+unit);    deadtime.setPeriod(period, unit);}```## Process the \"set deadtime 
period\" command streamOur commands are on the ``TStream cmds`` stream. Each 
``JsonObject`` tuple is a command with the properties \"period\" and 
\"unit\".```javacmds.sink(json -> setDeadtimePeriod(deadtimeFilteredEngineTemp, 
   json.getAsJsonPrimitive(\"period\").getAsLong(),    
TimeUnit.valueOf(json.getAsJsonPrimitive(\"unit\").getAsString())));```## The 
final applicationWhen the application is run it will initially print out 
temperature sensor readings every second for 15 seconds—the deadtime 
period is 0. Then every 15 seconds the application will toggle the deadtime 
period between 5 seconds and 0 seconds, resulting in a reduction in tuples 
being printed during the 5 second d
 eadtime period.```javaimport java.util.Date;import 
java.util.concurrent.TimeUnit;import 
java.util.concurrent.atomic.AtomicInteger;import 
com.google.gson.JsonObject;import 
org.apache.edgent.analytics.sensors.Deadtime;import 
org.apache.edgent.console.server.HttpServer;import 
org.apache.edgent.providers.development.DevelopmentProvider;import 
org.apache.edgent.providers.direct.DirectProvider;import 
org.apache.edgent.samples.utils.sensor.SimulatedTemperatureSensor;import 
org.apache.edgent.topology.TStream;import 
org.apache.edgent.topology.Topology;/** * A recipe for using an Adaptable 
Deadtime Filter. */public class AdaptableDeadtimeFilterRecipe {    /**     * 
Poll a temperature sensor to periodically obtain temperature readings.     * 
Create a \"deadtime\" filtered stream: after passing a tuple,     * any

<TRUNCATED>

Reply via email to