| /*
|
| * Copyright 1999-2011 Alibaba Group.
|
| *
|
| * Licensed 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 com.alibaba.dubbo.rpc.protocol.dubbo; |
| |
| import static com.alibaba.dubbo.rpc.protocol.dubbo.CallbackServiceCodec.decodeInvocationArgument;
|
| import static com.alibaba.dubbo.rpc.protocol.dubbo.CallbackServiceCodec.encodeInvocationArgument;
|
|
|
| import java.io.IOException;
|
| import java.lang.reflect.Type;
|
| import java.util.HashMap;
|
| import java.util.Map;
|
|
|
| import com.alibaba.dubbo.common.Constants;
|
| import com.alibaba.dubbo.common.Version;
|
| import com.alibaba.dubbo.common.serialize.ObjectInput;
|
| import com.alibaba.dubbo.common.serialize.ObjectOutput;
|
| import com.alibaba.dubbo.common.utils.ReflectUtils;
|
| import com.alibaba.dubbo.common.utils.StringUtils;
|
| import com.alibaba.dubbo.remoting.Channel;
|
| import com.alibaba.dubbo.remoting.Codec;
|
| import com.alibaba.dubbo.remoting.exchange.codec.ExchangeCodec;
|
| import com.alibaba.dubbo.rpc.Invocation;
|
| import com.alibaba.dubbo.rpc.Result;
|
| import com.alibaba.dubbo.rpc.RpcInvocation;
|
| import com.alibaba.dubbo.rpc.RpcResult;
|
| import com.alibaba.dubbo.rpc.support.RpcUtils;
|
| |
| /** |
| * Dubbo codec. |
| * |
| * @author qianlei |
| * @author chao.liuc |
| */ |
| public class DubboCodec extends ExchangeCodec implements Codec {
|
|
|
| public static final String NAME = "dubbo"; |
| |
| private static final String DUBBO_VERSION = Version.getVersion(DubboCodec.class, Version.getVersion()); |
| |
| private static final byte RESPONSE_WITH_EXCEPTION = 0; |
| |
| private static final byte RESPONSE_VALUE = 1; |
| |
| private static final byte RESPONSE_NULL_VALUE = 2; |
| |
| private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0]; |
| |
| private static final Class<?>[] EMPTY_CLASS_ARRAY = new Class<?>[0]; |
| |
| |
| @Override |
| protected void encodeRequestData(Channel channel, ObjectOutput out, Object data) throws IOException { |
| RpcInvocation inv = (RpcInvocation) data; |
| |
| out.writeUTF(inv.getAttachment(Constants.DUBBO_VERSION_KEY, DUBBO_VERSION)); |
| out.writeUTF(inv.getAttachment(Constants.PATH_KEY)); |
| out.writeUTF(inv.getAttachment(Constants.VERSION_KEY)); |
| |
| out.writeUTF(inv.getMethodName()); |
| out.writeUTF(ReflectUtils.getDesc(inv.getParameterTypes())); |
| Object[] args = inv.getArguments(); |
| if (args != null) |
| for (int i = 0; i < args.length; i++){ |
| out.writeObject(encodeInvocationArgument(channel, inv, i)); |
| } |
| out.writeObject(inv.getAttachments()); |
| } |
| |
| @Override |
| @SuppressWarnings("unchecked") |
| protected Object decodeRequestData(Channel channel, ObjectInput in) throws IOException { |
| RpcInvocation inv = new RpcInvocation(); |
| |
| inv.setAttachment(Constants.DUBBO_VERSION_KEY, in.readUTF()); |
| inv.setAttachment(Constants.PATH_KEY, in.readUTF()); |
| inv.setAttachment(Constants.VERSION_KEY, in.readUTF()); |
| |
| inv.setMethodName(in.readUTF()); |
| try { |
| Object[] args; |
| Class<?>[] pts; |
| String desc = in.readUTF(); |
| if (desc.length() == 0) { |
| pts = EMPTY_CLASS_ARRAY; |
| args = EMPTY_OBJECT_ARRAY; |
| } else { |
| pts = ReflectUtils.desc2classArray(desc); |
| args = new Object[pts.length]; |
| for (int i = 0; i < args.length; i++){ |
| try{ |
| args[i] = in.readObject(pts[i]); |
| }catch (Exception e) { |
| e.printStackTrace(); |
| } |
| } |
| } |
| inv.setParameterTypes(pts); |
| |
| Map<String, String> map = (Map<String, String>) in.readObject(Map.class); |
| if (map != null && map.size() > 0) { |
| Map<String, String> attachment = inv.getAttachments(); |
| if (attachment == null) { |
| attachment = new HashMap<String, String>(); |
| } |
| attachment.putAll(map); |
| inv.setAttachments(attachment); |
| } |
| //decode argument ,may be callback |
| for (int i = 0; i < args.length; i++){ |
| args[i] = decodeInvocationArgument(channel, inv, pts, i, args[i]); |
| } |
| |
| inv.setArguments(args); |
| |
| } catch (ClassNotFoundException e) { |
| throw new IOException(StringUtils.toString("Read invocation data failed.", e)); |
| } |
| return inv; |
| } |
| |
| @Override |
| protected void encodeResponseData(Channel channel, ObjectOutput out, Object data) throws IOException { |
| Result result = (Result) data; |
| |
| Throwable th = result.getException(); |
| if (th == null) { |
| Object ret = result.getValue(); |
| if (ret == null) { |
| out.writeByte(RESPONSE_NULL_VALUE); |
| } else { |
| out.writeByte(RESPONSE_VALUE); |
| out.writeObject(ret); |
| } |
| } else { |
| out.writeByte(RESPONSE_WITH_EXCEPTION); |
| out.writeObject(th); |
| } |
| }
|
| |
| @Override |
| protected Object decodeResponseData(Channel channel, ObjectInput in, Object request) throws IOException { |
| Invocation invocation = (Invocation) request;
|
| RpcResult result = new RpcResult(); |
| |
| byte flag = in.readByte(); |
| switch (flag) { |
| case RESPONSE_NULL_VALUE: |
| break; |
| case RESPONSE_VALUE: |
| try { |
| Type[] returnType = RpcUtils.getReturnTypes(invocation);
|
| result.setValue(returnType == null || returnType.length == 0 ? in.readObject() :
|
| (returnType.length == 1 ? in.readObject((Class<?>)returnType[0])
|
| : in.readObject((Class<?>)returnType[0], returnType[1]))); |
| } catch (ClassNotFoundException e) { |
| throw new IOException(StringUtils.toString("Read response data failed.", e)); |
| } |
| break; |
| case RESPONSE_WITH_EXCEPTION: |
| try { |
| Object obj = in.readObject(); |
| if (obj instanceof Throwable == false) throw new IOException("Response data error, expect Throwable, but get " + obj); |
| result.setException((Throwable) obj); |
| } catch (ClassNotFoundException e) { |
| throw new IOException(StringUtils.toString("Read response data failed.", e)); |
| } |
| break; |
| default: |
| throw new IOException("Unknown result flag, expect '0' '1' '2', get " + flag); |
| } |
| return result; |
| } |
| } |