Menu

jadeAgent.ivoke() Problem

Help
Timon
2006-03-16
2013-03-08
  • Timon

    Timon - 2006-03-16

    Hi Guys!

    First: great idea, David, and thx ;-)

    Now the question:
    i created an agent with JadePlatform.createNewAgent() from an Java Server Faces Bean and got my JadeAgent for that agent.
    I now tried to invoke a method "public String helloFromAgent(void)" that i coded in "myAgent extends JademxAgent" and put that String (like "Hello") on display.

    I do:

    agentMBean.invoke("helloFromAgent",null,null);

    But i get always an "ReflectionException: no action named "helloFromAgent" with given signature".

    Do i have to implement the ivoke method in my own agent?
    Sry, but i studied all api's and src's and googeled the hell out of me...

    Regards,
    Timon

     
    • Timon

      Timon - 2006-03-16

      by the way:
      agent.waitForJademxAgentBinding(30*1000,0)
      returns "false" always.... did i forget anything?

       
    • David Bernstein

      David Bernstein - 2006-03-17

      Timon,

      I saw your question first on the jade-develop mailing list and posted a response there: http://avalon.cselt.it/pipermail/jade-develop/2006q1/008543.html .

      To make sure there's a response here, I've copied it in:

      ------------------------
      Timon,

      If you want to use jademx for external access to an agent, then you
      definitely do need to use JMX.  jademx agents do need to override invoke()
      and make an MBeanInfo for the agent.  I have thought about improvements to
      reduce the need for intermediary code
      (https://sourceforge.net/tracker/index.php?func=detail&aid=1409597&group_id=145486&atid=762143),
      but this is not yet implemented.  There should be a hierarchy of invoke()
      methods and MBeanInfo objects corresponding to the agent class hierarchy.
      Please see the tutorial at http://jademx.sourceforge.net/tutorial.html .
      If you think something is unclear in or missing from the tutorial, please
      let me know (the jademx forum at
      https://sourceforge.net/forum/?group_id=145486 is a good way to do this).
      For detailed examples, the tutorial points to running code in the test
      suite, which comes with the source.

      I do think that there are a couple problems in the code that you posted.

      The first is related to specifying the method signature:

      <code>
      this.helloMsg = (String) agent.invoke("helloFromAgent",new Object[]
      {},new String[] {"java.lang.Void"});
      </code>
      (the method just returns a String like "Hello!"):
      <code>
      public String helloFromAgent(){
          return("Hello!");
      }
      </code>

      If there are no arguments to a method then the signature should be an
      empty string array, rather than containing "java.lang.Void", which I think
      might be a confusion from writing "void" indicate no arguments to a C
      function.  So, for example perhaps something like:

      this.helloMsg = (String)agent.invoke("helloFromAgent",new Object[]{}, new
      String[]{});

      might be more appropriate for what you intended in your case (if you had
      an "invoke()" method to match the call to your actual method and had
      described the agent to JMX with MBeanInfo), except that the agent's
      invoke() method is not really meant to be ever called by your code, which
      is the second problem.  It's not really right to interact directly with
      the JadeAgent object in your code.  Your code may be in a different JVM on
      a different physical machine.  In that case, the JadeAgent object would
      not be in your JVM.  You should have an MBeanServer object, which acts as
      a proxy to connect with the JMX code wherever your managed objects really
      are.  So, this example should be something more like:

      mBeanServer.invoke( agentObjectName, "helloFromAgent, new Object[]{}, new
      String[]{});

      This is admittedly a bit clumsy.  You can hide this and get some type
      safety in your code by making an agent proxy, which for you might look
      similar to:

      import jade.jademx.agent.JademxAgentProxy;
      import jade.jademx.mbean.JademxException;
      import javax.management.MBeanServer;
      import javax.management.ObjectName;
      public class MyAgentProxy extends JademxAgentProxy {
          public MyAgentProxy( ObjectName objectName, MBeanServer mBeanServer ) {
            super( objectName, mBeanServer );
          }
          public String helloFromAgent() throws JademxException {
              try {
                  return (String) mBeanServer.invoke(objectName,
                      "helloFromAgent",
                      new Object[] {},
                      new String[] {} );
              }
              catch (Exception e) {
                  throw new JademxException("exception invoking operation "
                          + "helloFromAgent", e);
              }
          }
      }

      and then you could just have code that looks like:

        MyAgentProxy myAgentProxy = new MyAgentProxy( myAgentObjectName,
      myAgentsMBeanServer );
        ...
        String hello = myAgentProxy.helloFromAgent();

      I'm not really familiar with "jboss.invoke", so I assume that's a good way
      to get an MBean with your JBoss installation.

      The latest release 0.4 was the first to support proxy methods to make it
      easier and more natural to invoke methods.  The tutorial describes this
      and points to an example.

      All that having been said, I should make clear to anybody who might
      misinterpret that jademx is *not* a replacement method for inter-agent
      communication, for which one should just use the JADE built-in messaging
      services.  The point of using jademx is to allow an agent to interact
      outside of the JADE system in a manner consistent with java standards
      (i.e. JMX).

      Best regards,
      Dave

      P.S.  I encourage anybody who is using jademx to post on the jademx forum
      listed above.  Knowing I have people actively using jademx helps to
      motivate me to work on it. :-)
      ------------------------

      Also, I suspect that your problem with waiting for the jademx agent binding is also caused by trying to invoke the method directly rather than through the MBeanServer.  The point of that method is to let your client pause while waiting for the agent and JMX to get synched up.

       
    • Timon

      Timon - 2006-03-19

      Hi Dave!

      Thanks for the reply!!"

      I still got a problem and the results i got from 2 days of testing are confusing me.

      I started my CommAgent within the jademx-config.xml (like the pingAgent-example) and the JadeAgent got the new MBeanInfo i created including my helloFromAgent method.

      The problem is:
      i have to use the jadePlatform.createNewAgent() method.
      <code>
      JadeAgent agent = (JadeAgent) jboss.invoke(new ObjectName("jade:Type=Platform,Name=platform0,Runtime=default"), "createNewAgent", args, sig);
      </code>

      This seemed to be succesfull but if i try this:
      <code>
      this.helloMsg = (String) jboss.invoke(new ObjectName("jade:Type=Agent,Name=CommAgent,Platform=platform0,Runtime=default"),"helloFromAgent", new Object[]{},new String[]{});
      </code>
      i still get the
      "ReflectionException: no action named "helloFromAgent" with given signature"
      This exception is thrown by the JadeAgent mBean, isn't it.

      Confusing is, that the jboss knows of the "helloFromAgent" and lets me invoke it per click.
      So there seemes to be an difference between starting an agent with the platform and starting it later.
      By the way if i do mBeanInfoChanged() in my Agent it says: JadeAgent is null...

      I already studied the source code but i can't figure out, what i have to do to connect JadeAgent and JademxAgent an the waitForJademxAgentBinding returns "false" whatever i do...

      As code says more than words, i post the to files ;-) :

      CommAgent.java
      -----------------------------
      public class CommAgent extends JademxAgent {

          public CommAgent() {
              super();

              MBeanOperationInfo oI[] = new MBeanOperationInfo[] { new MBeanOperationInfo(
                      "helloFromAgent", "einfachen String zurückgeben",
                      new MBeanParameterInfo[] {}, String.class.getName(),
                      MBeanOperationInfo.INFO) };

              MBeanInfo mBeanInfoThisLevel = new MBeanInfo(getClass().getName(),
                      "Der Kommunikationsagent", new MBeanAttributeInfo[0],
                      new MBeanConstructorInfo[0], oI, new MBeanNotificationInfo[0]);

              mBeanInfoSuper = super.getMBeanInfo();

              mBeanInfoMerged = MBeanUtil.mergeMBeanInfo(getClass().getName(),
                      "Der Kommunikationsagent", mBeanInfoThisLevel, mBeanInfoSuper);

              this.changedMBeanInfo();
         
          }//public CommAgent()

          /** MBeanInfo for this class and superclass(es) */
          private MBeanInfo mBeanInfoMerged = null;

          /** MBeanInfo for superclass(es) */
          private MBeanInfo mBeanInfoSuper = null;

          /** MBeanInfo for for this class but not superclass(es) */
          private MBeanInfo mBeanInfoThisLevel = null;

          /* Ein kurzes Hallo vom Agenten*/
          public String helloFromAgent() {
              return ("Hallo, ich bin ihr Kommunikationsagent");
          }

          /* this is a merge of the agent, this class, and this class's superclass.
           * @return MBean information for ping agent including JademxAgent
           */
          public MBeanInfo getMBeanInfo() {
              return mBeanInfoMerged;
          }

          /* invoke() überschreiben, sonst keene Chance das zu bekommen... */
          public Object invoke(String actionName, Object params[], String signature[])
                  throws MBeanException, ReflectionException {
              Object o = null;
              o = this.helloFromAgent();
              return o;
          }

          /* Alles was vor dem Ausführen der behaviors laufen soll
           * @see jade.core.Agent#setup()
           */
          protected void setup() {
              super.setup();

          }

      }
      -----------------------------

      CommAgentBean.java
      -----------------------------

      JBossMBeanServerLocator sl = new JBossMBeanServerLocator();
      MBeanServer jboss = sl.getMBeanServer();
                     
      Object args[] = {"CommAgent","agents.CommAgent",null};

      String sig[] = {"java.lang.String","java.lang.String","[Ljava.lang.Object;"};
      JadeAgent agent = (JadeAgent) jboss.invoke(new ObjectName("jade:Type=Platform,Name=platform0,Runtime=default"), "createNewAgent", args, sig);
                     
      this.helloMsg = (String) jboss.invoke(new ObjectName("jade:Type=Agent,Name=CommAgent,Platform=platform0,Runtime=default"),"helloFromAgent", new Object[]{},new String[]{});

      -----------------------------

      Regards,
      Timon

       
    • Timon

      Timon - 2006-03-19

      Hi again!

      I got another crazy thing.
      As i'm invoking the "createNewAgent" method in an (browser session lasting) MBean (Java Server Faces) and read the MBeanInfo directly... i got just the JadeAgent-Info and waitfor<...>Binding=false

      I got a button on my JSP to invoke that method again and there it is... got the new info and <...>Binding = true!

      On the first invoke i can wait 3 days an it will not bind. On the second invoke i use "getAgent" from the platform bean an it works.

      The problem is... if i use create and then get in the same run... it will fail :-X
      Strange to me but could have something to do with the MBeans from Java Server Faces?

      So long,
      Timon

       
      • Timon

        Timon - 2006-03-19

        Last result for today:
        i managed this problem with creating the agent in the constructor of my bean.
        When a button on the Jsp is pushed i use jade.jademx.mbean.JadePlatform.getAgent (with an invoke on the MBeanServer) to get my JadeAgent and it works :-)
        See you tomorrow :-P
        Timon

         
    • David Bernstein

      David Bernstein - 2006-03-20

      Hi Timon,

      I think your question pointed me to some improvements that I can make in the documentation.  I hope to get to that soon.  I've written an example program that runs under J2SE 1.5 that I believe is quite close to what you're trying to do. I hope it explains how things work; please let me know.  It uses the example ping agent that comes with the jademx source in its regression suite.  You may be pleased to note that going through the process of writing this example program caused me to note a few usability issues in the API that I hope to improve soon, although it should certainly be usable now. :-)

      Below is an example compile and run (dates removed from log messages), followed by the source code.

      Regards,
      Dave

      /////////////////START COMPILE AND RUN

      c:\foodir\jademx\example>javac -classpath .;C:\eclipse\workspace\jademx\classes\src;C:\eclipse\workspace\jademx\classes\test;C:\eclipse\workspace\jademx\lib\ext\jade.jar RunPingAgents.java

      c:\foodir\jademx\example>java -classpath .;C:\eclipse\workspace\jademx\classes\src;C:\eclipse\workspace\jademx\classes\test;C:\eclipse\workspace\jademx\lib\ext\jade.jar -Djmx.invoke.getters=true RunPingAgents

      INFO: jademx 0.4.0, LGPL license, http://jademx.sourceforge.net/
      INFO: ----------------------------------
          This is JADE 3.3 - 2005/03/02 16:11:05
          downloaded in Open Source, under LGPL restrictions,
          at http://jade.cselt.it/
      ----------------------------------------
      INFO: Service jade.core.management.AgentManagement initialized
      INFO: Service jade.core.messaging.Messaging initialized
      INFO: Service jade.core.mobility.AgentMobility initialized
      INFO: Service jade.core.event.Notification initialized
      INFO: --------------------------------------
      Agent container Main-Container@JADE-IMTP://diamond is ready.
      --------------------------------------------
      INFO: runtimeON:jade:Type=Runtime,Name=default
      INFO: platformON:jade:Type=Platform,Name=platform0,Runtime=default
      INFO: pingerAgentON:jade:Type=Agent,Name=pinger,Platform=platform0,Runtime=default
      INFO: pingeeAgentON:jade:Type=Agent,Name=pingee,Platform=platform0,Runtime=default
      INFO: response from pingee back to pinger:Hallo, ich bin ihr Kommunikationsagent

      c:\foodir\jademx\example>

      /////////////////END COMPILE AND RUN

      /////////////////START RunPingAgents.java
      // jademx - JADE management using JMX
      // Copyright 2006 Caboodle Networks, Inc.
      //
      // 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; either
      // version 2.1 of the License, or (at your option) any later version.
      //
      // 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA

      import jade.jademx.agent.JademxPingAgentProxy;
      import jade.jademx.config.jademx.onto.ConfigAgentSpecifier;
      import jade.jademx.config.jademx.onto.ConfigPlatform;
      import jade.jademx.config.jademx.onto.ConfigRuntime;
      import jade.jademx.config.jademx.onto.JademxConfig;
      import jade.jademx.mbean.JadeAgent;
      import jade.jademx.mbean.JadeFactory;
      import jade.jademx.mbean.JadeRuntimeMBean;
      import jade.jademx.server.JadeMXServer;
      import jade.jademx.server.JavaPlatform;

      import java.util.logging.Level;
      import java.util.logging.Logger;

      import javax.management.MBeanServer;
      import javax.management.ObjectName;

      /**
      * A complete example to show how to start, call, and stop jademx agents.
      * Uses the regression test jade.jademx.agent.JademxPingAgent class and its
      * proxy class JademxPingAgentProxy, both included with jademx source.
      */
      public class RunPingAgents {

          /** my logger */
          private final static Logger logger =
          Logger.getLogger(RunPingAgents.class.getName());

          /** MBeanServer being used */
          private MBeanServer mBeanServer = null;
          /** ObjectName for JadeRuntimeMBean */
          private ObjectName runtimeON = null;
          /** ObjectName for JadePlatformMBean */
          private ObjectName platformON = null;
          /** ObjectName for JadeAgentMBean of agent "pinger" */
          private ObjectName pingerAgentON = null;
          /** ObjectName for JadeAgentMBean of agent "pingee" */
          private ObjectName pingeeAgentON = null;
          /** created JadeRuntimeMBean */
          private JadeRuntimeMBean runtime = null;
          /** proxy for "pinger" agent */
          private JademxPingAgentProxy pingerProxy = null;
          /** proxy for "pingee" agent */
          private JademxPingAgentProxy pingeeProxy = null;

          private JademxConfig buildPingerAgentCfg() {
          // instantiate the configuration we're going to return
              JademxConfig jademxConfig = new JademxConfig();
          // runtime at top of hierarchy
              ConfigRuntime cfgRuntime = new ConfigRuntime();
              jademxConfig.addRuntime( cfgRuntime );
          // one platform
              ConfigPlatform platform = new ConfigPlatform();
              cfgRuntime.addPlatform( platform );
              platform.addOption( "port=1917" );
              platform.addOption( "nomtp=true" );
          // add JademxPingAgent as "pinger" as part of original configuration
              ConfigAgentSpecifier agentSpecifier;
              agentSpecifier = new ConfigAgentSpecifier(
                          "pinger",
                          "jade.jademx.agent.JademxPingAgent" );
              platform.addAgentSpecifier( agentSpecifier );
          // return the constructed configuration
              return jademxConfig;
          }

          protected void setUp() throws Exception {
              // create a jademx config of one ping agent
              JademxConfig jademxConfig = buildPingerAgentCfg();
              // start the configuration
              // first get JadeMXServer
              JadeMXServer jadeMXServer = new JavaPlatform();
              mBeanServer = jadeMXServer.getMBeanServer();
              // now get a factory to use
              JadeFactory jadeFactory = new JadeFactory( jadeMXServer );
              // instantiate the configuration
          runtime = jadeFactory.instantiateRuntime( jademxConfig );
              // get ObjectName for runtime
              runtimeON = runtime.getObjectName();
          logger.log( Level.INFO, "runtimeON:"+runtimeON);
              // get ObjectName for platform
          ObjectName[] platformObjectNames = (ObjectName[])
              mBeanServer.invoke( runtimeON,
                      "getPlatformObjectNames",
                      new Object[]{},
                      new String[]{} );
          platformON = platformObjectNames[0];
          logger.log( Level.INFO, "platformON:"+platformON);
          // get ObjectName for "pinger" agent
          pingerAgentON = (ObjectName)
              mBeanServer.invoke( platformON,
                      "getAgentObjectName",
                      new Object[]{"pinger"},
                      new String[]{"java.lang.String"} );       
          logger.log( Level.INFO, "pingerAgentON:"+pingerAgentON);
          // add the "pingee" agent to the already started platform
          String pingeeName = (String)
              mBeanServer.invoke( platformON,
                      "createNewAgentReturnName",
                      new Object[]{
                          "pingee",
                          "jade.jademx.agent.JademxPingAgent",
                          null},
                      new String[]{
                          "java.lang.String",
                          "java.lang.String",
                          Object[].class.getName()} );
          pingeeAgentON = new ObjectName( pingeeName );
          logger.log( Level.INFO, "pingeeAgentON:"+pingeeAgentON);
          // make agent proxies for easier access
          pingerProxy = new JademxPingAgentProxy( pingerAgentON, mBeanServer );
          pingeeProxy = new JademxPingAgentProxy( pingeeAgentON, mBeanServer );
          }

          protected void tearDown() throws Exception {
              // shutdown the configuration
          mBeanServer.invoke( runtimeON,
                      JadeRuntimeMBean.OPER_SHUTDOWN,
                      new Object[]{},
                      JadeRuntimeMBean.OPER_SHUTDOWN_SIGNATURE );
          }

          public void run() {
          try {
              setUp();
              pingeeProxy.setResponse("Hallo, ich bin ihr Kommunikationsagent");
              String pingeeFullName = (String)
              mBeanServer.getAttribute( pingeeAgentON,
                            JadeAgent.ATTR_FULL_NAME );
              String pingResponse = pingerProxy.ping( pingeeFullName );
              logger.log( Level.INFO, "response from pingee back to pinger:"+
                  pingResponse);
              tearDown();
          }
          catch ( Exception e ) {
              throw new RuntimeException( e );
          }
          }

          public static void main( String args[] ) {
          RunPingAgents runPingAgents = new RunPingAgents();
          runPingAgents.run();
          System.exit(0);
          }

      }

      /////////////////END RunPingAgents.java

       
    • Timon

      Timon - 2006-03-20

      Hi Dave!
      I think there still a difference between my and your processing.
      You start the platform and the agent at the same time using a platformConfig. I deleted the lines that start the agent with the platform (in jademx-config.xml) to start it on the already running empty platform.
      So the confusing thing is:
      i use JadePlatform.createAgent() to get an agent and then directly read the OperationInfos with JadeAgent.getMBeanInfo() which should succeed with my added info because creatAgent() calls the JademxAgents constructor and it's setup() (where the super() constructor and setup() is called).

      I created a new logger and it showed me a surprising sequence of called methods:
      createAgent() calles my JademxAgents constructor (but not the setup()!!!);
      then my command getMBeanInfo() is invoked ond the JadeAgent;
      and now the JademxAgents setup() is called (thats obviously to late ;-) )

      That definitly explains why i didn't get my own written method at first try, but at the second.
      Thats why i put the createAgent() in the JSF-Beans constructor, which is called when the user arrives my Jsp. So if he pushed the button on the same Jsp that invokes the helloFromAgent() through the same Bean it will succeed.

      I looked at the createAgent() src-code but i'm still not getting the point why this method does not instantly returns an JadeAgent with references to my JademxAgent while on the second try the binding is done.
      Also, i can't point out if it is an JFS-Bean problem or something related to the createAgent().

      Well, putting it in the beans constructor works for me, but it still is an interesting point to me.

      Greetings,
      Timon

       
    • David Bernstein

      David Bernstein - 2006-03-20

      Timon,

      The jademx system sits inbetween JADE and the agent and does not have any special agent knowledge; in particular, it does not start with a reference to the instantiated jade.core.Agent object.  Please take a look at the javadoc comment for JadeAgent (http://jademx.sourceforge.net/api/jade/jademx/mbean/JadeAgent.html) for the design issues and tradeoffs.  Please note that a superclass of JademxAgent is not registered as a DynamicMBean with JMX and does not have its particular JMX attributes/operations/notifications exposed until JademxAgent.setup() has been called (which should usually be a super.setup() call from the agent's own setup() method).  It is not until after that event that the agent has registered itself with jademx and JMX and a JadeAgent object then has a jade.jademx.agent.JademxAgent reference and can call the real agent's invoke()/getAttribute()/setAttribute() methods.

      In the example I posted I made a point of starting agents both with platform startup and also with createNewAgent to show that attributes can be accesseed and operations can be invoked on agents that have been started either way.

      If you're interested in seeing a complete running example of a jademx system that runs under JBoss, the open-source Semantical Project (http://www.semantical.org/) is implemented this way.  It starts jademx by configuring the JBoss web.xml to notice that the servlet context has been initialized.  Its agents are then created from a configuration file.  It seems to me that you could follow a similar design pattern or modify it so that agents are created using createNewAgent().

      I hope with the examples of RunPingAgents using a proxy to access an agent started by createNewAgent() and Semantical starting up under JBoss, that you should be able to morph the code into something that works for you.

      Best regards,
      Dave

       

Log in to post a comment.