package com.wangyin.ak47.pipes.dubbo; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.util.ArrayList; import java.util.List; import java.util.Map; import com.alibaba.dubbo.common.Version; import com.alibaba.dubbo.common.utils.ReflectUtils; import com.alibaba.dubbo.rpc.protocol.dubbo.DubboCodec; import com.caucho.hessian.io.Hessian2Input; import com.caucho.hessian.io.Hessian2Output; import com.caucho.hessian.io.HessianFactory; import com.wangyin.ak47.common.CollectionUtil; import com.wangyin.ak47.common.Logger; import com.wangyin.ak47.common.YmlUtil; import com.wangyin.ak47.core.HandlerContext; import com.wangyin.ak47.core.Message; import com.wangyin.ak47.core.Request; import com.wangyin.ak47.core.Response; import com.wangyin.ak47.core.exception.Ak47RuntimeException; import com.wangyin.ak47.pipes.dubbo.AbstractDubboPipe; import com.wangyin.ak47.pipes.dubbo.DubboData; import com.wangyin.ak47.pipes.dubbo.DubboHeader; /** * * Dubbo-protocol + Hessian2.0-serialize * * @author hubingyin * */ public final class DubboHessianPipe extends AbstractDubboPipe<DubboHessianRequest, DubboHessianResponse> { private static final Logger log = new Logger(DubboHessianPipe.class); public static final byte HESSIAN_SERIALIZATION_ID = 0x02; public static final String DEFAULT_DUBBO_VERSION = Version.getVersion(DubboCodec.class, Version.getVersion()); public static final String DEFAULT_METHOD_VERSION = "0.0.0"; public static final byte RESPONSE_WITH_EXCEPTION = 0; public static final byte RESPONSE_VALUE = 1; public static final byte RESPONSE_NULL_VALUE = 2; private HessianFactory hessianFactory = new HessianFactory(); @Override public void decodeDubboRequest(DubboData dd, Request<DubboHessianRequest> request) throws Exception { DubboHessianRequest dubboreq = new DubboHessianRequest(); DubboHeader dh = dd.getDubboHeader(); byte flag = dh.getFlag(); if( (flag & FLAG_EVENT) != 0 ){ // heart beat // do nothing. }else if( (flag & SERIALIZATION_MASK) == HESSIAN_SERIALIZATION_ID ){ // decode hessian ByteArrayInputStream bis = new ByteArrayInputStream(dd.getBody()); Hessian2Input h2in = hessianFactory.createHessian2Input(bis); String dubboVersion = h2in.readString(); dubboreq.setDubboVersion(dubboVersion); String service = h2in.readString(); dubboreq.setService(service); String version = h2in.readString(); dubboreq.setVersion(version); String method = h2in.readString(); dubboreq.setMethod(method); // this dont work! // Object[] args = h2in.readArguments(); String argsdesc = h2in.readString(); Class<?>[] argtypes = ReflectUtils.desc2classArray(argsdesc); List<Object> args = new ArrayList<Object>(argtypes.length); for(int i=0;i<argtypes.length;i++){ args.add(h2in.readObject(argtypes[i])); } dubboreq.setArgs(args); @SuppressWarnings("unchecked") Map<String, String> attachments = (Map<String, String>) h2in.readObject(Map.class); dubboreq.setAttachments(attachments); log.debug("decodeDubboRequest dubboVersion:{} service:{} version:{} method:{} args.size:{} attachments:{}", dubboVersion, service, version, method, args.size(), YmlUtil.obj2Yml(attachments)); }else{ // not hessian serialization throw new Ak47RuntimeException("Unsupport serialization type. flag is " + flag ); } dubboreq.setDubboHeader(dh); request.pojo(dubboreq); } @Override public void encodeDubboRequest(Request<DubboHessianRequest> request, DubboData dd) throws Exception { DubboHessianRequest dubboreq = request.pojo(); // set flag DubboHeader dh = dubboreq.getDubboHeader(); dh.setFlag((byte) (FLAG_REQUEST | FLAG_TWOWAY | HESSIAN_SERIALIZATION_ID) ); // set body ByteArrayOutputStream bos = new ByteArrayOutputStream(); Hessian2Output h2out = hessianFactory.createHessian2Output(bos); String dubboVersion = dubboreq.getDubboVersion(); if( null == dubboVersion ) dubboVersion = DEFAULT_DUBBO_VERSION; h2out.writeString(dubboVersion); String service = dubboreq.getService(); h2out.writeString(service); String version = dubboreq.getVersion(); if( null == version ) version = DEFAULT_METHOD_VERSION; h2out.writeString(version); String method = dubboreq.getMethod(); h2out.writeString(method); Class<?>[] argtypes = CollectionUtil.objects2Classes( dubboreq.getArgs() ); String argsdesc = ReflectUtils.getDesc(argtypes); h2out.writeString(argsdesc); for( Object obj : dubboreq.getArgs() ){ h2out.writeObject(obj); } Map<String, String> attachments = dubboreq.getAttachments(); h2out.writeObject(attachments); h2out.close(); byte[] body = bos.toByteArray(); dd.setDubboHeader(dubboreq.getDubboHeader()); dd.setBody(body); log.debug("encodeDubboRequest dubboVersion:{} service:{} version:{} method:{} args.size:{} attachments:{}", dubboVersion, service, version, method, argtypes.length, YmlUtil.obj2Yml(attachments)); } @Override public void decodeDubboResponse(DubboData dd, Response<DubboHessianResponse> response) throws Exception { DubboHessianResponse dubbores = new DubboHessianResponse(); DubboHeader dh = dd.getDubboHeader(); dubbores.setDubboHeader(dh); byte flag = dh.getFlag(); if( (flag & FLAG_EVENT) != 0 ){ // heart beat // do nothing. }else if( (flag & SERIALIZATION_MASK) == HESSIAN_SERIALIZATION_ID ){ // decode hessian ByteArrayInputStream bis = new ByteArrayInputStream(dd.getBody()); Hessian2Input h2in = hessianFactory.createHessian2Input(bis); int resvalue = h2in.readInt(); if( resvalue == RESPONSE_WITH_EXCEPTION ){ dubbores.setResult(h2in.readObject()); }else if( resvalue == RESPONSE_NULL_VALUE){ dubbores.setResult(null); }else if( resvalue == RESPONSE_VALUE){ dubbores.setResult(h2in.readObject()); }else{ throw new Ak47RuntimeException("Unrecognized response value. resvalue is " + resvalue); } }else{ // not hessian serialization throw new Ak47RuntimeException("Unsupport serialization type. flag is " + flag ); } response.pojo(dubbores); } @Override public void encodeDubboResponse(Response<DubboHessianResponse> response, DubboData dd) throws Exception { DubboHessianResponse dubbores = response.pojo(); // set flag DubboHeader dh = dubbores.getDubboHeader(); dd.setDubboHeader(dubbores.getDubboHeader()); // set body dh.setFlag((byte) (dh.getFlag() | HESSIAN_SERIALIZATION_ID) ); ByteArrayOutputStream bos = new ByteArrayOutputStream(); Hessian2Output h2out = hessianFactory.createHessian2Output(bos); h2out.writeInt(RESPONSE_VALUE); h2out.writeObject(dubbores.getResult()); h2out.close(); byte[] body = bos.toByteArray(); dd.setBody(body); } @Override public boolean filterReceivedInStub( HandlerContext<DubboHessianResponse, DubboHessianRequest> ctx, Message<DubboHessianRequest> msg){ DubboHessianRequest dubboreq = msg.getPojo(); byte flag = dubboreq.getDubboHeader().getFlag(); if( (flag & FLAG_EVENT) != 0 ){ // heartbeat Message<DubboHessianResponse> resmsg = msg.newMessage(); DubboHessianResponse dubbores = new DubboHessianResponse(); DubboHeader dh = dubbores.getDubboHeader(); dh.setFlag((byte)(dh.getFlag()|FLAG_EVENT)); resmsg.setPojo(dubbores); ctx.send(resmsg); return true; }else{ return false; } } @Override public boolean filterReceivedInDriver( HandlerContext<DubboHessianRequest, DubboHessianResponse> ctx, Message<DubboHessianResponse> msg){ DubboHessianResponse dubbores = msg.getPojo(); byte flag = dubbores.getDubboHeader().getFlag(); if( (flag & FLAG_EVENT) != 0 ){ // heartbeat Message<DubboHessianRequest> reqmsg = msg.newMessage(); DubboHessianRequest dubboreq = new DubboHessianRequest(); DubboHeader dh = dubboreq.getDubboHeader(); dh.setFlag((byte)(dh.getFlag()|FLAG_EVENT)); reqmsg.setPojo(dubboreq); ctx.send(reqmsg); return true; }else{ return false; } } }