Skip to content

Commit

Permalink
[all] Add the function "setSkillIfAbsent" into the Agent API.
Browse files Browse the repository at this point in the history
Signed-off-by: Stéphane Galland <galland@arakhne.org>
  • Loading branch information
gallandarakhneorg committed Mar 11, 2020
1 parent fe98526 commit 4979bf2
Show file tree
Hide file tree
Showing 9 changed files with 238 additions and 60 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -613,7 +613,7 @@ implemented capacity.
In the following example, the agent is creating the [:skiskill:] skill. This instance is associated with
the corresponding capacity [:capcap:] with the function `[:setskillfctfull]{[:setskillfct](setSkill)(Skill, Class<? extends Capacity>*)}`.

When the function `setSkill` is returning, the agent becomes able to use the skill.
When the function [:setskillfct:] is returning, the agent becomes able to use the skill.

[:Success:]
package io.sarl.docs.reference.ar
Expand All @@ -638,6 +638,32 @@ When the function `setSkill` is returning, the agent becomes able to use the ski
[:End:]



If some cases, you may want to set the skill if one was not set up before. The specific behavior
is supported by `[:setskillifabsfctfull]{[:setskillifabsfct](setSkillIfabsent)(Skill, Class<? extends Capacity>*)}`.

[:Success:]
package io.sarl.docs.reference.ar
import io.sarl.core.Logging
import io.sarl.core.Initialize
capacity Cap {
def action
}
skill [:skiskill](Ski) implements [:capcap](Cap) {
uses Logging
def action {
info("Action")
}
}
[:On]
agent MyAgent {
on Initialize {
var theSkill = new Ski
[:setskillifabsfct!](theSkill)
}
}
[:End:]

### Giving a Built-in Skill to an Agent

