Skip to content

Commit

Permalink
[docs] Add documentation on the proving API.
Browse files Browse the repository at this point in the history
see #756

Signed-off-by: Stéphane Galland <galland@arakhne.org>
  • Loading branch information
gallandarakhneorg committed Aug 20, 2020
1 parent bd6f1b4 commit 149e0e4
Show file tree
Hide file tree
Showing 8 changed files with 293 additions and 27 deletions.
Expand Up @@ -167,7 +167,8 @@ The Namespace service is defined as:

[:ShowType:](io.sarl.api.naming.namespace.NamespaceService)

The functions `findObject` search for an object based on the given name (whatever it is an object of type `SarlName` representing the super-type of all the names, or a string representation of the URI).
The functions `findObject` search for an object based on the given name (whatever it is an object of type
`SarlName` representing the super-type of all the names, an URI, or a string representation of an URI).

To use this service, you have to get it from the SRE, as illustrated below:

Expand All @@ -179,7 +180,7 @@ To use this service, you have to get it from the SRE, as illustrated below:
static def main(arguments : String*) {
[:On]
var bootstrap = SRE::getBootstrap
var namingService = boostrap.getService(typeof(NamespaceService))
var namingService = bootstrap.getService(typeof(NamespaceService))
var theAgent = namingService.findObject("agent:a7fbd4cc-9e1a-48c3-8ee8-3a7974ccb05c")
[:Off]
}
Expand Down
137 changes: 137 additions & 0 deletions docs/io.sarl.docs.markdown/src/main/documentation/api/Probing.md
@@ -0,0 +1,137 @@
# SRE Observing and Probes

[:Outline:]

The multi-agent system is composed of multiple elements, including agents, behaviors, contexts and spaces, but not limited to.
Organizational models in multi-agent systems usually position agents as actors-observers within environments shared
by multiple agents and organizational structures at different levels of granularity.
Then, the agents may have the capacity to observe the environment and the other agents, without directly interacting
with them. The observing agent is able to extract information from another agent or from a society of agents, that could be opaque
according to a possible holonic architecture of the system.

Observation means that data or information could be extracted from the observed object without filtering from this latter.
The observer is not intrusive from the agent point of view. In other words, the observed agent has no knowledge about the fact it
is observed or not. In this case, it cannot adapt its behavior on its observation status.

Because an agent is defined as an autonomous entity, the agent is supposed to be enabled to specify if a part of itself
is observable or not, i.e. to specify the access rights.

<caution>The right access management is not yet supported by the SARL API</caution>

## What is Observable?

The first question arising when considering the concept of observable multi-agent system is: what is observable?

Any object within the multi-agent system that could be referred with a name is possibly subject of an observation.
The objects are referred according to a [specific naming convention](./Naming.md).

Because observation is related to data extraction, only fields could be observed at the concrete level.
Consequently, the observable objects a the fields declared within an:
* agent
* behavior
* skill
* agent context
* space
* service

## Probe: generic observer implementation

### General Principles

A probe is an implementation of the proxy and observer software design patterns for observable multi-agent system.
It is a software tool that extracts the data from the observed object and provide the data to the observer.
Since a probe is a proxy, it filters the interaction from the observer to the observed object by enabling the first
only to get the data (no other function declared into the observed object is accessible).
The implementation of a probe ensures that it is not intrusive to the observed object.

The observer has to create a probe on a field of the observable object (agent, behavior, etc.).
Then, the probe could be read to obtain the data, or the observer could be notified each time the data has changed
(according to the observer software design pattern).

### Concrete Definition

A probe is defined as:

[:ShowType:](io.sarl.api.probing.Probe)

The functions are:
* `getName`: Reply the name of the probe, that is constant.
* `getUri`: Reply the URI of the observed object.
* `getValue` : Reply the observed value.
* `getType` : Reply the type of the observed value.
* `sync`: Force the synchronization of the observed value.
* `release`: Release any resource associated to the probe.
* `isActive`: Reply if this probe is active. When a probe is active, it could be synchronized to the observed object.
* `isInvalid`: Reply if this probe is invalid. When a probe is invalid, the value replied by `getValue` may not corresponds to the observed element's value.

