Skip to content

Commit

Permalink
[core][sre][docs] Add scope parameter to the wake function.
Browse files Browse the repository at this point in the history
see #516

Signed-off-by: Stéphane Galland <galland@arakhne.org>
  • Loading branch information
gallandarakhneorg committed Nov 22, 2016
1 parent c8860d5 commit 3e69bfb
Show file tree
Hide file tree
Showing 7 changed files with 341 additions and 113 deletions.
Expand Up @@ -1279,30 +1279,38 @@ describe "Built-in Capacity Reference" {
* to wake it with an event. This particular feature is
* supported by:
*
* def wake(evt : Event)
* def wake(evt : Event, scope : Scope<Address> = null)
*
*
* <p>This function emits the given event into the inner context
* of the agent (in the default space).
*
* <importantnote> It is not
* possible to execute a particular behavior explicitly.
* All the behaviors that are waiting for a given event will
* be executed by this function.</importantnote>
* <p>If a scope is provided, it is used for filtering the agents that will
* receive the event. The filterable agents are the current agent itself, and
* all the sub-agents (sub-holons) that were created inside the current agent.
*
* <importantnote>Because a behavior has no associated address, it cannot be
* filtered by the scope. All the agent's behaviors that are waiting for a given event will
* be executed.</importantnote>
*
* @filter(.*)
*/
fact "Executing a Behavior"{
" package io.sarl.docs.reference.bic
import io.sarl.core.Behaviors
import io.sarl.lang.core.Event
import io.sarl.lang.core.Scope
import io.sarl.lang.core.Address
event E
agent A {
uses Behaviors
def myaction {
var e : Event
e = new E
wake(e)
wake(e, null)
var scope : Scope<Address> = null
wake(e, scope)
}
}".parseSuccessfully
}
Expand Down
Expand Up @@ -1786,20 +1786,44 @@ describe "Creating a SARL Run-time Environment for the tinyMAS platform"{
* Its implementation retrieves the SARL event listener of the agent by calling
* the `asEventListener` function. And, it invokes the receiving function of
* the listener with the event as argument.
*
* <p>If a scope is provided, it must be used for filtering the receivers which have
* an address. In the context of the tinyMAS platform, only the agent fits this requirement.
* Consequently, the scope is matched against the agent's address in its internal context
* (not the agent's address in the default space of its default context).
* The `getInnerAddress` function computes the agent's address in the agent internal context.
*
* @filter(.* = '''|'''|.parseSuccessfully.*)
*/
fact "Waking the behaviors with an event" {
'''
def wake(^event : Event) {
asEventListener.receiveEvent(^event)
def wake(^event : Event, scope : Scope<Address> = null) {
if (scope === null || scope.matches(innerAddress)) {
asEventListener.receiveEvent(^event)
}
}
private def getInnerAddress : Address {
var id = (owner as TMSarlAgent).ID
return new Address(
new SpaceID(id, UUID.randomUUID, typeof(EventSpaceSpecification)),
id)
}
'''.parseSuccessfully(
'''
package io.sarl.docs.tutorials.tinyMASSRE
import java.util.UUID
import io.sarl.lang.core.Event
import io.sarl.lang.core.EventSpaceSpecification
import io.sarl.lang.core.Scope
import io.sarl.lang.core.Address
import io.sarl.lang.core.SpaceID
import io.sarl.core.Behaviors
interface TMSarlAgent {
def getID : UUID
}
abstract class BehaviorsSkill implements Behaviors {
def getOwner : io.sarl.lang.core.Agent
''',
// TEXT
'''
Expand Down
11 changes: 10 additions & 1 deletion eclipse-sarl/plugins/io.sarl.core/src/io/sarl/core/bic.sarl
Expand Up @@ -23,6 +23,7 @@ package io.sarl.core
import java.text.MessageFormat
import java.util.UUID
import java.util.concurrent.TimeUnit
import java.util.Collection

import io.sarl.core.AgentTask
import io.sarl.lang.core.EventSpace
Expand Down Expand Up @@ -249,9 +250,16 @@ capacity Behaviors {
/**
* Wake the agent's behaviors reacting to the Event evt.
*
* <p>Note that the scope parameter could be used only for filtering the agents (the current agent and its sub-agents)
* in order to determine the ones that will receive the event.
* The behaviors of the current agent (registered with {@link #registerBehavior(Behavior)} will always
* receive the event if the current agent is not discarded. Indeed, because the behaviors have no associated address,
* they cannot be filtered individually.
*
* @param event the event to emit to the agent's behaviors and in the internal context.
* @param scope the definition of the scope that will be used for selected the receivers of the events.
*/
def wake(^event : Event)
def wake(^event : Event, scope : Scope<Address> = null)

/**
* Replies the interface to dispatch an event to agent's Behaviors.
Expand All @@ -260,6 +268,7 @@ capacity Behaviors {
*/
@Pure
def asEventListener : EventListener

}

/**
Expand Down
10 changes: 6 additions & 4 deletions eclipse-sarl/plugins/io.sarl.util/src/io/sarl/util/Scopes.java
Expand Up @@ -34,6 +34,8 @@
*/
public final class Scopes {

private static final Scope<?> ALL = new AlwaysTrueScope();

private Scopes() {
//
}
Expand All @@ -44,8 +46,9 @@ private Scopes() {
* @param <T> - type of the elements in the scope.
* @return the scope that corresponds to all.
*/
@SuppressWarnings("unchecked")
public static <T> Scope<T> allParticipants() {
return new AlwaysTrueScope<>();
return (Scope<T>) ALL;
}

/** Create an scope restricted to the given addresses.
Expand All @@ -59,13 +62,12 @@ public static Scope<Address> addresses(Address... addresses) {

/** A scope that is matching all the elements.
*
* @param <T> - the type of the elements to match to.
* @author $Author: sgalland$
* @version $FullVersion$
* @mavengroupid $GroupId$
* @mavenartifactid $ArtifactId$
*/
private static class AlwaysTrueScope<T> implements Scope<T> {
private static class AlwaysTrueScope implements Scope<Object> {

private static final long serialVersionUID = -3193147362292037L;

Expand All @@ -79,7 +81,7 @@ public String toString() {
}

@Override
public boolean matches(T element) {
public boolean matches(Object element) {
return true;
}

Expand Down
Expand Up @@ -29,6 +29,7 @@
import io.sarl.lang.core.Event;
import io.sarl.lang.core.EventListener;
import io.sarl.lang.core.EventSpace;
import io.sarl.lang.core.Scope;

/**
* Janus implementation of SARL's {@link Behaviors} built-in capacity.
Expand Down Expand Up @@ -76,7 +77,12 @@ public synchronized Behavior unregisterBehavior(Behavior attitude) {
}

@Override
public synchronized void wake(Event evt) {
public void wake(Event evt) {
wake(evt, $DEFAULT_VALUE$WAKE_0);
}

@Override
public synchronized void wake(Event evt, Scope<Address> scope) {
// Use the inner space so all behaviors (even agents inside the holon
// running in distant kernels) are notified. The event will return into
// the agent via the inner default space add call internalReceiveEvent
Expand All @@ -87,14 +93,17 @@ public synchronized void wake(Event evt) {
if ((!(context instanceof InnerContextSkill)) || ((InnerContextSkill) context).hasInnerContext()) {
final EventSpace defSpace = context.getInnerContext().getDefaultSpace();
evt.setSource(defSpace.getAddress(getOwner().getID()));
defSpace.emit(evt);
defSpace.emit(evt, scope);
} else {
// Do not call getInnerContext(), which is creating the inner context automatically.
// In place, try to send the event inside the agent only (and its behaviors).
final EventListener listener = getSkill(InternalEventBusCapacity.class).asEventListener();
assert listener != null;
evt.setSource(this.agentAddressInInnerDefaultSpace);
listener.receiveEvent(evt);
final InternalEventBusCapacity eventBus = getSkill(InternalEventBusCapacity.class);
if (scope == null || scope.matches(eventBus.getInnerDefaultSpaceAddress())) {
final EventListener listener = eventBus.asEventListener();
assert listener != null;
evt.setSource(this.agentAddressInInnerDefaultSpace);
listener.receiveEvent(evt);
}
}

}
Expand Down

0 comments on commit 3e69bfb

Please sign in to comment.