diff --git a/main/coreplugins/io.sarl.lang.core/src/io/sarl/lang/core/Agent.java b/main/coreplugins/io.sarl.lang.core/src/io/sarl/lang/core/Agent.java index 235aca3e7f..d39389197e 100644 --- a/main/coreplugins/io.sarl.lang.core/src/io/sarl/lang/core/Agent.java +++ b/main/coreplugins/io.sarl.lang.core/src/io/sarl/lang/core/Agent.java @@ -57,6 +57,8 @@ @SarlSpecification(SARLVersion.SPECIFICATION_RELEASE_VERSION_STRING) public class Agent extends AgentProtectedAPIObject implements Identifiable { + private static final DynamicSkillProvider SINGLETON = (it0, it1) -> null; + private final UUID id; private final UUID parentID; @@ -125,7 +127,11 @@ public Agent( DynamicSkillProvider skillProvider) { this.parentID = parentID; this.id = (agentID == null) ? UUID.randomUUID() : agentID; - this.skillProvider = skillProvider; + if (skillProvider == null) { + this.skillProvider = SINGLETON; + } else { + this.skillProvider = skillProvider; + } } @Override @@ -160,7 +166,11 @@ public UUID getID() { * @since 0.6 */ void $setDynamicSkillProvider(DynamicSkillProvider provider) { - this.skillProvider = provider; + if (provider == null) { + this.skillProvider = SINGLETON; + } else { + this.skillProvider = provider; + } } /** Replies the skill repository. @@ -359,39 +369,67 @@ protected final S getSkill(Class capacity) { @Pure protected AtomicClearableReference $getSkill(Class capacity) { AtomicClearableReference skill = $getSkillRepository().get(capacity); + // Check if the stored skill is still not empty + if (skill != null) { + final Skill s = skill.get(); + if (s == null) { + skill = null; + } + } if (skill == null) { // Try to load dynamically the skill - final DynamicSkillProvider dsp = this.skillProvider; - if (dsp != null) { - final ClearableReference reference = dsp.installSkill(this, capacity); - if (reference != null) { - return reference; - } + skill = createSkillFromProvider(capacity); + if (skill == null) { + // Use the default skill declaration if present. + skill = createDefaultSkill(capacity); } - // Use the default skill declaration if present. - final DefaultSkill annotation = capacity.getAnnotation(DefaultSkill.class); - if (annotation != null) { + if (skill == null) { + throw new UnimplementedCapacityException(capacity, getID()); + } + } + return skill; + } + + private AtomicClearableReference createSkillFromProvider(Class capacity) { + assert this.skillProvider != null; + final AtomicClearableReference reference = this.skillProvider.installSkill(this, capacity); + if (reference != null) { + final Skill s = reference.get(); + if (s != null) { + return reference; + } + } + return null; + } + + private AtomicClearableReference createDefaultSkill(Class capacity) { + final DefaultSkill annotation = capacity.getAnnotation(DefaultSkill.class); + if (annotation != null) { + try { + final Class type = annotation.value(); + Constructor cons; try { - final Class type = annotation.value(); - Constructor cons; - try { - cons = type.getConstructor(Agent.class); - cons.setAccessible(true); - final Skill skillInstance = cons.newInstance(this); - return $setSkill(skillInstance); - } catch (Throwable exception) { - cons = type.getConstructor(); - } + cons = type.getConstructor(Agent.class); cons.setAccessible(true); - final Skill skillInstance = cons.newInstance(); + final Skill skillInstance = cons.newInstance(this); return $setSkill(skillInstance); } catch (Throwable exception) { - throw new UnimplementedCapacityException(capacity, getID(), exception); + cons = type.getConstructor(); + } + cons.setAccessible(true); + final Skill skillInstance = cons.newInstance(); + final AtomicClearableReference ref = $setSkill(skillInstance); + if (ref != null) { + final Skill s = ref.get(); + if (s != null) { + return ref; + } } + } catch (Throwable exception) { + throw new UnimplementedCapacityException(capacity, getID(), exception); } - throw new UnimplementedCapacityException(capacity, getID()); } - return skill; + return null; } @Override diff --git a/tests/io.sarl.lang.core.tests/src/test/java/io/sarl/lang/core/tests/core/AgentTest.java b/tests/io.sarl.lang.core.tests/src/test/java/io/sarl/lang/core/tests/core/AgentTest.java index 2e4197cd39..0d146d99b5 100644 --- a/tests/io.sarl.lang.core.tests/src/test/java/io/sarl/lang/core/tests/core/AgentTest.java +++ b/tests/io.sarl.lang.core.tests/src/test/java/io/sarl/lang/core/tests/core/AgentTest.java @@ -47,6 +47,7 @@ import io.sarl.lang.core.Capacity; import io.sarl.lang.core.DefaultSkill; import io.sarl.lang.core.Event; +import io.sarl.lang.core.SREutils; import io.sarl.lang.core.Skill; import io.sarl.lang.core.UnimplementedCapacityException; import io.sarl.lang.util.AtomicClearableReference; @@ -451,6 +452,94 @@ public void getSkill_defaultskill() throws Exception { assertSame(ref0, ref1); } + @Test + public void getSkill_noRegistration() throws Exception { + assertException(UnimplementedCapacityException.class, () -> { + this.agent.$getSkill(Capacity4.class); + }); + // + assertException(UnimplementedCapacityException.class, () -> { + this.agent.$getSkill(Capacity5.class); + }); + } + + @Test + public void getSkill_registrationSkill6() throws Exception { + Skill expected = new Skill6(); + SREutils.setInternalSkill(this.agent, expected, new Class[0]); + // + AtomicClearableReference actual = this.agent.$getSkill(Capacity4.class); + assertNotNull(actual); + assertSame(expected, actual.get()); + // + assertException(UnimplementedCapacityException.class, () -> { + this.agent.$getSkill(Capacity5.class); + }); + } + + @Test + public void getSkill_registrationSkill7() throws Exception { + Skill expected = new Skill7(); + SREutils.setInternalSkill(this.agent, expected, new Class[0]); + // + AtomicClearableReference actual0 = this.agent.$getSkill(Capacity4.class); + assertNotNull(actual0); + assertSame(expected, actual0.get()); + // + AtomicClearableReference actual1 = this.agent.$getSkill(Capacity5.class); + assertNotNull(actual1); + assertSame(expected, actual1.get()); + } + + @Test + public void getSkill_registrationSkill6_clearReference() throws Exception { + Skill expected = new Skill6(); + SREutils.setInternalSkill(this.agent, expected, new Class[0]).clear(); + // + assertException(UnimplementedCapacityException.class, () -> { + this.agent.$getSkill(Capacity4.class); + }); + // + assertException(UnimplementedCapacityException.class, () -> { + this.agent.$getSkill(Capacity5.class); + }); + } + + @Test + public void getSkill_registrationSkill7_clearReference0() throws Exception { + Skill expected = new Skill7(); + // The following line clear the Capacity5 reference only. + SREutils.setInternalSkill(this.agent, expected, new Class[0]).clear(); + // + AtomicClearableReference actual = this.agent.$getSkill(Capacity4.class); + assertNotNull(actual); + assertSame(expected, actual.get()); + assertException(UnimplementedCapacityException.class, () -> { + this.agent.$getSkill(Capacity5.class); + }); + // + assertException(UnimplementedCapacityException.class, () -> { + this.agent.$getSkill(Capacity5.class); + }); + } + + @Test + public void getSkill_registrationSkill7_clearReference1() throws Exception { + Skill expected = new Skill7(); + // The following line clear the Capacity5 reference only. + SREutils.setInternalSkill(this.agent, expected, new Class[0]).clear(); + // The following line clear the Capacity4 reference only. + SREutils.getInternalSkillReference(this.agent, Capacity4.class).clear(); + // + assertException(UnimplementedCapacityException.class, () -> { + this.agent.$getSkill(Capacity4.class); + }); + // + assertException(UnimplementedCapacityException.class, () -> { + this.agent.$getSkill(Capacity5.class); + }); + } + /** Only for making public several protected methods. * * @author $Author: sgalland$ @@ -470,7 +559,6 @@ public AgentMock(UUID parentID) { public S setSkill_Fake(S skill, Class... capacity) { return setSkill(skill, capacity); } - @Override public AtomicClearableReference $getSkill(Class capacity) { @@ -577,6 +665,50 @@ public Skill3() { } } + /** + * @author $Author: sgalland$ + * @version $FullVersion$ + * @mavengroupid $GroupId$ + * @mavenartifactid $ArtifactId$ + */ + private static interface Capacity4 extends Capacity { + // + } + + /** + * @author $Author: sgalland$ + * @version $FullVersion$ + * @mavengroupid $GroupId$ + * @mavenartifactid $ArtifactId$ + */ + private static interface Capacity5 extends Capacity4 { + // + } + + /** + * @author $Author: sgalland$ + * @version $FullVersion$ + * @mavengroupid $GroupId$ + * @mavenartifactid $ArtifactId$ + */ + private static class Skill6 extends Skill implements Capacity4 { + public Skill6() { + // + } + } + + /** + * @author $Author: sgalland$ + * @version $FullVersion$ + * @mavengroupid $GroupId$ + * @mavenartifactid $ArtifactId$ + */ + private static class Skill7 extends Skill implements Capacity5 { + public Skill7() { + // + } + } + /** * @author $Author: sgalland$ * @version $FullVersion$