RpcChannel.java revision b5a588df
1420c9859SShuo Chenpackage muduo.rpc;
2420c9859SShuo Chen
3420c9859SShuo Chenimport java.util.Map;
4420c9859SShuo Chenimport java.util.concurrent.ConcurrentHashMap;
5420c9859SShuo Chenimport java.util.concurrent.atomic.AtomicLong;
6420c9859SShuo Chen
7420c9859SShuo Chenimport muduo.rpc.proto.RpcProto.ErrorCode;
8420c9859SShuo Chenimport muduo.rpc.proto.RpcProto.MessageType;
9420c9859SShuo Chenimport muduo.rpc.proto.RpcProto.RpcMessage;
10420c9859SShuo Chenimport muduo.rpc.proto.RpcProto.RpcMessage.Builder;
11420c9859SShuo Chen
12420c9859SShuo Chenimport org.jboss.netty.channel.Channel;
13420c9859SShuo Chenimport org.jboss.netty.channel.ChannelHandlerContext;
14420c9859SShuo Chenimport org.jboss.netty.channel.MessageEvent;
15420c9859SShuo Chen
16b5a588dfSShuo Chenimport com.google.protobuf.BlockingRpcChannel;
17420c9859SShuo Chenimport com.google.protobuf.ByteString;
18420c9859SShuo Chenimport com.google.protobuf.Descriptors.MethodDescriptor;
19420c9859SShuo Chenimport com.google.protobuf.Message;
20420c9859SShuo Chenimport com.google.protobuf.RpcCallback;
21420c9859SShuo Chenimport com.google.protobuf.RpcController;
22420c9859SShuo Chenimport com.google.protobuf.Service;
23b5a588dfSShuo Chenimport com.google.protobuf.ServiceException;
24420c9859SShuo Chen
25b5a588dfSShuo Chenpublic class RpcChannel implements com.google.protobuf.RpcChannel, BlockingRpcChannel {
26420c9859SShuo Chen
27b5a588dfSShuo Chen    private final static class BlockingRpcCallback implements RpcCallback<Message> {
28b5a588dfSShuo Chen        public Message response;
29420c9859SShuo Chen
30b5a588dfSShuo Chen        @Override
31b5a588dfSShuo Chen        public void run(Message response) {
32b5a588dfSShuo Chen            synchronized (this) {
33b5a588dfSShuo Chen                this.response = response;
34b5a588dfSShuo Chen                notify();
35b5a588dfSShuo Chen            }
36420c9859SShuo Chen        }
37b5a588dfSShuo Chen    }
38b5a588dfSShuo Chen
39b5a588dfSShuo Chen    private final static class Outstanding {
40420c9859SShuo Chen
41420c9859SShuo Chen        public Message responsePrototype;
42420c9859SShuo Chen        public RpcCallback<Message> done;
43b5a588dfSShuo Chen
44b5a588dfSShuo Chen        public Outstanding(Message responsePrototype, RpcCallback<Message> done) {
45b5a588dfSShuo Chen            this.responsePrototype = responsePrototype;
46b5a588dfSShuo Chen            this.done = done;
47b5a588dfSShuo Chen        }
48420c9859SShuo Chen    }
49420c9859SShuo Chen
50420c9859SShuo Chen    private Channel channel;
51420c9859SShuo Chen    private AtomicLong id = new AtomicLong(1);
52420c9859SShuo Chen    private Map<Long, Outstanding> outstandings = new ConcurrentHashMap<Long, Outstanding>();
53420c9859SShuo Chen    private Map<String, Service> services;
54420c9859SShuo Chen
55420c9859SShuo Chen    public RpcChannel(Channel channel) {
56420c9859SShuo Chen        this.channel = channel;
57420c9859SShuo Chen    }
58420c9859SShuo Chen
59420c9859SShuo Chen    public void setServiceMap(Map<String, Service> services) {
60420c9859SShuo Chen        this.services = services;
61420c9859SShuo Chen    }
62420c9859SShuo Chen
63420c9859SShuo Chen    public Channel getChannel() {
64420c9859SShuo Chen        return channel;
65420c9859SShuo Chen    }
66420c9859SShuo Chen
67b5a588dfSShuo Chen    public void disconnect() {
68b5a588dfSShuo Chen        channel.disconnect();
69b5a588dfSShuo Chen    }
70b5a588dfSShuo Chen
71420c9859SShuo Chen    public void messageReceived(ChannelHandlerContext ctx, final MessageEvent e) {
72420c9859SShuo Chen        RpcMessage message = (RpcMessage) e.getMessage();
73420c9859SShuo Chen        assert e.getChannel() == channel;
74b5a588dfSShuo Chen        // System.out.println(message);
75420c9859SShuo Chen        if (message.getType() == MessageType.REQUEST) {
76420c9859SShuo Chen            doRequest(message);
77420c9859SShuo Chen        } else if (message.getType() == MessageType.RESPONSE) {
78420c9859SShuo Chen            Outstanding o = outstandings.get(message.getId());
79b5a588dfSShuo Chen            // System.err.println("messageReceived " + this);
80420c9859SShuo Chen            if (o != null) {
81420c9859SShuo Chen                Message resp = fromByteString(o.responsePrototype, message.getResponse());
82420c9859SShuo Chen                o.done.run(resp);
83b5a588dfSShuo Chen            } else {
84b5a588dfSShuo Chen                System.err.println("Unknown id " + message.getId());
85420c9859SShuo Chen            }
86420c9859SShuo Chen        }
87420c9859SShuo Chen    }
88420c9859SShuo Chen
89420c9859SShuo Chen    private void doRequest(RpcMessage message) {
90420c9859SShuo Chen        Service service = services.get(message.getService());
91420c9859SShuo Chen        Builder errorBuilder = RpcMessage.newBuilder().setType(MessageType.ERROR);
92420c9859SShuo Chen        boolean succeed = false;
93420c9859SShuo Chen        if (service != null) {
94420c9859SShuo Chen            MethodDescriptor method = service.getDescriptorForType()
95420c9859SShuo Chen                    .findMethodByName(message.getMethod());
96420c9859SShuo Chen            if (method != null) {
97420c9859SShuo Chen                Message request = fromByteString(service.getRequestPrototype(method),
98420c9859SShuo Chen                        message.getRequest());
99420c9859SShuo Chen                if (request != null) {
100420c9859SShuo Chen                    final long id = message.getId();
101420c9859SShuo Chen                    RpcCallback<Message> done = new RpcCallback<Message>() {
102420c9859SShuo Chen                        @Override
103420c9859SShuo Chen                        public void run(Message response) {
104420c9859SShuo Chen                            done(response, id);
105420c9859SShuo Chen                        }
106420c9859SShuo Chen                    };
107420c9859SShuo Chen                    succeed = doCall(request, service, method, done);
108420c9859SShuo Chen                } else {
109420c9859SShuo Chen                    errorBuilder.setError(ErrorCode.INVALID_REQUEST);
110420c9859SShuo Chen                }
111420c9859SShuo Chen            } else {
112420c9859SShuo Chen                errorBuilder.setError(ErrorCode.NO_METHOD);
113420c9859SShuo Chen            }
114420c9859SShuo Chen        } else {
115420c9859SShuo Chen            errorBuilder.setError(ErrorCode.NO_SERVICE);
116420c9859SShuo Chen        }
117420c9859SShuo Chen        if (!succeed) {
118420c9859SShuo Chen            RpcMessage resp = errorBuilder.build();
119420c9859SShuo Chen            channel.write(resp);
120420c9859SShuo Chen        }
121420c9859SShuo Chen    }
122420c9859SShuo Chen
123420c9859SShuo Chen    private Message fromByteString(Message prototype, ByteString bytes) {
124420c9859SShuo Chen        Message message = null;
125420c9859SShuo Chen        try {
126420c9859SShuo Chen            message = prototype.toBuilder().mergeFrom(bytes).build();
127420c9859SShuo Chen        } catch (Exception e) {
128420c9859SShuo Chen        }
129420c9859SShuo Chen        return message;
130420c9859SShuo Chen    }
131420c9859SShuo Chen
132420c9859SShuo Chen    private boolean doCall(Message request, Service service, MethodDescriptor method,
133420c9859SShuo Chen            RpcCallback<Message> done) {
134420c9859SShuo Chen        service.callMethod(method, null, request, done);
135420c9859SShuo Chen        return true;
136420c9859SShuo Chen    }
137420c9859SShuo Chen
138420c9859SShuo Chen    protected void done(Message response, long id) {
139420c9859SShuo Chen        if (response != null) {
140420c9859SShuo Chen            RpcMessage resp = RpcMessage.newBuilder()
141420c9859SShuo Chen                    .setType(MessageType.RESPONSE)
142420c9859SShuo Chen                    .setId(id)
143420c9859SShuo Chen                    .setResponse(response.toByteString())
144420c9859SShuo Chen                    .build();
145420c9859SShuo Chen            channel.write(resp);
146420c9859SShuo Chen        } else {
147420c9859SShuo Chen            RpcMessage resp = RpcMessage.newBuilder()
148420c9859SShuo Chen                    .setType(MessageType.ERROR)
149420c9859SShuo Chen                    .setId(id)
150420c9859SShuo Chen                    .setError(ErrorCode.INVALID_RESPONSE)
151420c9859SShuo Chen                    .build();
152420c9859SShuo Chen            channel.write(resp);
153420c9859SShuo Chen        }
154420c9859SShuo Chen    }
155420c9859SShuo Chen
156420c9859SShuo Chen    @Override
157420c9859SShuo Chen    public void callMethod(MethodDescriptor method, RpcController controller, Message request,
158420c9859SShuo Chen            Message responsePrototype, RpcCallback<Message> done) {
159420c9859SShuo Chen        long callId = id.getAndIncrement();
160420c9859SShuo Chen        RpcMessage message = RpcMessage.newBuilder()
161420c9859SShuo Chen                .setType(MessageType.REQUEST)
162420c9859SShuo Chen                .setId(callId)
163420c9859SShuo Chen                .setService(method.getService().getFullName())
164420c9859SShuo Chen                .setMethod(method.getName())
165420c9859SShuo Chen                .setRequest(request.toByteString())
166420c9859SShuo Chen                .build();
167420c9859SShuo Chen        outstandings.put(callId, new Outstanding(responsePrototype, done));
168420c9859SShuo Chen        channel.write(message);
169420c9859SShuo Chen    }
170420c9859SShuo Chen
171b5a588dfSShuo Chen    @Override
172b5a588dfSShuo Chen    public Message callBlockingMethod(MethodDescriptor method, RpcController controller,
173b5a588dfSShuo Chen            Message request, Message responsePrototype) throws ServiceException {
174b5a588dfSShuo Chen        BlockingRpcCallback done = new BlockingRpcCallback();
175b5a588dfSShuo Chen        callMethod(method, controller, request, responsePrototype, done);
176b5a588dfSShuo Chen        // if (channel instanceof NioClientSocketChannel)
177b5a588dfSShuo Chen        // channel.get
178b5a588dfSShuo Chen        // assert
179b5a588dfSShuo Chen        synchronized (done) {
180b5a588dfSShuo Chen            while (done.response == null) {
181b5a588dfSShuo Chen                try {
182b5a588dfSShuo Chen                    done.wait();
183b5a588dfSShuo Chen                } catch (InterruptedException e) {
184b5a588dfSShuo Chen                }
185b5a588dfSShuo Chen            }
186b5a588dfSShuo Chen        }
187b5a588dfSShuo Chen        return done.response;
188b5a588dfSShuo Chen    }
189420c9859SShuo Chen}
190