MAY Tutorial V1 » Historique » Révision 4
Révision 3 (Anonyme, 23/04/2010 14:09) → Révision 4/6 (Anonyme, 11/05/2010 11:37)
h1. Make Agents Yourself MAY Tutorial {{>toc}} % TODO : exemple complet, clair et qui colle au code % ajouter utilisation objet commun à plusieurs composants (ou remplacé par un compo (Representation)) Plan % retirer code généré ! h2. Introduction In this tutorial, we are going to see an introduction to MAY. This tool was made to build application-specific models of agent and to generate dedicated framework providing them. Such framework would then be usable to program agents compliant with the realised model of agent. More specifically, a model of agent is realised by an architecture divided in two levels: "container" (the how), hidden to the user of the framework and "application" (the what) expression what the agent does. These two levels links MuComponents together to form a MuArchitecture realising the model. Furthermore, such agents have the possibility to self-adapt at runtime: currently, this means that a MuComponent is able to change the implementation of another MuComponent of the MuArchitecture. In practice, these models are described with the help of the MuADL description language, and from this description, the Java code needed to implement the MuComponents is generated. The MuArchitecture itself is generated and is directly usable by setting the implementation of its MuComponents. This tool being experimental, several functionalities described are are subject to change in the future. If possible, this will be stated in this document. h3. Requirements To use MAY, the _Eclipse IDE_ is needed. It can be found at http://www.eclipse.org/. h3. Installation The installation is done from the _Software Update_ in _Eclipse_ by adding the following _Update Sites_: <pre> http://www.irit.fr/PERSONNEL/SMAC/noel/may/update/ http://oawbranch.pluginbuilder.org/releases/p2-updateSite/ </pre> Choose to install _Make Agents Yourself_. h3. Upgrades In the future, upgrades will be available, just use the _Update_ feature of _Eclipse_. h2. Typical Development Process of an Agent with MAY As explained before, MAY is a tool usable to description MuArchitectures based on MuComponents to generate a framework that will be distributed to application developers. Several phases in the development can be distinguished: * Description of the MuComponents and MuArchitectures: * Create a MAY project * Describe the model with MuADL * Generate the corresponding Java code * Implantation of the MuComponents with Java * Implantation of a _Factory_ with Java * Generation of the distributable framework in the form of a JAR file The following sections will describe in detail these development phases. We will see the tools MAY adds to _Eclipse_, a description of MuADL and some advice to develop an agent and its MuComponents. h2. Added Tools to _Eclipse_ The tools proposed by MAY are the following: * Creation of a MAY project * Creation of a textual MuADL description file * Generation of the corresponding code in Java - A graphical editor is currently being worked on. h3. Creation of a Project A MAY project is just a Java _Eclipse_ project with supplementary dependencies, an empty MuADL description file and the required directories already created. To create a new project, go to _File_ menu, _New_, _Project..._, _Make Agents Yourself_ category and choose _MAY Project_. la découverte des composants logiciels - Introduction - Etude de cas ... Follow the instruction. h3. Creation of a Textual MuADL Description File The description of a model of agent is represented by a text file containing the description of MuComponents and MuArchitectures with MuADL (presented Sect.~\ref{muadl}). - Présentatation de May ... The extension of these files is @muadlt@. The editor features syntactic colouration, completion and validation of MuArchitectures. To create a new MuADL file, go to _File_, _New_, _Others..._, _Make Agents Yourself_ category and choose _MuADL Text file_. Follow the instructions. h3. Generation of the corresponding code in Java This action generates the classes required for the implementation of the MuComponents described in the MuADL file (the @QuasiComponent@), the class representing the mediator of the MuArchitecture and the class façade representing an agent compliant with the MuArchitecture. To generate the corresponding code of a MuADL file (a file ending in @.muadlt@), do a right click on it and in the sub-menu _Make Agents Yourself_, choose _Generate QC and Architecture_. The generated code will be in the @src-gen@ directory. It is important to notice that the content of this directory must never be modified. h2. MuADL: Description Language for Agent Architectures As said before, MAY, using MuADL, make possible to describe: * MuComponents that: \todo{MuADL does not permit to specify how they will be implemented (no information of the constructors, the class attributes or private methods)} * Provides operations * Requires (from the MuArchitecture) operations * Requires (from the MuArchitecture) the possibility to change other MuComponents * Have a state that must be persisted by the MuArchitecture when their implementation is changed at runtime * MuArchitectures containing MuComponents and divided in two levels * Datatypes use by MuComponents and corresponding to Java types (classes or interfaces). We detail here how to describe these elements. h3. DataTypes To refer to Java types, we give them a name in the MuADL file. The syntax is as following: <pre> DataType AliasLocal : package.NomClass DataType AliasLocal : package.NomClass<Generique> DataType AliasLocal : package.NomClass<package.Generique> // examples DataType String : String DataType Int : int DataType Msg : my.package.Msg DataType ListString : java.util.List<String> DataType MailBox : java.util.List<my.package.Msg> </pre> \todo{Currently, no verification is done on the existence of these classes} It is important to understand that DataTypes are just aliases, they can't be used inside generics parameters. h3. MuComponents Elements of a MuComponent : * A name * Provided operations (@provided@) * Required operations (@required@) * Attributes that must be persisted between runtime replacement of implementations (@persistent@) * A set of MuComponents whose implementation could be changed at runtime \todo{This point is likely to change in the future} (@change@) The MuComponents operations are similar to Java methods: they have a name, ordered typed parameters and a return type. To refer to a method, it is only needed to know its name, its ordered parameter types and its return type. An example of MuComponent : <pre> MuComponent Message { package a.test.package provided send(mess : String) provided receive() : String persistent mailbox : MailBox required do(String) : Int change LifeCycle } </pre> h3. MuArchitectures A MuArchitecture have: * A name * A set of MuComponents in the container level (@container@) * A set of MuComponents in the application level (@application@) * A set of visibility modifiers on th MuComponents operations (@visibility@) The MuComponents can be specified as changeable (with @changeable@) by other MuComponents. MuComponents can only change MuComponents of the same level. By default, a MuComponent operation of the application level is visible by every MuComponents of the MuArchitecture, and a MuComponent operation of the container level is only visible by the MuComponents of the container level. This fact can be changed by specifying (with @application@ visibility) that an operation of the container level is visible in the application level. An operation of the MuArchitecture can be specified as being available from outside of the agent (with @external@ \todo{This is susceptible to change in the future}). An example of MuArchitecture : <pre> MuArchitecture MyAgent { package another.test.package container { changeable LifeCycle Message } application { Behavior } visibility { external Message.send(String) application Message.receive() : String } } </pre> Notice that : * If a MuComponent @A@ requires an operation @0@, then a MuComponent providing @0@ must be present in the MuArchitecture. * Requirements are only validated in the MuArchitecture. * Two MuComponents can't provide the same operation. h3. Complementary Informations MuADL allows for comments : <pre> // a comment /* a multi-line comment */ </pre> h2. Implantation of MuComponents, use of MuArchitectures and Framework Distribution After the Java code from a MuADL file was generated (see \ref{generation}), MuComponents implementation and MuArchitectures instantiation is possible. The generation result in a set of Java classes situated in the @src-gen@ directory. To implement MuComponents, we will write Java classes (typically in the @src@ directory) that extends some of these generated classes. h3. MuComponents Implementations For each MuComponent @X@ defined in the MuADL file, MAY generates a class @QuasiComponentX@ and a class @AdapterX@. The first must be extended to implement @X@. For example, there is the two generated classes for a component @LifeCyle@: <pre> public abstract class QuasiComponentLifeCycle extends QuasiComponent<AdapterLifeCycle> { abstract public void suicide(); } </pre> <pre> public interface AdapterLifeCycle extends Adapter { public void cycle(java.lang.String arg0); public java.lang.String receive(); } </pre> Thus, by extending @QuasiComponentLifeCycle@, one can use the required methods of the MuComponent by using the architecture through the method @this.architecture()@. There is an example of this MuComponent : <pre> public class LifeCycle extends QuasiComponentLifeCycle { private boolean alive = true; @Override public void start() { Runnable me = new Runnable() { public void run() { while (alive) { String msg = architecture().receive(); architecture().cycle(msg); } } }; new Thread(me).start(); } public void suicide() { alive = false; } } </pre> The important points to notice are: * A method @void start()@ is present to execute instructions at the start of the agent * @this.architecture()@ gives access to required methods through the MuArchitecture There is an example of a generated MuComponent with a persistent state: <pre> public abstract class QuasiComponentMessage extends QuasiComponent<AdapterMessage> implements WithPersistentState<PersistentStateMessage> { abstract public void send(java.lang.String message); abstract public java.lang.String receive(); } </pre> <pre> public interface AdapterMessage extends Adapter {} </pre> When implementing it, one has access to the methods needed for the handling of the persistent state (automatically called by the architecture if the MuComponent implementation is changed at runtime). There is an example of implementation for this MuComponent: <pre> public class Message extends QuasiComponentMessage { private ArrayBlockingQueue<String> messageBox = new ArrayBlockingQueue<String>(100); public void send(String message) { try { messageBox.put(message); } catch (InterruptedException e) { e.printStackTrace(); } } public PersistentStateMessage getPersistentState() { return new PersistentStateMessage( new ArrayList<String>(messageBox) ); } public void setPersistentState(PersistentStateMessage state) { messageBox = new ArrayBlockingQueue<String>(10, false, state.messageBox); System.out.println("Message Component started with "+ messageBox.size()+ " messages"); } public String receive() { try { return messageBox.take(); } catch (InterruptedException e) { e.printStackTrace(); return ""; } } } </pre> Notice that we use an object of type @PersistentStateMessage@ to store and read the persistent state. There is an example of a generated MuComponent changing another MuComponent implementation: <pre> public abstract class QuasiComponentAdaptation extends QuasiComponent<AdapterAdaptation> { abstract public void adapt(); } </pre> <pre> public interface AdapterAdaptation extends Adapter { public void change(QuasiComponentMessage _comp); } </pre> Notice that a @void change(QuasiComponentMessage _comp)@ method is present to give access to the replacement functionalities of the MuArchitecture. There is an example of implementation of this MuComponent: <pre> public class Adaptation extends QuasiComponentAdaptation { public void adapt() { architecture().change(new Message()); } } </pre> We can also see here for the first time the instantiation of a MuComponent. When calling @change(...)@, the MuArchitecture will get the current state of @Message@ and will inject it in the new implementation with the methods we defined previously in @Message@. h3. MuArchitecture Use To use a MuArchitecture is to create an agent complying to this MuArchitecture by instantiating each of its MuComponents. For this, the generated code of a MuArchitecture @X@ consists into 2 classes: @XMediator@ and @X@. The first one is the implementation of the MuArchitecture itself, and the second one is a façade providing the external methods of the agent \todo{This will change in the future.}. Thus, to create an agent compliant with a MuArchitecture @SimpleAgent@ with 4 MuComponents @Adaptation@, @Message@, @LifeCycle@ and @Behavior@ is done like this: <pre> SimpleAgent agent1 = new SimpleAgent( new Message(), new LifeCycle(), new Adaptation(), new Behavior()); agent1.start(); </pre> Notice the call to @start()@ that starts each of the MuComponents and thus the agent. h3. _Factory_ One of the objectives of MAY being to reduce the development effort by distributing models of agents ready to use, it is necessary to be able to provide partially instantiated MuArchitecture where some of the MuComponents implementation are already fixed. These will then be directly usable by users by choosing the remaining MuComponent implementations. This is done by using a _Factory_, which currently must be built by hand. A factory is only a class providing one (or several) static methods instantiating some MuComponents and an agent. For example: <pre> public class MySimpleAgent { public static SimpleAgent create(QuasiComponentBehavior behavior) { SimpleAgent agent = new SimpleAgent(new Message(), new LifeCycle(), new Adaptation(), behavior); agent.start(); return agent; } } </pre> Thus, to create an agent, one just need to know @MySimpleAgent.create(...)@. For example: <pre> public class Main { public static void main(String[] args) { SimpleAgent agent1 = create(new Behavior2("agent1")); SimpleAgent agent2 = create(new Behavior("agent2", agent1)); agent2.send("hello"); } } </pre> h3. Framework Distribution The created classes in the previous sections form a framework usable by a user of the model of agent to create agents. Delivering them to such an user is to export the _Eclipse_ project as a JAR using its export facilities: right-click on the project, choose _Export..._, in the _Java_ category, choose _JAR File_ and follow the instructions. The resulting JAR file will only need the _fr.irit.smac.muadl.impl_X.X.X.jar_ file available of the MAY website. For example they can both be added to a classic _Eclipse_ Java project as dependencies.