// Path: socket/src/main/java/rpc/SimpleRpcFramework.java
// public static void export(Object serviceImpl, int port) {
//     try {
//         try (ServerSocket server = new ServerSocket(port)) {
//             while (!Thread.currentThread().isInterrupted()) {
//                 Socket socket = server.accept();
//                 new Thread(() -> {
//                     try (ObjectInputStream in = new ObjectInputStream(socket.getInputStream())) {
//                         Method method = serviceImpl.getClass().getMethod(in.readUTF(), (Class<?>[]) in.readObject());
//                         Object result = method.invoke(serviceImpl, (Object[]) in.readObject());
//                         try (ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream())) {
//                             out.writeObject(result);
//                         }
//                         System.out.println("Invoke method [" + method.getName() + "()] success, form " + socket.getRemoteSocketAddress());
//                     } catch (Exception e) {
//                         throw new RuntimeException("Export service fail .", e);
//                     }
//                 }).start();
//             }
//         }
//     } catch (Exception e) {
//         throw new RuntimeException("Export service fail .", e);
//     }
//     System.out.println("Export service " + serviceImpl.getClass().getSimpleName() + " success on port " + port);
// }
// 
// Path: socket/src/main/java/rpc/SimpleRpcFramework.java
// public static <T> T use(Class<T> serviceInterface, String host, int port) {
//     System.out.println(String.format("Use remote service [%s] from [%s:%s]", serviceInterface.getSimpleName(), host, port));
//     return (T) Proxy.newProxyInstance(serviceInterface.getClassLoader(), new Class<?>[]{serviceInterface}, (proxy, method, args) -> {
//         try (Socket socket = new Socket(host, port)) {
//             try (ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream())) {
//                 out.writeUTF(method.getName());
//                 out.writeObject(method.getParameterTypes());
//                 out.writeObject(args);
//                 try (ObjectInputStream in = new ObjectInputStream(socket.getInputStream())) {
//                     return in.readObject();
//                 }
//             }
//         }
//     });
// }


import java.util.concurrent.TimeUnit;
import static rpc.SimpleRpcFramework.export;
import static rpc.SimpleRpcFramework.use;
package rpc;



/**
 * Created by 李恒名 on 2017/8/17.
 */
public class RpcTest {
    private static final String HOST = "localhost";
    private static final int PORT = 8888;

    interface ComputeService {
        int sum(int a, int b);
    }


    static class ComputeServiceImpl implements ComputeService {

        @Override
        public int sum(int a, int b) {
            return a + b;
        }
    }

    //服务提供者
    static class Provider implements Runnable {
        @Override
        public void run() {
            //暴露服务
            export(new ComputeServiceImpl(), PORT);
        }
    }

    //服务消费者
    static class Customer implements Runnable {
        @Override
        public void run() {
            //使用服务
// Path: socket/src/main/java/rpc/SimpleRpcFramework.java
// public static void export(Object serviceImpl, int port) {
//     try {
//         try (ServerSocket server = new ServerSocket(port)) {
//             while (!Thread.currentThread().isInterrupted()) {
//                 Socket socket = server.accept();
//                 new Thread(() -> {
//                     try (ObjectInputStream in = new ObjectInputStream(socket.getInputStream())) {
//                         Method method = serviceImpl.getClass().getMethod(in.readUTF(), (Class<?>[]) in.readObject());
//                         Object result = method.invoke(serviceImpl, (Object[]) in.readObject());
//                         try (ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream())) {
//                             out.writeObject(result);
//                         }
//                         System.out.println("Invoke method [" + method.getName() + "()] success, form " + socket.getRemoteSocketAddress());
//                     } catch (Exception e) {
//                         throw new RuntimeException("Export service fail .", e);
//                     }
//                 }).start();
//             }
//         }
//     } catch (Exception e) {
//         throw new RuntimeException("Export service fail .", e);
//     }
//     System.out.println("Export service " + serviceImpl.getClass().getSimpleName() + " success on port " + port);
// }
// 
// Path: socket/src/main/java/rpc/SimpleRpcFramework.java
// public static <T> T use(Class<T> serviceInterface, String host, int port) {
//     System.out.println(String.format("Use remote service [%s] from [%s:%s]", serviceInterface.getSimpleName(), host, port));
//     return (T) Proxy.newProxyInstance(serviceInterface.getClassLoader(), new Class<?>[]{serviceInterface}, (proxy, method, args) -> {
//         try (Socket socket = new Socket(host, port)) {
//             try (ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream())) {
//                 out.writeUTF(method.getName());
//                 out.writeObject(method.getParameterTypes());
//                 out.writeObject(args);
//                 try (ObjectInputStream in = new ObjectInputStream(socket.getInputStream())) {
//                     return in.readObject();
//                 }
//             }
//         }
//     });
// }


// Path: socket/src/main/java/rpc/RpcTest.java
import java.util.concurrent.TimeUnit;
import static rpc.SimpleRpcFramework.export;
import static rpc.SimpleRpcFramework.use;

package rpc;



/**
 * Created by 李恒名 on 2017/8/17.
 */
public class RpcTest {
    private static final String HOST = "localhost";
    private static final int PORT = 8888;

    interface ComputeService {
        int sum(int a, int b);
    }


    static class ComputeServiceImpl implements ComputeService {

        @Override
        public int sum(int a, int b) {
            return a + b;
        }
    }

    //服务提供者
    static class Provider implements Runnable {
        @Override
        public void run() {
            //暴露服务
            export(new ComputeServiceImpl(), PORT);
        }
    }

    //服务消费者
    static class Customer implements Runnable {
        @Override
        public void run() {
            //使用服务
            ComputeService computeService = use(ComputeService.class, HOST, PORT);