oaaconnector.java

来自「SRI international 发布的OAA框架软件」· Java 代码 · 共 310 行

JAVA
310
字号
/*
#=========================================================================
# Copyright 2003 SRI International.  All rights reserved.
#
# The material contained in this file is confidential and proprietary to SRI
# International and may not be reproduced, published, or disclosed to others
# without authorization from SRI International.
#
# DISCLAIMER OF WARRANTIES
#
# SRI International MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE
# SUITABILITY OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT
# LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
# PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SRI International SHALL NOT BE
# LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
# OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES
#=========================================================================
*/
package com.sri.oaa2.tools.oaatest;
import java.util.*;
import com.sri.oaa2.com.*;
import com.sri.oaa2.lib.*;
import com.sri.oaa2.icl.*;


/** OaaConnector maintains a connection to the OAA facilitator and records all events from the 
 * facilitator in an event queue.
 */
class OaaConnector {
  /** Make the singleton connection to facilitator.  Must be called before 
   *  singleton().  Doesn nothing if already connected.
   * @throws ConnectionException if unable to connect
   */
  static void connect() throws ConnectionException {
    if (singleton != null) {
      return;
    }    
    singleton = new OaaConnector();
  }
  
  /** Disconnect from the facilitator and destroy singleton.  Does nothing if
   * not connected.
   */
  static void disconnect() {
    if (singleton == null) {
      return;
    }
    singleton._disconnect();
    singleton = null;
  }

  /** Slightly different than the usual singleton pattern in that caller must explicitly call
   * connect() / disconnect() to create/destroy the singleton object.  Will return null if
   * not connected.
   * @return the singleton OaaConnector object
   */
  static OaaConnector get() {
    return singleton;
  }

  /** Ask the StartIt agent to kill itself and any apps it is running. */ 
  void killStartIt() {
    IclList params = (IclList)IclUtils.fromString(true,"[reply(none)]");
    libOaa.oaaSolve(IclTerm.fromString(true,"kill_and_exit_startit"),
                    params,new IclList());
  }

  /** The queue of events coming from the facilitator.  A synchronized List of Event.  This
   * list can be used as a monitor.  If the list is empty, caller can wait() on the list and expect to
   * be notified when an event is added. */
  List getEventQ() {
    return eventQ;
  }

  void flushEventQ() {
    eventQ.clear();
  }
  
  LibOaa getLibOaa() {
    return libOaa;
  }

  private OaaConnector() throws ConnectionException {    
    // Connect to facilitator.
    LibCom com = new LibCom(new LibComTcpProtocol(),new String[0]);
    libOaa = new LibOaa(com);
      
    libOaa.oaaRegisterCallback("app_do_event",
      new OAAEventListener() {
        public boolean doOAAEvent(IclTerm goal,IclList params,IclList answers) {
          return appDoEvent(goal,params,answers);
        }
      }
    );
    if (!libOaa.oaaSetupCommunication(AGENT_NAME)) {
      throw new ConnectionException();
    } 
  
    // Register solvables.
    if (!libOaa.oaaRegister("parent",AGENT_NAME, 
                            IclTerm.fromString(true, "[tst_ev(Op,Id,Ev)]"),
                            new IclList())) {
      throw new ConnectionException();
    }

    libOaa.oaaReady(true);
  }

  /** Should not call any methods on OaaConnector after _disconnect() */
  private void _disconnect() {
    // Explicitly remove triggers.
    setTriggers(null,null);
    libOaa.oaaDisconnect(new IclList());
  }

  private boolean appDoEvent(IclTerm goal,IclList params,IclList answers) {
    // Don't need to compute this every time.
    final IclTerm tstEvEvent = IclTerm.fromString(true,"tst_ev(Dir,_,Event)"); 
    final IclTerm evSolvedEvent = IclTerm.fromString(true,"ev_solved(_,_,_,_,_,_)");

    Event event;
    Unifier unifier = Unifier.getInstance();
    HashMap bindings = new HashMap();

    // The ususal case, receive a tst_ev from a trigger notification.
    if (unifier.unify(tstEvEvent,goal,bindings) != null) {
      IclTerm dir = (IclTerm)bindings.get("Dir");
      if (dir == null) {
        throw new RuntimeException("Bug in unification.");
      }
      IclTerm iclTerm = (IclTerm)bindings.get("Event");
      if (iclTerm == null) {
        throw new RuntimeException("Bug in unification.");
      }
      String iclStr = dir.toString();
      if (iclStr.equals("send")) {
        event = new SendEvent(iclTerm);
      }
      else if (iclStr.equals("recv")) {
        event = new RecvEvent(iclTerm);      
      }
      else {
        return false;
      }
    }
    
    // Something of a hack, temporary bug workaround.
    // Treat received ev_solved events like a tst_ev(send,...), or <fromFac>
/*    else {
      bindings.clear();
      if (unifier.unify(evSolvedEvent,goal,bindings) != null) {
        event = new SendEvent(goal);
      }
      else {
        return false;
      }
    }
  */
    else {
      return false;
    }
    
    synchronized (eventQ) {
      // Trim eventQ to at least one element less than MAX_EVENTS.
      // Remove oldest elements.
      while (eventQ.size() >= MAX_EVENTS) {
        eventQ.remove(0);
      }
      // Add to eventQ.
      eventQ.add(event);
      // An empty queue just had an element added.  There may be threads waiting on
      // this queue.
      if (eventQ.size() == 1) {
        eventQ.notifyAll();
      }
    }

    return true;
  }

