2017-02-17 71 views
0

我的项目简要描述: 我正在写一个名为“GreetingsNode”的java类,它在分布式环境中工作,其中有一个“managementNode”作为服务存储库并接收和存储其他节点的信息(主机端口号和所提供的服务),并分发由注册服务提供的方法的RPC。如果一个节点可以回答RPC,则打开一个节点套接字并在主叫节点和应答节点之间建立连接,并且应答节点返回结果。Apache Thrift RPC在分布式环境中的Java方法实现

我使用Apache thrift作为IDL和RPC的框架。

现在的问题。 My GreetingsNodeHandler类实现了一个包含单个方法“getHello(user)”(用户是包含节点名称的结构,它是GreetingsNode类的构造函数的参数)的简单节点接口。 当连接到管理节点的GreetingsNode X创建该方法的RPC时,另一个注册的GreetingsNode必须回答消息“hello X”。

我不明白如何实现返回结果的处理程序部分,因此我无法理解应该如何编写junit测试来检查方法实现是否正常工作。

断言像 的assertEquals(client.getHello(用户).getMessage(), “John Doe:您好”)

会的工作,但我不明白怎么回事,在我的情况,我应该把客户端部分...

为GreetingService的节俭服务代码:

struct Message { 
    1: string message 
} 

struct User { 
    1: string name 
} 

service GreetingsService { 
    Message getHello(1: User user) 
} 

代码GreetingsServiceHandler必须实现GreetingsService方法getHello()

public class GreetingsServiceHandler implements GreetingsService.Iface { 

private static Random random = new Random(10); 
private ManagementService.Client managementClient; 
private GreetingsService.Client helloClient; 

@Override 
public Message getHello(User user) throws TException { 
    Message answer = null; 
    // class ServiceProvider is generated by thrift, part of ManagementService thrift service 
    ServiceProvider provider = null; 
    List<ServiceProvider>providers = managementClient.getProvidersForService(user.name); 

    if (providers.isEmpty()) 
     throw new NoProviderAvailableException(); //separate file contains Exception 
    else { 
     provider = providers.get(random.nextInt(providers.size())); 
     //connection between nodes is established here 
     TTransport helloTransport = new TSocket(provider.getHostName(), provider.getPort()); 
     TProtocol helloProtocol = new TBinaryProtocol(helloTransport); 
     helloClient = new GreetingsService.Client(helloProtocol); 
     helloTransport.open(); 

     // here lies my problem 
     answer = helloClient.getHello(user); 
     //if I use this instead, then helloClient variable is clearly not used, but of course I need it to answer the method call 
     answer = answer.setMessage("Ciao " + user.getName() + ", welcome among us!"); 

    } 
    return answer; 

} 

和GreetingsNode代码如下:

public class GreetingsNode implements NodeIface { 

private ThriftServer helloServer; 
private ManagementService.Client managementClient; 
private NodeManifest nodeManifest; 
private User user; 
private String name; 

public GreetingsNode(NodeManifest nodeManifest, String name) { 
    this.nodeManifest = nodeManifest; 
    this.helloServer = new ThriftServer(GreetingsServiceHandler.class); 
    this.name = name; 
} 

@Override 
public void turnOn() throws TException { 

    helloServer.start(); 

    TSocket helloServerTransport = new TSocket("localhost", Constants.SERVER_PORT); 
    TBinaryProtocol helloServerProtocol = new TBinaryProtocol(helloServerTransport); 
    managementClient = new ManagementService.Client(helloServerProtocol); 
    this.setUser(new User(name)); 
    helloServerTransport.open(); 

    helloServer = new ThriftServer(GreetingsServiceHandler.class); 
    //portNegotiator is a class described in a separate file, that handles the registration of other nodes to the managementNode. NodeManifest is a file generated by thrift, part of managementService thrift file, describing a struct that contains hostname and port number of nodes. 
    PortNegotiator negotiator = new PortNegotiator(managementClient); 
    negotiator.negotiate(nodeManifest, helloServer); 

} 

@Override 
public void turnOff() { 
    helloServer.stop(); 
} 

public User getUser() { 
    return user; 
} 

public void setUser(User user) { 
    this.user = user; 
} 
+0

你有看过[教程代码](https:// thrift。apache.org/tutorial/java)? – JensG

+0

当然我做了,我已经实现了一个函数算术计算器,其中“算法节点”应答由另一个节点所做的“executeOperation”方法的调用。 当我使用字符串时,我无法翻译这种行为...不知道为什么实际上因为这个概念应该是非常相似,如果不相同 – Gaspare79

回答

1

的基本方法在处理IMPL是非常简单的,类似下面应该做的(免责声明:未测试):

@Override 
public Message getHello(User user) throws TException { 
    Message answer = new Message(); 
    answer = answer.setMessage("Ciao " + user.getName() + ", welcome among us!"); 
    return answer; 
} 

如果我用这个代替,那么helloClient变量显然没有用,但我当然需要它来回答方法调用

当连接到管理节点的GreetingsNode X创建该方法的RPC时,另一个注册的GreetingsNode必须回答消息“hello X”。

如果这意味着我们要像客户端=>服务器A =>服务器B调用序列则这也是可能的,只需要稍作修改。从我们的基本出发例如上面,我们相应提高了代码:

private Message callTheOtherNode(User user) { 
    // class ServiceProvider is generated by Thrift, 
    // part of ManagementService Thrift service 
    ServiceProvider provider = null; 
    List<ServiceProvider>providers = managementClient.getProvidersForService(user.name); 

    if (providers.isEmpty()) 
     throw new NoProviderAvailableException(); //separate file contains Exception 

    provider = providers.get(random.nextInt(providers.size())); 
    //connection between nodes is established here 
    TTransport helloTransport = new TSocket(provider.getHostName(), provider.getPort()); 
    TProtocol helloProtocol = new TBinaryProtocol(helloTransport); 
    helloClient = new GreetingsService.Client(helloProtocol); 
    helloTransport.open(); 
    return helloClient.getHello(user); 
} 

@Override 
public Message getHello(User user) throws TException { 
    Message answer = callTheOtherNode(user); 
    return answer; 
} 

当然,“其他节点”被称为需求真正做到与请求的东西,而不是简单地转发一遍又一节点。

+0

我怀疑我过于复杂:( 非常感谢您的先生 – Gaspare79

+0

两个疑问:1)我不知道应该在哪里放置私人CallOtherNode方法的代码,它会在Handler文件中,我猜。这样做会使eclipse发出警告,“来自GreetingsServiceHandler类型的方法CallOtherNode(User)从不在本地使用”2)第二个getHello()应该以不同的方式命名和/或包含在我的thrift服务文件中,否则eclipse会一直告诉我(正确)“的GreetingsServiceHandler类型的方法sayHello(用户)必须覆盖或实现超类型方法”(因为它不包含在生成的节俭文件中)。 – Gaspare79

+0

是的,呼叫序列将是Client(它是一个GreetingsNode)==> Server A(它是managementNode)==> Server B(它是另一个Greetings节点)。然后,服务器B与客户建立连接并接听电话。 – Gaspare79