mirror of https://github.com/longtai-cn/hippo4j
add new model hippo4j-rpc and Transfer rpc code to hippo4j-rpc (#912)
* fix : add new model hippo4j-rpc (#812) * fix : fix : Transfer code to hippo4j-rpc (#812) * fix : Add set multiple ChannelHandler(#812) * fix : Code format modificationpull/913/head
parent
f19ec20c57
commit
ed19c983f2
@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>cn.hippo4j</groupId>
|
||||
<artifactId>hippo4j-all</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<artifactId>hippo4j-rpc</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<properties>
|
||||
<maven.deploy.skip>true</maven.deploy.skip>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>cn.hippo4j</groupId>
|
||||
<artifactId>hippo4j-common</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-all</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hippo4j.rpc.handler;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* Manage the Handler used in the processing.<br>
|
||||
* The Handler must be able to exist multiple times and be invoked once in a single execution
|
||||
*/
|
||||
public interface HandlerManager<T> {
|
||||
|
||||
/**
|
||||
* Add handler to the end of the Handler chain
|
||||
*
|
||||
* @param name name
|
||||
* @param handler handler
|
||||
*/
|
||||
HandlerManager<T> addLast(String name, T handler);
|
||||
|
||||
/**
|
||||
* Add handler to the head of the Handler chain
|
||||
*
|
||||
* @param name name
|
||||
* @param handler handler
|
||||
*/
|
||||
HandlerManager<T> addFirst(String name, T handler);
|
||||
|
||||
/**
|
||||
* Add handler to the end of the Handler chain, without specifying a name
|
||||
*
|
||||
* @param handler handler
|
||||
*/
|
||||
HandlerManager<T> addLast(T handler);
|
||||
|
||||
/**
|
||||
* Adds handler to the head of the Handler chain, without specifying a name
|
||||
*
|
||||
* @param handler handler
|
||||
*/
|
||||
HandlerManager<T> addFirst(T handler);
|
||||
|
||||
/**
|
||||
* Create a handler
|
||||
*
|
||||
* @param order order
|
||||
* @param handler Handler
|
||||
* @param name Handler name
|
||||
* @return HandlerEntity
|
||||
*/
|
||||
default HandlerEntity<T> getHandlerEntity(long order, T handler, String name) {
|
||||
return new HandlerEntity<>(order, handler, name);
|
||||
}
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
class HandlerEntity<T> implements Comparable<HandlerEntity<T>> {
|
||||
|
||||
/**
|
||||
* order, The Handler with a larger value is executed after the Handler with a smaller value
|
||||
*/
|
||||
long order;
|
||||
|
||||
/**
|
||||
* handler
|
||||
*/
|
||||
T handler;
|
||||
|
||||
/**
|
||||
* A high level summary of handler functionality
|
||||
*/
|
||||
String name;
|
||||
|
||||
@Override
|
||||
public int compareTo(HandlerEntity<T> o) {
|
||||
return (int) (this.getOrder() - o.getOrder());
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hippo4j.rpc.handler;
|
||||
|
||||
import cn.hippo4j.common.web.exception.IllegalException;
|
||||
import cn.hippo4j.rpc.response.Response;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
|
||||
/**
|
||||
* Interconnect with the netty mediation layer
|
||||
*/
|
||||
@ChannelHandler.Sharable
|
||||
public class NettyClientTakeHandler extends AbstractNettyTakeHandler implements ConnectHandler {
|
||||
|
||||
@Override
|
||||
public void channelRead(ChannelHandlerContext ctx, Object msg) {
|
||||
try {
|
||||
Response response = (Response) msg;
|
||||
handler(response);
|
||||
ctx.flush();
|
||||
} catch (Exception e) {
|
||||
ctx.close();
|
||||
throw new IllegalException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hippo4j.rpc.handler;
|
||||
|
||||
import cn.hippo4j.common.toolkit.Assert;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Processor manager for ChannelHandler in netty
|
||||
*/
|
||||
public abstract class NettyHandlerManager implements HandlerManager<ChannelHandler> {
|
||||
|
||||
protected final List<HandlerEntity<ChannelHandler>> handlers;
|
||||
|
||||
AtomicLong firstIndex = new AtomicLong(-1);
|
||||
|
||||
AtomicLong lastIndex = new AtomicLong(0);
|
||||
|
||||
protected NettyHandlerManager(List<ChannelHandler> handlers) {
|
||||
this.handlers = handlers.stream()
|
||||
.filter(Objects::nonNull)
|
||||
.map(c -> getHandlerEntity(lastIndex.getAndIncrement(), c, null))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
protected NettyHandlerManager(ChannelHandler... handlers) {
|
||||
this(handlers != null ? Arrays.asList(handlers) : Collections.emptyList());
|
||||
}
|
||||
|
||||
protected NettyHandlerManager() {
|
||||
this.handlers = new LinkedList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @param name name
|
||||
* @param handler handler
|
||||
* @return NettyHandlerManager
|
||||
*/
|
||||
public NettyHandlerManager addLast(String name, ChannelHandler handler) {
|
||||
Assert.notNull(handler);
|
||||
this.handlers.add(getHandlerEntity(lastIndex.getAndIncrement(), handler, name));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @param name name
|
||||
* @param handler handler
|
||||
* @return NettyHandlerManager
|
||||
*/
|
||||
public NettyHandlerManager addFirst(String name, ChannelHandler handler) {
|
||||
Assert.notNull(handler);
|
||||
this.handlers.add(getHandlerEntity(firstIndex.getAndIncrement(), handler, name));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @param handler handler
|
||||
* @return NettyHandlerManager
|
||||
*/
|
||||
public NettyHandlerManager addLast(ChannelHandler handler) {
|
||||
Assert.notNull(handler);
|
||||
this.handlers.add(getHandlerEntity(lastIndex.getAndIncrement(), handler, null));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @param handler handler
|
||||
* @return NettyHandlerManager
|
||||
*/
|
||||
public NettyHandlerManager addFirst(ChannelHandler handler) {
|
||||
Assert.notNull(handler);
|
||||
this.handlers.add(getHandlerEntity(firstIndex.getAndDecrement(), handler, null));
|
||||
return this;
|
||||
}
|
||||
}
|
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hippo4j.rpc.process;
|
||||
|
||||
import cn.hippo4j.rpc.request.Request;
|
||||
import cn.hippo4j.rpc.response.Response;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Processor chain for easier processing of processors in different scenarios<br>
|
||||
* reference resources: spring HandlerExecutionChain
|
||||
*
|
||||
* @see ActivePostProcess
|
||||
*/
|
||||
@Slf4j
|
||||
public final class ActiveProcessChain {
|
||||
|
||||
/**
|
||||
* A collection of processors that will be applied to their assigned programs.
|
||||
* Processors will perform different actions on different occasions for both the server and the client,
|
||||
* but the execution period of that action must be the same
|
||||
*/
|
||||
List<ActivePostProcess> processes;
|
||||
|
||||
/**
|
||||
* index <br>
|
||||
* that identifies where the {@link ActivePostProcess#preHandler(Request)} processing is performed<br>
|
||||
* This allows for the fact that some processors will add shutable operations to the class<br>
|
||||
* eg: {@link java.io.Closeable}, The {@link ActivePostProcess#afterCompletion(Request, Response, Exception)}
|
||||
* operation is not performed after an exception if the preprocessor is not executed
|
||||
*/
|
||||
int index = -1;
|
||||
|
||||
public ActiveProcessChain(List<ActivePostProcess> processes) {
|
||||
this.processes = processes;
|
||||
}
|
||||
|
||||
public ActiveProcessChain(ActivePostProcess... processes) {
|
||||
this((processes != null ? Arrays.asList(processes) : Collections.emptyList()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply postHandle methods of registered processes.
|
||||
*/
|
||||
public boolean applyPreHandle(Request request) {
|
||||
for (int i = 0; i < this.processes.size(); i++) {
|
||||
ActivePostProcess handle = processes.get(i);
|
||||
if (!handle.preHandler(request)) {
|
||||
afterCompletion(request, null, null);
|
||||
return false;
|
||||
}
|
||||
this.index = i;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply postHandle methods of registered processes.
|
||||
*/
|
||||
public void applyPostHandle(Request request, Response response) {
|
||||
for (int i = processes.size() - 1; i >= 0; i--) {
|
||||
ActivePostProcess handle = processes.get(i);
|
||||
handle.postHandler(request, response);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger afterCompletion callbacks on the mapped ActivePostProcess.
|
||||
* Will just invoke afterCompletion for all interceptors whose preHandle invocation
|
||||
* has successfully completed and returned true.
|
||||
*/
|
||||
public void afterCompletion(Request request, Response response, Exception ex) {
|
||||
for (int i = this.index; i >= 0; i--) {
|
||||
ActivePostProcess handle = processes.get(i);
|
||||
try {
|
||||
handle.afterCompletion(request, response, ex);
|
||||
} catch (Throwable e) {
|
||||
log.error("HandlerInterceptor.afterCompletion threw exception", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hippo4j.rpc.client;
|
||||
|
||||
import cn.hippo4j.rpc.handler.NettyClientPoolHandler;
|
||||
import cn.hippo4j.rpc.handler.NettyClientTakeHandler;
|
||||
import cn.hippo4j.rpc.handler.NettyServerTakeHandler;
|
||||
import cn.hippo4j.rpc.request.DefaultRequest;
|
||||
import cn.hippo4j.rpc.request.Request;
|
||||
import cn.hippo4j.rpc.response.Response;
|
||||
import cn.hippo4j.rpc.server.NettyServerConnection;
|
||||
import cn.hippo4j.rpc.server.RPCServer;
|
||||
import cn.hippo4j.rpc.server.ServerConnection;
|
||||
import cn.hippo4j.rpc.support.ClassRegistry;
|
||||
import cn.hippo4j.rpc.support.DefaultInstance;
|
||||
import cn.hippo4j.rpc.support.Instance;
|
||||
import io.netty.channel.pool.ChannelPoolHandler;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class RPCClientTest {
|
||||
|
||||
String host = "localhost";
|
||||
int port = 8888;
|
||||
int portTest = 8889;
|
||||
|
||||
@Test
|
||||
public void connection() throws IOException {
|
||||
Class<CallManager> cls = CallManager.class;
|
||||
String className = cls.getName();
|
||||
ClassRegistry.put(className, cls);
|
||||
// The mode connection was denied when the server was started on the specified port
|
||||
Instance instance = new DefaultInstance();
|
||||
NettyServerTakeHandler handler = new NettyServerTakeHandler(instance);
|
||||
ServerConnection connection = new NettyServerConnection(handler);
|
||||
RPCServer rpcServer = new RPCServer(port, connection);
|
||||
CompletableFuture.runAsync(rpcServer::bind);
|
||||
try {
|
||||
TimeUnit.SECONDS.sleep(3);
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
ChannelPoolHandler channelPoolHandler = new NettyClientPoolHandler(new NettyClientTakeHandler());
|
||||
NettyClientConnection clientConnection = new NettyClientConnection(host, port, channelPoolHandler);
|
||||
RPCClient rpcClient = new RPCClient(clientConnection);
|
||||
Request request = new DefaultRequest("127.0.0.18888", className, "call", null, null);
|
||||
for (int i = 0; i < 100; i++) {
|
||||
Response response = rpcClient.connection(request);
|
||||
boolean active = rpcClient.isActive();
|
||||
Assert.assertTrue(active);
|
||||
Assert.assertEquals(response.getObj(), 1);
|
||||
}
|
||||
rpcClient.close();
|
||||
rpcServer.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* This test case can be overridden under the handler and coder packages
|
||||
*/
|
||||
@Test
|
||||
public void connectionTest() throws IOException {
|
||||
Class<CallManager> cls = CallManager.class;
|
||||
String className = cls.getName();
|
||||
ClassRegistry.put(className, cls);
|
||||
// The mode connection was denied when the server was started on the specified port
|
||||
Instance instance = new DefaultInstance();
|
||||
NettyServerTakeHandler handler = new NettyServerTakeHandler(instance);
|
||||
ServerConnection connection = new NettyServerConnection(handler);
|
||||
RPCServer rpcServer = new RPCServer(portTest, connection);
|
||||
CompletableFuture.runAsync(rpcServer::bind);
|
||||
try {
|
||||
TimeUnit.SECONDS.sleep(3);
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
ChannelPoolHandler channelPoolHandler = new NettyClientPoolHandler(new NettyClientTakeHandler());
|
||||
NettyClientConnection clientConnection = new NettyClientConnection(host, portTest, channelPoolHandler);
|
||||
RPCClient rpcClient = new RPCClient(clientConnection);
|
||||
Class<?>[] classes = new Class<?>[2];
|
||||
classes[0] = Integer.class;
|
||||
classes[1] = Integer.class;
|
||||
Object[] objects = new Object[2];
|
||||
objects[0] = 1;
|
||||
objects[1] = 2;
|
||||
Request request = new DefaultRequest("127.0.0.18889", className, "callTest", classes, objects);
|
||||
Response response = rpcClient.connection(request);
|
||||
boolean active = rpcClient.isActive();
|
||||
Assert.assertTrue(active);
|
||||
Assert.assertEquals(response.getObj(), 3);
|
||||
rpcClient.close();
|
||||
rpcServer.close();
|
||||
}
|
||||
}
|
@ -1,68 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hippo4j.config.rpc.client;
|
||||
|
||||
import cn.hippo4j.config.rpc.request.DefaultRequest;
|
||||
import cn.hippo4j.config.rpc.request.Request;
|
||||
import cn.hippo4j.config.rpc.response.Response;
|
||||
import cn.hippo4j.config.rpc.server.NettyServerConnection;
|
||||
import cn.hippo4j.config.rpc.server.RPCServer;
|
||||
import cn.hippo4j.config.rpc.server.ServerConnection;
|
||||
import cn.hippo4j.config.rpc.support.DefaultInstance;
|
||||
import cn.hippo4j.config.rpc.support.Instance;
|
||||
import cn.hippo4j.config.rpc.support.ClassRegistry;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class RPCClientTest {
|
||||
|
||||
String host = "localhost";
|
||||
int port = 8888;
|
||||
|
||||
@Test
|
||||
public void connection() throws IOException {
|
||||
|
||||
Class<CallManager> cls = CallManager.class;
|
||||
String className = cls.getName();
|
||||
ClassRegistry.put(className, cls);
|
||||
// The mode connection was denied when the server was started on the specified port
|
||||
Instance instance = new DefaultInstance();
|
||||
ServerConnection connection = new NettyServerConnection(instance);
|
||||
RPCServer rpcServer = new RPCServer(port, connection);
|
||||
CompletableFuture.runAsync(rpcServer::bind);
|
||||
try {
|
||||
TimeUnit.SECONDS.sleep(3);
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
NettyClientConnection clientConnection = new NettyClientConnection(host, port);
|
||||
RPCClient rpcClient = new RPCClient(clientConnection);
|
||||
Request request = new DefaultRequest("127.0.0.18888", className, "call", null, null);
|
||||
for (int i = 0; i < 100; i++) {
|
||||
Response response = rpcClient.connection(request);
|
||||
Assert.assertEquals(response.getObj(), 1);
|
||||
}
|
||||
rpcClient.close();
|
||||
rpcServer.close();
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in new issue