class AbstractEndpointFactory implements EndpointFactory {

    /**
     * 维持share channel 的service列表
     **/
    protected final Map<String, Server> ipPort2ServerShareChannel = new HashMap<>();
    protected ConcurrentMap<Server, Set<String>> server2UrlsShareChannel = new ConcurrentHashMap<>();

    private EndpointManager heartbeatClientEndpointManager;

    public AbstractEndpointFactory() {
        heartbeatClientEndpointManager = new HeartbeatClientEndpointManager();
        heartbeatClientEndpointManager.init();
    }

    @Override
    public Server createServer(URL url, MessageHandler messageHandler) {<FILL_FUNCTION_BODY>}

    @Override
    public Client createClient(URL url) {
        LoggerUtil.info(this.getClass().getSimpleName() + " create client: url={}", url);
        return createClient(url, heartbeatClientEndpointManager);
    }

    @Override
    public void safeReleaseResource(Server server, URL url) {
        safeReleaseResource(server, url, ipPort2ServerShareChannel, server2UrlsShareChannel);
    }

    @Override
    public void safeReleaseResource(Client client, URL url) {
        destroy(client);
    }

    private <T extends Endpoint> void safeReleaseResource(T endpoint, URL url, Map<String, T> ipPort2Endpoint,
                                                          ConcurrentMap<T, Set<String>> endpoint2Urls) {
        boolean shareChannel = url.getBooleanParameter(URLParamType.shareChannel.getName(), URLParamType.shareChannel.getBooleanValue());

        if (!shareChannel) {
            destroy(endpoint);
            return;
        }

        synchronized (ipPort2Endpoint) {
            String ipPort = url.getServerPortStr();
            String protocolKey = MotanFrameworkUtil.getProtocolKey(url);

            if (endpoint != ipPort2Endpoint.get(ipPort)) {
                destroy(endpoint);
                return;
            }

            Set<String> urls = endpoint2Urls.get(endpoint);
            urls.remove(protocolKey);

            if (urls.isEmpty()) {
                destroy(endpoint);
                ipPort2Endpoint.remove(ipPort);
                endpoint2Urls.remove(endpoint);
            }
        }
    }

    private <T> void saveEndpoint2Urls(ConcurrentMap<T, Set<String>> map, T endpoint, String namespace) {
        Set<String> sets = map.get(endpoint);

        if (sets == null) {
            sets = new HashSet<>();
            sets.add(namespace);
            map.putIfAbsent(endpoint, sets); // 规避并发问题，因为有release逻辑存在，所以这里的sets预先add了namespace
            sets = map.get(endpoint);
        }

        sets.add(namespace);
    }

    private HeartbeatFactory getHeartbeatFactory(URL url) {
        String heartbeatFactoryName = url.getParameter(URLParamType.heartbeatFactory.getName(), URLParamType.heartbeatFactory.getValue());
        return getHeartbeatFactory(heartbeatFactoryName);
    }

    private HeartbeatFactory getHeartbeatFactory(String heartbeatFactoryName) {
        return ExtensionLoader.getExtensionLoader(HeartbeatFactory.class).getExtension(heartbeatFactoryName);
    }

    private Client createClient(URL url, EndpointManager endpointManager) {
        Client client = innerCreateClient(url);

        endpointManager.addEndpoint(client);

        return client;
    }

    private <T extends Endpoint> void destroy(T endpoint) {
        if (endpoint instanceof Client) {
            endpoint.close();
            heartbeatClientEndpointManager.removeEndpoint(endpoint);
        } else { // as Server
            endpoint.close();
            GlobalRuntime.removeServer(endpoint.getUrl().getServerPortStr());
        }
    }

    public Map<String, Server> getShallServerChannels() {
        return Collections.unmodifiableMap(ipPort2ServerShareChannel);
    }

    public EndpointManager getEndpointManager() {
        return heartbeatClientEndpointManager;
    }

    protected abstract Server innerCreateServer(URL url, MessageHandler messageHandler);

    protected abstract Client innerCreateClient(URL url);

}

        messageHandler = getHeartbeatFactory(url).wrapMessageHandler(messageHandler);

        synchronized (ipPort2ServerShareChannel) {
            String ipPort = url.getServerPortStr();
            String protocolKey = MotanFrameworkUtil.getProtocolKey(url);

            boolean shareChannel =
                    url.getBooleanParameter(URLParamType.shareChannel.getName(), URLParamType.shareChannel.getBooleanValue());

            if (!shareChannel) { // 独享一个端口
                LoggerUtil.info(this.getClass().getSimpleName() + " create no_share_channel server: url={}", url);

                if (url.getPort() == 0) { // create new url for random port，the origin url port will be replaced in exporter
                    url = url.createCopy();
                }
                // 如果端口已经被使用了，使用该server bind 会有异常
                return innerCreateServer(url, messageHandler);
            }

            LoggerUtil.info(this.getClass().getSimpleName() + " create share_channel server: url={}", url);

            Server server = ipPort2ServerShareChannel.get(ipPort);

            if (server != null) {
                // can't share service channel
                if (!MotanFrameworkUtil.checkIfCanShareServiceChannel(server.getUrl(), url)) {
                    throw new MotanFrameworkException(
                            "Service export Error: share channel but some config param is different, protocol or codec or serialize or maxContentLength or maxServerConnection or maxWorkerThread or heartbeatFactory, source="
                                    + server.getUrl() + " target=" + url, MotanErrorMsgConstant.FRAMEWORK_EXPORT_ERROR);
                }

                saveEndpoint2Urls(server2UrlsShareChannel, server, protocolKey);

                return server;
            }

            url = url.createCopy();
            url.setPath(""); // 共享server端口，由于有多个interfaces存在，所以把path设置为空

            server = innerCreateServer(url, messageHandler);

            ipPort2ServerShareChannel.put(ipPort, server);
            saveEndpoint2Urls(server2UrlsShareChannel, server, protocolKey);
            GlobalRuntime.addServer(ipPort, server);
            return server;
        }
    
<no_super_class>