Because the built-in capacities are supported by the runtime environment, the corresponding
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,7 @@ It is possible for a behavior to assign a skill to its agent.
uses Logging
def action { info("Action") }
}
[:On]
behavior MyBehavior {
new (owner : Agent) {
super(owner)
Expand All @@ -516,6 +517,34 @@ It is possible for a behavior to assign a skill to its agent.
[:End:]





If some cases, you may want to set the skill if one was not set up before. The specific behavior
is supported by `[:setskillifabsfctfull]{[:setskillifabsfct](setSkillIfAbsent)(Skill, Class<? extends Capacity>*)}`.

[:Success:]
package io.sarl.docs.reference.br
import io.sarl.core.Logging
import io.sarl.lang.core.Agent
capacity Cap {
def action
}
skill Ski implements Cap {
uses Logging
def action { info("Action") }
}
[:On]
behavior MyBehavior {
new (owner : Agent) {
super(owner)
var theSkill = new Ski
setSkillIfAbsent( theSkill, Cap )
}
}
[:End:]


### Using a Capacity with the Getters

For invoking a function implemented by a skill, the two following steps must be done:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,19 +88,26 @@ public AbstractSkillContainer(
@Override
@SafeVarargs
protected final <S extends Skill> S setSkill(S skill, Class<? extends Capacity>... capacities) {
$setSkill(skill, capacities);
$setSkill(skill, false, capacities);
return skill;
}

@Override
@SafeVarargs
protected final void setSkillIfAbsent(Skill skill, Class<? extends Capacity>... capacities) {
$setSkill(skill, true, capacities);
}

/** Add a skill to the agent.
*
* @param skill the new skill.
* @param ifabsent indicates if the skill mapping is set up if it is absent.
* @param capacities the implemented capacities by the skill.
* @return the reference to the skill.
* @since 16.0
* @since 0.11
*/
@SafeVarargs
protected final AtomicSkillReference $setSkill(Skill skill, Class<? extends Capacity>... capacities) {
protected final AtomicSkillReference $setSkill(Skill skill, boolean ifabsent, Class<? extends Capacity>... capacities) {
assert skill != null : "the skill parameter must not be null"; //$NON-NLS-1$
$attachOwner(skill);
AtomicSkillReference newRef = null;
Expand All @@ -110,7 +117,7 @@ protected final <S extends Skill> S setSkill(S skill, Class<? extends Capacity>.
final Class<?> type = element.getRawType();
if (Capacity.class.isAssignableFrom(type) && !Capacity.class.equals(type)) {
final Class<? extends Capacity> capacityType = type.asSubclass(Capacity.class);
newRef = registerSkill(skill, capacityType, newRef);
newRef = registerSkill(skill, ifabsent, capacityType, newRef);
}
}
} else {
Expand All @@ -122,7 +129,7 @@ protected final <S extends Skill> S setSkill(S skill, Class<? extends Capacity>.
"the skill must implement the given capacity " //$NON-NLS-1$
+ capacity.getName());
}
newRef = registerSkill(skill, capacity, newRef);
newRef = registerSkill(skill, ifabsent, capacity, newRef);
}
}
return newRef;
Expand All @@ -135,11 +142,19 @@ protected final <S extends Skill> S setSkill(S skill, Class<? extends Capacity>.
*/
protected abstract void $attachOwner(Skill skill);

private AtomicSkillReference registerSkill(Skill skill, Class<? extends Capacity> capacity, AtomicSkillReference firstRef) {
final AtomicSkillReference newReference = new AtomicSkillReference(skill);
final AtomicSkillReference oldReference = $getSkillRepository().put(capacity, newReference);
if (oldReference != null) {
oldReference.clear();
private AtomicSkillReference registerSkill(Skill skill, boolean ifabsent,
Class<? extends Capacity> capacity, AtomicSkillReference firstRef) {
final AtomicSkillReference newReference;
if (ifabsent) {
newReference = $getSkillRepository().computeIfAbsent(capacity, it -> {
return new AtomicSkillReference(skill);
});
} else {
newReference = new AtomicSkillReference(skill);
final AtomicSkillReference oldReference = $getSkillRepository().put(capacity, newReference);
if (oldReference != null) {
oldReference.clear();
}
}
if (firstRef == null) {
return newReference;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ public Agent(
final Map<Class<? extends Capacity>, Skill> builtinCapacities = provider.getBuiltinCapacities(this);
if (builtinCapacities != null && !builtinCapacities.isEmpty()) {
for (final Entry<Class<? extends Capacity>, Skill> bic : builtinCapacities.entrySet()) {
$setSkill(bic.getValue(), bic.getKey());
$setSkill(bic.getValue(), false, bic.getKey());
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,12 +90,24 @@ public final String toString() {
*
* @param <S> - type of the skill.
* @param capacities the capacity or the capacities to set.
* @param skill implementaion of <code>capacity</code>.
* @param skill implementation of <code>capacity</code>.
* @return the skill that was set.
* @see #setSkillIfAbsent(Skill, Class...)
*/
@SuppressWarnings("unchecked")
protected abstract <S extends Skill> S setSkill(S skill, Class<? extends Capacity>... capacities);

/**
* Set the skill for the {@link Capacity} <code>capacity</code> if the mapping is not yet set.
*
* @param capacities the capacity or the capacities to set.
* @param skill implementation of <code>capacity</code>.
* @see #setSkill(Skill, Class...)
* @since 0.11
*/
@SuppressWarnings("unchecked")
protected abstract void setSkillIfAbsent(Skill skill, Class<? extends Capacity>... capacities);

/**
* Clears the Skill associated with the capacity.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,15 @@ protected final <S extends Skill> S setSkill(S skill, Class<? extends Capacity>.
return owner.setSkill(skill, capacities);
}

@Override
@SafeVarargs
protected final void setSkillIfAbsent(Skill skill, Class<? extends Capacity>... capacities) {
final Agent owner = getOwner();
if (owner != null) {
owner.setSkillIfAbsent(skill, capacities);
}
}

@Override
protected <S extends Capacity> S clearSkill(Class<S> capacity) {
final Agent owner = getOwner();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,20 @@ public static <S extends Capacity> S castInternalSkillReference(AbstractSkillCon
*/
public static AtomicSkillReference setInternalSkill(AbstractSkillContainer container, Skill skill, Class<? extends Capacity>[] capacities) {
assert capacities != null;
return container.$setSkill(skill, capacities);
return container.$setSkill(skill, false, capacities);
}

/** Set the internal skill of a skill container if the skill is not yet mapped.
*
* @param container the container.
* @param skill the skill instance to attach to the container.
* @param capacities the list of implemented capacities. This array cannot be {@code null}.
* @return the reference to the skill.
* @since 0.11
*/
public static AtomicSkillReference setInternalSkillIfAbsent(AbstractSkillContainer container, Skill skill, Class<? extends Capacity>[] capacities) {
assert capacities != null;
return container.$setSkill(skill, true, capacities);
}

/** Replies the internal skill of a skill container.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
import io.sarl.lang.core.Skill;
import io.sarl.lang.core.SpaceID;
import io.sarl.lang.core.UnimplementedCapacityException;
import io.sarl.lang.core.tests.core.AbstractAgentTraitBehaviorTest.Capacity1.ContextAwareCapacityWrapper;
import io.sarl.tests.api.AbstractSarlTest;
import io.sarl.tests.api.Nullable;

Expand Down Expand Up @@ -147,6 +148,33 @@ public void setSkill() throws Exception {
assertInstanceOf(Capacity1.class, result);
}

@Test
public void setSkillIfAbsent() throws Exception {
Skill1 skill = new Skill1();
//
Object instance = getInstance();
invokeProc(instance.getClass(), instance,
"setSkillIfAbsent", new Class[] {Skill.class, Class[].class}, skill, new Class[] {Capacity1.class});
Object result = invokeFunc(instance.getClass(), instance, Object.class,
"getSkill", new Class[] {Class.class}, Capacity1.class);
while (result instanceof Capacity.ContextAwareCapacityWrapper) {
result = ((Capacity.ContextAwareCapacityWrapper<?>) result).getDelegate();
}
//
assertSame(skill, result);
//
Skill1 skill2 = new Skill1();
invokeProc(instance.getClass(), instance,
"setSkillIfAbsent", new Class[] {Skill.class, Class[].class}, skill2, new Class[] {Capacity1.class});
result = invokeFunc(instance.getClass(), instance, Object.class,
"getSkill", new Class[] {Class.class}, Capacity1.class);
while (result instanceof Capacity.ContextAwareCapacityWrapper) {
result = ((Capacity.ContextAwareCapacityWrapper<?>) result).getDelegate();
}
//
assertSame(skill, result);
}

@Test
public void operator_mappedTo() throws Exception {
Skill1 skill = new Skill1();
Expand Down
Loading

0 comments on commit 4979bf2

Please sign in to comment.