All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.wl4g.infra.integration.feign.istio.config.FeignSpringBootIstioTargetFactory Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2017 ~ 2025 the original author or authors. James Wong >
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.wl4g.infra.integration.feign.istio.config;

import static com.wl4g.infra.common.lang.Assert2.hasText;
import static com.wl4g.infra.common.lang.Assert2.notNullOf;
import static com.wl4g.infra.integration.feign.istio.config.FeignSpringBootIstioProperties.FeignServiceProperties.DEFAULT_SVC_SCHEMA;
import static java.lang.String.valueOf;
import static org.apache.commons.lang3.StringUtils.contains;
import static org.apache.commons.lang3.StringUtils.isBlank;

import java.net.URI;

import javax.validation.constraints.NotNull;

import com.wl4g.infra.integration.feign.core.annotation.FeignConsumer;
import com.wl4g.infra.integration.feign.core.annotation.FeignSpringBootTargetFactory;
import com.wl4g.infra.integration.feign.core.config.FeignSpringBootProperties;

import feign.Target;

/**
 * {@link FeignSpringBootIstioTargetFactory}
 * 
 * @author James Wong <[email protected]>
 * @version 2022-03-10 v1.0.0
 * @since v1.0.0
 */
public class FeignSpringBootIstioTargetFactory implements FeignSpringBootTargetFactory {

    private FeignSpringBootIstioProperties istioConfig;

    public FeignSpringBootIstioTargetFactory(FeignSpringBootIstioProperties istioConfig) {
        this.istioConfig = notNullOf(istioConfig, "istioConfig");
    }

    @Override
    public  Target create(
            FeignSpringBootProperties config,
            Class type,
            String name,
            String namespace,
            String url,
            String path) {
        return new IstioFeignUrlTarget(istioConfig, config, type, name, namespace, url, path);
    }

    public static class IstioFeignUrlTarget extends FeignSpringBootUrlTarget {
        private FeignSpringBootIstioProperties istioConfig;
        private String actualStdKubernetesSvcDomain;

        public IstioFeignUrlTarget(@NotNull FeignSpringBootIstioProperties istioConfig, @NotNull FeignSpringBootProperties config,
                @NotNull Class type, String name, String namespace, String url, String path) {
            super(config, type, name, namespace, url, path);
            this.istioConfig = notNullOf(istioConfig, "istioConfig");
        }

        // see:https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/#namespaces-of-services
        @Override
        protected String buildByName() {
            // Because it will be intercepted and enhanced by sidecar, you can
            // use http fixedly.
            return DEFAULT_SVC_SCHEMA.concat(obtainStdKubernetesSvcDomainUri()).concat(cleanPath());
        }

        public String obtainStdKubernetesSvcDomainUri() {
            actualStdKubernetesSvcDomain = buildStdKubernetesSvcDomain();
            if (isBlank(actualStdKubernetesSvcDomain)) {
                synchronized (this) {
                    if (isBlank(actualStdKubernetesSvcDomain)) {
                        actualStdKubernetesSvcDomain = buildStdKubernetesSvcDomain();
                    }
                }
            }
            return actualStdKubernetesSvcDomain;
        }

        private String buildStdKubernetesSvcDomain() {
            String clusterDomain = istioConfig.getKubeConfig().getClusterDomain();
            String str = hasText(name(), "Feign service '%s' @%s name is required.", type(), FeignConsumer.class.getSimpleName());

            // make sure it can be parsed.
            URI uri = URI.create(str);
            if (!contains(str, "://")) {
                uri = URI.create(DEFAULT_SVC_SCHEMA.concat(str));
            }

            // Gets serviceId(host)
            String serviceId = str;
            if (!isBlank(uri.getHost())) {
                serviceId = uri.getHost();
            }

            // Gets port info
            String portInfo = "";
            if (uri.getPort() > 0) {
                portInfo = ":".concat(valueOf(uri.getPort()));
            }

            // // Resolve to namespace and serviceId.
            /// **
            // * 
            // * @FeignConsumer(name = "mynamespace(order-service)")
            // * @RequestMapping("/order")
            // * public interface OrderService {
            // * }
            // * 
// */ // int start = str.indexOf("("); // int end = str.indexOf(")"); // int lstart = str.lastIndexOf("("); // int lend = str.indexOf(")"); // if (start != lstart || end != lend) { // throw new IllegalArgumentException(format( // "Syntax error for @%s(name = \"%s\") configuration, because there // are multiple '(' or ')' characters", // FeignConsumer.class.getSimpleName(), str, start, lstart)); // } // if (start >= 0 && start < end) { // namespace = str.substring(0, start); // serviceId = str.substring(start + 1, end); // } return new StringBuffer(64).append(serviceId) .append(".") .append(namespace()) .append(".svc.") .append(clusterDomain) .append(portInfo) .toString(); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy