Archived

This forum has been archived. Please start a new discussion on GitHub.

Error sending object to server

Hi,

I'm trying to make a program with a generic mobile agent. Both server and client have an abstract class called "Agent" and another class called "AgentI" which extends Agent implementing the required method(s).
I made a method to send an "Agent" to the server and try to send an instance from "AgentI". It returns "NoObjectFactoryException" even though I made one.

Client code:
ClientContactPrx receiver = ...
ServerContactPrx sender = ...		
Agent age = new AgentI();
Ice.ObjectFactory factory = new AgentObjectFactory();
communicator().addObjectFactory(factory, MobileAgent.Agent.ice_staticId());
sender.initiate(age, receiver); //line 50

AgentI class:
public class AgentI extends Agent {
    public int execute(Current __current) {
        System.out.println("Success!!!");
        return 0;
    }
}

AgentObjectFactory's "create" method:
public Object create(String type) {
    if (type.equals("::MobileAgent::Agent"))
        return new AgentI();
    return null;
}

Server's "initiate" method:
public int initiate(Agent agent, ClientContactPrx proxy, Current __current) {
    System.out.println("Request received");
    agent.execute();
    return 0;
}

Client output:
!! 22/03/12 19:47:29:956 Client: error: main: Ice.UnknownLocalException
unknown = "Ice::NoObjectFactoryException
Ice.NoObjectFactoryException

reason = ""

type = "::MobileAgent::Agent"

at IceInternal.BasicStream.readObject(BasicStream.java:1440)

at IceInternal.BasicStream.readPendingObjects(BasicStream.java:1665)

at MobileAgent._ServerContactDisp.___initiate(_ServerContactDisp.java:96)

at MobileAgent._ServerContactDisp.__dispatch(_ServerContactDisp.java:142)

at IceInternal.Incoming.invoke(Incoming.java:159)

at Ice.ConnectionI.invokeAll(ConnectionI.java:2357)

at Ice.ConnectionI.dispatch(ConnectionI.java:1208)

at Ice.ConnectionI.message(ConnectionI.java:1163)

at IceInternal.ThreadPool.run(ThreadPool.java:302)

at IceInternal.ThreadPool.access$300(ThreadPool.java:12)

at IceInternal.ThreadPool$EventHandlerThread.run(ThreadPool.java:643)

at java.lang.Thread.run(Unknown Source)

"
at IceInternal.Outgoing.invoke(Outgoing.java:147)
at MobileAgent._ServerContactDelM.initiate(_ServerContactDelM.java:43)
at MobileAgent.ServerContactPrxHelper.initiate(ServerContactPrxHelper.java:53)
at MobileAgent.ServerContactPrxHelper.initiate(ServerContactPrxHelper.java:28)
at client.Client.run(Client.java:50)
at Ice.Application.doMain(Application.java:202)
at Ice.Application.main(Application.java:182)
at Ice.Application.main(Application.java:118)
at client.Client.main(Client.java:20)

Server output:
-! 22/03/12 19:47:29:947 Server 1: warning: Ice.ThreadPool.Server-0: dispatch exception:
identity: Contact
facet:
operation: initiate
remote host: ... remote port: 50313
Ice.NoObjectFactoryException
reason = ""
type = "::MobileAgent::Agent"
at IceInternal.BasicStream.readObject(BasicStream.java:1440)
at IceInternal.BasicStream.readPendingObjects(BasicStream.java:1665)
at MobileAgent._ServerContactDisp.___initiate(_ServerContactDisp.java:96)
at MobileAgent._ServerContactDisp.__dispatch(_ServerContactDisp.java:142)
at IceInternal.Incoming.invoke(Incoming.java:159)
at Ice.ConnectionI.invokeAll(ConnectionI.java:2357)
at Ice.ConnectionI.dispatch(ConnectionI.java:1208)
at Ice.ConnectionI.message(ConnectionI.java:1163)
at IceInternal.ThreadPool.run(ThreadPool.java:302)
at IceInternal.ThreadPool.access$300(ThreadPool.java:12)
at IceInternal.ThreadPool$EventHandlerThread.run(ThreadPool.java:643)
at java.lang.Thread.run(Unknown Source)


What am I doing wrong?

- Rafael

Comments

  • benoit
    benoit Rennes, France
    Hi,

    You need the register the object factory on the peer that receives the object, in your case, it's the server that receives the object and therefore needs to instantiate it. So you should register the object factory in the server instead of the client.

    In the object factory implementation I also recommend using the static id rather a plain string to compare the type ID of the Slice class:
    public Object create(String type) {
        if (type.equals(MobileAgent.Agent.ice_staticId()))
            return new AgentI();
        return null;
    }
    

    Cheers,
    Benoit.
  • Hi Benoit,

    Thank you for the fast reply.
    In the ice demo "value" the client was registering the object factory, but now I see in that scenario the client was receiving the server's object. Here I have the opposite. It's working now.

    - Rafael
  • Hello again,

    I tried to implement the method I need instead of just showing the message "Success!!!" and I got a problem. Looks like when the object is "transferred" it is actually not transferred; a new object is created and the content of the original object's attributes are lost.

    How can I transfer an object and keep it's attributes values?

    - Rafael
  • benoit
    benoit Rennes, France
    Hi,

    Only attributes declared in the Slice class are transferred over the wire. The Slice attributes are marshaled by the client and upon receive the server instantiate a new object and un-marshalls the Slice attributes. So you must declare the attributes in the Slice if you want them to be transferred.

    Cheers,
    Benoit.
  • Hello again,

    Being unable to transfer the extended class' attributes messed up the idea of a "generic agent". I've been trying to do it manually but it can't be helped. I'll have to make a byte array in the slice which can be used to store all variables values... unless there is another option:

    CORBA has the type "any". For example:
    interface Example {
      void op(in any value);
    };
    

    I read the Ice manual but didn't find it. Does Ice have the type "any" or anything which does the job?

    - Rafael
  • benoit
    benoit Rennes, France
    Hi Rafael,

    There's no need for an Any type with Slice :). What about the following slice to implement your generic agents:
    class AbstractAgent
    {
         int execute();
    };
    
    class ConcreteAgent1 extends AbstactAgent
    {
         string attr1;
    };
    
    class ConcreteAgent2 extends AbstactAgent
    {
         int attr1;
    };
    
    

    Wouldn't this achieve what you're looking for?

    Cheers,
    Benoit.
  • Hi Benoit,

    I was trying to do it in a way you wouldn't need to edit the slice file and build again, but your suggestion is interesting as the class Agent (the "generic agent") will always stay the same. I'll try that.

    Thank you.

    - Rafael