From 56b56a05df559cd9dcd2271d2c142c30e1e13b87 Mon Sep 17 00:00:00 2001 From: Markus Heiden Date: Tue, 5 Mar 2024 19:24:35 +0100 Subject: [PATCH] Fix concurrency issue --- .../bingads/internal/ServiceFactory.java | 2 +- .../bingads/internal/ServiceFactoryImpl.java | 403 +++++++++--------- .../bingads/internal/ServiceInfo.java | 33 +- .../restful/RestfulServiceClient.java | 101 ++--- 4 files changed, 249 insertions(+), 290 deletions(-) diff --git a/src/main/java/com/microsoft/bingads/internal/ServiceFactory.java b/src/main/java/com/microsoft/bingads/internal/ServiceFactory.java index 8d4c455095..56e29516fc 100644 --- a/src/main/java/com/microsoft/bingads/internal/ServiceFactory.java +++ b/src/main/java/com/microsoft/bingads/internal/ServiceFactory.java @@ -5,7 +5,7 @@ public interface ServiceFactory { - Service createService(Class serviceInterface, ApiEnvironment env); + Service createService(Class serviceInterface, ApiEnvironment env); T createProxyFromService(Service service, ApiEnvironment env, Class serviceInterface); } diff --git a/src/main/java/com/microsoft/bingads/internal/ServiceFactoryImpl.java b/src/main/java/com/microsoft/bingads/internal/ServiceFactoryImpl.java index ba8c63532b..aded54de71 100644 --- a/src/main/java/com/microsoft/bingads/internal/ServiceFactoryImpl.java +++ b/src/main/java/com/microsoft/bingads/internal/ServiceFactoryImpl.java @@ -1,210 +1,193 @@ -package com.microsoft.bingads.internal; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.logging.Level; -import java.util.logging.Logger; - -import javax.xml.namespace.QName; - -import com.microsoft.bingads.ApiEnvironment; -import com.microsoft.bingads.InternalException; - -import jakarta.jws.WebService; -import jakarta.xml.ws.BindingProvider; -import jakarta.xml.ws.Service; -import jakarta.xml.ws.handler.MessageContext; -import jakarta.xml.ws.spi.Provider; - -public class ServiceFactoryImpl implements ServiceFactory { - - private static final String VERSION = "13.0.18"; - - private static final int DEFAULT_WS_CREATE_TIMEOUT_IN_SECOND = 60; - - private static final int WS_CREATE_RETRY_INTERVAL_IN_SECOND = 5; - - private static final int WS_CREATE_RETRY_TIMES = 3; - - private static Logger logger = Logger.getLogger(ServiceFactoryImpl.class.getName()); - - private static final Map endpoints = new HashMap() { - { - - put(com.microsoft.bingads.v13.customerbilling.ICustomerBillingService.class, new ServiceInfo() { - { - setProductionUrl("https://clientcenter.api.bingads.microsoft.com/Api/Billing/v13/CustomerBillingService.svc"); - setSandboxUrl("https://clientcenter.api.sandbox.bingads.microsoft.com/Api/Billing/v13/CustomerBillingService.svc"); - } - }); - - put(com.microsoft.bingads.v13.customermanagement.ICustomerManagementService.class, new ServiceInfo() { - { - setProductionUrl("https://clientcenter.api.bingads.microsoft.com/Api/CustomerManagement/v13/CustomerManagementService.svc"); - setSandboxUrl("https://clientcenter.api.sandbox.bingads.microsoft.com/Api/CustomerManagement/v13/CustomerManagementService.svc"); - } - }); - - put(com.microsoft.bingads.v13.reporting.IReportingService.class, new ServiceInfo() { - { - setProductionUrl("https://reporting.api.bingads.microsoft.com/Api/Advertiser/Reporting/v13/ReportingService.svc"); - setSandboxUrl("https://reporting.api.sandbox.bingads.microsoft.com/Api/Advertiser/Reporting/v13/ReportingService.svc"); - } - }); - put(com.microsoft.bingads.v13.campaignmanagement.ICampaignManagementService.class, new ServiceInfo() { - { - setProductionUrl("https://campaign.api.bingads.microsoft.com/Api/Advertiser/CampaignManagement/v13/CampaignManagementService.svc"); - setSandboxUrl("https://campaign.api.sandbox.bingads.microsoft.com/Api/Advertiser/CampaignManagement/v13/CampaignManagementService.svc"); - } - }); - put(com.microsoft.bingads.v13.adinsight.IAdInsightService.class, new ServiceInfo() { - { - setProductionUrl("https://adinsight.api.bingads.microsoft.com/Api/Advertiser/AdInsight/v13/AdInsightService.svc"); - setSandboxUrl("https://adinsight.api.sandbox.bingads.microsoft.com/Api/Advertiser/AdInsight/v13/AdInsightService.svc"); - } - }); - put(com.microsoft.bingads.v13.bulk.IBulkService.class, new ServiceInfo() { - { - setProductionUrl("https://bulk.api.bingads.microsoft.com/Api/Advertiser/CampaignManagement/v13/BulkService.svc"); - setSandboxUrl("https://bulk.api.sandbox.bingads.microsoft.com/Api/Advertiser/CampaignManagement/v13/BulkService.svc"); - } - }); - //End of v13 - } - }; - - @Override - public Service createService(Class serviceInterface, ApiEnvironment env) - { - try { - return createServiceWithRetry(serviceInterface, env); - } catch (Exception e) { - e.printStackTrace(); - throw new InternalException(e); - } - } - - // per #863657, Service.Create sometimes get hang. We implement timeout and retry for it. - private Service createServiceWithRetry(Class serviceInterface, ApiEnvironment env) throws Exception { - final QName qName = getServiceQname(serviceInterface); - final boolean isCxf = Provider.provider().getClass().getName().contains("org.apache.cxf"); - final URL url = (isCxf ? null : new URL(getServiceUrl(serviceInterface, env) + "?wsdl")); - - int retryLeft = WS_CREATE_RETRY_TIMES; - int timeout = 0; - ExecutorService pool = Executors.newSingleThreadExecutor(); - - try { - while (retryLeft > 0) { - retryLeft--; - timeout = prolongTimeout(timeout); - Future future = pool.submit(new Callable() { - public Service call() throws Exception { - if (isCxf) { - // CXF doesn't require WSDL url to be passed - return Service.create(qName); - } else { - return Service.create(url, qName); - } - } - }); - - try { - return future.get(timeout, TimeUnit.SECONDS); - } catch (TimeoutException e) { - System.out.println(String.format("Timeout. Failed to create web service %s in %d seconds for %s. retry left %d", - serviceInterface.getName(), timeout, env.value(), retryLeft)); - future.cancel(true); - - try { - if (retryLeft > 0) { - Thread.sleep(WS_CREATE_RETRY_INTERVAL_IN_SECOND * 1000); - } - } catch (InterruptedException e1) { - e1.printStackTrace(); - } - } - } - } finally { - pool.shutdown(); - } - throw new Exception(String.format("Failed to create Service %s for %s!", serviceInterface.getName(), env.value())); - } - - private int prolongTimeout(int timeout) { - return timeout + DEFAULT_WS_CREATE_TIMEOUT_IN_SECOND; - } - - private String getServiceUrl(Class serviceInterface, ApiEnvironment env) { - String serviceUrl = ServiceUtils.getServiceUrlFromConfig(serviceInterface); - - if (serviceUrl == null) { - ServiceInfo serviceInfo = endpoints.get(serviceInterface); - - serviceUrl = serviceInfo.GetUrl(env); - } - - return serviceUrl; - } - - private QName getServiceQname(Class serviceInterface) { - WebService webServiceAnnotation = (WebService) serviceInterface.getAnnotation(WebService.class); - - String serviceName = webServiceAnnotation.name(); - if (serviceName.startsWith("I")) { - serviceName = serviceName.substring(1); - } - - QName qName = new QName(webServiceAnnotation.targetNamespace(), serviceName); - - return qName; - } - - @Override - public T createProxyFromService(Service service, ApiEnvironment env, Class serviceInterface) { - T port = service.getPort(serviceInterface); - String serviceUrl = getServiceUrl(serviceInterface, env); - ((BindingProvider) port).getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, serviceUrl); - configServiceProxy(port); - addUserAgent(port); - - return port; - } - - /** - * Inherited class could set timeout properties by override this method. - * @param port Proxy supports Service T - */ - protected void configServiceProxy(T port) { - // By default nothing is add here. - } - - private void addUserAgent(T port) { - Map headers = new HashMap(); - - String userAgent = "BingAdsSDKJava " + VERSION; - - String javaVersion = System.getProperty("java.version"); - if (javaVersion.matches("\\d+[\\d|\\.|\\_]*\\d+")) { - // matches to 1.8.0_222, 11.0.2 and so on - userAgent += " " + javaVersion; - } - headers.put("User-Agent", Arrays.asList(userAgent)); - - ((BindingProvider) port).getRequestContext().put(MessageContext.HTTP_REQUEST_HEADERS, headers); - } -} +package com.microsoft.bingads.internal; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import java.util.concurrent.TimeoutException; +import java.util.logging.Logger; + +import javax.xml.namespace.QName; + +import com.microsoft.bingads.ApiEnvironment; +import com.microsoft.bingads.InternalException; + +import com.microsoft.bingads.v13.adinsight.IAdInsightService; +import com.microsoft.bingads.v13.campaignmanagement.ICampaignManagementService; +import com.microsoft.bingads.v13.customerbilling.ICustomerBillingService; +import com.microsoft.bingads.v13.customermanagement.ICustomerManagementService; +import com.microsoft.bingads.v13.reporting.IReportingService; +import jakarta.jws.WebService; +import jakarta.xml.ws.BindingProvider; +import jakarta.xml.ws.Service; +import jakarta.xml.ws.handler.MessageContext; +import jakarta.xml.ws.spi.Provider; + +import static java.lang.String.format; +import static java.util.concurrent.Executors.newCachedThreadPool; +import static java.util.concurrent.TimeUnit.SECONDS; +import static java.util.logging.Level.INFO; +import static java.util.logging.Level.SEVERE; + +public class ServiceFactoryImpl implements ServiceFactory { + + private static final String VERSION = "13.0.18"; + + private static final int DEFAULT_WS_CREATE_TIMEOUT_IN_SECOND = 60; + + private static final int WS_CREATE_RETRY_INTERVAL_IN_SECOND = 5; + + private static final int WS_CREATE_RETRY_TIMES = 3; + + private static Logger logger = Logger.getLogger(ServiceFactoryImpl.class.getName()); + + // + // Create service. + // + + @Override + public Service createService(Class serviceInterface, ApiEnvironment env) { + try { + return createServiceWithRetry(serviceInterface, env); + } catch (Exception e) { + logger.log(SEVERE, e.getMessage(), e); + throw new InternalException(e); + } + } + + // per #863657, Service.Create sometimes get hang. We implement timeout and retry for it. + private Service createServiceWithRetry(Class serviceInterface, ApiEnvironment env) throws Exception { + ExecutorService pool = newCachedThreadPool(); + try { + int timeout = 0; + for (int retryLeft = WS_CREATE_RETRY_TIMES; retryLeft > 0; retryLeft--) { + Future future = pool.submit(() -> createServiceInstance(serviceInterface, env)); + try { + // Linear increasing timeout. + timeout += DEFAULT_WS_CREATE_TIMEOUT_IN_SECOND; + return future.get(timeout, SECONDS); + } catch (TimeoutException e) { + logger.log(INFO, format( + "Timeout. Failed to create %s in %d seconds for %s. %d retries left.", + serviceInterface.getSimpleName(), timeout, env.value(), retryLeft)); + future.cancel(true); + + if (retryLeft > 1) { + Thread.sleep(WS_CREATE_RETRY_INTERVAL_IN_SECOND * 1000); + } + } + } + } finally { + pool.shutdownNow(); + } + + throw new Exception(format("Failed to create %s for %s.", serviceInterface.getSimpleName(), env.value())); + } + + /** + * Create the {@link Service} instance. + * Synchronized to avoid concurrency issues. + */ + private synchronized Service createServiceInstance(Class serviceInterface, ApiEnvironment env) throws Exception { + boolean isCxf = Provider.provider().getClass().getName().contains("org.apache.cxf"); + QName qName = getServiceQname(serviceInterface); + if (isCxf) { + // CXF doesn't require WSDL url to be passed. + return Service.create(qName); + } + + URL url = getServiceWsdlUrl(serviceInterface, env); + return Service.create(url, qName); + } + + // + // Create proxy. + // + + @Override + public T createProxyFromService(Service service, ApiEnvironment env, Class serviceInterface) { + T port = service.getPort(serviceInterface); + String serviceUrl = getServiceUrl(serviceInterface, env); + ((BindingProvider) port).getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, serviceUrl); + configServiceProxy(port); + addUserAgent(port); + + return port; + } + + /** + * Inherited class could set timeout properties by override this method. + * @param port Proxy supports Service T + */ + protected void configServiceProxy(T port) { + // By default nothing is add here. + } + + private void addUserAgent(T port) { + Map> headers = new HashMap<>(); + + String userAgent = "BingAdsSDKJava " + VERSION; + String javaVersion = System.getProperty("java.version"); + if (javaVersion.matches("\\d+[\\d|\\.|\\_]*\\d+")) { + // matches to 1.8.0_222, 11.0.2 and so on + userAgent += " " + javaVersion; + } + headers.put("User-Agent", Arrays.asList(userAgent)); + + ((BindingProvider) port).getRequestContext().put(MessageContext.HTTP_REQUEST_HEADERS, headers); + } + + // + // Service configuration. + // + + private QName getServiceQname(Class serviceInterface) { + WebService webServiceAnnotation = serviceInterface.getAnnotation(WebService.class); + + String serviceName = webServiceAnnotation.name(); + if (serviceName.startsWith("I")) { + serviceName = serviceName.substring(1); + } + + return new QName(webServiceAnnotation.targetNamespace(), serviceName); + } + + private static final Map, ServiceInfo> ENDPOINTS = new HashMap<>(); + static { + ENDPOINTS.put(ICustomerBillingService.class, new ServiceInfo( + "https://clientcenter.api.bingads.microsoft.com/Api/Billing/v13/CustomerBillingService.svc", + "https://clientcenter.api.sandbox.bingads.microsoft.com/Api/Billing/v13/CustomerBillingService.svc")); + ENDPOINTS.put(ICustomerManagementService.class, new ServiceInfo( + "https://clientcenter.api.bingads.microsoft.com/Api/CustomerManagement/v13/CustomerManagementService.svc", + "https://clientcenter.api.sandbox.bingads.microsoft.com/Api/CustomerManagement/v13/CustomerManagementService.svc")); + ENDPOINTS.put(IReportingService.class, new ServiceInfo( + "https://reporting.api.bingads.microsoft.com/Api/Advertiser/Reporting/v13/ReportingService.svc", + "https://reporting.api.sandbox.bingads.microsoft.com/Api/Advertiser/Reporting/v13/ReportingService.svc")); + ENDPOINTS.put(ICampaignManagementService.class, new ServiceInfo( + "https://campaign.api.bingads.microsoft.com/Api/Advertiser/CampaignManagement/v13/CampaignManagementService.svc", + "https://campaign.api.sandbox.bingads.microsoft.com/Api/Advertiser/CampaignManagement/v13/CampaignManagementService.svc")); + ENDPOINTS.put(IAdInsightService.class, new ServiceInfo( + "https://adinsight.api.bingads.microsoft.com/Api/Advertiser/AdInsight/v13/AdInsightService.svc", + "https://adinsight.api.sandbox.bingads.microsoft.com/Api/Advertiser/AdInsight/v13/AdInsightService.svc")); + ENDPOINTS.put(com.microsoft.bingads.v13.bulk.IBulkService.class, new ServiceInfo( + "https://bulk.api.bingads.microsoft.com/Api/Advertiser/CampaignManagement/v13/BulkService.svc", + "https://bulk.api.sandbox.bingads.microsoft.com/Api/Advertiser/CampaignManagement/v13/BulkService.svc")); + //End of v13 + } + + private String getServiceUrl(Class serviceInterface, ApiEnvironment env) { + String serviceUrl = ServiceUtils.getServiceUrlFromConfig(serviceInterface); + if (serviceUrl == null) { + serviceUrl = ENDPOINTS.get(serviceInterface).getUrl(env); + } + return serviceUrl; + } + + private URL getServiceWsdlUrl(Class serviceInterface, ApiEnvironment env) throws MalformedURLException { + return new URL(getServiceUrl(serviceInterface, env) + "?wsdl"); + } +} diff --git a/src/main/java/com/microsoft/bingads/internal/ServiceInfo.java b/src/main/java/com/microsoft/bingads/internal/ServiceInfo.java index 9d71dfbc47..5ab8b0e8b3 100644 --- a/src/main/java/com/microsoft/bingads/internal/ServiceInfo.java +++ b/src/main/java/com/microsoft/bingads/internal/ServiceInfo.java @@ -4,38 +4,33 @@ public class ServiceInfo { - private String productionUrl; - - private String sandboxUrl; + private final String productionUrl; + private final String sandboxUrl; - public String getProductionUrl() { - return productionUrl; + public ServiceInfo(String productionUrl, String sandboxUrl) { + this.productionUrl = productionUrl; + this.sandboxUrl = sandboxUrl; } - public void setProductionUrl(String productionUrl) { - this.productionUrl = productionUrl; + public String getProductionUrl() { + return productionUrl; } public String getSandboxUrl() { return sandboxUrl; } - public void setSandboxUrl(String sandboxUrl) { - this.sandboxUrl = sandboxUrl; - } - - public String GetUrl(ApiEnvironment environment) { + public String getUrl(ApiEnvironment environment) { switch (environment) { + case PRODUCTION: + return productionUrl; case SANDBOX: - if (getSandboxUrl() == null) { - throw new UnsupportedOperationException("The service is not available in Sandbox"); + if (sandboxUrl == null) { + throw new UnsupportedOperationException("The service is not available in " + environment.value()); } - - return getSandboxUrl(); - case PRODUCTION: - return getProductionUrl(); + return sandboxUrl; default: - throw new UnsupportedOperationException("The service is not available in Sandbox"); + throw new IllegalArgumentException("Unsupported environment " + environment.value()); } } } diff --git a/src/main/java/com/microsoft/bingads/internal/restful/RestfulServiceClient.java b/src/main/java/com/microsoft/bingads/internal/restful/RestfulServiceClient.java index b5920944de..4ee6de9630 100644 --- a/src/main/java/com/microsoft/bingads/internal/restful/RestfulServiceClient.java +++ b/src/main/java/com/microsoft/bingads/internal/restful/RestfulServiceClient.java @@ -16,6 +16,12 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import com.microsoft.bingads.v13.adinsight.IAdInsightService; +import com.microsoft.bingads.v13.bulk.IBulkService; +import com.microsoft.bingads.v13.campaignmanagement.ICampaignManagementService; +import com.microsoft.bingads.v13.customerbilling.ICustomerBillingService; +import com.microsoft.bingads.v13.customermanagement.ICustomerManagementService; +import com.microsoft.bingads.v13.reporting.IReportingService; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPut; import org.apache.http.entity.ContentType; @@ -33,8 +39,6 @@ import jakarta.xml.ws.AsyncHandler; import jakarta.xml.ws.Response; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonMappingException; import com.microsoft.bingads.ApiEnvironment; import com.microsoft.bingads.AuthorizationData; import com.microsoft.bingads.HeadersImpl; @@ -92,22 +96,6 @@ public void setSoapService(Object soapService) this.soapService = soapService; } - private String getServiceUrl(String entityEndpoint) { - String serviceUrl = ServiceUtils.getServiceUrlFromConfig(serviceInterface); - - if (serviceUrl == null) { - ServiceInfo serviceInfo = endpoints.get(serviceInterface); - - serviceUrl = serviceInfo.GetUrl(environment); - } - else { - URI uri = URI.create(serviceUrl); - serviceUrl = "https://" + uri.getAuthority() + "/CampaignManagement/v13"; - } - - return serviceUrl + entityEndpoint; - } - private List buildHeaders() { List headers = new ArrayList(); @@ -387,49 +375,42 @@ public Map getContext() { }; } - private static final Map endpoints = new HashMap() { - { - - put(com.microsoft.bingads.v13.customerbilling.ICustomerBillingService.class, new ServiceInfo() { - { - setProductionUrl("https://clientcenter.api.bingads.microsoft.com/Billing/v13"); - setSandboxUrl("https://clientcenter.api.sandbox.bingads.microsoft.com/Billing/v13"); - } - }); - - put(com.microsoft.bingads.v13.customermanagement.ICustomerManagementService.class, new ServiceInfo() { - { - setProductionUrl("https://clientcenter.api.bingads.microsoft.com/CustomerManagement/v13"); - setSandboxUrl("https://clientcenter.api.sandbox.bingads.microsoft.com/CustomerManagement/v13"); - } - }); + // + // Service configuration. + // + + private static final Map, ServiceInfo> ENDPOINTS = new HashMap<>(); + static { + ENDPOINTS.put(ICustomerBillingService.class, new ServiceInfo( + "https://clientcenter.api.bingads.microsoft.com/Billing/v13", + "https://clientcenter.api.sandbox.bingads.microsoft.com/Billing/v13")); + ENDPOINTS.put(ICustomerManagementService.class, new ServiceInfo( + "https://clientcenter.api.bingads.microsoft.com/CustomerManagement/v13", + "https://clientcenter.api.sandbox.bingads.microsoft.com/CustomerManagement/v13")); + ENDPOINTS.put(IReportingService.class, new ServiceInfo( + "https://reporting.api.bingads.microsoft.com/Reporting/v13", + "https://reporting.api.sandbox.bingads.microsoft.com/Reporting/v13")); + ENDPOINTS.put(ICampaignManagementService.class, new ServiceInfo( + "https://campaign.api.bingads.microsoft.com/CampaignManagement/v13", + "https://campaign.api.sandbox.bingads.microsoft.com/CampaignManagement/v13")); + ENDPOINTS.put(IAdInsightService.class, new ServiceInfo( + "https://adinsight.api.bingads.microsoft.com/AdInsight/v13", + "https://adinsight.api.sandbox.bingads.microsoft.com/AdInsight/v13")); + ENDPOINTS.put(IBulkService.class, new ServiceInfo( + "https://bulk.api.bingads.microsoft.com/CampaignManagement/v13", + "https://bulk.api.sandbox.bingads.microsoft.com/CampaignManagement/v13")); + // End of v13 + } - put(com.microsoft.bingads.v13.reporting.IReportingService.class, new ServiceInfo() { - { - setProductionUrl("https://reporting.api.bingads.microsoft.com/Reporting/v13"); - setSandboxUrl("https://reporting.api.sandbox.bingads.microsoft.com/Reporting/v13"); - } - }); - put(com.microsoft.bingads.v13.campaignmanagement.ICampaignManagementService.class, new ServiceInfo() { - { - setProductionUrl("https://campaign.api.bingads.microsoft.com/CampaignManagement/v13"); - setSandboxUrl("https://campaign.api.sandbox.bingads.microsoft.com/CampaignManagement/v13"); - } - }); - put(com.microsoft.bingads.v13.adinsight.IAdInsightService.class, new ServiceInfo() { - { - setProductionUrl("https://adinsight.api.bingads.microsoft.com/AdInsight/v13"); - setSandboxUrl("https://adinsight.api.sandbox.bingads.microsoft.com/AdInsight/v13"); - } - }); - put(com.microsoft.bingads.v13.bulk.IBulkService.class, new ServiceInfo() { - { - setProductionUrl("https://bulk.api.bingads.microsoft.com/CampaignManagement/v13"); - setSandboxUrl("https://bulk.api.sandbox.bingads.microsoft.com/CampaignManagement/v13"); - } - }); - // End of v13 + private String getServiceUrl(String entityEndpoint) { + String serviceUrl = ServiceUtils.getServiceUrlFromConfig(serviceInterface); + if (serviceUrl == null) { + serviceUrl = ENDPOINTS.get(serviceInterface).getUrl(environment); + } else { + URI uri = URI.create(serviceUrl); + serviceUrl = "https://" + uri.getAuthority() + "/CampaignManagement/v13"; } - }; + return serviceUrl + entityEndpoint; + } }