/**
* Tencent is pleased to support the open source community by making MSEC available.
*
* Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the GNU General Public 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
*
* https://opensource.org/licenses/GPL-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 org.msec.net;
import com.google.protobuf.ByteString;
import com.google.protobuf.Message;
import com.google.protobuf.MessageLite;
import com.googlecode.protobuf.format.JsonFormat;
import org.apache.log4j.Logger;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBufferOutputStream;
import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.handler.codec.oneone.OneToOneEncoder;
import org.msec.rpc.HttpResponse;
import org.msec.rpc.RpcRequest;
import org.msec.rpc.RpcResponse;
import org.msec.rpc.ServiceFactory;
import srpc.Head;
import java.io.IOException;
public class ResponseEncoder extends OneToOneEncoder {
private static Logger log = Logger.getLogger(ResponseEncoder.class.getName());
protected int encodeProtobufHead(RpcResponse rpcResponse, ChannelBufferOutputStream stream) throws IOException {
//TODO: set coloring, color_id & caller..
Head.CRpcHead.Builder builder = Head.CRpcHead.newBuilder();
builder.clear();
builder.setSequence(rpcResponse.getSeq());
builder.setColoring(0);
builder.setColorId(0);
builder.setFlowId(0);
builder.setErr(rpcResponse.getErrno());
builder.setResult(0);
if (rpcResponse.getErrno() != 0) {
if (rpcResponse.getError() != null && rpcResponse.getError().getMessage() != null) {
builder.setErrMsg(ByteString.copyFromUtf8(rpcResponse.getError().getMessage()));
} else {
builder.setErrMsg(ByteString.copyFromUtf8("Unknown exception!"));
}
}
else {
builder.setErrMsg(ByteString.EMPTY);
}
builder.setCaller(ByteString.copyFromUtf8(ServiceFactory.getModuleName()));
builder.setMethodName(ByteString.EMPTY);
builder.addCallerStack(ByteString.EMPTY);
Head.CRpcHead rpchead = builder.build();
stream.write(rpchead.toByteArray());
return rpchead.getSerializedSize();
}
protected int encodeProtobufBody(RpcResponse rpcResponse, ChannelBufferOutputStream stream) throws IOException {
if (rpcResponse.getResultObj() == null) {
return 0;
}
MessageLite message = (MessageLite)rpcResponse.getResultObj();
stream.write(message.toByteArray());
return message.getSerializedSize();
}
protected ChannelBuffer serializeProtobufPakcage(ChannelHandlerContext channelHandlerContext, RpcResponse response, ChannelBufferOutputStream stream) throws IOException {
stream.writeByte('(');
stream.writeLong(0);
int headLen = encodeProtobufHead(response, stream);
int bodyLen = encodeProtobufBody(response, stream);
stream.writeByte(')');
ChannelBuffer buffer = stream.buffer();
buffer.setInt(1, headLen);
buffer.setInt(5, bodyLen);
return buffer;
}
protected ChannelBuffer serializeHTTPPakcage(ChannelHandlerContext channelHandlerContext, RpcResponse response, ChannelBufferOutputStream stream) throws IOException {
HttpResponse httpResponse = new HttpResponse();
String body = "";
httpResponse.setStatusCode("200 OK");
if (response.getResultObj() != null && !(response.getResultObj() instanceof Message)) {
//If result object is not protobuf message, just call toString()
httpResponse.setContentType("text/html; charset=utf-8");
body = response.getResultObj().toString();
} else {
//If result object is protobuf message, transfer it into json
httpResponse.setContentType("application/json");
body = "{\"ret\":" + response.getErrno();
body += ", \"errmsg\": \"";
if (response.getError() != null)
body += response.getError().getMessage();
body += "\"";
body += ", \"resultObj\":";
if (response.getResultObj() != null && response.getResultObj() instanceof Message) {
body += JsonFormat.printToString((Message) response.getResultObj());
} else {
body += "{}";
}
body += "}";
}
httpResponse.setBody(body);
stream.writeBytes(httpResponse.write());
return stream.buffer();
}
private static final int estimatedLength = 10240;
@Override
protected Object encode(ChannelHandlerContext ctx, Channel channel, Object msg) throws Exception {
if (msg instanceof RpcResponse) {
RpcResponse message = (RpcResponse) msg;
try {
ChannelBufferOutputStream bout = new ChannelBufferOutputStream(ChannelBuffers.dynamicBuffer(estimatedLength, ctx.getChannel()
.getConfig().getBufferFactory()));
ChannelBuffer buffer;
if (message.getSerializeMode() == RpcRequest.SerializeMode.SERIALIZE_MODE_PROTOBUF) {
buffer = serializeProtobufPakcage(ctx, message, bout);
} else {
buffer = serializeHTTPPakcage(ctx, message, bout);
}
return buffer;
} catch (Exception ex) {
log.error(ex.getMessage(), ex);
throw ex;
}
}
return null;
}
}