Skip to content

Commit

Permalink
Merge pull request #3 from inomera/1-add-runtime-configs-interceptors
Browse files Browse the repository at this point in the history
1 add runtime configs interceptors
  • Loading branch information
turgaycan authored Jan 23, 2025
2 parents c7e818e + 26e926c commit 8b96671
Show file tree
Hide file tree
Showing 42 changed files with 1,702 additions and 173 deletions.
6 changes: 3 additions & 3 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ subprojects {
ext {
versions = [
//main libs
integration : '1.0.0',
middleware : '1.0.0',
integration : '1.1.0',
middleware : '1.1.0',
//adapter ext
dac_bridge : '1.0.0',
dac_bridge : '1.1.0',
//ext libs
spring_boot_ws : '3.1.5',
spring_ws_core : '4.0.5',
Expand Down
2 changes: 1 addition & 1 deletion dynamic-adapter-config-bridge/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.0.0
1.1.0
9 changes: 6 additions & 3 deletions dynamic-adapter-config-bridge/build.gradle
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
plugins {
id 'java'
id 'java-library'
id 'maven-publish'
}

Expand All @@ -14,15 +14,18 @@ repositories {
}

dependencies {
//INFO : disabled comment out line for only development!! DO NOT REMOVE THE INFO LINE
//implementation project(path: ':micro-integration')

implementation project(path: ':micro-integration')
implementation 'com.inomera.telco.commons:config-manager-spring:4.0.0'
api "com.inomera.integration:micro-integration:${versions.integration}"
api 'com.inomera.telco.commons:config-manager-spring:4.0.0'

implementation "org.projectlombok:lombok:${versions.lombok}"
annotationProcessor "org.projectlombok:lombok:${versions.lombok}"

testImplementation "org.junit.jupiter:junit-jupiter-api:${versions.junit}"
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${versions.junit}"
testImplementation "org.springframework.boot:spring-boot-starter-test:${versions.spring_boot_test}"
}

test {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,35 +15,48 @@
import com.inomera.telco.commons.lang.Assert;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

@Slf4j
@RequiredArgsConstructor
public class DynamicAdapterConfigDataBridgeSupplierHandler implements AdapterConfigDataSupplier {

private static final String COMMON_CONFIG_V1_KEY = "config.adapter.common.v1";
private final ConcurrentHashMap<String, String> configReloadMap = new ConcurrentHashMap<>();

private final ConfigurationHolder configurationHolder;

@Override
public AdapterConfig getConfigV1(String key) {
Assert.notNull(key);
Assert.notNull(key, "Key cannot be null");
try {
final Map<String, Object> adapterPropertiesMap = getConfig(key, Map.class);
if (null == adapterPropertiesMap) {
throw new AdapterConfigException("adapter config Key::" + key + " is not found");
// Get the adapter properties map
Map<String, Object> adapterPropertiesMap = getConfig(key, Map.class);
if (adapterPropertiesMap == null) {
throw new AdapterConfigException("Adapter config for key '" + key + "' is not found");
}

Map<String, Object> authMap = (Map<String, Object>) adapterPropertiesMap.get("auth");
final Auth authCredentials = getAuthCredentials(authMap);
final AdapterProperties adapterProperties = getConfig(key, AdapterProperties.class);
// Extract and set authentication credentials
Auth authCredentials = extractAuthCredentials(adapterPropertiesMap);

// Create AdapterProperties and set authentication
AdapterProperties adapterProperties = getConfig(key, AdapterProperties.class);
adapterProperties.setAuth(authCredentials);
final AdapterConfig adapterConfig = new AdapterConfig(key, adapterProperties);
return mergeWithCommonConfigIfNotSetInAdapterConfig(adapterConfig);

// Merge with common configuration
AdapterConfig adapterConfig = new AdapterConfig(key, adapterProperties);
AdapterConfig mergedAdapterConfig = mergeWithCommonConfigIfNotSetInAdapterConfig(adapterConfig);

// Handle configuration reload logic
handleConfigReload(key, mergedAdapterConfig);

return mergedAdapterConfig;
} catch (Exception e) {
LOG.error("key::{}, Config deserialization error occurred", key, e);
throw new AdapterConfigException("Adapter Config Exception", e.getCause());
LOG.error("Key: {}, Config deserialization error occurred", key, e);
throw new AdapterConfigException("Adapter Config Exception", e);
}
}

Expand Down Expand Up @@ -97,6 +110,30 @@ public <T> List<T> getConfigs(String key, Class<T> classToDeserialize, List<T> d
}


private Auth extractAuthCredentials(Map<String, Object> adapterPropertiesMap) {
Map<String, Object> authMap = (Map<String, Object>) adapterPropertiesMap.get("auth");
if (authMap == null) {
throw new AdapterConfigException("'auth' section is missing in adapter properties");
}
return getAuthCredentials(authMap);
}

private void handleConfigReload(String key, AdapterConfig mergedAdapterConfig) {
final String currentHash = configReloadMap.get(key);
if (StringUtils.isBlank(currentHash)) {
// Initial load
configReloadMap.put(key, mergedAdapterConfig.hashConfig());
mergedAdapterConfig.setRefresh(true);
} else if (currentHash.equals(mergedAdapterConfig.hashConfig())) {
// No changes in configuration
mergedAdapterConfig.setRefresh(false);
} else {
// Configuration has changed
configReloadMap.put(key, mergedAdapterConfig.hashConfig());
mergedAdapterConfig.setRefresh(true);
}
}

private Auth getAuthCredentials(Map<String, Object> authMap) {
String authType = (String) authMap.get("type");
switch (AuthType.valueOf(authType)) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,28 +1,132 @@
package com.inomera.adapter.config.bridge;

import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import static org.junit.jupiter.api.Assertions.*;
import com.inomera.adapter.config.bridge.exception.AdapterConfigException;
import com.inomera.integration.config.model.AdapterConfig;
import com.inomera.integration.config.model.AdapterProperties;
import com.inomera.telco.commons.config.ConfigurationHolder;
import java.util.List;
import java.util.Map;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

class DynamicAdapterConfigDataBridgeSupplierHandlerTest {

@InjectMocks
private DynamicAdapterConfigDataBridgeSupplierHandler handler;

@Mock
private ConfigurationHolder configurationHolder;

private AutoCloseable autoCloseable;
@BeforeEach
void setUp() {
autoCloseable = MockitoAnnotations.openMocks(this);
}

@AfterEach
void destroy() throws Exception {
autoCloseable.close();
}


@Test
void testGetConfigV1_Success() {
String key = "testKey";
AdapterProperties mockAdapterProperties = new AdapterProperties();
mockAdapterProperties.setAuth(null);

Map<String, Object> mockAdapterPropertiesMap = Map.of("auth", Map.of("type", "NONE"));

when(configurationHolder.getJsonObjectProperty(eq(key), eq(Map.class))).thenReturn(mockAdapterPropertiesMap);
when(configurationHolder.getJsonObjectProperty(eq(key), eq(AdapterProperties.class))).thenReturn(mockAdapterProperties);

AdapterConfig result = handler.getConfigV1(key);

assertNotNull(result);
assertEquals(key, result.getKey());
assertNotNull(result.getAdapterProperties());
verify(configurationHolder, times(1)).getJsonObjectProperty(eq(key), eq(Map.class));
}

@Test
void getConfigV1() {
void testGetConfigV1_KeyNotFound_ThrowsException() {
String key = "testKey";

when(configurationHolder.getJsonObjectProperty(eq(key), eq(Map.class))).thenReturn(null);

AdapterConfigException exception = assertThrows(AdapterConfigException.class, () -> handler.getConfigV1(key));
assertEquals("Adapter config for key 'testKey' is not found", exception.getCause().getMessage());

verify(configurationHolder, times(1)).getJsonObjectProperty(eq(key), eq(Map.class));
}

@Test
void getConfig() {
void testGetConfig_StringProperty_Success() {
String key = "stringKey";
String expectedValue = "testValue";

when(configurationHolder.getStringProperty(eq(key))).thenReturn(expectedValue);

String result = handler.getConfig(key, String.class);

assertNotNull(result);
assertEquals(expectedValue, result);
verify(configurationHolder, times(1)).getStringProperty(eq(key));
}

@Test
void testGetConfig() {
void testGetConfig_JsonObject_Success() {
String key = "jsonKey";
AdapterProperties expectedObject = new AdapterProperties();

when(configurationHolder.getJsonObjectProperty(eq(key), eq(AdapterProperties.class))).thenReturn(expectedObject);

AdapterProperties result = handler.getConfig(key, AdapterProperties.class);

assertNotNull(result);
assertEquals(expectedObject, result);
verify(configurationHolder, times(1)).getJsonObjectProperty(eq(key), eq(AdapterProperties.class));
}

@Test
void getConfigs() {
void testGetConfigs_Success() {
String key = "listKey";
AdapterProperties mockObject1 = new AdapterProperties();
AdapterProperties mockObject2 = new AdapterProperties();

when(configurationHolder.getJsonListProperty(eq(key), eq(AdapterProperties.class)))
.thenReturn(List.of(mockObject1, mockObject2));

List<AdapterProperties> result = handler.getConfigs(key, AdapterProperties.class);

assertNotNull(result);
assertEquals(2, result.size());
verify(configurationHolder, times(1)).getJsonListProperty(eq(key), eq(AdapterProperties.class));
}

@Test
void testGetConfigs() {
void testGetConfigV1_AuthExtraction_ThrowsException() {
String key = "testKey";
Map<String, Object> mockAdapterPropertiesMap = Map.of();

when(configurationHolder.getJsonObjectProperty(eq(key), eq(Map.class))).thenReturn(mockAdapterPropertiesMap);

AdapterConfigException exception = assertThrows(AdapterConfigException.class, () -> handler.getConfigV1(key));
assertEquals("'auth' section is missing in adapter properties", exception.getCause().getMessage());

verify(configurationHolder, times(1)).getJsonObjectProperty(eq(key), eq(Map.class));
}
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.inomera.adapter.config.bridge.util;

import com.inomera.integration.config.model.AdapterConfig;
import com.inomera.integration.config.model.AdapterProperties;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;
Expand All @@ -8,5 +10,17 @@ class AdapterConfigMergerTest {

@Test
void mergeIfNotExistAdapterConfig() {
AdapterConfig commonConfig = new AdapterConfig();
commonConfig.setRefresh(false);
commonConfig.setKey("config.adapter.common");
AdapterConfig mirketAdapterConfig = new AdapterConfig();
mirketAdapterConfig.setKey("config.adapter.mirket.v1");
mirketAdapterConfig.setAdapterProperties(new AdapterProperties());
mirketAdapterConfig.setRefresh(true);
AdapterConfig adapterConfig = AdapterConfigMerger.mergeIfNotExistAdapterConfig(
mirketAdapterConfig, commonConfig);

assertEquals("config.adapter.mirket.v1", adapterConfig.getKey());
assertTrue(adapterConfig.isRefresh());
}
}
18 changes: 7 additions & 11 deletions example/ms-example/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -30,28 +30,24 @@ tasks.withType(Zip).configureEach {
dependencies {

//INFO : mirket-adapter -> publishToMavenLocal for local lib testing
// implementation 'com.inomera.adapters:mirket-adapter:1.0.0'
implementation 'com.inomera.adapters:mirket-adapter:1.1.0'

/* DEVELOPMENT SITE DEPENDENCIES BEGIN*/
//INFO : disabled comment out line for only development!! DO NOT REMOVE THE INFO LINE
implementation project(path: ':mirket-adapter')
implementation project(path: ':micro-integration')
implementation project(path: ':micro-middleware')
implementation project(path: ':dynamic-adapter-config-bridge')
implementation 'com.inomera.telco.commons:config-manager-spring:4.0.0'
implementation "org.apache.httpcomponents.client5:httpclient5:${versions.httpclient5}"
implementation "org.apache.httpcomponents.client5:httpclient5-fluent:${versions.httpclient5}"

// implementation project(path: ':mirket-adapter')
// implementation project(path: ':micro-integration')
// implementation project(path: ':micro-middleware')
// implementation project(path: ':dynamic-adapter-config-bridge')
// implementation 'com.inomera.telco.commons:config-manager-spring:4.0.0'
/* DEVELOPMENT SITE DEPENDENCIES END */

developmentOnly 'org.springframework.boot:spring-boot-devtools'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'

implementation "org.projectlombok:lombok:${versions.lombok}"
annotationProcessor "org.projectlombok:lombok:${versions.lombok}"



implementation 'org.springframework.boot:spring-boot-starter-web'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,18 @@
package com.inomera.adapter.example.msexample;

import com.inomera.integration.model.AdapterResponse;
import com.inomera.middleware.config.HttpBeanConfiguration;
import com.inomera.mirketadapter.MirketAdapterBeanConfiguration;
import com.inomera.mirketadapter.rest.MirketAdapter;
import com.inomera.mirketadapter.soap.CountryAdapter;
import com.inomera.mirketadapter.soap.model.Continents;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Import;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@Slf4j
@SpringBootApplication
@Import({MirketAdapterBeanConfiguration.class, HttpBeanConfiguration.class})
public class MsExampleApplication {

@Autowired
Expand Down
4 changes: 2 additions & 2 deletions example/ms-example/src/main/resources/settings.properties
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
config.adapter.common.v1={"logging":{"strategy":"REQ_RES","sensitiveFields":[],"nonLoggingFields":[]},"headers":{},"http":{"requestTimeout":30000,"connectTimeout":10000,"idleConnectionsTimeout":180000,"maxConnections":10,"maxConnPerRoute":10,"poolConcurrencyPolicy":"LAX","timeToLive":60000,"skipSsl":true,"redirectsEnable":true},"auth":{"type":"NONE"}}
config.adapter.mirket.v1={"auth":{"type":"NONE"},"headers":{"X-GW-TOKEN":""},"http":{"requestTimeout":30000,"connectTimeout":10000,"idleConnectionsTimeout":60000,"maxConnections":50,"maxConnPerRoute":50,"poolConcurrencyPolicy":"LAX","timeToLive":60000,"skipSsl":true,"redirectsEnable":true},"logging":{"strategy":"REQ_RES","sensitiveFields":["Authorization"],"nonLoggingFields":["file","content"]},"url":"https://api.mirket.inomera.com/"}
config.adapter.country.v1={"logging":{"strategy":"ALL","sensitiveFields":[],"nonLoggingFields":[]},"headers":{},"http":{"requestTimeout":30000,"connectTimeout":10000,"idleConnectionsTimeout":180000,"maxConnections":10,"maxConnPerRoute":10,"poolConcurrencyPolicy":"LAX","timeToLive":60000,"skipSsl":true,"redirectsEnable":true},"auth":{"type":"NONE"},"url": "http://webservices.oorsprong.org/websamples.countryinfo/CountryInfoService.wso"}
config.adapter.mirket.v1={"runtime": true,"auth":{"type":"NONE"},"headers":{"X-GW-TOKEN":""},"http":{"requestTimeout":30000,"connectTimeout":10000,"idleConnectionsTimeout":60000,"maxConnections":50,"maxConnPerRoute":50,"poolConcurrencyPolicy":"LAX","timeToLive":60000,"skipSsl":true,"redirectsEnable":true},"logging":{"strategy":"REQ_RES","sensitiveFields":["Authorization"],"nonLoggingFields":["file","content"]},"url":"https://api.mirket.inomera.com/"}
config.adapter.country.v1={"runtime": true,"logging":{"strategy":"ALL","sensitiveFields":[],"nonLoggingFields":[]},"headers":{},"http":{"requestTimeout":30000,"connectTimeout":10000,"idleConnectionsTimeout":180000,"maxConnections":10,"maxConnPerRoute":10,"poolConcurrencyPolicy":"LAX","timeToLive":60000,"skipSsl":true,"redirectsEnable":true},"auth":{"type":"NONE"},"url": "http://webservices.oorsprong.org/websamples.countryinfo/CountryInfoService.wso"}
File renamed without changes.
File renamed without changes.
File renamed without changes.
Loading

0 comments on commit 8b96671

Please sign in to comment.