1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19 package org.apache.hadoop.hbase.ipc;
20
21 import java.io.IOException;
22
23 import org.apache.hadoop.hbase.classification.InterfaceAudience;
24 import org.apache.hadoop.util.StringUtils;
25
26 import com.google.protobuf.RpcCallback;
27 import com.google.protobuf.RpcController;
28 import org.apache.hadoop.util.StringUtils;
29
30 import java.io.IOException;
31
32 /**
33 * Used for server-side protobuf RPC service invocations. This handler allows
34 * invocation exceptions to easily be passed through to the RPC server from coprocessor
35 * {@link com.google.protobuf.Service} implementations.
36 *
37 * <p>
38 * When implementing {@link com.google.protobuf.Service} defined methods,
39 * coprocessor endpoints can use the following
40 * pattern to pass exceptions back to the RPC client:
41 * <code>
42 * public void myMethod(RpcController controller, MyRequest request,
43 * RpcCallback<MyResponse> done) {
44 * MyResponse response = null;
45 * try {
46 * // do processing
47 * response = MyResponse.getDefaultInstance(); // or use a new builder to populate the response
48 * } catch (IOException ioe) {
49 * // pass exception back up
50 * ResponseConverter.setControllerException(controller, ioe);
51 * }
52 * done.run(response);
53 * }
54 * </code>
55 * </p>
56 */
57 @InterfaceAudience.Private
58 public class ServerRpcController implements RpcController {
59 /**
60 * The exception thrown within
61 * {@link com.google.protobuf.Service#callMethod(
62 * Descriptors.MethodDescriptor, RpcController, Message, RpcCallback)},
63 * if any.
64 */
65 // TODO: it would be good widen this to just Throwable, but IOException is what we allow now
66 private IOException serviceException;
67 private String errorMessage;
68
69 @Override
70 public void reset() {
71 serviceException = null;
72 errorMessage = null;
73 }
74
75 @Override
76 public boolean failed() {
77 return (failedOnException() || errorMessage != null);
78 }
79
80 @Override
81 public String errorText() {
82 return errorMessage;
83 }
84
85 @Override
86 public void startCancel() {
87 // not implemented
88 }
89
90 @Override
91 public void setFailed(String message) {
92 errorMessage = message;
93 }
94
95 @Override
96 public boolean isCanceled() {
97 return false;
98 }
99
100 @Override
101 public void notifyOnCancel(RpcCallback<Object> objectRpcCallback) {
102 // not implemented
103 }
104
105 /**
106 * Sets an exception to be communicated back to the {@link com.google.protobuf.Service} client.
107 * @param ioe the exception encountered during execution of the service method
108 */
109 public void setFailedOn(IOException ioe) {
110 serviceException = ioe;
111 setFailed(StringUtils.stringifyException(ioe));
112 }
113
114 /**
115 * Returns any exception thrown during service method invocation, or {@code null} if no exception
116 * was thrown. This can be used by clients to receive exceptions generated by RPC calls, even
117 * when {@link RpcCallback}s are used and no {@link com.google.protobuf.ServiceException} is
118 * declared.
119 */
120 public IOException getFailedOn() {
121 return serviceException;
122 }
123
124 /**
125 * Returns whether or not a server exception was generated in the prior RPC invocation.
126 */
127 public boolean failedOnException() {
128 return serviceException != null;
129 }
130
131 /**
132 * Throws an IOException back out if one is currently stored.
133 */
134 public void checkFailed() throws IOException {
135 if (failedOnException()) {
136 throw getFailedOn();
137 }
138 }
139 }