  /* Add triggers on facilitator to watch for these events (sent
   * or received).  Will remove any previous triggers added with setTrigger().
   * null or empty list for recv/sendEvents means don't watch for any 
   * recv/send events, respectively.
   */ 
  public void setTriggers(IclList recvEvents,IclList sendEvents) {
    if (triggers == null) {
      triggers = new TriggerInfo();
      triggers.type = new IclStr("comm"); 
      triggers.condition = IclTerm.fromString(true,"event(E,P)");
      triggers.recvAction = IclTerm.fromString(true,
        "oaa_Solve(tst_ev(recv,Id,E),[reply(none),address(" 
        + libOaa.oaaPrimaryAddress() + ")])");
      triggers.sendAction = IclTerm.fromString(true,
        "oaa_Solve(tst_ev(send,Id,E),[reply(none),address(" 
        + libOaa.oaaPrimaryAddress() + ")])");
      triggers.recvParams = null;
      triggers.sendParams = null;
    }
    else {
      // Only remove triggers if added in the first place.
      if (triggers.recvParams != null) {
        libOaa.oaaRemoveTrigger(triggers.type,triggers.condition,
                                triggers.recvAction,triggers.recvParams);
        triggers.recvParams = null;
      }
      if (triggers.sendParams != null) {
        libOaa.oaaRemoveTrigger(triggers.type,triggers.condition,
                                triggers.sendAction,triggers.sendParams);
        triggers.sendParams = null;
      }
    }
    // At this point, triggers is a valid struct with everything except
    // send/recvParams filled in.
        

    if (recvEvents != null && recvEvents.getNumChildren() > 0) {
      IclGroup testBody = new IclGroup(
        IclTerm.fromString(true,"memberchk(from(Id),P)"),
        new IclStruct("memberchk",new IclVar("E"),recvEvents));
      testBody.setStarter('(');
      testBody.setEnder(')');    
      IclTerm eventTest = new IclStruct("test",testBody);
  
      triggers.recvParams = (IclList)IclTerm.fromString(true,"[recurrence(whenever),address(parent),on(receive)]"); 
      triggers.recvParams.add(eventTest);   
      libOaa.oaaAddTrigger(triggers.type,triggers.condition,
                           triggers.recvAction,triggers.recvParams);
    }
    else {
      // Indication that no trigger added to fac.
      triggers.recvParams = null;
    }

    if (sendEvents != null && sendEvents.getNumChildren() > 0) {
      IclGroup testBody = new IclGroup(
        IclTerm.fromString(true,"memberchk(address(Id),P)"),
        new IclStruct("memberchk",new IclVar("E"),sendEvents));
      testBody.setStarter('(');
      testBody.setEnder(')');    
      IclTerm eventTest = new IclStruct("test",testBody);
  
      triggers.sendParams = (IclList)IclTerm.fromString(true, "[recurrence(whenever),address(parent),on(send)]");
      triggers.sendParams.add(eventTest);
      libOaa.oaaAddTrigger(triggers.type,triggers.condition,
                           triggers.sendAction,triggers.sendParams);
    }
    else {
      // Indication that no trigger added to fac.
      triggers.sendParams = null;
    }
  }

  
/*
  // Copied from Monitor agent with a few changes.
  private void logAllEvents(IclTerm me) {
    // Add trigger to trace any events from or to agents.
    // Don't trace events coming to/from me, or from any other oaatest or monitor agent.
    // Do this in two steps, one for receive and once for send, because
    // constraint check is slightly different.
    
    IclTerm recTest = IclTerm.fromString(true, "(memberchk(from(Id),P),agent_data(Id,Type,Status,Sv,Name,Info),not(memberchk(solvable(tst_ev(_,_,_),_,_),Sv)),not(memberchk(solvable(m_ev(_,_,_),_,_),Sv)))");
    IclList recParams = (IclList)IclTerm.fromString(true, "[recurrence(whenever),address(parent),on(receive)]"); 
    recParams.add(new IclStruct("test", recTest));
    libOaa.oaaAddTrigger(
     new IclStr("comm"), 
     IclTerm.fromString(true, "event(E,P)"),
     IclTerm.fromString(true, "oaa_Solve(tst_ev(receive,Id,E),[reply(none),address(" + me.toString() + ")])"),
     recParams);
    boolean res1 = libOaa.oaaAddTrigger(
     new IclStr("comm"), 
     IclTerm.fromString(true, "event(E,P)"),
     IclTerm.fromString(true, "oaa_Solve(tst_ev(receive,Id,E),[reply(none),address(" + me.toString() + ")])"),
     IclTerm.fromString()"");[recurrence(whenever),address(parent),on(receive)]
     memberchk(E,[event1,event2,s)

     
    IclTerm sendTest = IclTerm.fromString(true, "(memberchk(address(Id),P),agent_data(Id,Type,Status,Sv,Name,Info),not(memberchk(solvable(tst_ev(_,_,_),_,_),Sv)),not(memberchk(solvable(m_ev(_,_,_),_,_),Sv)))");
    IclList sendParams = (IclList)IclTerm.fromString(true, "[recurrence(whenever),address(parent),on(send)]");
    sendParams.add(new IclStruct("test", sendTest));
    libOaa.oaaAddTrigger(
     new IclStr("comm"), 
     IclTerm.fromString(true, "event(E,P)"),
     sendParams);
  }
*/

  private static OaaConnector singleton = null;

  private static final String AGENT_NAME = "oaatest";
  /** Maximum size of eventQ, will start dropping oldest events when full. */ 
  private static int MAX_EVENTS = 1000;

  private LibOaa libOaa;
  private List eventQ = Collections.synchronizedList(new LinkedList());

  /** Triggers we have installed on facilitator, or null. */
  private TriggerInfo triggers;
  
  private static class TriggerInfo {
    IclStr type;
    IclTerm condition;
    IclTerm recvAction;
    IclTerm sendAction;
    IclTerm recvParams;
    IclTerm sendParams;
  } 
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?