this is my very first thread on StackOverflow so please be patient!

Starting from a simple thrift service, I want to create a java client/server application, where each node offers one or more services to other nodes in a distributed computing system. I want to start with a simple system where each node is characterized by two strings, "hostname" and "servicename", that identify each from others. I have created this class:

class NodePort <Node, integer> {
  private Node node;
  private int port;

  NodePort(Node node, int port) {
    this.node = node;
    this.port = port;
  }

  Node getNode() {
    return node;
  }

  int getPort() {
    return port;
  }
}

Then, I've written a management thrift service that does two things:

1) registers a node to a server, returning the port used

2) lists all the services available at the moment

typedef i32 int

struct Node {
  1: string hostName,
  2: string serviceName,
}

service ManagementService {
  int NodeRegister(i32 port)
  Node getNodeForService(Node node)
}

When NodeRegister is used, the server creates a Map where keys are given by serviceNames and values are NodePorts, and returns the port used by the client.

When getNodeForService is used, it should return a list of services present in the Map registered by a client.

I'm not sure about how to write the implementation of the two methods. I've written this but when I try a test it doesn't work:

import org.apache.thrift.TException;

import it.uniud.atta.profiling.thrift.ManagementService;

public class ManagementServiceImpl implements ManagementService.Iface {

  public int NodeRegister(int port) throws TException {
    return port;
  }

  public Node getNodeForService(Node node) throws TException {
    return node;
  }
}

I'm pretty sure that this doesn't work the way I want, and also I don't really know where to put the Map code. How could I proceed?

Thanks in advance for any help!

edit: I'm adding the content of my "answer to the question with a question" post. Sorry about it, next time i'll read the rules better!

i actually need help writing the test file. So far i've created a standard thrift server listening on a port, and a thrift client. The code is the following:

public class ManagementServiceTest {

public static class Server implements Runnable {

private TServer tserver;

  public void run() {
      try {
           TServerSocket serverTransport = new TServerSocket(7911);

           ManagementService.Processor<ManagementServiceHandler> processor = new      ManagementService.Processor<ManagementServiceHandler>(new ManagementServiceHandler());

           tserver = new TThreadPoolServer(new TThreadPoolServer.Args(serverTransport).
                    processor(processor));
           System.out.println("Starting server on port 7911 ...");
           tserver.serve();
          } catch (TTransportException e) {
              e.printStackTrace();
          }
   }

  public void start() {
    new Thread(this).start();
  }

  public void unserve() {
    tserver.stop();
  } 
}

@Test
public void testServerCompletion() {
    Server server = new Server();
    server.start();

    TTransport transport;
    try {

        Thread.sleep(200);
            transport = new TSocket("localhost", 7911);
            TProtocol protocol = new TBinaryProtocol(transport);

            ManagementService.Client client = new ManagementService.Client(protocol);
            transport.open();



//          client.getNodes(testNode.hostName, testNode.serviceName);
//          System.out.println("Servizi disponibili: " + testNode.serviceName);
//            
//          for (String key: nodes.keySet()) {
//
//                System.out.println("key : " + key);
//                System.out.println("value : " + nodes.get(key));            

            transport.close();

            server.unserve();   
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

I'm not sure about what do I have to write after the transport.open() line. Right now, I should have a server open on port 7911 and listening, a transport open and an unused client variable that I need to initialize. I want to use the RegisterNode() method and the getNodes() method, but so far all my attempts have been unsuccessfull. i've tried with:

Node node1;
node1 = client.RegisterNode(1025);

but it returns "The method RegisterNode(Node, int) in the type ManagementService.Client is not applicable for the arguments (String, int)"

So i tried with

Node node1;
node1 = client.RegisterNode(node1, 1025);

but it returns "Type mismatch: cannot convert from int to Node".

I haven't tried with the other method yet, but I guess i'll receive a similar kind of errors.

I'm not sure I've understood how to write a test file... Any hint?

edit: ok, I've managed to solve the problem with this:

int port = 0;
Node node1 = new Node();
node1.hostname = "Node 1";
node1.serviceName = "Hello World Service";
port = client.RegisterNode(node1, 1025);
System.out.println("Node hostname: " + node1.hostName + "Node Port Used: " + port);

it indeed returns the name of the node and the port used.

Now the second method, getNodes(), presents issues as well. I'm using this:

Nodes nodes = new Nodes();
client.getNodes(node1.hostName, node1.serviceName);
System.out.println("Servizi disponibili: " + node1.serviceName);

for (String key: nodes.keySet()) {

  System.out.println("key : " + key);
  System.out.println("value : " + nodes.get(key));    
}

but it returns two errors about keySet() and get() methods not being defined for the tyoe Nodes. I'm not sure on how should I proceed...

有帮助吗?

解决方案

I would structure the service differently, like so:

struct Node {
  1: string hostName,
  2: string serviceName,
}

struct Nodes {
  1: map<Node, i32>  allNodes
}

service ManagementService {
  /** registers a node to a server, returning the port used */
  i32 RegisterNode(1 : Node hostAndService, 2 : i32 preferredPort)

  /** lists all the services available at the moment. 
      Optionally specify host and/or service name to narrow the search */
  Nodes GetNodes(1: string host, 2: string service)
}

The map<> code would be in both service routines. In RegisterNode() a node is added to the map, in GetNodes() the map would be scanned for the values needed.

Sample code, not tested (not even compiled, to be honest):

public static class ManagementServiceHandler implements ManagementService.Iface {

    private Map<Node,int> nodes;

    public ManagementServiceHandler() 
    {
        nodes = new Map<Node,int>()
    }

    /**
     * registers a node to a server, returning the port used
     */
    public int RegisterNode(Node hostAndService, int preferredPort) {
        int port = preferredPort;
        // TODO: check whether port can be used
        nodes.Add( hostAndService, port);
        return port;    
    }

    /**
     * lists all the services available at the moment.
     * Optionally specify host and/or service name to narrow the search
     */
    public Nodes GetNodes(String host, String svcname)  {
        var Nodes retval = new Nodes();
        retval.allNodes = new Map<Node,int>();

        for( var node : nodes) {
            if( (host.isEmpty() || (host == node.key.host)) {
                if( (svcname.isEmpty() || (svcname == node.key.serviceName)) {
                    retval.allNodes.add(node)
                }
            }
        }

        return retval;
    }
}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top