Package jade.core.behaviours

Source Code of jade.core.behaviours.LoaderBehaviour

/*****************************************************************
JADE - Java Agent DEvelopment Framework is a framework to develop
multi-agent systems in compliance with the FIPA specifications.
Copyright (C) 2000 CSELT S.p.A.

GNU Lesser General Public License

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation,
version 2.1 of the License.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA  02111-1307, USA.
*****************************************************************/

package jade.core.behaviours;

//#MIDP_EXCLUDE_FILE

import jade.core.Agent;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;
import jade.content.ContentManager;
import jade.content.lang.Codec;
import jade.content.lang.leap.LEAPCodec;
import jade.content.onto.Ontology;
import jade.content.onto.OntologyException;
import jade.content.onto.basic.Action;
import jade.content.onto.basic.Result;
import jade.domain.mobility.*;
import jade.domain.FIPAAgentManagement.ExceptionVocabulary;
import jade.util.leap.List;
import jade.util.leap.ArrayList;
import jade.util.leap.Iterator;

import java.util.Hashtable;
import java.util.zip.*;
import java.io.*;

/**
   This behaviour serves behaviour-loading requests
   according to the Behaviour-loading ontology.
   When an agent runs an instance of this behaviour it becomes able
   to load and execute completely new behaviours, i.e. behaviours
   whose code is not included in the classpath of the JVM where the
   agent lives.
   Loading behaviour requests must have the <code>ACLMessage.REQUEST</code>
   performative and must use the BehaviourLoading ontology and the
   LEAP language.
  
   <br>
   <b>NOT available in MIDP</b>
   <br>
     
   @see jade.domain.mobility.LoadBehaviour
   @see jade.domain.mobility.BehaviourLoadingOntology
   @see jade.content.lang.leap.LEAPCodec
   @author Giovanni Caire - TILAB
*/
public class LoaderBehaviour extends Behaviour {
  private Codec codec = new LEAPCodec();
  private Ontology onto = BehaviourLoadingOntology.getInstance();
  private ContentManager myContentManager = new ContentManager();
  private ClassLoader localLoader;
 
  private MessageTemplate myTemplate = MessageTemplate.and(
    MessageTemplate.MatchPerformative(ACLMessage.REQUEST),
    MessageTemplate.and(
      MessageTemplate.MatchLanguage(codec.getName()),
      MessageTemplate.MatchOntology(onto.getName())
    )
  );
 
  private boolean finished = false;
 
  /**
     Construct a LoaderBehaviour.
   */
  public LoaderBehaviour() {
    super();
    init();
  }
 
  /**
     Construct a LoaderBehaviour to be executed by a given agent.
   */
  public LoaderBehaviour(Agent a) {
    super(a);
    init();
  }
 
  /**
     Construct a LoaderBehaviour to be executed by a given agent and that will use a given class loader to load behaviours whose code
     is not embedded in the LoadBehaviour request.
   */
  public LoaderBehaviour(Agent a, ClassLoader cl) {
    super(a);
    init();
    localLoader = cl;
  }
 