The following functions are provided for convenience, but they should be used with caution:
* `setValue`: Force the observed field to have a specific value (brokes the agent's autonomy)

### Observe the Probe

The observer software design pattern that enables to be notified when the observed value changed in implemented into the probe.
According to the standard implementation best practices of the Java programming language, an observer (in this design pattern)
is named a listener, and it defined by an interface. Two types of observers are defined on probes: [:probelistener:]
and [:probereleaselistener:].

[:probelistener:] is defined as:

[:ShowType:](io.sarl.api.probing.[:probelistener]$IProbeListener$)

It corresponds to the observer on value changes.


[:probereleaselistener:] is defined as:

[:ShowType:](io.sarl.api.probing.[:probereleaselistener]$IProbeReleaseListener$)

It corresponds to the observer on the release of a probe.


The functions `addProbeListener`, `addProbeReleaseListener`, `removeProbeListener` and `removeProbeReleaseListener` enable to (un)register an event listener on the probe.


## Probing Service

In order to manage and run the different probes, the SRE must implement a dedicated service: the [:probeservicename:].
It is defined as:

[:ShowType:](io.sarl.api.probing.[:probeservicename]$ProbeService$)


Creating a probe is done by calling the `probe` function. Basically, you need to specify the [name](./Naming.md) of the
observed field, the expected type of the value, and optionally the name of the probe.

From the probe service, you could force the synchronization of all the managed probes by calling the `sync` function.

Finally, two functions are provided from retrieving the list of the managed probes `getProbes` and releasing all
the probes `releaseAllProbes`.

To use this service, you have to get it from the SRE, as illustrated below:

[:Success:]
package io.sarl.docs.namespace
import io.sarl.bootstrap.SRE
import io.sarl.api.probing.ProbeService
class MyProgram {
static def main(arguments : String*) {
[:On]
var bootstrap = SRE::getBootstrap
var probeService = bootstrap.getService(typeof(ProbeService))
var probe = probeService.probe("agent:[:agentid]$a7fbd4cc-9e1a-48c3-8ee8-3a7974ccb05c$#[:emergencyfield]$emergency$", typeof([:fieldtype]$Integer$), "[:probename]$My Probe$")
while (true) {
System.out.println("Probe: " + probe.value)
}
[:Off]
}
}
[:End:]

In this example, the probe service is obtained from the SRE.
An probe is attached to the field named [:emergencyfield:] of type [:fieldtype:] that is defined within the agent [:agentid:].
The name [:probename:] is given to the probe.
The example loops for displaying the observed value (of course it is not the most efficient usage of a probe).


[:Include:](../legal.inc)

36 changes: 18 additions & 18 deletions docs/io.sarl.docs.markdown/src/main/documentation/api/SRE.md
Expand Up @@ -97,7 +97,7 @@ For starting the SRE without agent, you have to invoke [:startWithoutAgentFct:]:
static def main(arguments : String*) {
[:On]
var bootstrap = SRE::getBootstrap
var context = boostrap.[:startWithoutAgentFct](startWithoutAgent)
var context = bootstrap.[:startWithoutAgentFct](startWithoutAgent)
[:Off]
}
}
Expand All @@ -119,7 +119,7 @@ Both of them are launching an agent of a given type. For example, the following
static def main(arguments : String*) {
[:On]
var bootstrap = SRE::getBootstrap
var context = boostrap.[:startAgentFct](startAgent)(typeof([:myagent!]))
bootstrap.[:startAgentFct](startAgent)(typeof([:myagent!]))
[:Off]
}
}
Expand All @@ -136,7 +136,7 @@ In the following example, [:numberofagents!] agents are launched into the SRE.
static def main(arguments : String*) {
[:On]
var bootstrap = SRE::getBootstrap
var context = boostrap.startAgent([:numberofagents](5), typeof([:myagent!]))
bootstrap.startAgent([:numberofagents](5), typeof([:myagent!]))
[:Off]
}
}
Expand All @@ -155,8 +155,8 @@ precision floating point number [:param2:].
static def main(arguments : String*) {
[:On]
var bootstrap = SRE::getBootstrap
var context = boostrap.startAgent([:numberofagents](5), typeof([:myagent!]), [:param1]("arg1"), [:param2](4.5))
[:Off]
bootstrap.startAgent(typeof([:myagent!]), [:param1]$"arg1"$, [:param2]$4.5$)
[:Off]
}
}
[:End:]
Expand Down Expand Up @@ -195,7 +195,7 @@ This function enables to pass initialization arguments to the launched agent.
[:On]
var theIdentifier : UUID = computeOrGetTheAgentIdentifier()
var bootstrap = SRE::getBootstrap
boostrap.[:startAgentWithIDFct](startAgentWithID)(typeof([:myagent!]), theIdentifier)
bootstrap.[:startAgentWithIDFct](startAgentWithID)(typeof([:myagent!]), theIdentifier)
[:Off]
}
}
Expand Down Expand Up @@ -234,12 +234,12 @@ the SRE is stopping. The following code shows you the start and stop of the SRE.
[:Success:]
package io.sarl.docs.bootstrap
import io.sarl.bootstrap.SRE
agent [:MyAgent!] {}
agent [:myagent!] {}
class MyProgram {
static def main(arguments : String*) {
[:On]
var bootstrap = SRE::getBootstrap
boostrap.startAgent([:numberofagents!], typeof([:myagent!]))
bootstrap.startAgent([:numberofagents!], typeof([:myagent!]))
bootstrap.[:shutdownFct](shutdown)
[:Off]
}
Expand All @@ -253,12 +253,12 @@ In the following example, we are waiting 15 seconds for stopping the SRE.
[:Success:]
package io.sarl.docs.bootstrap
import io.sarl.bootstrap.SRE
agent [:MyAgent!] {}
agent [:myagent!] {}
class MyProgram {
static def main(arguments : String*) {
[:On]
var bootstrap = SRE::getBootstrap
boostrap.startAgent([:numberofagents!], typeof([:myagent!]))
bootstrap.startAgent([:numberofagents!], typeof([:myagent!]))
bootstrap.[:shutdownFct](shutdown)(1500)
[:Off]
}
Expand Down Expand Up @@ -290,13 +290,13 @@ The following functions are provided on the SRE bootstrap to change the SRE conf
class MyProgram {
static def main(arguments : String*) {
var bootstrap = SRE::getBootstrap
bootstrap.[:setRandomContextUUID](setRandomContextUUID)
bootstrap.[:setBootAgentTypeContextUUID](setBootAgentTypeContextUUID)
bootstrap.[:setSpecificContextUUID](setSpecificContextUUID)
bootstrap.[:setUniverseContextUUID](setUniverseContextUUID)(UUID:randomUUID)
var id0 : UUID = bootstrap.[:getUniverseContextUUID](getUniverseContextUUID)
bootstrap.[:setUniverseSpaceUUID](setUniverseSpaceUUID)(UUID:randomUUID)
var id1 : UUID = bootstrap.[:getUniverseSpaceUUID](getUniverseSpaceUUID)
bootstrap.[:setRandomContextUUID]$setRandomContextUUID$
bootstrap.[:setBootAgentTypeContextUUID]$setBootAgentTypeContextUUID$
bootstrap.[:setSpecificContextUUID]$setSpecificContextUUID$
bootstrap.[:setUniverseContextUUID]$setUniverseContextUUID$(UUID::randomUUID)
var id0 : UUID = bootstrap.[:getUniverseContextUUID]$getUniverseContextUUID$
bootstrap.[:setUniverseSpaceUUID]$setUniverseSpaceUUID$(UUID::randomUUID)
var id1 : UUID = bootstrap.[:getUniverseSpaceUUID]$getUniverseSpaceUUID$
}
}
[:End:]
Expand Down Expand Up @@ -333,7 +333,7 @@ You could control in a generic way the verbose level of the kernel logger by cal
class MyProgram {
static def main(arguments : String*) {
[:On]
var [bootstrap = [:sre](SRE)::getBootstrap
var bootstrap = SRE::getBootstrap
bootstrap.[:setVerboseLevelFct](setVerboseLevel)(2)
[:Off]
}
Expand Down
1 change: 1 addition & 0 deletions docs/io.sarl.docs.markdown/src/main/documentation/index.md
Expand Up @@ -94,6 +94,7 @@

* [Programmatic Access to the SARL Run-time Environment](./api/SRE.md)
* [Naming and Namespaces](./api/Naming.md)
* [SRe Observation and Probes](./api/Probing.md)

## Compilation and Generation Infrastructure

Expand Down
Expand Up @@ -23,6 +23,7 @@ package io.sarl.api.naming.namespace
import com.google.common.util.concurrent.Service
import io.sarl.api.naming.name.SarlName
import io.sarl.api.naming.parser.INameParser
import java.net.URI

/**
* This service enables to manage the name spaces into the SRE.
Expand Down Expand Up @@ -110,4 +111,40 @@ interface NamespaceService extends Service {
return findObject(sarlName)
}

/**
* Finds and replies the object with the given name and of the given type.
*
* @param name the name of the object. See the documentation of {@link NamespaceService}
* for details.
* @return the root context. A {@code null} value is replied if the object is not found.
* @since 0.12
*/
@Pure
def findObject(name : URI, type : Class<T>) : T with T {
var parser = this.nameParser
var sarlName = parser.decode(name)
if (sarlName === null) {
return null
}
return findObject(sarlName, type)
}

/**
* Finds and replies the object with the given name and of the given type.
*
* @param name the name of the object. See the documentation of {@link NamespaceService}
* for details.
* @return the object with the given name. A {@code null} value is replied if the object is not found.
* @since 0.12
*/
@Pure
def findObject(name : URI) : Object {
var parser = this.nameParser
var sarlName = parser.decode(name)
if (sarlName === null) {
return null
}
return findObject(sarlName)
}

}
Expand Up @@ -27,6 +27,7 @@
import java.io.IOException;
import java.io.Reader;
import java.lang.ref.WeakReference;
import java.lang.reflect.TypeVariable;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collection;
Expand Down Expand Up @@ -2652,9 +2653,26 @@ public String passThrough(ParsingContext context, String dynamicTag, String para
return ""; //$NON-NLS-1$
}

private void appendGenericTypes(StringBuilder it, Class<?> type) {
if (type.getTypeParameters() != null && type.getTypeParameters().length > 0) {
it.append("<"); //$NON-NLS-1$
boolean first = true;
for (final TypeVariable<?> genType : type.getTypeParameters()) {
if (first) {
first = false;
} else {
it.append(", ");
}
it.append(genType.getName());
}
it.append(">"); //$NON-NLS-1$
}
}

private String extractInterface(Class<?> type) {
final StringBuilder it = new StringBuilder();
it.append("interface ").append(type.getSimpleName()); //$NON-NLS-1$
appendGenericTypes(it, type);
if (type.getSuperclass() != null && !Object.class.equals(type.getSuperclass())) {
it.append(" extends ").append(type.getSuperclass().getSimpleName()); //$NON-NLS-1$
}
Expand All @@ -2677,7 +2695,7 @@ private String extractEnumeration(Class<?> type) {

private String extractAnnotation(Class<?> type) {
final StringBuilder it = new StringBuilder();
it.append("interface ").append(type.getSimpleName()); //$NON-NLS-1$
it.append("annotation ").append(type.getSimpleName()); //$NON-NLS-1$
it.append(" {\n"); //$NON-NLS-1$
ReflectExtensions.appendPublicMethods(it, true, type);
it.append("}"); //$NON-NLS-1$
Expand All @@ -2686,7 +2704,8 @@ private String extractAnnotation(Class<?> type) {

private String extractClass(Class<?> type) {
final StringBuilder it = new StringBuilder();
it.append("interface ").append(type.getSimpleName()); //$NON-NLS-1$
it.append("class ").append(type.getSimpleName()); //$NON-NLS-1$
appendGenericTypes(it, type);
if (type.getSuperclass() != null && !Object.class.equals(type.getSuperclass())) {
it.append(" extends ").append(type.getSuperclass().getSimpleName()); //$NON-NLS-1$
}
Expand Down

0 comments on commit 149e0e4

Please sign in to comment.