/*
* $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.lang.core;
import java.lang.reflect.Constructor;
/** Utility functions related to the capacities.
*
* @author $Author: sgalland$
* @version $FullVersion$
* @mavengroupid $GroupId$
* @mavenartifactid $ArtifactId$
* @since 0.5
*/
public final class Capacities {
/** Local thread variable that contains the caller of a capacity function.
*/
static final ThreadLocal<AgentTrait> CALLER = new ThreadLocal<>();
private static final String CAPACITY_WRAPPER_NAME = "$" + Capacity.ContextAwareCapacityWrapper.class.getSimpleName(); //$NON-NLS-1$;
private Capacities() {
//
}
/** Replies the caller of the capacity functions.
*
* <p>The replied value has a meaning inside the skills' functions that
* are implemented the capacities' functions.
*
* @return the caller, or {@code null} if the caller is unknown (assuming that the caller is the agent itself).
*/
public static AgentTrait getCaller() {
return CALLER.get();
}
/** Create a delegator for the given skill.
*
* <p>The delegator is wrapping the original skill in order to set the value of the caller
* that will be replied by {@link #getCaller()}. The associated caller is given as argument.
*
* <p>The delegator is an instance of an specific inner type, sub-type of {@link Capacity.ContextAwareCapacityWrapper},
* which is declared in the given {@code capacity}.
*
* <p>This function fails if the delegator instance cannot be created due to inner type not found, invalid constructor signature,
* run-time exception when creating the instance.
* This functions assumes that the name of the definition type is the same as {@link Capacity.ContextAwareCapacityWrapper},
* and this definition extends the delegator definition of the first super type of the {@code capacity}, and implements
* all the super types of the {@code capacity}. The expected constructor for this inner type has the same
* signature as the one of {@link Capacity.ContextAwareCapacityWrapper}.
*
* <p>The function {@link #createSkillDelegatorIfPossible(Skill, Class, AgentTrait)} is a similar function than this
* function, except that it does not fail when the delegator instance cannot be created. In this last case,
* the function {@link #createSkillDelegatorIfPossible(Skill, Class, AgentTrait)} reply the original skill itself.
*
* @param <C> the type of the capacity.
* @param originalSkill the skill to delegate to after ensure the capacity caller is correctly set.
* @param capacity the capacity that contains the definition of the delegator.
* @param capacityCaller the caller of the capacity functions.
* @return the delegator.
* @throws Exception if the delegator cannot be created.
* @see #createSkillDelegatorIfPossible(Skill, Class, AgentTrait)
*/
public static <C extends Capacity> C createSkillDelegator(Skill originalSkill, Class<C> capacity, AgentTrait capacityCaller)
throws Exception {
final String name = capacity.getName() + CAPACITY_WRAPPER_NAME;
final Class<?> type = Class.forName(name, true, capacity.getClassLoader());
final Constructor<?> cons = type.getDeclaredConstructor(capacity, AgentTrait.class);
return capacity.cast(cons.newInstance(originalSkill, capacityCaller));
}
/** Create a delegator for the given skill when it is possible.
*
* <p>The delegator is wrapping the original skill in order to set the value of the caller
* that will be replied by {@link #getCaller()}. The associated caller is given as argument.
*
* <p>The delegator is an instance of an specific inner type, sub-type of {@link Capacity.ContextAwareCapacityWrapper},
* which is declared in the given {@code capacity}.
*
* <p>This functions assumes that the name of the definition type is the same as {@link Capacity.ContextAwareCapacityWrapper},
* and this definition extends the delegator definition of the first super type of the {@code capacity}, and implements
* all the super types of the {@code capacity}. The expected constructor for this inner type has the same
* signature as the one of {@link Capacity.ContextAwareCapacityWrapper}.
* If the delegator instance cannot be created due to to inner type not found, invalid constructor signature,
* run-time exception when creating the instance, this function replies the original skill.
*
* <p>The function {@link #createSkillDelegator(Skill, Class, AgentTrait)} is a similar function than this
* function, except that it fails when the delegator instance cannot be created.
*
* @param <C> the type of the capacity.
* @param originalSkill the skill to delegate to after ensure the capacity caller is correctly set.
* @param capacity the capacity that contains the definition of the delegator.
* @param capacityCaller the caller of the capacity functions.
* @return the delegator, or the original skill.
* @throws ClassCastException if the skill is not implementing the capacity.
* @see #createSkillDelegator(Skill, Class, AgentTrait)
*/
public static <C extends Capacity> C createSkillDelegatorIfPossible(Skill originalSkill, Class<C> capacity, AgentTrait capacityCaller)
throws ClassCastException {
try {
return Capacities.createSkillDelegator(originalSkill, capacity, capacityCaller);
} catch (Exception e) {
return capacity.cast(originalSkill);
}
}
}