package eis;
import java.util.Collection;
import java.util.Map;
import eis.eis2java.environment.AbstractEnvironment;
import eis.exceptions.ActException;
import eis.exceptions.AgentException;
import eis.exceptions.EntityException;
import eis.exceptions.ManagementException;
import eis.exceptions.NoEnvironmentException;
import eis.exceptions.PerceiveException;
import eis.exceptions.QueryException;
import eis.exceptions.RelationException;
import eis.iilang.Action;
import eis.iilang.EnvironmentState;
import eis.iilang.Parameter;
import eis.iilang.Percept;
/**
* This interface is the main-interface of EIS. All environment-interfaces have
* to implement this interface and its methods.
* <p/>
* Each environment interface should implement these functionalities:
* <ul>
* <li>attaching and detaching listeners;</li>
* <li>registering and unregistering agents;</li>
* <li>adding and removing entities;</li>
* <li>managing the agents-entities-relationship;</li>
* <li>performing actions and retrieving percepts;</li>
* <li>managing the environment; and</li>
* <li>loading environment-interfaces from jar-files.</li>
* </ul>
*
* <h1>Thread Safety</h1>
* This interface does not pose any requirements on thread safety. Therefore it
* can not be assumed that an environment behind this interface is thread safe.
*
* <h1>Initialization</h1>
* Implementors of this must have an empty default constructor, so that an
* instance of the interface can be created without any additional requirements.
* Your environment state can stay {@link EnvironmentState#INITIALIZING} and
* will become usable only after {@link #init(Map)} is called.
*
* @author tristanbehrens
*
*/
public interface EnvironmentInterfaceStandard {
/**
* Attaches an environment-listener.
* <p/>
* If the listener is already attached, nothing will happen.
*
* @param listener
* is the listener
*/
void attachEnvironmentListener(EnvironmentListener listener);
/**
* Detaches an environment-listener.
* <p/>
* If the listener is not attached, nothing will happen.
*
* @param listener
* is the listener
*/
void detachEnvironmentListener(EnvironmentListener listener);
/**
* Attaches an agent-listener.
* <p/>
* If the agent has not been registered nothing will happen.
*
* @param agent
* is the agent
* @param listener
* is the listener of the agent
*/
void attachAgentListener(String agent, AgentListener listener);
/**
* Detaches an agent-listener.
* <p/>
* If the agent has not been registered and/or the listener does not exist
* nothing will happen.
*
* @param agent
* is the agent
* @param listener
* is the listener of the agent
*/
void detachAgentListener(String agent, AgentListener listener);
/**
* Registers an agent to the environment.
*
* @param agent
* the identifier of the agent.
* @throws PlatformException
* if the agent has already been registered.
*/
void registerAgent(String agent) throws AgentException;
/**
* Unregisters an agent from the environment.
*
* @param agent
* the identifier of the agent.
* @throws AbstractException
* if the agent has not registered before.
*/
void unregisterAgent(String agent) throws AgentException;
/**
* Retrieves the list of registered agents.
*
* @return a list of agent-ids.
*/
Collection<String> getAgents();
/**
* Retrieves the list of entities.
*
* @return a list of entity-ids.
*/
Collection<String> getEntities();
/**
* Associates an entity with an agent.
*
* @param agent
* the id of the agent.
* @param entity
* the id of the entity.
* @throws PlatformException
* if the entity is not free, and if it or the agent does not
* exist.
*/
void associateEntity(String agent, String entity) throws RelationException;
/**
* Frees an entity from its associated agent(s). This will re=announce an
* entity as free and therefore can only be used when environment is
* {@link EnvironmentState#RUNNING} or {@link EnvironmentState#PAUSED}
*
* @param entity
* the id of the entity to be freed.
* @throws EntityException
* if the entity can't be freed
* @throws PlatformException
* is thrown if the entity does not exist, or if it is not
* associated.
*/
void freeEntity(String entity) throws RelationException, EntityException;
/**
* Frees an agent from the agents-entities-relation. This will re=announce
* an entity as free and therefore should only be used when environment is
* {@link EnvironmentState#RUNNING} or {@link EnvironmentState#PAUSED}
*
* @param agent
* is the agent to be freed.
* @throws RelationException
* is thrown if the agent has not been registered.
* @throws EntityException
* if the entity can't be freed
*/
void freeAgent(String agent) throws RelationException, EntityException;
/**
* Removes a pair from the agents-entities-relation. This un-associates the
* agent from the entity, and is the reverse of
* {@link #associateEntity(String, String)}. This should re=announce an
* entity as free and therefore should only be used when environment is
* {@link EnvironmentState#RUNNING} or {@link EnvironmentState#PAUSED}.
*
* @param agent
* the agent to be freed
* @param entity
* the entity to be freed
* @throws RelationException
* is thrown when the agent is not associated with the entity
* @throws EntityException
* if the entity can't be freed
*/
void freePair(String agent, String entity) throws RelationException,
EntityException;
/**
* Returns the entities associated to a given agent.
*
* @param agent
* is the agent.
* @return a set of entities.
* @throws AgentException
*/
Collection<String> getAssociatedEntities(String agent)
throws AgentException;
/**
* Returns the agents associated to a given entity.
*
* @param entity
* is the entity.
* @return a set of agents.
* @throws AgentException
*/
Collection<String> getAssociatedAgents(String entity)
throws EntityException;
/**
* Retrieves the list of free entities.
*
* @return a list of entity-ids.
*/
Collection<String> getFreeEntities();
/**
* Returns the type of an entity.
*
* @param entity
* is the entity
* @return either the type of the entity
* @throws EntityException
* is thrown if the entity does not exist.
*/
String getType(String entity) throws EntityException;
/**
* Lets an agent perform an action.
*
* @param agent
* is the agent whose associated entities are supposed to act.
* @param action
* is the action. The action's name determines the name of the
* method that is called.
* @param entities
* is an array of entities through which an agent is supposed to
* act. If the array is empty, all entities are used.
* @return a map of action-results. Keys are the entity name that gave the
* result percept. Only add items if the percept is not null. If an
* action has a null result, just do not add the result to the map.
* @throws ActException
* is thrown if the agent has not been registered, if the agent
* has no associated entities, if at least one of the given
* entities is not associated, or if at least one one the
* actions fails.
* @throws NoEnvironmentException
* if the interface is not connected to an environment.
*/
Map<String, Percept> performAction(String agent, Action action,
String... entities) throws ActException;
/**
* Gets all percepts.
* <p/>
* Either returns the percepts of all associated entities of or a subset.
* <p/>
* This function should be called only when {@link #getState()} is
* {@link EnvironmentState#RUNNING} or {@link EnvironmentState#PAUSED}.
* <p/>
* <em>NOTE</em> In many environments the return value depends on previous
* calls to getAllPercepts. There may be special percepts that are provided
* only the first time getAllPercepts is called. There may be percepts that
* are sent only once. There may percepts that are sent if they were not
* sent the previous time already. The exact behaviour is to be defined in
* environment's documentation. Both {@link EIDefaultImpl} and
* {@link AbstractEnvironment} implements such a more detailed version of
* getAllPercepts.
*
*
* @param agent
* the agent that requests the percepts.
* @return a list of percepts
* @throws PerceiveException
* if the agent is not registered or if the agents requests
* percepts from an entity that is not associated.
* @throws NoEnvironmentException
*/
Map<String, Collection<Percept>> getAllPercepts(String agent,
String... entities) throws PerceiveException,
NoEnvironmentException;
/**
* Checks whether a state transition between two states is possible or not.
*
* @param oldState
* is the old state.
* @param newState
* is the new state.
* @return true iff transition valid
*/
// TODO needs to go to the default implementation
boolean isStateTransitionValid(EnvironmentState oldState,
EnvironmentState newState);
/**
* Initializes the environment(-interface) with a set of key-value-pairs.
* Normally, here an environment initializes its environment and moves to
* the {@link EnvironmentState#PAUSED} or {@link EnvironmentState#RUNNING}
* state. After that it then proceeds calling
* {@link EnvironmentListener#handleNewEntity(String)} for all entities.
*
* @param parameters
* @throws ManagementException
* is thrown either when the initializing is not supported or
* the parameters are wrong.
*/
void init(Map<String, Parameter> parameters) throws ManagementException;
/**
* Soft resset. Resets the environment(-interface) with a set of
* key-value-pairs. Resetting the environment means the following
* <ul>
* <li>set the environment state to {@link EnvironmentState#INITIALIZING}.
* <li>Reset environment to its initial state (initial map for instance)
* <li>Reset all entities to their initial state
* <li>Prepare to send the entities the initial percept (note:
* "initial percepts" is not a contract with EIS but might a contract with
* the specific environment)
* <li>keep all agents attached, do not remove entities or create new ones
* etc.
* </ul>
*
* @param parameters
* @throws ManagementException
* is thrown either when the initializing is not supported or
* the parameters are wrong.
*/
void reset(Map<String, Parameter> parameters) throws ManagementException;
/**
* Starts the environment(-interface). Should change the state to
* {@link EnvironmentState#RUNNING}.
*
* @throws ManagementException
* when starting is not supported
*/
void start() throws ManagementException;
/**
* Pauses the environment(-interface). Should change the state to
* {@link EnvironmentState#PAUSED}
*
* @throws ManagementException
* when pausing is not supported
*/
void pause() throws ManagementException;
/**
* Kills the environment. Environment should change to
* {@link EnvironmentState#KILLED}
*
* @throws ManagementException
* when killing is not supported.
*/
void kill() throws ManagementException;
/**
* Retrieves the state of the environment-interface.
*
* @return current {@link EnvironmentState}.
*/
EnvironmentState getState();
/**
* Returns true when the init-command is supported.
*
* @return true iff {@link #init(Map)} is supported.
*/
boolean isInitSupported();
/**
* Returns true when the start-command is supported.
*
* @return true iff {@link #start()} is supported
*/
boolean isStartSupported();
/**
* Returns true when the pause-command is supported.
*
* @return true iff {@link #pause()} is supported
*/
boolean isPauseSupported();
/**
* Returns true when the kill-command is supported.
*
* @return iff {@link #kill()} is supported
*/
boolean isKillSupported();
/**
* Returns the EIS-runtime-version that is compatible with the implemented
* environment.
*/
String requiredVersion();
/**
* Queries the interface of a certain property.
*
* @param property
* property to query
* @return String defining the propery, or null if no such property.
*/
String queryProperty(String property) throws QueryException;
/**
* Queries an entity of a certain property.
*
* @param entity
* the entity to query
* @param property
* the property to query
* @return String property value for given entity/property combination, or
* null if no such property.
*/
String queryEntityProperty(String entity, String property)
throws QueryException;
}