From dd1652a3d699c6a9a5565c7daa87b15a572a72a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Galland?= Date: Sun, 3 Sep 2017 16:22:24 +0200 Subject: [PATCH] [util][docs] Add scope of identifiers. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit see #639 Signed-off-by: Stéphane Galland --- .../bic/DefaultContextInteractions.md | 24 ++++- .../tutorials/CreateSREWithTinyMAS.md | 2 +- .../documentation/tutorials/HolonicAuction.md | 6 +- .../documentation/tutorials/PingPongSpace.md | 13 ++- .../src/io/sarl/util/IdentifierScope.sarl | 82 +++++++++++++++++ .../io.sarl.util/src/io/sarl/util/Scopes.sarl | 25 +++++- .../util/tests/util/IdentifierScopeTest.java | 87 +++++++++++++++++++ .../io/sarl/util/tests/util/ScopesTest.java | 44 ++++++++++ 8 files changed, 274 insertions(+), 9 deletions(-) create mode 100644 main/apiplugins/io.sarl.util/src/io/sarl/util/IdentifierScope.sarl create mode 100644 tests/io.sarl.util.tests/src/test/java/io/sarl/util/tests/util/IdentifierScopeTest.java diff --git a/docs/io.sarl.docs.markdown/src/main/documentation/reference/bic/DefaultContextInteractions.md b/docs/io.sarl.docs.markdown/src/main/documentation/reference/bic/DefaultContextInteractions.md index 1a12746e10..e6dc39ba14 100644 --- a/docs/io.sarl.docs.markdown/src/main/documentation/reference/bic/DefaultContextInteractions.md +++ b/docs/io.sarl.docs.markdown/src/main/documentation/reference/bic/DefaultContextInteractions.md @@ -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:] @@ -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). diff --git a/docs/io.sarl.docs.markdown/src/main/documentation/tutorials/CreateSREWithTinyMAS.md b/docs/io.sarl.docs.markdown/src/main/documentation/tutorials/CreateSREWithTinyMAS.md index 640268258b..53db0cc457 100644 --- a/docs/io.sarl.docs.markdown/src/main/documentation/tutorials/CreateSREWithTinyMAS.md +++ b/docs/io.sarl.docs.markdown/src/main/documentation/tutorials/CreateSREWithTinyMAS.md @@ -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] } diff --git a/docs/io.sarl.docs.markdown/src/main/documentation/tutorials/HolonicAuction.md b/docs/io.sarl.docs.markdown/src/main/documentation/tutorials/HolonicAuction.md index 8c93464339..08ae19b5ca 100644 --- a/docs/io.sarl.docs.markdown/src/main/documentation/tutorials/HolonicAuction.md +++ b/docs/io.sarl.docs.markdown/src/main/documentation/tutorials/HolonicAuction.md @@ -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 { @@ -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) } } diff --git a/docs/io.sarl.docs.markdown/src/main/documentation/tutorials/PingPongSpace.md b/docs/io.sarl.docs.markdown/src/main/documentation/tutorials/PingPongSpace.md index ad1a3a6c7f..c67543caad 100644 --- a/docs/io.sarl.docs.markdown/src/main/documentation/tutorials/PingPongSpace.md +++ b/docs/io.sarl.docs.markdown/src/main/documentation/tutorials/PingPongSpace.md @@ -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 @@ -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:] diff --git a/main/apiplugins/io.sarl.util/src/io/sarl/util/IdentifierScope.sarl b/main/apiplugins/io.sarl.util/src/io/sarl/util/IdentifierScope.sarl new file mode 100644 index 0000000000..c1d9550a90 --- /dev/null +++ b/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
{ + + 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 + } + +} + diff --git a/main/apiplugins/io.sarl.util/src/io/sarl/util/Scopes.sarl b/main/apiplugins/io.sarl.util/src/io/sarl/util/Scopes.sarl index d809728549..4e08798d14 100644 --- a/main/apiplugins/io.sarl.util/src/io/sarl/util/Scopes.sarl +++ b/main/apiplugins/io.sarl.util/src/io/sarl/util/Scopes.sarl @@ -21,6 +21,8 @@ package io.sarl.util +import java.util.UUID + import io.sarl.lang.core.Address import io.sarl.lang.core.Scope @@ -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. @@ -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
{ + 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
{ + not(identifiers(identifiers)) + } + + /** Create an scope that is the negation of the given scope. * * @param scope the scope to negate. diff --git a/tests/io.sarl.util.tests/src/test/java/io/sarl/util/tests/util/IdentifierScopeTest.java b/tests/io.sarl.util.tests/src/test/java/io/sarl/util/tests/util/IdentifierScopeTest.java new file mode 100644 index 0000000000..a9f0e9dc81 --- /dev/null +++ b/tests/io.sarl.util.tests/src/test/java/io/sarl/util/tests/util/IdentifierScopeTest.java @@ -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)); + } + +} + diff --git a/tests/io.sarl.util.tests/src/test/java/io/sarl/util/tests/util/ScopesTest.java b/tests/io.sarl.util.tests/src/test/java/io/sarl/util/tests/util/ScopesTest.java index 85ffad61c8..b297d575ce 100644 --- a/tests/io.sarl.util.tests/src/test/java/io/sarl/util/tests/util/ScopesTest.java +++ b/tests/io.sarl.util.tests/src/test/java/io/sarl/util/tests/util/ScopesTest.java @@ -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; /** @@ -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; @@ -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
scope = Scopes.allParticipants(); @@ -80,6 +106,24 @@ public void notAddresses() { assertTrue(scope.matches(this.base4)); } + @Test + public void identifiers() { + Scope
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
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
s1 = Scopes.addresses(this.base1, this.base2);