  /**
     The action() method is redefined to serve behaviour loading requests
   */
  public final void action() {
    if (!finished) {
      ACLMessage msg = myAgent.receive(myTemplate);
      if (msg != null) {
        ACLMessage reply = msg.createReply();
       
        if (accept(msg)) {
          try {
            Action actionExpr = (Action) myContentManager.extractContent(msg);
            LoadBehaviour lb = (LoadBehaviour) actionExpr.getAction();
           
            // Load the behaviour
            String className = lb.getClassName();
            Behaviour b = null;
            byte[] code = lb.getCode();
            byte[] zip = lb.getZip();
            if (code != null) {
              // Try from the class byte code
              b = loadFromCode(className, code);
            }
            else if (zip != null) {
              // Try from the zip
              b = loadFromZip(className, zip);
            }
            else {
              // Try using the local loader if any. Otherwise load from the classpath
              if (localLoader != null) {
                b = (Behaviour) Class.forName(className, true, localLoader).newInstance();
              }
              else {
                b = (Behaviour) Class.forName(className).newInstance();
              }
            }
           
            // Set parameters
            List params = lb.getParameters();
            setInputParameters(b, params);
           
            // Start the behaviour and prepare a positive reply
            SequentialBehaviour sb = new SequentialBehaviour(myAgent);
            sb.addSubBehaviour(b);
            sb.addSubBehaviour(new ResultCollector(b, params, actionExpr, msg));
            myAgent.addBehaviour(sb);
            reply.setPerformative(ACLMessage.AGREE);
          }
          catch (Codec.CodecException ce) {
            ce.printStackTrace();
            reply.setPerformative(ACLMessage.NOT_UNDERSTOOD);
            reply.setContent("(("+ExceptionVocabulary.UNRECOGNISEDVALUE+" content))");
          }
          catch (OntologyException oe) {
            oe.printStackTrace();
            reply.setPerformative(ACLMessage.NOT_UNDERSTOOD);
            reply.setContent("(("+ExceptionVocabulary.UNRECOGNISEDVALUE+" content))");
          }
          catch (Exception e) {
            e.printStackTrace();
            reply.setPerformative(ACLMessage.FAILURE);
            reply.setContent("((internal-error \""+e.toString()+"\"))");
          }
        }
        else {
          reply.setPerformative(ACLMessage.REFUSE);
        }
        myAgent.send(reply);
      }
      else {
        block();
      }
    }
  }
 
  /**
     The done() method is redefined to make this behaviour terminate
     when its <code>stop()</code> method is called.
   */
  public boolean done() {
    return finished;
  }

  /**
     Make this behaviour terminate.
   */
  public void stop() {
    finished = true;
    restart();
  }

  /**
     Add a loaded behaviour to the agent.
     Subclasses may redefine this method to handle the behaviour
     addition operation in an application specific way.
     @param b The <code>Behaviour</code> to be added.
     @param request The <code>ACLMessage</code> carrying the
     <code>LoadBehaviour</code> request.
   */
  protected void addBehaviour(Behaviour b, ACLMessage request) {
    myAgent.addBehaviour(b);
  }

  /**
     Suclasses may redefine this method to prevent the behaviour
     loading operation under specific conditions.
     This default implementation always returns <code>true</code>
   */
  protected boolean accept(ACLMessage msg) {
    return true;
  }
 
  ///////////////////////////
  // Private utility methods
  ///////////////////////////
  private void init() {
    // Register LEAP language and BehaviourLoading ontology in a
    // local ContentManager
    myContentManager.registerLanguage(codec);
    myContentManager.registerOntology(onto);
   
    localLoader = getClass().getClassLoader();
  }
   
