This is an automated email from the ASF dual-hosted git repository.

wangxin pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-dubbo.git


The following commit(s) were added to refs/heads/master by this push:
     new 667f227  [Dubbo-3886] Integrate with SOFARegistry. (#3886)
667f227 is described below

commit 667f2271b3c93f0c4f321368e32eb37a62d1fe0c
Author: Geng Zhang <zhanggeng...@antfin.com>
AuthorDate: Thu May 2 10:07:05 2019 +0800

    [Dubbo-3886] Integrate with SOFARegistry. (#3886)
    
    * Integrate with SOFARegistry.
---
 dubbo-all/pom.xml                                  |   8 +
 dubbo-bom/pom.xml                                  |   5 +
 dubbo-dependencies-bom/pom.xml                     |  15 +-
 dubbo-distribution/pom.xml                         |   5 +
 dubbo-registry/dubbo-registry-sofa/pom.xml         | 141 ++++++++++
 .../apache/dubbo/registry/sofa/SofaRegistry.java   | 292 +++++++++++++++++++++
 .../dubbo/registry/sofa/SofaRegistryConstants.java |  43 +++
 .../dubbo/registry/sofa/SofaRegistryFactory.java   |  41 +++
 .../org.apache.dubbo.registry.RegistryFactory      |   1 +
 .../apache/dubbo/registry/sofa/HelloService.java   |  24 ++
 .../dubbo/registry/sofa/HelloServiceImpl.java      |  44 ++++
 .../dubbo/registry/sofa/SofaRegistryTest.java      | 148 +++++++++++
 .../src/test/resources/log4j.properties            |   7 +
 dubbo-registry/pom.xml                             |   1 +
 .../dubbo/rpc/protocol/thrift/ThriftCodec.java     |   3 +-
 15 files changed, 775 insertions(+), 3 deletions(-)

diff --git a/dubbo-all/pom.xml b/dubbo-all/pom.xml
index e0e2366..08621e4 100644
--- a/dubbo-all/pom.xml
+++ b/dubbo-all/pom.xml
@@ -256,6 +256,13 @@
         </dependency>
         <dependency>
             <groupId>org.apache.dubbo</groupId>
+            <artifactId>dubbo-registry-sofa</artifactId>
+            <version>${project.version}</version>
+            <scope>compile</scope>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.dubbo</groupId>
             <artifactId>dubbo-monitor-api</artifactId>
             <version>${project.version}</version>
             <scope>compile</scope>
@@ -530,6 +537,7 @@
                                     
<include>org.apache.dubbo:dubbo-registry-redis</include>
                                     
<include>org.apache.dubbo:dubbo-registry-consul</include>
                                     
<include>org.apache.dubbo:dubbo-registry-etcd3</include>
+                                    
<include>org.apache.dubbo:dubbo-registry-sofa</include>
                                     
<include>org.apache.dubbo:dubbo-monitor-api</include>
                                     
<include>org.apache.dubbo:dubbo-monitor-default</include>
                                     
<include>org.apache.dubbo:dubbo-config-api</include>
diff --git a/dubbo-bom/pom.xml b/dubbo-bom/pom.xml
index e894f8b..148b49a 100644
--- a/dubbo-bom/pom.xml
+++ b/dubbo-bom/pom.xml
@@ -254,6 +254,11 @@
             </dependency>
             <dependency>
                 <groupId>org.apache.dubbo</groupId>
+                <artifactId>dubbo-registry-sofa</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.dubbo</groupId>
                 <artifactId>dubbo-monitor-api</artifactId>
                 <version>${project.version}</version>
             </dependency>
diff --git a/dubbo-dependencies-bom/pom.xml b/dubbo-dependencies-bom/pom.xml
index 2d8be67..6d68457 100644
--- a/dubbo-dependencies-bom/pom.xml
+++ b/dubbo-dependencies-bom/pom.xml
@@ -145,6 +145,7 @@
         <spring_test_version>4.3.16.RELEASE</spring_test_version>
 
         <metrics_version>2.0.1</metrics_version>
+        <sofa_registry_version>5.2.0</sofa_registry_version>
         <gson_version>2.8.5</gson_version>
         <jsonrpc_version>1.2.0</jsonrpc_version>
         <portlet_version>2.0</portlet_version>
@@ -458,7 +459,6 @@
                 <version>${commons_lang3_version}</version>
             </dependency>
 
-
             <!-- for dubbo-rpc-webservice -->
             <dependency>
                 <groupId>javax.xml.bind</groupId>
@@ -519,6 +519,19 @@
                 <artifactId>metrics-rest</artifactId>
                 <version>${metrics_version}</version>
             </dependency>
+            
+            <!-- for dubbo-registry-sofa -->
+            <dependency>
+                <groupId>com.alipay.sofa</groupId>
+                <artifactId>registry-client-all</artifactId>
+                <version>${sofa_registry_version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.alipay.sofa</groupId>
+                <artifactId>registry-test</artifactId>
+                <version>${sofa_registry_version}</version>
+                <scope>test</scope>
+            </dependency>
 
             <!-- Test lib -->
             <dependency>
diff --git a/dubbo-distribution/pom.xml b/dubbo-distribution/pom.xml
index 50fd855..e92363d 100644
--- a/dubbo-distribution/pom.xml
+++ b/dubbo-distribution/pom.xml
@@ -182,6 +182,11 @@
         </dependency>
         <dependency>
             <groupId>org.apache.dubbo</groupId>
+            <artifactId>dubbo-registry-sofa</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.dubbo</groupId>
             <artifactId>dubbo-monitor-api</artifactId>
             <version>${project.version}</version>
         </dependency>
diff --git a/dubbo-registry/dubbo-registry-sofa/pom.xml 
b/dubbo-registry/dubbo-registry-sofa/pom.xml
new file mode 100644
index 0000000..7a2415f
--- /dev/null
+++ b/dubbo-registry/dubbo-registry-sofa/pom.xml
@@ -0,0 +1,141 @@
+<!--
+  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.
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+    <parent>
+        <groupId>org.apache.dubbo</groupId>
+        <artifactId>dubbo-registry</artifactId>
+        <version>${revision}</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>dubbo-registry-sofa</artifactId>
+    <name>${project.artifactId}</name>
+    <description>The SOFARegistry module of Dubbo project</description>
+
+    <properties>
+        <javax.ws.rs.version>2.1</javax.ws.rs.version>
+        <argline>-Dnetwork_interface_denylist=docker0</argline>
+    </properties>
+    
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.dubbo</groupId>
+            <artifactId>dubbo-registry-api</artifactId>
+            <version>${project.version}</version>
+            <optional>true</optional>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.dubbo</groupId>
+            <artifactId>dubbo-common</artifactId>
+            <version>${project.version}</version>
+            <optional>true</optional>
+        </dependency>
+
+        <dependency>
+            <groupId>com.alipay.sofa</groupId>
+            <artifactId>registry-client-all</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>com.alipay.sofa</groupId>
+                    <artifactId>sofa-common-tools</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+        <!-- Test Libraries -->
+        <dependency>
+            <groupId>org.apache.dubbo</groupId>
+            <artifactId>dubbo-config-api</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.dubbo</groupId>
+            <artifactId>dubbo-rpc-dubbo</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.dubbo</groupId>
+            <artifactId>dubbo-remoting-netty4</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.dubbo</groupId>
+            <artifactId>dubbo-serialization-hessian2</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>ch.qos.logback</groupId>
+            <artifactId>logback-classic</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <!-- test modules -->
+        <dependency>
+            <groupId>com.alipay.sofa</groupId>
+            <artifactId>registry-test</artifactId>
+            <scope>test</scope>
+            <exclusions>
+                <exclusion>
+                    <artifactId>log4j-over-slf4j</artifactId>
+                    <groupId>org.slf4j</groupId>
+                </exclusion>
+                <exclusion>
+                    <artifactId>log4j-jcl</artifactId>
+                    <groupId>org.apache.logging.log4j</groupId>
+                </exclusion>
+                <exclusion>
+                    <artifactId>log4j-core</artifactId>
+                    <groupId>org.apache.logging.log4j</groupId>
+                </exclusion>
+                <exclusion>
+                    <artifactId>log4j-api</artifactId>
+                    <groupId>org.apache.logging.log4j</groupId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+        <dependency>
+            <groupId>org.jboss.resteasy</groupId>
+            <artifactId>resteasy-jaxrs</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.jboss.resteasy</groupId>
+            <artifactId>resteasy-netty4</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>javax.ws.rs</groupId>
+            <artifactId>javax.ws.rs-api</artifactId>
+            <version>${javax.ws.rs.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>javax.xml.bind</groupId>
+            <artifactId>jaxb-api</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+    </dependencies>
+</project>
\ No newline at end of file
diff --git 
a/dubbo-registry/dubbo-registry-sofa/src/main/java/org/apache/dubbo/registry/sofa/SofaRegistry.java
 
b/dubbo-registry/dubbo-registry-sofa/src/main/java/org/apache/dubbo/registry/sofa/SofaRegistry.java
new file mode 100644
index 0000000..a514d7a
--- /dev/null
+++ 
b/dubbo-registry/dubbo-registry-sofa/src/main/java/org/apache/dubbo/registry/sofa/SofaRegistry.java
@@ -0,0 +1,292 @@
+/*
+ * 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 org.apache.dubbo.registry.sofa;
+
+import com.alipay.sofa.registry.client.api.RegistryClient;
+import com.alipay.sofa.registry.client.api.RegistryClientConfig;
+import com.alipay.sofa.registry.client.api.Subscriber;
+import com.alipay.sofa.registry.client.api.model.RegistryType;
+import com.alipay.sofa.registry.client.api.model.UserData;
+import com.alipay.sofa.registry.client.api.registration.PublisherRegistration;
+import com.alipay.sofa.registry.client.api.registration.SubscriberRegistration;
+import com.alipay.sofa.registry.client.provider.DefaultRegistryClient;
+import 
com.alipay.sofa.registry.client.provider.DefaultRegistryClientConfigBuilder;
+import com.alipay.sofa.registry.core.model.ScopeEnum;
+import org.apache.dubbo.common.Constants;
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.logger.Logger;
+import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.common.utils.ConfigUtils;
+import org.apache.dubbo.common.utils.StringUtils;
+import org.apache.dubbo.registry.NotifyListener;
+import org.apache.dubbo.registry.support.FailbackRegistry;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import static 
org.apache.dubbo.registry.sofa.SofaRegistryConstants.ADDRESS_WAIT_TIME_KEY;
+import static 
org.apache.dubbo.registry.sofa.SofaRegistryConstants.DEFAULT_GROUP;
+import static 
org.apache.dubbo.registry.sofa.SofaRegistryConstants.LOCAL_DATA_CENTER;
+import static 
org.apache.dubbo.registry.sofa.SofaRegistryConstants.LOCAL_REGION;
+
+/**
+ * The Sofa registry.
+ *
+ * @since 2.7.2
+ */
+public class SofaRegistry extends FailbackRegistry {
+
+    private static final Logger LOGGER = 
LoggerFactory.getLogger(SofaRegistry.class);
+
+    /**
+     * Cache subscriber by dataId
+     */
+    private final Map<String, Subscriber> subscribers = new 
ConcurrentHashMap<>();
+
+    /**
+     * Direct registry client
+     */
+    private RegistryClient registryClient;
+    /**
+     * wait address from registry
+     */
+    private int waitAddressTimeout;
+
+    /**
+     * Instantiates a new Sofa registry.
+     *
+     * @param url the url
+     */
+    public SofaRegistry(URL url) {
+        super(url);
+        if (LOGGER.isInfoEnabled()) {
+            LOGGER.info("Build sofa registry by url:" + url);
+        }
+        this.registryClient = buildClient(url);
+        this.waitAddressTimeout = 
Integer.parseInt(ConfigUtils.getProperty(ADDRESS_WAIT_TIME_KEY, "5000"));
+    }
+
+    /**
+     * Build client registry client.
+     *
+     * @param url the url
+     * @return the registry client
+     */
+    protected RegistryClient buildClient(URL url) {
+        RegistryClientConfig config = 
DefaultRegistryClientConfigBuilder.start()
+                .setDataCenter(LOCAL_DATA_CENTER)
+                .setZone(LOCAL_REGION)
+                .setRegistryEndpoint(url.getHost())
+                .setRegistryEndpointPort(url.getPort()).build();
+
+        DefaultRegistryClient registryClient = new 
DefaultRegistryClient(config);
+        registryClient.init();
+        return registryClient;
+    }
+
+    @Override
+    public boolean isAvailable() {
+        return true;
+    }
+
+    @Override
+    public void doRegister(URL url) {
+        if (!url.getParameter(Constants.REGISTER_KEY, true)
+                || Constants.CONSUMER_PROTOCOL.equals(url.getProtocol())) {
+            return;
+        }
+
+        String serviceName = buildServiceName(url);
+        String serviceData = url.toFullString();
+
+        PublisherRegistration registration = new 
PublisherRegistration(serviceName);
+        addAttributesForPub(registration);
+
+        registryClient.register(registration, serviceData);
+    }
+
+    /**
+     * Add attributes for pub.
+     *
+     * @param publisherRegistration the publisher registration
+     */
+    protected void addAttributesForPub(PublisherRegistration 
publisherRegistration) {
+        publisherRegistration.setGroup(DEFAULT_GROUP);
+    }
+
+    @Override
+    public void doUnregister(URL url) {
+        if (!url.getParameter(Constants.REGISTER_KEY, true)
+                || Constants.CONSUMER_PROTOCOL.equals(url.getProtocol())) {
+            return;
+        }
+        String serviceName = buildServiceName(url);
+        registryClient.unregister(serviceName, DEFAULT_GROUP, 
RegistryType.PUBLISHER);
+    }
+
+    @Override
+    public void doSubscribe(URL url, final NotifyListener listener) {
+        if (!url.getParameter(Constants.SUBSCRIBE_KEY, true)
+                || Constants.PROVIDER_PROTOCOL.equals(url.getProtocol())) {
+            return;
+        }
+
+        String serviceName = buildServiceName(url);
+        // com.alipay.test.TestService:1.0:group@dubbo
+        Subscriber listSubscriber = subscribers.get(serviceName);
+
+        if (listSubscriber != null) {
+            LOGGER.warn("Service name [" + serviceName + "] have bean 
registered in SOFARegistry.");
+
+            CountDownLatch countDownLatch = new CountDownLatch(1);
+            handleRegistryData(listSubscriber.peekData(), listener, 
countDownLatch);
+            waitAddress(serviceName, countDownLatch);
+            return;
+        }
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        SubscriberRegistration subscriberRegistration = new 
SubscriberRegistration(serviceName,
+                (dataId, data) -> {
+                    //record change
+                    printAddressData(dataId, data);
+                    handleRegistryData(data, listener, latch);
+                });
+
+        addAttributesForSub(subscriberRegistration);
+        listSubscriber = registryClient.register(subscriberRegistration);
+
+        subscribers.put(serviceName, listSubscriber);
+
+        waitAddress(serviceName, latch);
+    }
+
+    private void waitAddress(String serviceName, CountDownLatch 
countDownLatch) {
+        try {
+            if (!countDownLatch.await(waitAddressTimeout, 
TimeUnit.MILLISECONDS)) {
+                LOGGER.warn("Subscribe data failed by dataId " + serviceName);
+            }
+        } catch (Exception e) {
+            LOGGER.error("Error when wait Address!", e);
+        }
+    }
+
+    @Override
+    public void doUnsubscribe(URL url, NotifyListener listener) {
+        if (!url.getParameter(Constants.SUBSCRIBE_KEY, true)
+                || Constants.PROVIDER_PROTOCOL.equals(url.getProtocol())) {
+            return;
+        }
+        String serviceName = buildServiceName(url);
+
+        registryClient.unregister(serviceName, DEFAULT_GROUP, 
RegistryType.SUBSCRIBER);
+    }
+
+    private void handleRegistryData(UserData data, NotifyListener 
notifyListener,
+                                    CountDownLatch latch) {
+        try {
+            List<URL> urls = new ArrayList<>();
+            if (null != data) {
+
+                List<String> datas = flatUserData(data);
+                for (String serviceUrl : datas) {
+                    URL url = URL.valueOf(serviceUrl);
+                    String serverApplication = 
url.getParameter(Constants.APPLICATION_KEY);
+                    if (StringUtils.isNotEmpty(serverApplication)) {
+                        url = url.addParameter("dstApp", serverApplication);
+                    }
+                    urls.add(url);
+                }
+            }
+            notifyListener.notify(urls);
+        } finally {
+            latch.countDown();
+        }
+    }
+
+    private String buildServiceName(URL url) {
+        // return url.getServiceKey();
+        StringBuilder buf = new StringBuilder();
+        buf.append(url.getServiceInterface());
+        String version = url.getParameter(Constants.VERSION_KEY);
+        if (StringUtils.isNotEmpty(version)) {
+            buf.append(":").append(version);
+        }
+        String group = url.getParameter(Constants.GROUP_KEY);
+        if (StringUtils.isNotEmpty(group)) {
+            buf.append(":").append(group);
+        }
+        buf.append("@").append(Constants.DUBBO);
+        return buf.toString();
+    }
+
+    /**
+     * Print address data.
+     *
+     * @param dataId   the data id
+     * @param userData the user data
+     */
+    protected void printAddressData(String dataId, UserData userData) {
+
+        List<String> datas;
+        if (userData == null) {
+            datas = new ArrayList<>(0);
+        } else {
+            datas = flatUserData(userData);
+        }
+
+        StringBuilder sb = new StringBuilder();
+        for (String provider : datas) {
+            sb.append("  >>> ").append(provider).append("\n");
+        }
+        if (LOGGER.isInfoEnabled()) {
+            LOGGER.info("Receive updated RPC service addresses: service[" + 
dataId
+                    + "]\n  .Available target addresses size [" + datas.size() 
+ "]\n"
+                    + sb.toString());
+        }
+    }
+
+    /**
+     * Add attributes for sub.
+     *
+     * @param subscriberRegistration the subscriber registration
+     */
+    protected void addAttributesForSub(SubscriberRegistration 
subscriberRegistration) {
+        subscriberRegistration.setGroup(DEFAULT_GROUP);
+        subscriberRegistration.setScopeEnum(ScopeEnum.global);
+    }
+
+    /**
+     * Flat user data list.
+     *
+     * @param userData the user data
+     * @return the list
+     */
+    protected List<String> flatUserData(UserData userData) {
+        List<String> result = new ArrayList<>();
+        Map<String, List<String>> zoneData = userData.getZoneData();
+
+        for (Map.Entry<String, List<String>> entry : zoneData.entrySet()) {
+            result.addAll(entry.getValue());
+        }
+
+        return result;
+    }
+}
diff --git 
a/dubbo-registry/dubbo-registry-sofa/src/main/java/org/apache/dubbo/registry/sofa/SofaRegistryConstants.java
 
b/dubbo-registry/dubbo-registry-sofa/src/main/java/org/apache/dubbo/registry/sofa/SofaRegistryConstants.java
new file mode 100644
index 0000000..f832e80
--- /dev/null
+++ 
b/dubbo-registry/dubbo-registry-sofa/src/main/java/org/apache/dubbo/registry/sofa/SofaRegistryConstants.java
@@ -0,0 +1,43 @@
+/*
+ * 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 org.apache.dubbo.registry.sofa;
+
+/**
+ * @since 2.7.2
+ */
+public class SofaRegistryConstants {
+
+    /**
+     * Default data center
+     */
+    public static final String LOCAL_DATA_CENTER = "DefaultDataCenter";
+
+    /**
+     * Default region
+     */
+    public static final String LOCAL_REGION = "DEFAULT_ZONE";
+
+    /**
+     * Default group
+     */
+    public static final String DEFAULT_GROUP = "SOFA";
+
+    /**
+     * parameter for address.wait.time of rpc reference
+     */
+    public static final String ADDRESS_WAIT_TIME_KEY = 
"rpc.reference.address.wait.time";
+}
diff --git 
a/dubbo-registry/dubbo-registry-sofa/src/main/java/org/apache/dubbo/registry/sofa/SofaRegistryFactory.java
 
b/dubbo-registry/dubbo-registry-sofa/src/main/java/org/apache/dubbo/registry/sofa/SofaRegistryFactory.java
new file mode 100644
index 0000000..18a7809
--- /dev/null
+++ 
b/dubbo-registry/dubbo-registry-sofa/src/main/java/org/apache/dubbo/registry/sofa/SofaRegistryFactory.java
@@ -0,0 +1,41 @@
+/*
+ * 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 org.apache.dubbo.registry.sofa;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.registry.Registry;
+import org.apache.dubbo.registry.support.AbstractRegistryFactory;
+
+/**
+ * @since 2.7.2
+ */
+public class SofaRegistryFactory extends AbstractRegistryFactory {
+
+    @Override
+    protected Registry createRegistry(URL url) {
+        initEnvironment(url);
+        return new SofaRegistry(url);
+    }
+
+    /**
+     * For extension, such as load zone/accessKey/secretKey/...
+     * 
+     * @param url URL
+     */
+    protected void initEnvironment(URL url) {
+    }
+}
diff --git 
a/dubbo-registry/dubbo-registry-sofa/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.registry.RegistryFactory
 
b/dubbo-registry/dubbo-registry-sofa/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.registry.RegistryFactory
new file mode 100644
index 0000000..dff4cbb
--- /dev/null
+++ 
b/dubbo-registry/dubbo-registry-sofa/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.registry.RegistryFactory
@@ -0,0 +1 @@
+sofa=org.apache.dubbo.registry.sofa.SofaRegistryFactory
\ No newline at end of file
diff --git 
a/dubbo-registry/dubbo-registry-sofa/src/test/java/org/apache/dubbo/registry/sofa/HelloService.java
 
b/dubbo-registry/dubbo-registry-sofa/src/test/java/org/apache/dubbo/registry/sofa/HelloService.java
new file mode 100644
index 0000000..cc66a5e
--- /dev/null
+++ 
b/dubbo-registry/dubbo-registry-sofa/src/test/java/org/apache/dubbo/registry/sofa/HelloService.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 org.apache.dubbo.registry.sofa;
+
+/**
+ */
+public interface HelloService {
+
+    String sayHello(String name);
+}
diff --git 
a/dubbo-registry/dubbo-registry-sofa/src/test/java/org/apache/dubbo/registry/sofa/HelloServiceImpl.java
 
b/dubbo-registry/dubbo-registry-sofa/src/test/java/org/apache/dubbo/registry/sofa/HelloServiceImpl.java
new file mode 100644
index 0000000..a9fb0ca
--- /dev/null
+++ 
b/dubbo-registry/dubbo-registry-sofa/src/test/java/org/apache/dubbo/registry/sofa/HelloServiceImpl.java
@@ -0,0 +1,44 @@
+/*
+ * 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 org.apache.dubbo.registry.sofa;
+
+import com.alipay.sofa.registry.server.test.TestRegistryMain;
+
+/**
+ */
+public class HelloServiceImpl implements HelloService {
+
+    private final String result;
+
+    public HelloServiceImpl(String result) {
+        this.result = result;
+    }
+
+    @Override
+    public String sayHello(String name) {
+        return result != null ? result : "hello, " + name + "!";
+    }
+
+    public static void main(String[] args) {
+        TestRegistryMain registryMain = new TestRegistryMain();
+        try {
+            registryMain.startRegistry();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+}
diff --git 
a/dubbo-registry/dubbo-registry-sofa/src/test/java/org/apache/dubbo/registry/sofa/SofaRegistryTest.java
 
b/dubbo-registry/dubbo-registry-sofa/src/test/java/org/apache/dubbo/registry/sofa/SofaRegistryTest.java
new file mode 100644
index 0000000..4d67b74
--- /dev/null
+++ 
b/dubbo-registry/dubbo-registry-sofa/src/test/java/org/apache/dubbo/registry/sofa/SofaRegistryTest.java
@@ -0,0 +1,148 @@
+/*
+ * 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 org.apache.dubbo.registry.sofa;
+
+import com.alipay.sofa.registry.server.test.TestRegistryMain;
+import org.apache.dubbo.common.logger.Logger;
+import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.config.ApplicationConfig;
+import org.apache.dubbo.config.ProtocolConfig;
+import org.apache.dubbo.config.ReferenceConfig;
+import org.apache.dubbo.config.RegistryConfig;
+import org.apache.dubbo.config.ServiceConfig;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+/**
+ */
+public class SofaRegistryTest {
+
+    public static final Logger LOGGER = 
LoggerFactory.getLogger(SofaRegistryTest.class);
+
+    private static TestRegistryMain registryMain;
+
+    private static ApplicationConfig applicationConfig = new 
ApplicationConfig("test-sofa-registry");
+
+    private static ProtocolConfig protocolConfig1;
+
+    private static ProtocolConfig protocolConfig2;
+
+    private static RegistryConfig registryConfig;
+
+    @BeforeAll
+    public static void beforeClass() {
+
+        protocolConfig1 = new ProtocolConfig();
+        protocolConfig1.setName("dubbo");
+        protocolConfig1.setPort(20890);
+
+        protocolConfig2 = new ProtocolConfig();
+        protocolConfig2.setName("dubbo");
+        protocolConfig2.setPort(20891);
+
+        registryConfig = new RegistryConfig();
+        registryConfig.setAddress("sofa://127.0.0.1:9603");
+        registryConfig.setProtocol("sofa");
+
+        registryMain = new TestRegistryMain();
+        try {
+            registryMain.startRegistry();
+        } catch (Exception e) {
+            LOGGER.error("start test sofa registry error!", e);
+        }
+    }
+
+    @Test
+    public void testPubAndSub() throws InterruptedException {
+
+        ServiceConfig<HelloService> serviceConfig1 = new ServiceConfig<>();
+        serviceConfig1.setInterface(HelloService.class);
+        serviceConfig1.setRef(new HelloServiceImpl("rrr11"));
+        serviceConfig1.setProtocol(protocolConfig1);
+        serviceConfig1.setRegistry(registryConfig);
+        serviceConfig1.setGroup("g1");
+        serviceConfig1.setApplication(applicationConfig);
+        serviceConfig1.export();
+
+        ServiceConfig<HelloService> serviceConfig2 = new ServiceConfig<>();
+        serviceConfig2.setInterface(HelloService.class);
+        serviceConfig2.setRef(new HelloServiceImpl("rrr22"));
+        serviceConfig2.setProtocol(protocolConfig1);
+        serviceConfig2.setRegistry(registryConfig);
+        serviceConfig2.setGroup("g2");
+        serviceConfig2.setApplication(applicationConfig);
+        serviceConfig2.setRegister(false);
+        serviceConfig2.export();
+
+        Thread.sleep(1000);
+
+        // do refer
+        ReferenceConfig<HelloService> referenceConfig1 = new 
ReferenceConfig<>();
+        referenceConfig1.setInterface(HelloService.class);
+        referenceConfig1.setProtocol("dubbo");
+        referenceConfig1.setInjvm(false);
+        referenceConfig1.setGroup("g1");
+        referenceConfig1.setRegistry(registryConfig);
+        referenceConfig1.setApplication(applicationConfig);
+        HelloService service = referenceConfig1.get();
+        Assertions.assertEquals("rrr11", service.sayHello("xxx"));
+
+        // do refer duplicated
+        ReferenceConfig<HelloService> referenceConfig2 = new 
ReferenceConfig<>();
+        referenceConfig2.setInterface(HelloService.class);
+        referenceConfig2.setProtocol("dubbo");
+        referenceConfig2.setInjvm(false);
+        referenceConfig2.setGroup("g1");
+        referenceConfig2.setRegistry(registryConfig);
+        referenceConfig2.setApplication(applicationConfig);
+        HelloService service2 = referenceConfig2.get();
+        Assertions.assertEquals("rrr11", service2.sayHello("xxx"));
+
+        // export one service
+        ServiceConfig<HelloService> serviceConfig3 = new ServiceConfig<>();
+        serviceConfig3.setInterface(HelloService.class);
+        serviceConfig3.setRef(new HelloServiceImpl("rrr12"));
+        serviceConfig3.setProtocol(protocolConfig2);
+        serviceConfig3.setRegistry(registryConfig);
+        serviceConfig3.setGroup("g1");
+        serviceConfig3.setApplication(applicationConfig);
+        serviceConfig3.export();
+        Assertions.assertTrue(service2.sayHello("xxx").startsWith("rrr1"));
+
+        // unrefer
+        referenceConfig1.destroy();
+        Assertions.assertTrue(service2.sayHello("xxx").startsWith("rrr1"));
+
+        // unexport one service
+        serviceConfig1.unexport();
+        Thread.sleep(2000);
+        Assertions.assertTrue(service2.sayHello("xxx").startsWith("rrr1"));
+    }
+
+    @AfterAll
+    public static void afterClass() {
+        try {
+            registryMain.stopRegistry();
+            protocolConfig1.destroy();
+        } catch (Exception e) {
+            LOGGER.error("Stop test sofa registry error!", e);
+        }
+    }
+
+}
\ No newline at end of file
diff --git 
a/dubbo-registry/dubbo-registry-sofa/src/test/resources/log4j.properties 
b/dubbo-registry/dubbo-registry-sofa/src/test/resources/log4j.properties
new file mode 100644
index 0000000..15a0900
--- /dev/null
+++ b/dubbo-registry/dubbo-registry-sofa/src/test/resources/log4j.properties
@@ -0,0 +1,7 @@
+###set log levels###
+log4j.rootLogger=info, stdout
+###output to the console###
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.Target=System.out
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=[%d{dd/MM/yy HH:mm:ss:SSS z}] 
%t %5p %c{2}: %m%n
\ No newline at end of file
diff --git a/dubbo-registry/pom.xml b/dubbo-registry/pom.xml
index c9c3441..962148b 100644
--- a/dubbo-registry/pom.xml
+++ b/dubbo-registry/pom.xml
@@ -37,5 +37,6 @@
         <module>dubbo-registry-consul</module>
         <module>dubbo-registry-etcd3</module>
         <module>dubbo-registry-nacos</module>
+        <module>dubbo-registry-sofa</module>
     </modules>
 </project>
diff --git 
a/dubbo-rpc/dubbo-rpc-thrift/src/main/java/org/apache/dubbo/rpc/protocol/thrift/ThriftCodec.java
 
b/dubbo-rpc/dubbo-rpc-thrift/src/main/java/org/apache/dubbo/rpc/protocol/thrift/ThriftCodec.java
index ceef6cc..564505a 100644
--- 
a/dubbo-rpc/dubbo-rpc-thrift/src/main/java/org/apache/dubbo/rpc/protocol/thrift/ThriftCodec.java
+++ 
b/dubbo-rpc/dubbo-rpc-thrift/src/main/java/org/apache/dubbo/rpc/protocol/thrift/ThriftCodec.java
@@ -19,6 +19,7 @@ package org.apache.dubbo.rpc.protocol.thrift;
 import org.apache.dubbo.common.Constants;
 import org.apache.dubbo.common.extension.ExtensionLoader;
 import org.apache.dubbo.common.utils.ClassUtils;
+import org.apache.dubbo.common.utils.StringUtils;
 import org.apache.dubbo.remoting.Channel;
 import org.apache.dubbo.remoting.Codec2;
 import org.apache.dubbo.remoting.buffer.ChannelBuffer;
@@ -29,8 +30,6 @@ import org.apache.dubbo.rpc.RpcException;
 import org.apache.dubbo.rpc.RpcInvocation;
 import org.apache.dubbo.rpc.RpcResult;
 import 
org.apache.dubbo.rpc.protocol.thrift.io.RandomAccessByteArrayOutputStream;
-
-import org.apache.commons.lang.StringUtils;
 import org.apache.thrift.TApplicationException;
 import org.apache.thrift.TBase;
 import org.apache.thrift.TException;

Reply via email to