In a SARL system, multiple elements are created at run-time, e.g. agents, behaviors, skills, spaces, contexts, etc. Each of these elements is identified by an unique universal identifier (UUID). This ensures that the identifiers are unique all the time.
Having access to the SARL elements above in a almost generic way is sometimes needed. For example, if you would like to observe the values of the fields of an agent, you need first to refer to the agent itself.
In order to help the SARL developers to do this referring, a generic and common API is defined for naming the SARL elements. This naming API is used by the namespace service in order to retrieve and reply the instances of the referred elements.
Basically the naming of the SARL element following the international standards of the Universal Resource Identifiers, or URI in short.
An URI is a string of characters that unambiguously identifies a particular resource. To guarantee uniformity, all URIs follow a predefined set of syntax rules. Such identification enables interaction with representations of the resource over a system or a network (typically the World Wide Web), using specific schemes.
Each URI following the general following format (where parts between brackets are optional):
scheme:[//authority]path[?query][#fragment]
The URI generic syntax consists of a hierarchical sequence of five components:
:
), consisting of a sequence of characters beginning with a letter and followed by any combination of letters, digits, plus (+
), period (.
), or hyphen (-
). The scheme name refers to a specification for assigning identifiers within that scheme.//
) that specifies the user information to use to be connected to the referred resource./
). A path is always defined for a URI, though the defined path may be empty (zero length). A segment may also be empty, resulting in two consecutive slashes (//
) in the path component.?
), containing a query string of non-hierarchical data. Its syntax is not well defined, but by convention is most often a sequence of attribute–value pairs separated by a delimiter.#
). The fragment contains a fragment identifier providing direction to a secondary resource, such as a section heading in an article identified by the remainder of the URI.This general URI syntax is refined in order to refer the SARL components.
Each agent may be referred by an URI-based name in which the scheme is always agent
. There is neither authority nor query part in the agent name.
The path of the agent name specifies the identification of the agent. You could refer an agent in three ways:
agent:a7fbd4cc-9e1a-48c3-8ee8-3a7974ccb05c
.agent:b9e6dcbc-d878-441d-afa1-35715950e22d/a7fbd4cc-9e1a-48c3-8ee8-3a7974ccb05c
.agent:b9e6dcbc-d878-441d-afa1-35715950e22d/0bec6efd-12b1-4394-8e34-1b56e6b99c5c/a7fbd4cc-9e1a-48c3-8ee8-3a7974ccb05c
.Where, b9e6dcbc-d878-441d-afa1-35715950e22d
is the context identifier, 0bec6efd-12b1-4394-8e34-1b56e6b99c5c
is the space identifier, and
a7fbd4cc-9e1a-48c3-8ee8-3a7974ccb05c
is the agent identifier.
The fragment part is the name of an attribute/field that is declared into the referred agent. If the fragment part is specified, then the URI refers to the field itself.
The general syntax of the agent names is defined by the following BNF grammar:
AGENT_NAME = "agent:" <ODSL> <CTX> <UUID> <FRG>
ODSL = "/" OSL | <empty>
OSL = "/" | <empty>
CTX = <UUID> "/" SPC | <empty>
SPC = <UUID> "/" | <empty>
FRG = "#" <ID> | <empty>
Each behavior of an agent may be referred by an URI-based name in which the scheme is always behavior
. There is neither authority nor query part in the behavior name.
The path of the behavior name specifies the identification of the behavior. A behavior is always attached to an agent. That’s why, the agent identifier is mandatory in all cases. Consequently, for each of the three cases for referring an agent, two cases are defined for referring a behavior of those agent:
behavior:a7fbd4cc-9e1a-48c3-8ee8-3a7974ccb05c/mypackage.MyBehavior
. If the agent has multiple instance of the behavior, the first one is considered.behavior:a7fbd4cc-9e1a-48c3-8ee8-3a7974ccb05c/mypackage.MyBehavior/1
.Where, a7fbd4cc-9e1a-48c3-8ee8-3a7974ccb05c
is the agent identifier.
mypackage.MyBehavior
is the fully qualified name of the behavior type to refer. It must be a sub-type of the io.sarl.lang.core.Behavior
type that is defined into the SARL API.
The fragment part is the name of an attribute/field that is declared into the referred behavior. If the fragment part is specified, then the URI refers to the field itself.
The general syntax of the behavior names is defined by the following BNF grammar (BNF rules in the previous section are re-used):
BEHAVIOR_NAME = "behavior:" <ODSL> <CTX> <UUID> "/" <ID> <IDX> <FRG>
IDX = "/" <INTEGER> | <empty>
Each skill of an agent may be referred by an URI-based name in which the scheme is always skill
. There is neither authority nor query part in the skill name.
The path of the skill name specifies the identification of the skill. A skill is always attached to an agent. That’s why, the agent identifier is mandatory in all cases. Moreover, a capacity must be implemented by only one skill within an agent. But a skill may implement multiple caapcities. Consequently, for each of the three cases for referring an agent, one case is defined for referring a skill of those agent:
skill:a7fbd4cc-9e1a-48c3-8ee8-3a7974ccb05c/mypackage.MyCapacity
.Where, a7fbd4cc-9e1a-48c3-8ee8-3a7974ccb05c
is the agent identifier.
mypackage.MyCapacity
is the fully qualified name of the capacity type that is implemented by the skill to refer. It must be a sub-type of the io.sarl.lang.core.Capacity
type that is defined into the SARL API.
The fragment part is the name of an attribute/field that is declared into the referred skill. If the fragment part is specified, then the URI refers to the field itself.
The general syntax of the skill names is defined by the following BNF grammar (BNF rules in the previous sections are re-used):
SKILL_NAME = "skill:" <ODSL> <CTX> <SPC> <UUID> "/" <ID> <FRG>
Each agent context may be referred by an URI-based name in which the scheme is always context
. There is neither authority nor query part in the context name.
The path of the context name specifies the identification of the context. You could refer a context as:
context:b9e6dcbc-d878-441d-afa1-35715950e22d
.Where, b9e6dcbc-d878-441d-afa1-35715950e22d
is the context identifier.
The fragment part is the name of an attribute/field that is declared into the referred context. If the fragment part is specified, then the URI refers to the field itself.
The general syntax of the agent names is defined by the following BNF grammar (BNF rules in the previous section are re-used):
CONTEXT_NAME = "context:" <ODSL> <UUID> <FRG>
Each space within a context may be referred by an URI-based name in which the scheme is always space
. There is neither authority nor query part in the space name.
The path of the space name specifies the identification of the space. A space is always defined into a context. That’s why, the context identifier is mandatory in all cases. Consequently, for each of the cases for referring a context, you could refer a space as:
space:b9e6dcbc-d878-441d-afa1-35715950e22d/0bec6efd-12b1-4394-8e34-1b56e6b99c5c
.Where, b9e6dcbc-d878-441d-afa1-35715950e22d
is the context identifier, and 0bec6efd-12b1-4394-8e34-1b56e6b99c5c
is the space identifier.
The fragment part is the name of an attribute/field that is declared into the referred space. If the fragment part is specified, then the URI refers to the field itself.
The general syntax of the space names is defined by the following BNF grammar (BNF rules in the previous section are re-used):
SPACE_NAME = "space:" <ODSL> <UUID> "/" <UUID> <FRG>
A SRE may implement services. Each service may be referred by an URI-based name in which the scheme is always service
.
There is neither authority nor query part in the service name.
The path of the service name specifies the identification of the service, i.e. its fully qualified name. You could refer a service with:
service:mypackage.MyService
.Where, mypackage.MyService
is the fully qualified name of the object interface that describes the service.
The fragment part is the name of an attribute/field that is declared into the referred service. If the fragment part is specified, then the URI refers to the field itself.
The general syntax of the service names is defined by the following BNF grammar (BNF rules in the previous section are re-used):
SERVICE_NAME = "service:" <ODSL> <ID> <FRG>
According to the Agent&Artifact metamodel, an artifact in a multi-agent system is a component of the agent environment
Each artifact may be referred by an URI-based name in which the scheme is always artifact
.
There is neither authority nor query part in the service name.
Please note that because the concept of artifact is not related to the agent society directly, the underlying SRE may
not provide a support for it.
The path of the artifact name specifies the identification of the artifact, i.e. its identifier. You could refer a artifact with:
artifact:37b13185-a9d5-43e5-9d7b-da2fa3ba3d54
.Where, 37b13185-a9d5-43e5-9d7b-da2fa3ba3d54
is the identifier of the artifact.
The fragment part is the name of an attribute/field that is declared into the referred artifact. If the fragment part is specified, then the URI refers to the field itself.
The general syntax of the service names is defined by the following BNF grammar (BNF rules in the previous section are re-used):
ARTIFACT_NAME = "artifact:" <ODSL> <UUID> <FRG>
A protocol is the specification of interactions between agents. When agents are running a given protocol, the interaction are supported by a protocol instance dedicated to the protocol and the participants. Please note that because the concept of protocol is not related to the agent definition itself, the underlying SRE may not provide a support for it.
The path of the protocol name specifies the identification of the protocol instance, i.e. its identifier. You could refer a protocol instance with:
protocol:37b13185-a9d5-43e5-9d7b-da2fa3ba3d54
.Where, 37b13185-a9d5-43e5-9d7b-da2fa3ba3d54
is the identifier of the protocol instance.
The general syntax of the service names is defined by the following BNF grammar (BNF rules in the previous section are re-used):
PROTOCOL_NAME = "protocol:" <ODSL> <UUID>
According to the public API of the SRE, it is possible to retrieve a service that is implemented and executed by the SRE. A service dedicated to finding SARL elements into the SRE environment based on their names is defined into the SARL API. It is named the Namespace service.
The role of the Namespace service is to search for a SARL element based on a given name (as defined above). This service explores the entire content of the SRE in order to find the requested element. If an object that is corresponding to the given name is found, then the Namespace service replies the found object, or an accessor to its field if a fragment part was specified into the given name.
The Namespace service is defined as:
interface NamespaceService {
def findObject(SarlName) : Object
def findObject(SarlName, Class<T>) : T with T
def findObject(String) : Object
def findObject(String, Class<T>) : T with T
def findObject(URI) : Object
def findObject(URI, Class<T>) : T with T
def getFieldAccessValidator : IFieldAccessValidator
def getNameParser : INameParser
}
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:
var bootstrap = SRE::getBootstrap
var namingService = bootstrap.getService(typeof(NamespaceService))
var theAgent = namingService.findObject("agent:a7fbd4cc-9e1a-48c3-8ee8-3a7974ccb05c")
In the case the given name targets a field (when it has a fragment part), the Namespace service create
a specific proxy of type FieldAccess
in order to have access to the field.
This type is defined as:
class FieldAccess {
def get : Object
def getField : Field
def getInstance : Object
def getName : SarlName
def isWritable : boolean
def set(Object) : Object
def toString : String
}
This accessor type enables to have access to the object instance and to the field value.
However, the instance of FieldAccess
is provided only if the field is observable.
Observation means that data or information could be extracted from the observed object. Because an agent is defined as an autonomous entity, the agent should be able to enable or disable the access to one of its fields.
In the standard SRE, this observability flag could be defined statically by annotating the obsevable field,
or one of its enclosing type, with the @Observable
annotation.
A second standard method is to implement a dedicated agent skill implementing the capacity FieldAccessValidationCapacity
that enables the agent to manage the access rights to its fields dynamically.
By default, into the SRE, the algorithm for checking the field access from an invoking entity is:
@Observable
annotation then
FieldAccessValidationCapacity
skill then
In the following example, two fields are defined for the agent MyAgent
.
The first field is named observableField
and it is marked as observable because it is annotated with @Observable
.
The second field is named notObservableField
and it is not observable.
agent MyAgent {
@Observable
var observableField : int
var notObservableField : int
}
Consequently, even if the field notObservableField
is declared, it will never be found by the Namespace space because it is hidden.
As described above, the @Observable
annotation could be attached to one of the enclosing type in order to mark all the
declared fields within a type as observable.
In the following example, the two fields observableField1
and observableField2
are observable because the type MyAgent2
is marked with the @Observable
annotation.
@Observable
agent MyAgent2 {
var observableField1 : int
var observableField2 : int
}
In order to enable an agent to manage the accesses to its own fields, you could equip this agent with a skill that implements
the FieldAccessValidationCapacity
capacity:
capacity FieldAccessValidationCapacity {
def getFieldAccessRight(Field) : FieldAccessRight
}
When an agent owns a skill implementing FieldAccessValidationCapacity
, this skill is included into the right checking for accessing to
the fields of the agent, its behaviors and its skills.
Let the agent implementation below:
agent MyAgent {
var field1 : int
var field2 : int
on Initialize {
setSkill(new AccessRightSkill)
}
}
In this agent, two fields are defined and named field1
and field2
.
We equip the agent with the AccessRightSkill
skill that implements the FieldAccessValidationCapacity
capacity:
skill AccessRightSkill implements FieldAccessValidationCapacity {
def getFieldAccessRight(field : Field) : FieldAccessRight {
if (field.name == "field1") {
return FieldAccessRight::READ
}
if (field.name == "field2") {
return FieldAccessRight::WRITE
}
return FieldAccessRight::NONE
}
}
This skill gives the reading access to the field field1
, and the reading/writing accesses to the field field2
.
Any other field cannot be observed.
Three levels of obersavility are defined into the enumeration FieldAccessRight
:
NONE
The field cannot be observed.READ
The field’s value could be read, but never changed from the outside of the agent.WRITE
The field’s value could be read and/or write from the outside of the agent.Copyright © 2014-2024 SARL.io, the Original Authors and Main Authors.
Documentation text and medias are licensed under the Creative Common CC-BY-SA-4.0; you may not use this file except in compliance with CC-BY-SA-4.0. You may obtain a copy of CC-BY-4.0.
Examples of SARL code are licensed under the Apache License, Version 2.0; you may not use this file except in compliance with the Apache License. You may obtain a copy of the Apache License.
You are free to reproduce the content of this page on copyleft websites such as Wikipedia.
Generated with the translator docs.generator 0.14.0.