diff --git a/all/pom.xml b/all/pom.xml index 74b93dcae..b9343a7f2 100644 --- a/all/pom.xml +++ b/all/pom.xml @@ -183,6 +183,11 @@ sofa-rpc-codec-jackson ${project.version} + + com.alipay.sofa + sofa-rpc-codec-sofa-fury + ${project.version} + com.alipay.sofa sofa-rpc-fault-tolerance @@ -519,6 +524,7 @@ com.alipay.sofa:sofa-rpc-codec-jackson com.alipay.sofa:sofa-rpc-codec-msgpack com.alipay.sofa:sofa-rpc-codec-sofa-hessian + com.alipay.sofa:sofa-rpc-codec-sofa-fury com.alipay.sofa:sofa-rpc-fault-tolerance com.alipay.sofa:sofa-rpc-fault-hystrix com.alipay.sofa:sofa-rpc-log-common-tools diff --git a/bom/pom.xml b/bom/pom.xml index 047b7b01a..a17ee2bee 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -39,6 +39,7 @@ 2.12.7.1 0.6.12 1.5.9 + 0.4.1 1.53.0 @@ -298,6 +299,11 @@ msgpack ${msgpack.version} + + org.furyio + fury-core + ${fury.version} + org.apache.curator diff --git a/codec/codec-sofa-hessian/src/main/java/com/alipay/sofa/rpc/codec/sofahessian/BlackListFileLoader.java b/codec/codec-api/src/main/java/com/alipay/sofa/rpc/codec/common/BlackAndWhiteListFileLoader.java similarity index 59% rename from codec/codec-sofa-hessian/src/main/java/com/alipay/sofa/rpc/codec/sofahessian/BlackListFileLoader.java rename to codec/codec-api/src/main/java/com/alipay/sofa/rpc/codec/common/BlackAndWhiteListFileLoader.java index 8b48c7a7b..54f4ddf64 100644 --- a/codec/codec-sofa-hessian/src/main/java/com/alipay/sofa/rpc/codec/sofahessian/BlackListFileLoader.java +++ b/codec/codec-api/src/main/java/com/alipay/sofa/rpc/codec/common/BlackAndWhiteListFileLoader.java @@ -14,10 +14,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.alipay.sofa.rpc.codec.sofahessian; +package com.alipay.sofa.rpc.codec.common; -import com.alipay.sofa.rpc.common.SofaConfigs; -import com.alipay.sofa.rpc.common.SofaOptions; +import com.alipay.sofa.common.config.SofaConfigs; import com.alipay.sofa.rpc.common.utils.StringUtils; import com.alipay.sofa.rpc.log.Logger; import com.alipay.sofa.rpc.log.LoggerFactory; @@ -30,6 +29,8 @@ import java.util.LinkedList; import java.util.List; +import static com.alipay.sofa.rpc.common.config.RpcConfigKeys.SERIALIZE_BLACKLIST_OVERRIDE; +import static com.alipay.sofa.rpc.common.config.RpcConfigKeys.SERIALIZE_WHITELIST_OVERRIDE; import static com.alipay.sofa.rpc.common.utils.IOUtils.closeQuietly; /** @@ -37,21 +38,24 @@ * * @author GengZhang */ -public class BlackListFileLoader { +public class BlackAndWhiteListFileLoader { - private static final Logger LOGGER = LoggerFactory.getLogger(BlackListFileLoader.class); + private static final Logger LOGGER = LoggerFactory + .getLogger(BlackAndWhiteListFileLoader.class); - public static final List SOFA_SERIALIZE_BLACK_LIST = loadFile("/sofa-rpc/serialize_blacklist.txt"); + public static final List SOFA_SERIALIZE_BLACK_LIST = loadBlackListFile("/sofa-rpc/serialize_blacklist.txt"); - static List loadFile(String path) { - List blackPrefixList = new ArrayList(); + public static final List SOFA_SERIALIZER_WHITE_LIST = loadWhiteListFile("/sofa-rpc/serialize_whitelist.txt"); + + public static List loadBlackListFile(String path) { + List blackPrefixList = new ArrayList<>(); InputStream input = null; try { - input = BlackListFileLoader.class.getResourceAsStream(path); + input = BlackAndWhiteListFileLoader.class.getResourceAsStream(path); if (input != null) { readToList(input, "UTF-8", blackPrefixList); } - String overStr = SofaConfigs.getStringValue(SofaOptions.CONFIG_SERIALIZE_BLACKLIST_OVERRIDE, ""); + String overStr = SofaConfigs.getOrCustomDefault(SERIALIZE_BLACKLIST_OVERRIDE, ""); if (StringUtils.isNotBlank(overStr)) { if (LOGGER.isInfoEnabled()) { LOGGER.info("Serialize blacklist will override with configuration: {}", overStr); @@ -68,6 +72,31 @@ static List loadFile(String path) { return blackPrefixList; } + public static List loadWhiteListFile(String path) { + List whitePrefixList = new ArrayList<>(); + InputStream input = null; + try { + input = BlackAndWhiteListFileLoader.class.getResourceAsStream(path); + if (input != null) { + readToList(input, "UTF-8", whitePrefixList); + } + String overStr = SofaConfigs.getOrCustomDefault(SERIALIZE_WHITELIST_OVERRIDE, ""); + if (StringUtils.isNotBlank(overStr)) { + if (LOGGER.isInfoEnabled()) { + LOGGER.info("Serialize whitelist will override with configuration: {}", overStr); + } + overrideWhiteList(whitePrefixList, overStr); + } + } catch (Exception e) { + if (LOGGER.isErrorEnabled()) { + LOGGER.error(e.getMessage(), e); + } + } finally { + closeQuietly(input); + } + return whitePrefixList; + } + /** * 读文件,将结果丢入List * @@ -100,12 +129,12 @@ private static void readToList(InputStream input, String encoding, List /** * Override blacklist with override string. - * - * @param originList Origin black list + * + * @param originList Origin black list * @param overrideStr The override string */ - static void overrideBlackList(List originList, String overrideStr) { - List adds = new LinkedList(); + public static void overrideBlackList(List originList, String overrideStr) { + List adds = new LinkedList<>(); String[] overrideItems = StringUtils.splitWithCommaOrSemicolon(overrideStr); for (String overrideItem : overrideItems) { if (StringUtils.isNotBlank(overrideItem)) { @@ -127,4 +156,19 @@ static void overrideBlackList(List originList, String overrideStr) { originList.addAll(adds); } } + + public static void overrideWhiteList(List originList, String overrideStr) { + List adds = new LinkedList<>(); + String[] overrideItems = StringUtils.splitWithCommaOrSemicolon(overrideStr); + for (String overrideItem : overrideItems) { + if (StringUtils.isNotBlank(overrideItem)) { + if (!originList.contains(overrideItem)) { + adds.add(overrideItem); + } + } + } + if (adds.size() > 0) { + originList.addAll(adds); + } + } } diff --git a/codec/codec-api/src/main/java/com/alipay/sofa/rpc/codec/common/SerializeCheckStatus.java b/codec/codec-api/src/main/java/com/alipay/sofa/rpc/codec/common/SerializeCheckStatus.java new file mode 100644 index 000000000..bcedf2101 --- /dev/null +++ b/codec/codec-api/src/main/java/com/alipay/sofa/rpc/codec/common/SerializeCheckStatus.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.alipay.sofa.rpc.codec.common; + +/** + * @author Even + * @date 2024/1/5 19:12 + */ +public enum SerializeCheckStatus { + /** + * Disable serialize check for all classes + */ + DISABLE(0), + + /** + * Only deny danger classes, warn if other classes are not in allow list + */ + WARN(1), + + /** + * Only allow classes in allow list, deny if other classes are not in allow list + */ + STRICT(2); + + private final int mode; + + SerializeCheckStatus(int mode) { + this.mode = mode; + } + + public int getSerializeCheckMode() { + return mode; + } +} diff --git a/codec/codec-sofa-hessian/src/main/resources/sofa-rpc/serialize_blacklist.txt b/codec/codec-api/src/main/resources/sofa-rpc/serialize_blacklist.txt similarity index 100% rename from codec/codec-sofa-hessian/src/main/resources/sofa-rpc/serialize_blacklist.txt rename to codec/codec-api/src/main/resources/sofa-rpc/serialize_blacklist.txt diff --git a/codec/codec-sofa-fury/pom.xml b/codec/codec-sofa-fury/pom.xml new file mode 100644 index 000000000..70150a8f9 --- /dev/null +++ b/codec/codec-sofa-fury/pom.xml @@ -0,0 +1,46 @@ + + + 4.0.0 + + + com.alipay.sofa + sofa-rpc-codec + ${revision} + + + sofa-rpc-codec-sofa-fury + + + + com.alipay.sofa + sofa-rpc-codec-api + + + com.alipay.sofa + sofa-rpc-api + + + com.alipay.sofa + sofa-rpc-log + + + + + org.furyio + fury-core + + + + org.slf4j + slf4j-log4j12 + test + + + junit + junit + test + + + diff --git a/codec/codec-sofa-fury/src/main/java/com/alipay/sofa/rpc/codec/fury/FurySerializer.java b/codec/codec-sofa-fury/src/main/java/com/alipay/sofa/rpc/codec/fury/FurySerializer.java new file mode 100644 index 000000000..e1a61a6fd --- /dev/null +++ b/codec/codec-sofa-fury/src/main/java/com/alipay/sofa/rpc/codec/fury/FurySerializer.java @@ -0,0 +1,182 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.alipay.sofa.rpc.codec.fury; + +import com.alipay.sofa.common.config.SofaConfigs; +import com.alipay.sofa.rpc.codec.AbstractSerializer; +import com.alipay.sofa.rpc.codec.CustomSerializer; +import com.alipay.sofa.rpc.codec.common.BlackAndWhiteListFileLoader; +import com.alipay.sofa.rpc.codec.common.SerializeCheckStatus; +import com.alipay.sofa.rpc.codec.fury.serialize.SofaRequestFurySerializer; +import com.alipay.sofa.rpc.codec.fury.serialize.SofaResponseFurySerializer; +import com.alipay.sofa.rpc.common.config.RpcConfigKeys; +import com.alipay.sofa.rpc.core.exception.SofaRpcException; +import com.alipay.sofa.rpc.core.request.SofaRequest; +import com.alipay.sofa.rpc.core.response.SofaResponse; +import com.alipay.sofa.rpc.ext.Extension; +import com.alipay.sofa.rpc.transport.AbstractByteBuf; +import com.alipay.sofa.rpc.transport.ByteArrayWrapperByteBuf; +import io.fury.Fury; +import io.fury.ThreadLocalFury; +import io.fury.config.Language; +import io.fury.memory.MemoryBuffer; +import io.fury.resolver.AllowListChecker; + +import java.util.List; +import java.util.Map; + +import static io.fury.config.CompatibleMode.COMPATIBLE; + +/** + * @author lipan + */ +@Extension(value = "fury2", code = 22) +public class FurySerializer extends AbstractSerializer { + + private final ThreadLocalFury fury; + + private final String checkerMode = SofaConfigs.getOrDefault(RpcConfigKeys.SERIALIZE_CHECKER_MODE); + + public FurySerializer() { + fury = new ThreadLocalFury(classLoader -> { + Fury f = Fury.builder().withLanguage(Language.JAVA) + .withRefTracking(true) + .withCodegen(true) + .withNumberCompressed(true) + .withCompatibleMode(COMPATIBLE) + .requireClassRegistration(false) + .withClassLoader(classLoader) + .withAsyncCompilation(true) + .build(); + + // Do not use any configuration + if (checkerMode.equalsIgnoreCase(SerializeCheckStatus.DISABLE.name())) { + AllowListChecker noChecker = new AllowListChecker(AllowListChecker.CheckLevel.DISABLE); + f.getClassResolver().setClassChecker(noChecker); + return f; + } else if (checkerMode.equalsIgnoreCase(SerializeCheckStatus.WARN.name())) { + AllowListChecker blackListChecker = new AllowListChecker(AllowListChecker.CheckLevel.WARN); + List blackList = BlackAndWhiteListFileLoader.SOFA_SERIALIZE_BLACK_LIST; + // To setting checker + f.getClassResolver().setClassChecker(blackListChecker); + blackListChecker.addListener(f.getClassResolver()); + // BlackList classes use wildcards + for (String key : blackList) { + blackListChecker.disallowClass(key + "*"); + } + } else if (checkerMode.equalsIgnoreCase(SerializeCheckStatus.STRICT.name())) { + AllowListChecker blackAndWhiteListChecker = new AllowListChecker(AllowListChecker.CheckLevel.STRICT); + List whiteList = BlackAndWhiteListFileLoader.SOFA_SERIALIZER_WHITE_LIST; + // To setting checker + f.getClassResolver().setClassChecker(blackAndWhiteListChecker); + blackAndWhiteListChecker.addListener(f.getClassResolver()); + // WhiteList classes use wildcards + for (String key : whiteList) { + blackAndWhiteListChecker.allowClass(key + "*"); + } + List blackList = BlackAndWhiteListFileLoader.SOFA_SERIALIZE_BLACK_LIST; + // To setting checker + f.getClassResolver().setClassChecker(blackAndWhiteListChecker); + blackAndWhiteListChecker.addListener(f.getClassResolver()); + // BlackList classes use wildcards + for (String key : blackList) { + blackAndWhiteListChecker.disallowClass(key + "*"); + } + } + f.register(SofaRequest.class); + f.register(SofaResponse.class); + f.register(SofaRpcException.class); + return f; + }); + addSerializer(SofaRequest.class, new SofaRequestFurySerializer(fury)); + addSerializer(SofaResponse.class, new SofaResponseFurySerializer(fury)); + } + + @Override + public AbstractByteBuf encode(final Object object, final Map context) throws SofaRpcException { + if (object == null) { + throw buildSerializeError("Unsupported null message!"); + } + ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); + try { + fury.setClassLoader(contextClassLoader); + CustomSerializer customSerializer = getObjCustomSerializer(object); + if (customSerializer != null) { + return customSerializer.encodeObject(object, context); + } else { + MemoryBuffer writeBuffer = MemoryBuffer.newHeapBuffer(32); + writeBuffer.writerIndex(0); + fury.serialize(writeBuffer, object); + return new ByteArrayWrapperByteBuf(writeBuffer.getBytes(0, writeBuffer.writerIndex())); + } + } catch (Exception e) { + throw buildSerializeError(e.getMessage(), e); + } finally { + fury.clearClassLoader(contextClassLoader); + } + } + + @Override + public Object decode(final AbstractByteBuf data, final Class clazz, final Map context) + throws SofaRpcException { + if (data.readableBytes() <= 0 || clazz == null) { + throw buildDeserializeError("Deserialized array is empty."); + } + ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); + try { + fury.setClassLoader(contextClassLoader); + CustomSerializer customSerializer = getSerializer(clazz); + if (customSerializer != null) { + return customSerializer.decodeObject(data, context); + } else { + MemoryBuffer readBuffer = MemoryBuffer.fromByteArray(data.array()); + return fury.deserialize(readBuffer); + } + } catch (Exception e) { + throw buildDeserializeError(e.getMessage(), e); + } finally { + fury.clearClassLoader(contextClassLoader); + } + } + + @Override + public void decode(final AbstractByteBuf data, final Object template, final Map context) + throws SofaRpcException { + if (template == null) { + throw buildDeserializeError("template is null!"); + } + ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); + try { + fury.setClassLoader(contextClassLoader); + CustomSerializer customSerializer = getObjCustomSerializer(template); + if (customSerializer != null) { + customSerializer.decodeObjectByTemplate(data, context, template); + } else { + throw buildDeserializeError("Only support decode from SofaRequest and SofaResponse template"); + } + } catch (Exception e) { + throw buildDeserializeError(e.getMessage(), e); + } finally { + fury.clearClassLoader(contextClassLoader); + } + } + + public ThreadLocalFury getFury() { + return fury; + } + +} diff --git a/codec/codec-sofa-fury/src/main/java/com/alipay/sofa/rpc/codec/fury/serialize/SofaRequestFurySerializer.java b/codec/codec-sofa-fury/src/main/java/com/alipay/sofa/rpc/codec/fury/serialize/SofaRequestFurySerializer.java new file mode 100644 index 000000000..9122c0c18 --- /dev/null +++ b/codec/codec-sofa-fury/src/main/java/com/alipay/sofa/rpc/codec/fury/serialize/SofaRequestFurySerializer.java @@ -0,0 +1,117 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.alipay.sofa.rpc.codec.fury.serialize; + +import com.alipay.sofa.rpc.codec.CustomSerializer; +import com.alipay.sofa.rpc.common.RemotingConstants; +import com.alipay.sofa.rpc.config.ConfigUniqueNameGenerator; +import com.alipay.sofa.rpc.core.exception.SofaRpcException; +import com.alipay.sofa.rpc.core.request.SofaRequest; +import com.alipay.sofa.rpc.transport.AbstractByteBuf; +import com.alipay.sofa.rpc.transport.ByteArrayWrapperByteBuf; +import io.fury.ThreadLocalFury; +import io.fury.memory.MemoryBuffer; + +import java.util.Map; + +/** + * @author Even + * @date 2024/1/4 19:29 + */ +public class SofaRequestFurySerializer implements CustomSerializer { + + private final ThreadLocalFury fury; + + public SofaRequestFurySerializer(ThreadLocalFury fury) { + this.fury = fury; + } + + @Override + public AbstractByteBuf encodeObject(SofaRequest object, Map context) throws SofaRpcException { + try { + MemoryBuffer writeBuffer = MemoryBuffer.newHeapBuffer(32); + writeBuffer.writerIndex(0); + + // 根据SerializeType信息决定序列化器 + boolean genericSerialize = context != null && + isGenericRequest(context.get(RemotingConstants.HEAD_GENERIC_TYPE)); + if (genericSerialize) { + // TODO support generic call + throw new SofaRpcException("Generic call is not supported for now."); + } + fury.serialize(writeBuffer, object); + final Object[] args = object.getMethodArgs(); + fury.serialize(writeBuffer, args); + + return new ByteArrayWrapperByteBuf(writeBuffer.getBytes(0, writeBuffer.writerIndex())); + } catch (Exception e) { + throw new SofaRpcException(e.getMessage(), e); + } + } + + @Override + public SofaRequest decodeObject(AbstractByteBuf data, Map context) throws SofaRpcException { + MemoryBuffer readBuffer = MemoryBuffer.fromByteArray(data.array()); + try { + SofaRequest sofaRequest = (SofaRequest) fury.deserialize(readBuffer); + String targetServiceName = sofaRequest.getTargetServiceUniqueName(); + if (targetServiceName == null) { + throw new SofaRpcException("Target service name of request is null!"); + } + String interfaceName = ConfigUniqueNameGenerator.getInterfaceName(targetServiceName); + sofaRequest.setInterfaceName(interfaceName); + final Object[] args = (Object[]) fury.deserialize(readBuffer); + sofaRequest.setMethodArgs(args); + return sofaRequest; + } catch (Exception e) { + throw new SofaRpcException(e.getMessage(), e); + } + } + + @Override + public void decodeObjectByTemplate(AbstractByteBuf data, Map context, SofaRequest template) + throws SofaRpcException { + if (data.readableBytes() <= 0) { + throw new SofaRpcException("Deserialized array is empty."); + } + try { + MemoryBuffer readBuffer = MemoryBuffer.fromByteArray(data.array()); + SofaRequest tmp = (SofaRequest) fury.deserialize(readBuffer); + String targetServiceName = tmp.getTargetServiceUniqueName(); + if (targetServiceName == null) { + throw new SofaRpcException("Target service name of request is null!"); + } + // copy values to template + template.setMethodName(tmp.getMethodName()); + template.setMethodArgSigs(tmp.getMethodArgSigs()); + template.setTargetServiceUniqueName(tmp.getTargetServiceUniqueName()); + template.setTargetAppName(tmp.getTargetAppName()); + template.addRequestProps(tmp.getRequestProps()); + String interfaceName = ConfigUniqueNameGenerator.getInterfaceName(targetServiceName); + template.setInterfaceName(interfaceName); + final Object[] args = (Object[]) fury.deserialize(readBuffer); + template.setMethodArgs(args); + } catch (Exception e) { + throw new SofaRpcException(e.getMessage(), e); + } + } + + protected boolean isGenericRequest(String serializeType) { + return serializeType != null && !serializeType.equals(RemotingConstants.SERIALIZE_FACTORY_NORMAL); + } + +} diff --git a/codec/codec-sofa-fury/src/main/java/com/alipay/sofa/rpc/codec/fury/serialize/SofaResponseFurySerializer.java b/codec/codec-sofa-fury/src/main/java/com/alipay/sofa/rpc/codec/fury/serialize/SofaResponseFurySerializer.java new file mode 100644 index 000000000..9a7402ab1 --- /dev/null +++ b/codec/codec-sofa-fury/src/main/java/com/alipay/sofa/rpc/codec/fury/serialize/SofaResponseFurySerializer.java @@ -0,0 +1,102 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.alipay.sofa.rpc.codec.fury.serialize; + +import com.alipay.sofa.rpc.codec.CustomSerializer; +import com.alipay.sofa.rpc.common.RemotingConstants; +import com.alipay.sofa.rpc.core.exception.SofaRpcException; +import com.alipay.sofa.rpc.core.response.SofaResponse; +import com.alipay.sofa.rpc.transport.AbstractByteBuf; +import com.alipay.sofa.rpc.transport.ByteArrayWrapperByteBuf; +import io.fury.ThreadLocalFury; +import io.fury.memory.MemoryBuffer; + +import java.util.Map; + +/** + * @author Even + * @date 2024/1/4 19:30 + */ +public class SofaResponseFurySerializer implements CustomSerializer { + + private final ThreadLocalFury fury; + + public SofaResponseFurySerializer(ThreadLocalFury fury) { + this.fury = fury; + } + + @Override + public AbstractByteBuf encodeObject(SofaResponse object, Map context) throws SofaRpcException { + try { + fury.setClassLoader(Thread.currentThread().getContextClassLoader()); + MemoryBuffer writeBuffer = MemoryBuffer.newHeapBuffer(32); + writeBuffer.writerIndex(0); + fury.serialize(writeBuffer, object); + return new ByteArrayWrapperByteBuf(writeBuffer.getBytes(0, writeBuffer.writerIndex())); + } catch (Exception e) { + throw new SofaRpcException(e.getMessage(), e); + } + } + + @Override + public SofaResponse decodeObject(AbstractByteBuf data, Map context) throws SofaRpcException { + MemoryBuffer readBuffer = MemoryBuffer.fromByteArray(data.array()); + try { + fury.setClassLoader(Thread.currentThread().getContextClassLoader()); + boolean genericSerialize = context != null && isGenericResponse( + context.get(RemotingConstants.HEAD_GENERIC_TYPE)); + if (genericSerialize) { + // TODO support generic call + throw new SofaRpcException("Generic call is not supported for now."); + } + return (SofaResponse) fury.deserialize(readBuffer); + } catch (Exception e) { + throw new SofaRpcException(e.getMessage(), e); + } + } + + @Override + public void decodeObjectByTemplate(AbstractByteBuf data, Map context, SofaResponse template) + throws SofaRpcException { + if (data.readableBytes() <= 0) { + throw new SofaRpcException("Deserialized array is empty."); + } + try { + fury.setClassLoader(Thread.currentThread().getContextClassLoader()); + MemoryBuffer readBuffer = MemoryBuffer.fromByteArray(data.array()); + // 根据SerializeType信息决定序列化器 + boolean genericSerialize = context != null && isGenericResponse( + context.get(RemotingConstants.HEAD_GENERIC_TYPE)); + if (genericSerialize) { + // TODO support generic call + throw new SofaRpcException("Generic call is not supported for now."); + } else { + SofaResponse tmp = (SofaResponse) fury.deserialize(readBuffer); + // copy values to template + template.setErrorMsg(tmp.getErrorMsg()); + template.setAppResponse(tmp.getAppResponse()); + template.setResponseProps(tmp.getResponseProps()); + } + } catch (Exception e) { + throw new SofaRpcException(e.getMessage(), e); + } + } + + protected boolean isGenericResponse(String serializeType) { + return serializeType != null && serializeType.equals(RemotingConstants.SERIALIZE_FACTORY_GENERIC); + } +} diff --git a/codec/codec-sofa-fury/src/main/resources/META-INF/services/sofa-rpc/com.alipay.sofa.rpc.codec.Serializer b/codec/codec-sofa-fury/src/main/resources/META-INF/services/sofa-rpc/com.alipay.sofa.rpc.codec.Serializer new file mode 100644 index 000000000..dc727a0dd --- /dev/null +++ b/codec/codec-sofa-fury/src/main/resources/META-INF/services/sofa-rpc/com.alipay.sofa.rpc.codec.Serializer @@ -0,0 +1 @@ +fury2=com.alipay.sofa.rpc.codec.fury.FurySerializer \ No newline at end of file diff --git a/codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/FurySerializerTest.java b/codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/FurySerializerTest.java new file mode 100644 index 000000000..fc4fde8cc --- /dev/null +++ b/codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/FurySerializerTest.java @@ -0,0 +1,289 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.alipay.sofa.rpc.codec.fury; + +import com.alipay.sofa.rpc.codec.Serializer; +import com.alipay.sofa.rpc.codec.fury.model.blacklist.BlackListClass; +import com.alipay.sofa.rpc.codec.fury.model.none.NoneClassHasBlackClass; +import com.alipay.sofa.rpc.codec.fury.model.whitelist.DemoRequest; +import com.alipay.sofa.rpc.codec.fury.model.whitelist.DemoResponse; +import com.alipay.sofa.rpc.codec.fury.model.whitelist.WhiteClassHasBlackClass; +import com.alipay.sofa.rpc.codec.fury.model.whitelist.DemoService; +import com.alipay.sofa.rpc.common.RemotingConstants; +import com.alipay.sofa.rpc.common.RpcConstants; +import com.alipay.sofa.rpc.core.exception.SofaRpcException; +import com.alipay.sofa.rpc.core.invoke.SofaResponseCallback; +import com.alipay.sofa.rpc.core.request.RequestBase; +import com.alipay.sofa.rpc.core.request.SofaRequest; +import com.alipay.sofa.rpc.core.response.SofaResponse; +import com.alipay.sofa.rpc.ext.ExtensionLoaderFactory; +import com.alipay.sofa.rpc.transport.AbstractByteBuf; +import com.alipay.sofa.rpc.transport.ByteArrayWrapperByteBuf; +import org.junit.Assert; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author lipan + */ +public class FurySerializerTest { + + private final FurySerializer serializer = (FurySerializer) ExtensionLoaderFactory.getExtensionLoader( + Serializer.class).getExtension("fury2"); + + @Test + public void encodeAndDecode() { + try { + serializer.encode(null, null); + Assert.fail(); + } catch (Exception e) { + + } + + DemoRequest demoRequest = new DemoRequest(); + demoRequest.setName("a"); + AbstractByteBuf byteBuf = serializer.encode(demoRequest, null); + DemoRequest req2 = (DemoRequest) serializer.decode(byteBuf, DemoRequest.class, null); + Assert.assertEquals(demoRequest.getName(), req2.getName()); + + AbstractByteBuf data = serializer.encode("xxx", null); + String dst = (String) serializer.decode(data, String.class, null); + Assert.assertEquals("xxx", dst); + + try { + serializer.decode(data, null, null); + Assert.fail(); + } catch (Exception e) { + } + + try { + serializer.decode(data, "", null); + Assert.fail(); + } catch (Exception e) { + + } + } + + @Test + public void testSofaRequest() throws Exception { + SofaRequest request = buildRequest(); + AbstractByteBuf data = serializer.encode(request, null); + + serializer.encode("123456", null); + SofaRequest decode = (SofaRequest) serializer.decode(data, SofaRequest.class, null); + assertEqualsSofaRequest(request, decode); + + SofaRequest newRequest = new SofaRequest(); + serializer.decode(data, newRequest, null); + assertEqualsSofaRequest(request, newRequest); + + // null request + newRequest = new SofaRequest(); + try { + serializer.decode(new ByteArrayWrapperByteBuf(new byte[0]), newRequest, null); + Assert.fail(); + } catch (Exception e) { + + } + } + + @Test + public void testSofaResponse() throws Exception { + SofaResponse response = new SofaResponse(); + final DemoResponse demoAppResponse = new DemoResponse(); + demoAppResponse.setWord("result"); + response.setAppResponse(demoAppResponse); + AbstractByteBuf data = serializer.encode(response, null); + + try { + serializer.decode(data, null, null); + Assert.fail(); + } catch (Exception e) { + + } + + try { + serializer.decode(data, new Object(), null); + Assert.fail(); + } catch (Exception e) { + + } + + SofaResponse decode = (SofaResponse) serializer.decode(data, SofaResponse.class, null); + Assert.assertFalse(decode.isError()); + Assert.assertEquals(response.getAppResponse(), decode.getAppResponse()); + Assert.assertEquals("result", ((DemoResponse) decode.getAppResponse()).getWord()); + + // success response + SofaResponse newResponse = new SofaResponse(); + serializer.decode(data, newResponse, null); + Assert.assertFalse(newResponse.isError()); + Assert.assertEquals(response.getAppResponse(), newResponse.getAppResponse()); + Assert.assertEquals("result", ((DemoResponse) newResponse.getAppResponse()).getWord()); + + // null response + newResponse = new SofaResponse(); + try { + serializer.decode(new ByteArrayWrapperByteBuf(new byte[0]), newResponse, null); + Assert.fail(); + } catch (Exception e) { + + } + // error response + response = new SofaResponse(); + response.setErrorMsg("1233"); + data = serializer.encode(response, null); + newResponse = new SofaResponse(); + serializer.decode(data, newResponse, null); + Assert.assertTrue(newResponse.isError()); + Assert.assertEquals(response.getErrorMsg(), newResponse.getErrorMsg()); + } + + private SofaRequest buildRequest() throws NoSuchMethodException { + SofaRequest request = new SofaRequest(); + request.setInterfaceName(DemoService.class.getName()); + request.setMethodName("say"); + request.setMethod(DemoService.class.getMethod("say", DemoRequest.class)); + final DemoRequest demoRequest = new DemoRequest(); + demoRequest.setName("name"); + request.setMethodArgs(new Object[] { demoRequest }); + request.setMethodArgSigs(new String[] { DemoRequest.class.getCanonicalName() }); + request.setTargetServiceUniqueName(DemoService.class.getName() + ":1.0"); + request.setTargetAppName("targetApp"); + request.setSerializeType((byte) 22); + request.setTimeout(1024); + request.setInvokeType(RpcConstants.INVOKER_TYPE_SYNC); + Map map = new HashMap(); + map.put("a", "xxx"); + map.put("b", "yyy"); + request.addRequestProp(RemotingConstants.RPC_TRACE_NAME, map); + request.setSofaResponseCallback(new SofaResponseCallback() { + @Override + public void onAppResponse(Object appResponse, String methodName, RequestBase request) { + + } + + @Override + public void onAppException(Throwable throwable, String methodName, RequestBase request) { + + } + + @Override + public void onSofaException(SofaRpcException sofaException, String methodName, RequestBase request) { + + } + }); + return request; + } + + private void assertEqualsSofaRequest(SofaRequest request, SofaRequest decode) { + Assert.assertEquals(decode.getInterfaceName(), request.getInterfaceName()); + Assert.assertEquals(decode.getMethodName(), request.getMethodName()); + Assert.assertArrayEquals(decode.getMethodArgSigs(), request.getMethodArgSigs()); + Assert.assertEquals(decode.getMethodArgs().length, request.getMethodArgs().length); + Assert.assertEquals("name", ((DemoRequest) decode.getMethodArgs()[0]).getName()); + Assert.assertEquals(decode.getTargetServiceUniqueName(), request.getTargetServiceUniqueName()); + Assert.assertEquals(decode.getTargetAppName(), request.getTargetAppName()); + Assert.assertEquals(decode.getRequestProp(RemotingConstants.RPC_TRACE_NAME), + request.getRequestProp(RemotingConstants.RPC_TRACE_NAME)); + } + + @Test + public void testChecker() throws Exception { + // default fury checkMode is STRICT + WhiteClassHasBlackClass whiteClassNullBlackClass = new WhiteClassHasBlackClass(); + NoneClassHasBlackClass noneClassNullBlackClass = new NoneClassHasBlackClass(); + + BlackListClass blackListClass = new BlackListClass(); + WhiteClassHasBlackClass whiteClassHasBlackClass = new WhiteClassHasBlackClass(); + whiteClassHasBlackClass.setBlackListClass(blackListClass); + NoneClassHasBlackClass noneClassHasBlackClass = new NoneClassHasBlackClass(); + noneClassHasBlackClass.setBlackListClass(blackListClass); + + try { + serializer.encode(noneClassNullBlackClass, null); + Assert.fail(); + } catch (Exception e) { + + } + + try { + serializer.encode(noneClassHasBlackClass, null); + Assert.fail(); + } catch (Exception e) { + + } + + try { + serializer.encode(blackListClass, null); + Assert.fail(); + } catch (Exception e) { + + } + + serializer.encode(whiteClassNullBlackClass, null); + try { + serializer.encode(whiteClassHasBlackClass, null); + Assert.fail(); + } catch (Exception e) { + + } + + // test change fury checkMode to blacklist + System.getProperties().put("sofa.rpc.codec.serialize.checkMode", "WARN"); + FurySerializer furySerializer = new FurySerializer(); + + furySerializer.encode(noneClassNullBlackClass, null); + + try { + furySerializer.encode(noneClassHasBlackClass, null); + Assert.fail(); + } catch (Exception e) { + + } + + try { + //Not registered this class + furySerializer.encode(blackListClass, null); + Assert.fail(); + } catch (Exception e) { + + } + + furySerializer.encode(whiteClassNullBlackClass, null); + try { + furySerializer.encode(whiteClassHasBlackClass, null); + Assert.fail(); + } catch (Exception e) { + + } + System.getProperties().remove("sofa.rpc.codec.serialize.checkMode"); + + // test change fury checkMode to none + System.getProperties().put("sofa.rpc.codec.serialize.checkMode", "DISABLE"); + FurySerializer noneFurySerializer = new FurySerializer(); + noneFurySerializer.encode(noneClassNullBlackClass, null); + noneFurySerializer.encode(noneClassHasBlackClass, null); + noneFurySerializer.encode(blackListClass, null); + noneFurySerializer.encode(whiteClassNullBlackClass, null); + noneFurySerializer.encode(whiteClassHasBlackClass, null); + System.getProperties().remove("sofa.rpc.codec.serialize.checkMode"); + } + +} \ No newline at end of file diff --git a/codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/model/blacklist/BlackListClass.java b/codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/model/blacklist/BlackListClass.java new file mode 100644 index 000000000..78281a910 --- /dev/null +++ b/codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/model/blacklist/BlackListClass.java @@ -0,0 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.alipay.sofa.rpc.codec.fury.model.blacklist; + +/** + * @author lipan + */ +public class BlackListClass { + private String test; +} diff --git a/codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/model/none/NoneClassHasBlackClass.java b/codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/model/none/NoneClassHasBlackClass.java new file mode 100644 index 000000000..8ddaaa9a8 --- /dev/null +++ b/codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/model/none/NoneClassHasBlackClass.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.alipay.sofa.rpc.codec.fury.model.none; + +import com.alipay.sofa.rpc.codec.fury.model.blacklist.BlackListClass; + +/** + * @author Even + * @date 2024/1/2 11:33 + */ +public class NoneClassHasBlackClass { + + private BlackListClass blackListClass; + + public BlackListClass getBlackListClass() { + return blackListClass; + } + + public void setBlackListClass(BlackListClass blackListClass) { + this.blackListClass = blackListClass; + } +} diff --git a/codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/model/whitelist/DemoRequest.java b/codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/model/whitelist/DemoRequest.java new file mode 100644 index 000000000..7b9bb7129 --- /dev/null +++ b/codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/model/whitelist/DemoRequest.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.alipay.sofa.rpc.codec.fury.model.whitelist; + +/** + * @author lipan + */ +public class DemoRequest { + + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} \ No newline at end of file diff --git a/codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/model/whitelist/DemoResponse.java b/codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/model/whitelist/DemoResponse.java new file mode 100644 index 000000000..ffca06616 --- /dev/null +++ b/codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/model/whitelist/DemoResponse.java @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.alipay.sofa.rpc.codec.fury.model.whitelist; + +/** + * @author lipan + */ +public class DemoResponse { + + private String word; + + public String getWord() { + return word; + } + + public void setWord(String word) { + this.word = word; + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (!(o instanceof DemoResponse)) + return false; + + DemoResponse that = (DemoResponse) o; + + return word != null ? word.equals(that.word) : that.word == null; + } + + @Override + public int hashCode() { + return word != null ? word.hashCode() : 0; + } +} \ No newline at end of file diff --git a/codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/model/whitelist/DemoService.java b/codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/model/whitelist/DemoService.java new file mode 100644 index 000000000..604473b7b --- /dev/null +++ b/codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/model/whitelist/DemoService.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.alipay.sofa.rpc.codec.fury.model.whitelist; + +import java.util.List; +import java.util.Map; + +/** + * @author lipan + */ +public interface DemoService { + + public DemoResponse say(DemoRequest demoRequest); + + public DemoResponse say2(DemoRequest demoRequest, Map ctx, int id); + + public List say3(List list); + +} \ No newline at end of file diff --git a/codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/model/whitelist/WhiteClassHasBlackClass.java b/codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/model/whitelist/WhiteClassHasBlackClass.java new file mode 100644 index 000000000..10e3943fb --- /dev/null +++ b/codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/model/whitelist/WhiteClassHasBlackClass.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.alipay.sofa.rpc.codec.fury.model.whitelist; + +import com.alipay.sofa.rpc.codec.fury.model.blacklist.BlackListClass; + +/** + * @author lipan + */ +public class WhiteClassHasBlackClass { + + private BlackListClass blackListClass; + + public BlackListClass getBlackListClass() { + return blackListClass; + } + + public void setBlackListClass(BlackListClass blackListClass) { + this.blackListClass = blackListClass; + } +} diff --git a/codec/codec-sofa-fury/src/test/resources/log4j.xml b/codec/codec-sofa-fury/src/test/resources/log4j.xml new file mode 100644 index 000000000..e95634f16 --- /dev/null +++ b/codec/codec-sofa-fury/src/test/resources/log4j.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/codec/codec-sofa-fury/src/test/resources/sofa-rpc/rpc-config.json b/codec/codec-sofa-fury/src/test/resources/sofa-rpc/rpc-config.json new file mode 100644 index 000000000..5b573549a --- /dev/null +++ b/codec/codec-sofa-fury/src/test/resources/sofa-rpc/rpc-config.json @@ -0,0 +1,4 @@ +{ + "rpc.config.order": 999, + "logger.impl": "com.alipay.sofa.rpc.log.SLF4JLoggerImpl" +} \ No newline at end of file diff --git a/codec/codec-sofa-fury/src/test/resources/sofa-rpc/serialize_blacklist.txt b/codec/codec-sofa-fury/src/test/resources/sofa-rpc/serialize_blacklist.txt new file mode 100644 index 000000000..991e2a54d --- /dev/null +++ b/codec/codec-sofa-fury/src/test/resources/sofa-rpc/serialize_blacklist.txt @@ -0,0 +1 @@ +com.alipay.sofa.rpc.codec.fury.model.blacklist. \ No newline at end of file diff --git a/codec/codec-sofa-fury/src/test/resources/sofa-rpc/serialize_whitelist.txt b/codec/codec-sofa-fury/src/test/resources/sofa-rpc/serialize_whitelist.txt new file mode 100644 index 000000000..6f1718654 --- /dev/null +++ b/codec/codec-sofa-fury/src/test/resources/sofa-rpc/serialize_whitelist.txt @@ -0,0 +1 @@ +com.alipay.sofa.rpc.codec.fury.model.whitelist. \ No newline at end of file diff --git a/codec/codec-sofa-hessian/src/main/java/com/alipay/sofa/rpc/codec/sofahessian/SofaHessianSerializer.java b/codec/codec-sofa-hessian/src/main/java/com/alipay/sofa/rpc/codec/sofahessian/SofaHessianSerializer.java index ae7eac3f0..06ec4a4a6 100644 --- a/codec/codec-sofa-hessian/src/main/java/com/alipay/sofa/rpc/codec/sofahessian/SofaHessianSerializer.java +++ b/codec/codec-sofa-hessian/src/main/java/com/alipay/sofa/rpc/codec/sofahessian/SofaHessianSerializer.java @@ -19,6 +19,7 @@ import com.alipay.hessian.ClassNameResolver; import com.alipay.hessian.NameBlackListFilter; import com.alipay.sofa.rpc.codec.AbstractSerializer; +import com.alipay.sofa.rpc.codec.common.BlackAndWhiteListFileLoader; import com.alipay.sofa.rpc.codec.sofahessian.serialize.CustomHessianSerializer; import com.alipay.sofa.rpc.codec.sofahessian.serialize.SofaRequestHessianSerializer; import com.alipay.sofa.rpc.codec.sofahessian.serialize.SofaResponseHessianSerializer; @@ -95,7 +96,7 @@ public SofaHessianSerializer() { if (RpcConfigs.getBooleanValue(RpcOptions.SERIALIZE_BLACKLIST_ENABLE) && SofaConfigs.getBooleanValue(SofaOptions.CONFIG_SERIALIZE_BLACKLIST, true)) { ClassNameResolver resolver = new ClassNameResolver(); - resolver.addFilter(new NameBlackListFilter(BlackListFileLoader.SOFA_SERIALIZE_BLACK_LIST, 8192)); + resolver.addFilter(new NameBlackListFilter(BlackAndWhiteListFileLoader.SOFA_SERIALIZE_BLACK_LIST, 8192)); serializerFactory.setClassNameResolver(resolver); genericSerializerFactory.setClassNameResolver(resolver); } else { diff --git a/codec/codec-sofa-hessian/src/test/java/com/alipay/sofa/rpc/codec/sofahessian/BlackListFileLoaderTest.java b/codec/codec-sofa-hessian/src/test/java/com/alipay/sofa/rpc/codec/sofahessian/BlackAndWhiteListFileLoaderTest.java similarity index 71% rename from codec/codec-sofa-hessian/src/test/java/com/alipay/sofa/rpc/codec/sofahessian/BlackListFileLoaderTest.java rename to codec/codec-sofa-hessian/src/test/java/com/alipay/sofa/rpc/codec/sofahessian/BlackAndWhiteListFileLoaderTest.java index df934b6a1..05d279e4f 100644 --- a/codec/codec-sofa-hessian/src/test/java/com/alipay/sofa/rpc/codec/sofahessian/BlackListFileLoaderTest.java +++ b/codec/codec-sofa-hessian/src/test/java/com/alipay/sofa/rpc/codec/sofahessian/BlackAndWhiteListFileLoaderTest.java @@ -17,6 +17,7 @@ package com.alipay.sofa.rpc.codec.sofahessian; import com.alipay.hessian.NameBlackListFilter; +import com.alipay.sofa.rpc.codec.common.BlackAndWhiteListFileLoader; import com.alipay.sofa.rpc.common.SofaOptions; import org.junit.Assert; import org.junit.Test; @@ -29,17 +30,17 @@ * * @author GengZhang */ -public class BlackListFileLoaderTest { +public class BlackAndWhiteListFileLoaderTest { @Test public void testAll() throws Exception { - List blacks = BlackListFileLoader.SOFA_SERIALIZE_BLACK_LIST; + List blacks = BlackAndWhiteListFileLoader.SOFA_SERIALIZE_BLACK_LIST; Assert.assertNotNull(blacks); String s = System.getProperty(SofaOptions.CONFIG_SERIALIZE_BLACKLIST_OVERRIDE); try { System.setProperty(SofaOptions.CONFIG_SERIALIZE_BLACKLIST_OVERRIDE, "-java.net.Socket"); - blacks = BlackListFileLoader.loadFile("/sofa-rpc/serialize_blacklist.txt"); + blacks = BlackAndWhiteListFileLoader.loadBlackListFile("/sofa-rpc/serialize_blacklist.txt"); } finally { if (s != null) { System.setProperty(SofaOptions.CONFIG_SERIALIZE_BLACKLIST_OVERRIDE, s); @@ -69,51 +70,51 @@ public void testAll() throws Exception { @Test public void overrideBlackList() { List origin = buildOriginList(); - BlackListFileLoader.overrideBlackList(origin, "-*"); + BlackAndWhiteListFileLoader.overrideBlackList(origin, "-*"); Assert.assertTrue(origin.size() == 0); origin = buildOriginList(); - BlackListFileLoader.overrideBlackList(origin, "!*"); + BlackAndWhiteListFileLoader.overrideBlackList(origin, "!*"); Assert.assertTrue(origin.size() == 0); origin = buildOriginList(); - BlackListFileLoader.overrideBlackList(origin, "-default"); + BlackAndWhiteListFileLoader.overrideBlackList(origin, "-default"); Assert.assertTrue(origin.size() == 0); origin = buildOriginList(); - BlackListFileLoader.overrideBlackList(origin, "!default"); + BlackAndWhiteListFileLoader.overrideBlackList(origin, "!default"); Assert.assertTrue(origin.size() == 0); origin = buildOriginList(); - BlackListFileLoader.overrideBlackList(origin, "-*,-com.xxx"); + BlackAndWhiteListFileLoader.overrideBlackList(origin, "-*,-com.xxx"); Assert.assertTrue(origin.size() == 0); origin = buildOriginList(); - BlackListFileLoader.overrideBlackList(origin, "aaa,-*,-com.xxx"); + BlackAndWhiteListFileLoader.overrideBlackList(origin, "aaa,-*,-com.xxx"); Assert.assertTrue(origin.size() == 1); origin = buildOriginList(); - BlackListFileLoader.overrideBlackList(origin, "-*,aaa"); + BlackAndWhiteListFileLoader.overrideBlackList(origin, "-*,aaa"); Assert.assertTrue(origin.size() == 1); origin = buildOriginList(); - BlackListFileLoader.overrideBlackList(origin, "-com.xxx"); + BlackAndWhiteListFileLoader.overrideBlackList(origin, "-com.xxx"); Assert.assertTrue(origin.size() == 2); origin = buildOriginList(); - BlackListFileLoader.overrideBlackList(origin, "-com.xxx,-com.yyy"); + BlackAndWhiteListFileLoader.overrideBlackList(origin, "-com.xxx,-com.yyy"); Assert.assertTrue(origin.size() == 1); origin = buildOriginList(); - BlackListFileLoader.overrideBlackList(origin, "com.xxx,-com.yyy"); + BlackAndWhiteListFileLoader.overrideBlackList(origin, "com.xxx,-com.yyy"); Assert.assertTrue(origin.size() == 2); origin = buildOriginList(); - BlackListFileLoader.overrideBlackList(origin, "com.aaa,-com.yyy"); + BlackAndWhiteListFileLoader.overrideBlackList(origin, "com.aaa,-com.yyy"); Assert.assertTrue(origin.size() == 3); origin = buildOriginList(); - BlackListFileLoader.overrideBlackList(origin, "com.aaa"); + BlackAndWhiteListFileLoader.overrideBlackList(origin, "com.aaa"); Assert.assertTrue(origin.size() == 4); origin = buildOriginList(); - BlackListFileLoader.overrideBlackList(origin, "com.xxx;com.yyy;com.zzz"); + BlackAndWhiteListFileLoader.overrideBlackList(origin, "com.xxx;com.yyy;com.zzz"); Assert.assertTrue(origin.size() == 3); origin = buildOriginList(); - BlackListFileLoader.overrideBlackList(origin, "com.aaa,com.bbb,com.ccc"); + BlackAndWhiteListFileLoader.overrideBlackList(origin, "com.aaa,com.bbb,com.ccc"); Assert.assertTrue(origin.size() == 6); } diff --git a/codec/pom.xml b/codec/pom.xml index 2ca5db8c2..25814b811 100644 --- a/codec/pom.xml +++ b/codec/pom.xml @@ -20,6 +20,7 @@ codec-protostuff codec-sofa-hessian codec-msgpack + codec-sofa-fury diff --git a/core/api/src/main/java/com/alipay/sofa/rpc/codec/AbstractSerializer.java b/core/api/src/main/java/com/alipay/sofa/rpc/codec/AbstractSerializer.java index 0b9ebc0eb..efe20c953 100644 --- a/core/api/src/main/java/com/alipay/sofa/rpc/codec/AbstractSerializer.java +++ b/core/api/src/main/java/com/alipay/sofa/rpc/codec/AbstractSerializer.java @@ -33,6 +33,8 @@ public abstract class AbstractSerializer implements Serializer { protected static Map genericServiceMap = new ConcurrentHashMap<>(); + protected Map customSerializers = new ConcurrentHashMap<>(); + protected SofaRpcException buildSerializeError(String message) { return new SofaRpcException(getErrorCode(true), LogCodes.getLog(LogCodes.ERROR_SERIALIZER, message)); } @@ -73,4 +75,19 @@ public static void registerGenericService(String serviceName, String className) public static void clear() { genericServiceMap.clear(); } + + protected CustomSerializer getObjCustomSerializer(Object obj) { + if (obj == null) { + return null; + } + return getSerializer(obj.getClass()); + } + + protected CustomSerializer getSerializer(Class clazz) { + return customSerializers.get(clazz); + } + + protected void addSerializer(Class clazz, CustomSerializer serializerManager) { + customSerializers.put(clazz, serializerManager); + } } diff --git a/core/api/src/main/java/com/alipay/sofa/rpc/codec/CustomSerializer.java b/core/api/src/main/java/com/alipay/sofa/rpc/codec/CustomSerializer.java new file mode 100644 index 000000000..42a4f6398 --- /dev/null +++ b/core/api/src/main/java/com/alipay/sofa/rpc/codec/CustomSerializer.java @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.alipay.sofa.rpc.codec; + +import com.alipay.sofa.rpc.core.exception.SofaRpcException; +import com.alipay.sofa.rpc.transport.AbstractByteBuf; + +import java.util.Map; + +/** + * @author leizhiyuan + */ +public interface CustomSerializer { + + /** + * 序列化 + * + * @param object 对象 + * @param context 上下文 + * @return 序列化后的对象 + * @throws SofaRpcException 序列化异常 + */ + public AbstractByteBuf encodeObject(T object, Map context) throws SofaRpcException; + + /** + * 反序列化,只有类型,返回对象 + * + * @param data 原始字节数组 + * @param context 上下文 + * @return 反序列化后的对象 + * @throws SofaRpcException 序列化异常 + */ + public T decodeObject(AbstractByteBuf data, Map context) throws SofaRpcException; + + /** + * 反序列化,已有数据,填充字段 + * + * @param data 原始字节数组 + * @param template 模板对象 + * @param context 上下文 + * @throws SofaRpcException 序列化异常 + */ + public void decodeObjectByTemplate(AbstractByteBuf data, Map context, T template) + throws SofaRpcException; + +} \ No newline at end of file diff --git a/core/api/src/main/java/com/alipay/sofa/rpc/ext/ExtensionLoader.java b/core/api/src/main/java/com/alipay/sofa/rpc/ext/ExtensionLoader.java index 8deb9200f..0e36f2365 100644 --- a/core/api/src/main/java/com/alipay/sofa/rpc/ext/ExtensionLoader.java +++ b/core/api/src/main/java/com/alipay/sofa/rpc/ext/ExtensionLoader.java @@ -34,6 +34,7 @@ import java.io.InputStreamReader; import java.lang.reflect.Modifier; import java.net.URL; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; @@ -184,7 +185,7 @@ protected void loadFromClassLoader(ClassLoader classLoader, String fullFileName) } BufferedReader reader = null; try { - reader = new BufferedReader(new InputStreamReader(url.openStream(), "UTF-8")); + reader = new BufferedReader(new InputStreamReader(url.openStream(), StandardCharsets.UTF_8)); String line; while ((line = reader.readLine()) != null) { readLine(url, line); diff --git a/core/common/src/main/java/com/alipay/sofa/rpc/common/SofaOptions.java b/core/common/src/main/java/com/alipay/sofa/rpc/common/SofaOptions.java index ae46681d5..4a9e1753c 100644 --- a/core/common/src/main/java/com/alipay/sofa/rpc/common/SofaOptions.java +++ b/core/common/src/main/java/com/alipay/sofa/rpc/common/SofaOptions.java @@ -160,6 +160,10 @@ public class SofaOptions { * 序列化覆盖 */ public static final String CONFIG_SERIALIZE_BLACKLIST_OVERRIDE = "rpc_serialize_blacklist_override"; + /** + * 序列化覆盖 + */ + public static final String CONFIG_SERIALIZE_WHITELIST_OVERRIDE = "rpc_serialize_whitelist_override"; //========= GRPC 相关配置 ========== /** diff --git a/core/common/src/main/java/com/alipay/sofa/rpc/common/config/RpcConfigKeys.java b/core/common/src/main/java/com/alipay/sofa/rpc/common/config/RpcConfigKeys.java index 009c35dbd..99910012b 100644 --- a/core/common/src/main/java/com/alipay/sofa/rpc/common/config/RpcConfigKeys.java +++ b/core/common/src/main/java/com/alipay/sofa/rpc/common/config/RpcConfigKeys.java @@ -18,6 +18,9 @@ import com.alipay.sofa.common.config.ConfigKey; +import static com.alipay.sofa.rpc.common.SofaOptions.CONFIG_SERIALIZE_BLACKLIST_OVERRIDE; +import static com.alipay.sofa.rpc.common.SofaOptions.CONFIG_SERIALIZE_WHITELIST_OVERRIDE; + /** * @author zhaowang * @version : RpcConfigKeys.java, v 0.1 2020年12月14日 9:56 下午 zhaowang Exp $ @@ -102,6 +105,31 @@ public class RpcConfigKeys { false, "judge the generic object exception fields.", new String[] { "sofa_rpc_generic_exception_fields" }); + + public static final ConfigKey SERIALIZE_BLACKLIST_OVERRIDE = ConfigKey + .build( + "sofa.rpc.serialize.blacklist.override", + "", + false, + "Additional serialization blacklist.", + new String[] { CONFIG_SERIALIZE_BLACKLIST_OVERRIDE }); + + public static final ConfigKey SERIALIZE_WHITELIST_OVERRIDE = ConfigKey + .build( + "sofa.rpc.serialize.whitelist.override", + "", + false, + "Additional serialization whitelist.", + new String[] { CONFIG_SERIALIZE_WHITELIST_OVERRIDE }); + + public static final ConfigKey SERIALIZE_CHECKER_MODE = ConfigKey + .build( + "sofa.rpc.codec.serialize.checkMode", + "STRICT", + true, + " The default filtering mode is STRICT.You can also set WARN or DISABLE", + new String[] { "sofa_rpc_codec_serialize_checkMode" }); + /** * biz thread pool type */ diff --git a/core/common/src/main/resources/com/alipay/sofa/rpc/common/rpc-config-default.json b/core/common/src/main/resources/com/alipay/sofa/rpc/common/rpc-config-default.json index 9becfcf3f..6ad8f836f 100644 --- a/core/common/src/main/resources/com/alipay/sofa/rpc/common/rpc-config-default.json +++ b/core/common/src/main/resources/com/alipay/sofa/rpc/common/rpc-config-default.json @@ -17,7 +17,7 @@ PS:大家也看到了,本JSON文档是支持注释的,而标准JSON是不支 "META-INF/services/" ], // 需要被加载的模块列表,多个用逗号隔开 - "module.load.list" : "*", + "module.load.list": "*", /*-------------RPC框架内部使用配置项-------------*/