Skip to content

Commit

Permalink
[util][docs] Add scope of identifiers.
Browse files Browse the repository at this point in the history
see #639

Signed-off-by: Stéphane Galland <galland@arakhne.org>
  • Loading branch information
gallandarakhneorg committed Sep 3, 2017
1 parent 54f1c97 commit dd1652a
Show file tree
Hide file tree
Showing 8 changed files with 274 additions and 9 deletions.
Expand Up @@ -194,7 +194,7 @@ The following example is equivalent to the feature call of [:emit:] without the
[:End:]


A default implementation of a scope using addresses is implemented in the class `[:addressscope](io.sarl.util.[:addressscopebn]$AddressScope$)`. [:Fact:]{typeof([:addressscope!])}
A default implementation of a scope using addresses, of `Address` type is implemented in the class `[:addressscope](io.sarl.util.[:addressscopebn]$AddressScope$)`. [:Fact:]{typeof([:addressscope!])}
The utility class [:scopesbn:] provides the [:addresses:] function for creating an instance of [:addressscopebn:].

[:Success:]
Expand All @@ -215,6 +215,28 @@ The utility class [:scopesbn:] provides the [:addresses:] function for creating
}
[:End:]

Another default implementation of a scope using identifiers, of `UUID` type is implemented in the class `[:identifierscope](io.sarl.util.[:identifierscopebn]$IdentifierScope$)`. [:Fact:]{typeof([:identifierscope!])}
The utility class [:scopesbn:] provides the [:identifiers:] function for creating an instance of [:identifierscopebn:].

[:Success:]
package io.sarl.docs.reference.bic
import java.util.UUID
import io.sarl.core.DefaultContextInteractions
import io.sarl.lang.core.Address
import [:scopes!]
event MyEvent
agent A {
uses DefaultContextInteractions
def myaction {
var id1 : UUID
var id2 : UUID
[:On]
emit(new MyEvent, [:scopesbn!]::[:identifiers](identifiers)(id1, id2))
[:Off]
}
}
[:End:]

The complete list of the functions that are provided by the [:scopesbn:] class is
accessible on the [Scopes API documentation](http://www.sarl.io/docs/api/index.html?io/sarl/util/Scopes.html).

Expand Down
Expand Up @@ -1482,7 +1482,7 @@ The obtained code is:
}