  private Behaviour loadFromCode(String className, final byte[] code) throws ClassNotFoundException, InstantiationException, IllegalAccessException
    Hashtable classes = new Hashtable(1);
    classes.put(className, code);
    return load(className, classes);
  }
 
  private Behaviour loadFromZip(String className, byte[] zip) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
    Hashtable classes = new Hashtable();
    try {
      ZipInputStream zis = new ZipInputStream(new ByteArrayInputStream(zip));
      ZipEntry ze = zis.getNextEntry();
      while (ze != null) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte[] tmp = new byte[1024];
        int k = zis.read(tmp, 0, tmp.length);
        while (k > 0) {
          baos.write(tmp, 0, k);
          k = zis.read(tmp, 0, tmp.length);
        }
        classes.put(ze.getName(), baos.toByteArray());
        zis.closeEntry();
        ze = zis.getNextEntry();
      }
      return load(className, classes);
    }
    catch (Exception e) {
      e.printStackTrace();
      throw new ClassNotFoundException("Error reading zip for class "+className+". "+e);
    }
  }
 
  private Behaviour load(String className, Hashtable classes) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
    ClassLoader loader = new HashClassLoader(classes, getClass().getClassLoader());
   
    Class c = Class.forName(className, true, loader);
    return (Behaviour) c.newInstance();
  }
 
  /**
     Inner class HashClassLoader
   */
  private class HashClassLoader extends ClassLoader {
    private Hashtable classes;
   
    public HashClassLoader(Hashtable ht, ClassLoader parent) {
      //#PJAVA_EXCLUDE_BEGIN
      super(parent);
      //#PJAVA_EXCLUDE_END
      /*#PJAVA_INCLUDE_BEGIN
      super();
      #PJAVA_INCLUDE_END*/
      classes = ht;
    }
     
    protected Class findClass(String name) throws ClassNotFoundException {
      String fileName = name.replace('.', '/') + ".class";
      byte[] code = (byte[]) classes.get(fileName);
      if (code != null) {
        return defineClass(name, code, 0, code.length);
      }
      else {
        throw new ClassNotFoundException("Class "+name+" does not exist");
      }
    }

    /*#PJAVA_INCLUDE_BEGIN In PersonalJava loadClass(String, boolean) is abstract --> we must implement it
    protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException {
      // 1) Try to see if the class has already been loaded
      Class c = findLoadedClass(name);
       
      // 2) Try to load the class using the system class loader
      if(c == null) {
        try {
            c = findSystemClass(name);
        }
        catch (ClassNotFoundException cnfe) {
        }
      }
       
      // 3) If still not found, try to load the class from the code
      if(c == null) {
        c = findClass(name);
      }
       
      if(resolve) {
          resolveClass(c);
      }
       
      return c;
    }
    #PJAVA_INCLUDE_END*/
  // END of inner class HashClassLoader   
 

  protected void setInputParameters(Behaviour b, List params) {
    DataStore ds = b.getDataStore();
    if (params != null) {
      Iterator it = params.iterator();
      while (it.hasNext()) {
        Parameter p = (Parameter) it.next();
        if (p.getMode() == Parameter.IN_MODE || p.getMode() == Parameter.INOUT_MODE) {
          ds.put(p.getName(), p.getValue());
        }
      }
    }
  }
 
  protected void getOutputParameters(Behaviour b, List params) {
    DataStore ds = b.getDataStore();
    if (params != null) {
      Iterator it = params.iterator();
      while (it.hasNext()) {
        Parameter p = (Parameter) it.next();
        if (p.getMode() == Parameter.OUT_MODE || p.getMode() == Parameter.INOUT_MODE) {
          p.setValue(ds.get(p.getName()));
        }
      }
    }
  }
 
 
  /**
     Inner class ResultCollector.
     This behaviour restores the output parameters at the end of
     the execution of the loaded behaviour and sends back the
     result notification to the requester.
   */
  private class ResultCollector extends OneShotBehaviour {
    private Behaviour myBehaviour;
    private List myParams;
    private Action actionExpr;
    private ACLMessage request;
   
    ResultCollector(Behaviour b, List l, Action a, ACLMessage m) {
      super();
      myBehaviour = b;
      myParams = l;
      actionExpr = a;
      request = m;
    }
   
    public void action() {
      // Avoid sending back the behaviour code
      LoadBehaviour lb = (LoadBehaviour) actionExpr.getAction();
      lb.setCode(null);
      lb.setZip(null);
     
      // Restore output parameters
      getOutputParameters(myBehaviour, myParams);
     
      if (myParams == null) {
        // Result cannot be null
        myParams = new ArrayList();
      }
      Result r = new Result(actionExpr, myParams);
      ACLMessage notification = request.createReply();
      try {
        myContentManager.fillContent(notification, r);
        notification.setPerformative(ACLMessage.INFORM);
      }
      catch (Exception e) {
        e.printStackTrace();
        notification.setPerformative(ACLMessage.FAILURE);
        notification.setContent("((internal-error \""+e.toString()+"\"))");
      }
      myAgent.send(notification)
    }
  } // END of inner class ResultCollector     
}
TOP

Related Classes of jade.core.behaviours.LoaderBehaviour

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.