def willReceive(receiver : UUID, ^event : Event) {
emit(^event, Scopes::addresses(defaultSpace.getAddress(receiver)))
emit(^event, Scopes::identifiers(receiver))
}
[:Off]
}
Expand Down
Expand Up @@ -270,8 +270,7 @@ Below, we update the bidding behavior by creating a scope, and providing it to t
if (priceIncrease > 0) {
var newPrice = occurrence.price + priceIncrease
if (newPrice <= maxPrice) {
var superScope = Scopes.addresses(
defaultSpace.getAddress(defaultContext.ID))
var superScope = Scopes::identifiers(defaultContext.ID)
emit(new Bid(newPrice), superScope)
myLastBid = newPrice
} else {
Expand Down Expand Up @@ -670,8 +669,7 @@ This function is provided by the [:lifecyclecap:] capacity.
if (priceIncrease > 0) {
var newPrice = occurrence.price + priceIncrease
if (newPrice <= maxPrice) {
var superScope = Scopes.addresses(
defaultSpace.getAddress(defaultContext.ID))
var superScope = Scopes::identifiers(defaultContext.ID)
emit(new Bid(newPrice), superScope)
}
}
Expand Down
Expand Up @@ -265,7 +265,16 @@ which is getting a collection of addresses for building the matching predicate i
[:Fact:]{typeof(io.sarl.util.Scopes)}
[:Fact:]{typeof(io.sarl.util.Scopes).shouldHaveMethod("addresses(io.sarl.lang.core.Address[]) : io.sarl.lang.core.Scope")}

In the following code, the scope permits to restrict to the initial sender of the [:pingevent:] event.
The SARL SDK contains also the class `IdentifierScope`. It is another implementation of a `Scope` on addresses. The creation
of an instance of `IdentifierScope` is done with the utility function `Scopes.identifiers(UUID*)`,
which is getting a collection of identifiers for building the matching predicate in the scope.
[:Fact:]{typeof(io.sarl.util.IdentifierScope)}
[:Fact:]{typeof(io.sarl.util.Scopes)}
[:Fact:]{typeof(io.sarl.util.Scopes).shouldHaveMethod("identifiers(java.util.UUID[]) : io.sarl.lang.core.Scope")}

In the following code, we select the first type of scope. It permits to restrict to the initial sender
of the [:pingevent:] event. Because, the address of the initial sender is known directly, it is easier to
use `Scopes.addresses(Address*)` than Scopes.identifiers(UUID*)`.

[:Success:]
package io.sarl.docs.tutorials.pingpongspace
Expand Down Expand Up @@ -305,7 +314,7 @@ In the following code, the scope permits to restrict to the initial sender of th
evt.source = ^space.getAddress(getID)
^space.emit(
evt,
Scopes.addresses( occurrence.source ))
Scopes::addresses( occurrence.source ))
}
}
[:End:]
Expand Down
82 changes: 82 additions & 0 deletions main/apiplugins/io.sarl.util/src/io/sarl/util/IdentifierScope.sarl
@@ -0,0 +1,82 @@
/*
* $Id$
*
* SARL is an general-purpose agent programming language.
* More details on http://www.sarl.io
*
* Copyright (C) 2014-2017 the original authors or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.sarl.util

import java.util.Arrays
import java.util.UUID

import io.sarl.lang.core.Address
import io.sarl.lang.core.Scope

/**
* Scope using {@link Address} for EventSpace's.
*
* @author $Author: srodriguez$
* @version $FullVersion$
* @mavengroupid $GroupId$
* @mavenartifactid $ArtifactId$
* @since 0.6
*/
class IdentifierScope implements Scope<Address> {

static val SCOPE_ID = "id://"

static val NO_IDENTIFIER : UUID[] = newArrayOfSize(0)

val identifiers : UUID[]

/**
* @param ids - identifiers to put in the scope.
*/
new (ids : UUID*) {
if (ids === null) {
this.identifiers = NO_IDENTIFIER
} else {
this.identifiers = ids
}
}

/** Replies the identifiers that are matched by this scope.
*
* @return the identifiers.
*/
def getIdentifiers : UUID[] {
this.identifiers
}

override toString : String {
SCOPE_ID + Arrays::toString(this.identifiers)
}

override matches(address : Address) : boolean {
assert address !== null
// TODO Do dichotomic search.
for (element : this.identifiers) {
if (element == address.UUID) {
return true
}
}
return false
}

}

25 changes: 24 additions & 1 deletion main/apiplugins/io.sarl.util/src/io/sarl/util/Scopes.sarl
Expand Up @@ -21,6 +21,8 @@

package io.sarl.util

import java.util.UUID

import io.sarl.lang.core.Address
import io.sarl.lang.core.Scope

Expand Down Expand Up @@ -58,7 +60,7 @@ final class Scopes {
new AddressScope(addresses)
}

/** Create an scope that is fordidding the given addresses.
/** Create an scope that is forbidding the given addresses.
*
* @param addresses - addresses to exclude from the scope.
* @return the scope forbidding the given addresses.
Expand All @@ -68,6 +70,27 @@ final class Scopes {
not(addresses(addresses))
}

/** Create an scope restricted to the given agent identifiers.
*
* @param identifiers - identifiers to put in the scope.
* @return the scope restricted to the given agent identifiers.
* @since 0.6
*/
static def identifiers(identifiers : UUID*) : Scope<Address> {
new IdentifierScope(identifiers)
}

/** Create an scope that is forbidding the given agent identifiers.
*
* @param identifiers - identifiers to exclude from the scope.
* @return the scope forbidding the given identifiers.
* @since 0.5
*/
static def notIdentifiers(identifiers : UUID*) : Scope<Address> {
not(identifiers(identifiers))
}


/** Create an scope that is the negation of the given scope.
*
* @param scope the scope to negate.
Expand Down
@@ -0,0 +1,87 @@
/*
* $Id$
*
* SARL is an general-purpose agent programming language.
* More details on http://www.sarl.io
*
* Copyright (C) 2014-2017 the original authors or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.sarl.util.tests.util;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.when;

import java.util.UUID;

import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import io.sarl.lang.core.Address;
import io.sarl.tests.api.AbstractSarlTest;
import io.sarl.tests.api.ManualMocking;
import io.sarl.tests.api.Nullable;
import io.sarl.util.IdentifierScope;

/**
* @author $Author: sgalland$
* @version $FullVersion$
* @mavengroupid $GroupId$
* @mavenartifactid $ArtifactId$
*/
@SuppressWarnings("all")
@ManualMocking
public class IdentifierScopeTest extends AbstractSarlTest {

@Nullable
private UUID base1;

@Nullable
private UUID base2;

@Mock
private Address adr1;

@Mock
private Address adr2;

@Mock
private Address adr3;

private IdentifierScope scope;

@Before
public void setUp() {
this.base1 = UUID.randomUUID();
this.base2 = UUID.randomUUID();
MockitoAnnotations.initMocks(this);
when(this.adr1.getUUID()).thenReturn(this.base1);
when(this.adr2.getUUID()).thenReturn(this.base2);
when(this.adr3.getUUID()).thenReturn(UUID.randomUUID());
this.scope = new IdentifierScope(this.base1, this.base2);
}

@Test
public void matches() {
assertTrue(this.scope.matches(this.adr1));
assertTrue(this.scope.matches(this.adr2));
assertFalse(this.scope.matches(this.adr3));
}

}

Expand Up @@ -24,12 +24,20 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import static org.mockito.Mockito.*;

import java.util.UUID;

import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import io.sarl.lang.core.Address;
import io.sarl.lang.core.Scope;
import io.sarl.tests.api.AbstractSarlTest;
import io.sarl.tests.api.ManualMocking;
import io.sarl.tests.api.Nullable;
import io.sarl.util.Scopes;

/**
Expand All @@ -39,8 +47,15 @@
* @mavenartifactid $ArtifactId$
*/
@SuppressWarnings("all")
@ManualMocking
public final class ScopesTest extends AbstractSarlTest {

@Nullable
private UUID id1;

@Nullable
private UUID id2;

@Mock
private Address base1;

Expand All @@ -53,6 +68,17 @@ public final class ScopesTest extends AbstractSarlTest {
@Mock
private Address base4;

@Before
public void setUp() {
this.id1 = UUID.randomUUID();
this.id2 = UUID.randomUUID();
MockitoAnnotations.initMocks(this);
when(this.base1.getUUID()).thenReturn(this.id1);
when(this.base2.getUUID()).thenReturn(this.id2);
when(this.base3.getUUID()).thenReturn(UUID.randomUUID());
when(this.base4.getUUID()).thenReturn(UUID.randomUUID());
}

@Test
public void allParticipants() {
Scope<Address> scope = Scopes.allParticipants();
Expand Down Expand Up @@ -80,6 +106,24 @@ public void notAddresses() {
assertTrue(scope.matches(this.base4));
}

@Test
public void identifiers() {
Scope<Address> scope = Scopes.identifiers(this.id1, this.id2);
assertTrue(scope.matches(this.base1));
assertTrue(scope.matches(this.base2));
assertFalse(scope.matches(this.base3));
assertFalse(scope.matches(this.base4));
}

@Test
public void notIdentifiers() {
Scope<Address> scope = Scopes.notIdentifiers(this.id1, this.id2);
assertFalse(scope.matches(this.base1));
assertFalse(scope.matches(this.base2));
assertTrue(scope.matches(this.base3));
assertTrue(scope.matches(this.base4));
}

@Test
public void not() {
Scope<Address> s1 = Scopes.addresses(this.base1, this.base2);
Expand Down

0 comments on commit dd1652a

Please sign in to comment.