Loading pom.xml 0 → 100644 +100 −0 Original line number Diff line number Diff line <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 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.etsi.osl.util</groupId> <artifactId>servicespecificationuploader</artifactId> <version>0.0.1-SNAPSHOT</version> <!-- Specify the Java version you're using --> <properties> <maven.compiler.source>17</maven.compiler.source> <maven.compiler.target>17</maven.compiler.target> </properties> <dependencies> <!-- Jackson JSON Processor --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.12.3</version> </dependency> <!-- Google Gson --> <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.8.6</version> </dependency> <!-- Your custom library dependency --> <dependency> <groupId>org.etsi.osl</groupId> <artifactId>org.etsi.osl.model.tmf</artifactId> <version>1.0.0</version> </dependency> <!-- SnakeYAML --> <dependency> <groupId>org.yaml</groupId> <artifactId>snakeyaml</artifactId> <version>2.0</version> </dependency> <!-- Commons cli --> <!-- https://mvnrepository.com/artifact/commons-cli/commons-cli --> <dependency> <groupId>commons-cli</groupId> <artifactId>commons-cli</artifactId> <version>1.9.0</version> </dependency> </dependencies> <build> <plugins> <!-- Maven Compiler Plugin --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.1</version> <configuration> <source>17</source> <target>17</target> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <version>3.2.0</version> <configuration> <archive> <manifest> <mainClass>org.etsi.osl.util.ServiceSpecificationUploader</mainClass> </manifest> </archive> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.4.1</version> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <createDependencyReducedPom>true</createDependencyReducedPom> <transformers> <!-- Ensures that the manifest specifies the main class --> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <mainClass>org.etsi.osl.util.ServiceSpecificationUploader</mainClass> <!-- Fully Qualified Name --> </transformer> </transformers> </configuration> </execution> </executions> </plugin> </plugins> </build> </project> src/main/java/org/etsi/osl/util/JsonStringReplacer.java 0 → 100644 +197 −0 Original line number Diff line number Diff line package org.etsi.osl.util; import com.fasterxml.jackson.databind.*; import com.fasterxml.jackson.databind.node.*; import org.yaml.snakeyaml.Yaml; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.*; import java.util.*; public class JsonStringReplacer { // Logger instance private static final Logger logger = LoggerFactory.getLogger(JsonStringReplacer.class); // Static variable to hold mappings private static Map<String, String> mappings = new HashMap<>(); /** * Sets the YAML file path and loads mappings. * If the file is missing, it sets mappings to an empty map and continues. * * @param yamlFilePath The path to the YAML mappings file. */ public static void setYamlFilePath(String yamlFilePath) { try { mappings = loadYamlMappings(yamlFilePath); } catch (FileNotFoundException e) { // Mappings file is missing; proceed with empty mappings logger.warn("Mappings file not found: {}. Proceeding without replacements.", yamlFilePath); mappings = new HashMap<>(); // Ensure mappings is empty } catch (IOException e) { // Other I/O errors logger.error("Error reading mappings file: {}. Proceeding without replacements.", e.getMessage()); mappings = new HashMap<>(); // Ensure mappings is empty } catch (Exception e) { // Handle any other exceptions logger.error("Unexpected error: {}. Proceeding without replacements.", e.getMessage(), e); mappings = new HashMap<>(); // Ensure mappings is empty } } /** * Replaces strings in a JSON content based on the loaded mappings. * If mappings are empty, it returns the original JSON content. * * @param jsonContent The input JSON content as a string. * @return The modified JSON content as a string. * @throws IOException If an I/O error occurs during processing. */ public static String replaceJsonStrings(String jsonContent) throws IOException { // If mappings are empty, return the original JSON content if (mappings == null || mappings.isEmpty()) { logger.info("Mappings are empty. Returning original JSON content."); return jsonContent; } // Create an ObjectMapper for JSON parsing ObjectMapper mapper = new ObjectMapper(); // Parse the JSON content into a JsonNode JsonNode rootNode = mapper.readTree(jsonContent); // Perform string replacements replaceStrings(rootNode); // Convert the modified JsonNode back into a JSON string String result = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(rootNode); logger.debug("Replacements completed successfully."); return result; } /** * Loads mappings from a YAML file. * * @param yamlFilePath The file path to the YAML mappings file. * @return A Map containing the mappings. * @throws IOException If an error occurs while reading the YAML file. */ private static Map<String, String> loadYamlMappings(String yamlFilePath) throws IOException { Yaml yaml = new Yaml(); Map<String, String> loadedMappings = new HashMap<>(); try (InputStream inputStream = new FileInputStream(yamlFilePath)) { Map<String, Object> yamlMaps = yaml.load(inputStream); if (yamlMaps == null || !yamlMaps.containsKey("mappings")) { logger.warn("The YAML file does not contain a 'mappings' key. Proceeding without replacements."); return loadedMappings; // Return empty mappings } Object mappingsObj = yamlMaps.get("mappings"); if (mappingsObj instanceof List) { List<?> mappingsList = (List<?>) mappingsObj; for (Object item : mappingsList) { if (item instanceof Map) { Map<?, ?> mapItem = (Map<?, ?>) item; Object fromObj = mapItem.get("from"); Object toObj = mapItem.get("to"); if (fromObj instanceof String && toObj instanceof String) { loadedMappings.put((String) fromObj, (String) toObj); } else { logger.warn("Invalid mapping entry: 'from' and 'to' must be strings. Skipping entry."); } } else { logger.warn("Invalid mapping format. Each mapping entry must be a map with 'from' and 'to' keys. Skipping entry."); } } } else if (mappingsObj instanceof Map) { Map<?, ?> mappingsMap = (Map<?, ?>) mappingsObj; for (Map.Entry<?, ?> entry : mappingsMap.entrySet()) { if (entry.getKey() instanceof String && entry.getValue() instanceof String) { loadedMappings.put((String) entry.getKey(), (String) entry.getValue()); } else { logger.warn("Invalid mapping entry: keys and values must be strings. Skipping entry."); } } } else { logger.warn("Unrecognized 'mappings' format in YAML file. Proceeding without replacements."); } } logger.info("Loaded {} mappings from YAML file.", loadedMappings.size()); return loadedMappings; } /** * Recursively replaces strings in a JsonNode based on the loaded mappings. * * @param node The JsonNode to process. */ private static void replaceStrings(JsonNode node) { if (node == null || mappings == null || mappings.isEmpty()) { return; } if (node.isObject()) { ObjectNode objNode = (ObjectNode) node; Iterator<Map.Entry<String, JsonNode>> fields = objNode.fields(); while (fields.hasNext()) { Map.Entry<String, JsonNode> entry = fields.next(); JsonNode childNode = entry.getValue(); if (childNode.isTextual()) { String textValue = childNode.asText(); if (mappings.containsKey(textValue)) { String replacement = mappings.get(textValue); objNode.put(entry.getKey(), replacement); logger.debug("Replaced text '{}' with '{}' in object field '{}'.", textValue, replacement, entry.getKey()); } } else { replaceStrings(childNode); } } } else if (node.isArray()) { ArrayNode arrayNode = (ArrayNode) node; for (int i = 0; i < arrayNode.size(); i++) { JsonNode element = arrayNode.get(i); if (element.isTextual()) { String textValue = element.asText(); if (mappings.containsKey(textValue)) { String replacement = mappings.get(textValue); arrayNode.set(i, new TextNode(replacement)); logger.debug("Replaced text '{}' with '{}' in array index {}.", textValue, replacement, i); } } else { replaceStrings(element); } } } // Other node types are not modified } // Example usage in the main method public static void main(String[] args) { String jsonInput = "{ \"greeting\": \"string1\", \"farewell\": \"string2\", \"nested\": { \"message\": \"string3\" }, \"array\": [\"string1\", \"hello\", \"string2\"] }"; String yamlFilePath = "org/etsi/osl/util/mappings.yaml"; // Adjust the path as needed // Set the YAML path from another class or context JsonStringReplacer.setYamlFilePath(yamlFilePath); try { // Perform the replacement String result = JsonStringReplacer.replaceJsonStrings(jsonInput); // Output the modified JSON System.out.println("Modified JSON:"); System.out.println(result); } catch (IOException e) { logger.error("An error occurred during JSON processing: {}", e.getMessage(), e); } } } src/main/java/org/etsi/osl/util/KeycloakAuthenticator.java 0 → 100644 +175 −0 Original line number Diff line number Diff line package org.etsi.osl.util; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import java.io.IOException; import java.net.URI; import java.net.URLEncoder; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.nio.charset.StandardCharsets; import java.time.Instant; import java.util.Properties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class KeycloakAuthenticator { private static final Logger logger = LoggerFactory.getLogger(KeycloakAuthenticator.class.getName()); private final Properties config; private final HttpClient client; private final ObjectMapper objectMapper; private String currentToken; private long tokenExpiryTime; private long tokenRefreshBufferSeconds; /** * Constructs a KeycloakAuthenticator with the specified configuration file path. * * @param configFilePath The file path to the configuration properties file. * @throws IOException If there is an error loading the configuration file. */ public KeycloakAuthenticator(Properties config) throws IOException { this.config = config; this.client = HttpClient.newHttpClient(); this.objectMapper = new ObjectMapper(); setTokenRefreshBufferSeconds(); } /** * Loads the configuration properties from the specified file path. * * @param configFilePath The file path to the configuration properties file. * @return The token refresh buffer time in seconds. * @throws IOException If the configuration file cannot be read. */ private void setTokenRefreshBufferSeconds() throws IOException { // Load the token refresh buffer time, defaulting to 60 seconds if not specified String bufferSecondsStr = this.config.getProperty("token.refresh.buffer.seconds", "60"); long bufferSeconds; try { bufferSeconds = Long.parseLong(bufferSecondsStr); if (bufferSeconds < 0) { throw new NumberFormatException("Buffer seconds cannot be negative."); } } catch (NumberFormatException ex) { logger.warn("Invalid token.refresh.buffer.seconds value: " + bufferSecondsStr + ". Using default of 60 seconds."); bufferSeconds = 60; } logger.info("Token refresh buffer set to " + bufferSeconds + " seconds."); this.tokenRefreshBufferSeconds=bufferSeconds; } /** * Retrieves a valid access token. If the current token is expired or not present, * it authenticates with Keycloak to obtain a new one. * * @return A valid access token as a String. * @throws IOException If an I/O error occurs during authentication. * @throws InterruptedException If the HTTP request is interrupted. */ public synchronized String getToken() throws IOException, InterruptedException { long currentEpochSeconds = Instant.now().getEpochSecond(); if (currentToken != null && currentEpochSeconds < (tokenExpiryTime - tokenRefreshBufferSeconds)) { logger.info("Using cached token. Token expires at " + Instant.ofEpochSecond(tokenExpiryTime)); return currentToken; } else { logger.info("Cached token is missing or nearing expiration. Authenticating to obtain a new token."); return authenticateAndGetToken(); } } /** * Authenticates with Keycloak and retrieves a new access token. * * @return The new access token as a String. * @throws IOException If the authentication request fails. * @throws InterruptedException If the HTTP request is interrupted. */ private String authenticateAndGetToken() throws IOException, InterruptedException { String keycloakUrl = config.getProperty("keycloak.url"); String clientId = config.getProperty("client.id"); String clientSecret = config.getProperty("client.secret"); String username = config.getProperty("username"); String password = config.getProperty("password"); // Validate required properties if (keycloakUrl == null || clientId == null || username == null || password == null) { String errorMsg = "Missing required configuration properties."; logger.error(errorMsg); throw new IOException(errorMsg); } // Build the form data with URL encoding String form = buildFormData(clientId, clientSecret, username, password); HttpRequest request = HttpRequest.newBuilder() .uri(URI.create(keycloakUrl)) .header("Content-Type", "application/x-www-form-urlencoded") .POST(HttpRequest.BodyPublishers.ofString(form)) .build(); logger.info("Sending authentication request to Keycloak."); HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString()); if (response.statusCode() == 200) { JsonNode responseJson = objectMapper.readTree(response.body()); currentToken = responseJson.get("access_token").asText(); long expiresIn = responseJson.get("expires_in").asLong(); tokenExpiryTime = Instant.now().getEpochSecond() + expiresIn; logger.info("Authentication successful. Token obtained. Token expires in " + expiresIn + " seconds."); return currentToken; } else { String errorMsg = "Authentication failed: HTTP status " + response.statusCode() + ": " + response.body(); logger.error(errorMsg); throw new IOException(errorMsg); } } /** * Builds the URL-encoded form data for the authentication request. * * @param clientId The client ID. * @param clientSecret The client secret (optional). * @param username The username. * @param password The password. * @return The URL-encoded form data as a String. * @throws IOException If URL encoding fails. */ private String buildFormData(String clientId, String clientSecret, String username, String password) throws IOException { StringBuilder form = new StringBuilder(); form.append("client_id=").append(urlEncode(clientId)); if (clientSecret != null && !clientSecret.isEmpty()) { form.append("&client_secret=").append(urlEncode(clientSecret)); } form.append("&username=").append(urlEncode(username)); form.append("&password=").append(urlEncode(password)); form.append("&grant_type=password"); return form.toString(); } /** * URL-encodes a string using UTF-8 encoding. * * @param value The string to encode. * @return The URL-encoded string. * @throws IOException If UTF-8 encoding is not supported. */ private String urlEncode(String value) throws IOException { try { return URLEncoder.encode(value, StandardCharsets.UTF_8.toString()); } catch (Exception ex) { logger.error("URL encoding failed for value: " + value, ex); throw new IOException("URL encoding failed.", ex); } } } src/main/java/org/etsi/osl/util/ResourceSpecificationPayloadsMaker.java 0 → 100644 +60 −0 Original line number Diff line number Diff line package org.etsi.osl.util; import org.etsi.osl.tmf.common.model.TimePeriod; import org.etsi.osl.tmf.rcm634.model.ResourceSpecification; import org.etsi.osl.tmf.rcm634.model.ResourceSpecificationCreate; import org.etsi.osl.tmf.rcm634.model.ResourceSpecificationUpdate; import java.util.ArrayList; public class ResourceSpecificationPayloadsMaker { // Change ServiceSpecificationCreate to ResourceSpecificationCreate public static ResourceSpecificationCreate createResourceSpecDataFromFile(ResourceSpecification resourceSpecFromFile) { // Parse the JSON file into a ServSpecCr object ResourceSpecificationCreate newResourceSpec = new ResourceSpecificationCreate(); newResourceSpec.setName(resourceSpecFromFile.getName()); newResourceSpec.setDescription(resourceSpecFromFile.getDescription()); //newServSpec.setAttachment(new ArrayList<>(resourceSpecFromFile.getAttachment())); newResourceSpec.setIsBundle(resourceSpecFromFile.isIsBundle()); //newServSpec.setRelatedParty(new ArrayList<>(resourceSpecFromFile.getRelatedParty())); //newServSpec.setResourceSpecification(new ArrayList<>(resourceSpecFromFile.getResourceSpecification())); //newServSpec.setServiceLevelSpecification(new ArrayList<>(resourceSpecFromFile.getServiceLevelSpecification())); //newServSpec.setServiceSpecCharacteristic(new ArrayList<>(resourceSpecFromFile.getServiceSpecCharacteristic())); //newServSpec.setServiceSpecRelationship(new ArrayList<>(resourceSpecFromFile.getServiceSpecRelationship())); newResourceSpec.setVersion(resourceSpecFromFile.getVersion()); newResourceSpec.setValidFor(new TimePeriod()); if (resourceSpecFromFile.getType() != null) { newResourceSpec.setType( resourceSpecFromFile.getType() ); } return newResourceSpec; } public static ResourceSpecificationUpdate updateResourceSpecDataFromFile(ResourceSpecification resourceSpecFromFile) { ResourceSpecificationUpdate newResourceSpecToUpdate = new ResourceSpecificationUpdate(); if (resourceSpecFromFile.getName() != null) { newResourceSpecToUpdate.setName(resourceSpecFromFile.getName()); } if (resourceSpecFromFile.getDescription() != null) { newResourceSpecToUpdate.setDescription(resourceSpecFromFile.getDescription()); } if (resourceSpecFromFile.isIsBundle() != null) { newResourceSpecToUpdate.setIsBundle(resourceSpecFromFile.isIsBundle()); } if (resourceSpecFromFile.getVersion() != null) { newResourceSpecToUpdate.setVersion(resourceSpecFromFile.getVersion()); } if (resourceSpecFromFile.getResourceSpecCharacteristic() != null) { System.out.println("ServiceSpecCharacteristic: " + resourceSpecFromFile.getResourceSpecCharacteristic()); newResourceSpecToUpdate.setResourceSpecificationCharacteristic(new ArrayList<>(resourceSpecFromFile.getResourceSpecCharacteristic())); } return newResourceSpecToUpdate; } } No newline at end of file Loading
pom.xml 0 → 100644 +100 −0 Original line number Diff line number Diff line <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 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.etsi.osl.util</groupId> <artifactId>servicespecificationuploader</artifactId> <version>0.0.1-SNAPSHOT</version> <!-- Specify the Java version you're using --> <properties> <maven.compiler.source>17</maven.compiler.source> <maven.compiler.target>17</maven.compiler.target> </properties> <dependencies> <!-- Jackson JSON Processor --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.12.3</version> </dependency> <!-- Google Gson --> <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.8.6</version> </dependency> <!-- Your custom library dependency --> <dependency> <groupId>org.etsi.osl</groupId> <artifactId>org.etsi.osl.model.tmf</artifactId> <version>1.0.0</version> </dependency> <!-- SnakeYAML --> <dependency> <groupId>org.yaml</groupId> <artifactId>snakeyaml</artifactId> <version>2.0</version> </dependency> <!-- Commons cli --> <!-- https://mvnrepository.com/artifact/commons-cli/commons-cli --> <dependency> <groupId>commons-cli</groupId> <artifactId>commons-cli</artifactId> <version>1.9.0</version> </dependency> </dependencies> <build> <plugins> <!-- Maven Compiler Plugin --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.1</version> <configuration> <source>17</source> <target>17</target> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <version>3.2.0</version> <configuration> <archive> <manifest> <mainClass>org.etsi.osl.util.ServiceSpecificationUploader</mainClass> </manifest> </archive> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.4.1</version> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <createDependencyReducedPom>true</createDependencyReducedPom> <transformers> <!-- Ensures that the manifest specifies the main class --> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <mainClass>org.etsi.osl.util.ServiceSpecificationUploader</mainClass> <!-- Fully Qualified Name --> </transformer> </transformers> </configuration> </execution> </executions> </plugin> </plugins> </build> </project>
src/main/java/org/etsi/osl/util/JsonStringReplacer.java 0 → 100644 +197 −0 Original line number Diff line number Diff line package org.etsi.osl.util; import com.fasterxml.jackson.databind.*; import com.fasterxml.jackson.databind.node.*; import org.yaml.snakeyaml.Yaml; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.*; import java.util.*; public class JsonStringReplacer { // Logger instance private static final Logger logger = LoggerFactory.getLogger(JsonStringReplacer.class); // Static variable to hold mappings private static Map<String, String> mappings = new HashMap<>(); /** * Sets the YAML file path and loads mappings. * If the file is missing, it sets mappings to an empty map and continues. * * @param yamlFilePath The path to the YAML mappings file. */ public static void setYamlFilePath(String yamlFilePath) { try { mappings = loadYamlMappings(yamlFilePath); } catch (FileNotFoundException e) { // Mappings file is missing; proceed with empty mappings logger.warn("Mappings file not found: {}. Proceeding without replacements.", yamlFilePath); mappings = new HashMap<>(); // Ensure mappings is empty } catch (IOException e) { // Other I/O errors logger.error("Error reading mappings file: {}. Proceeding without replacements.", e.getMessage()); mappings = new HashMap<>(); // Ensure mappings is empty } catch (Exception e) { // Handle any other exceptions logger.error("Unexpected error: {}. Proceeding without replacements.", e.getMessage(), e); mappings = new HashMap<>(); // Ensure mappings is empty } } /** * Replaces strings in a JSON content based on the loaded mappings. * If mappings are empty, it returns the original JSON content. * * @param jsonContent The input JSON content as a string. * @return The modified JSON content as a string. * @throws IOException If an I/O error occurs during processing. */ public static String replaceJsonStrings(String jsonContent) throws IOException { // If mappings are empty, return the original JSON content if (mappings == null || mappings.isEmpty()) { logger.info("Mappings are empty. Returning original JSON content."); return jsonContent; } // Create an ObjectMapper for JSON parsing ObjectMapper mapper = new ObjectMapper(); // Parse the JSON content into a JsonNode JsonNode rootNode = mapper.readTree(jsonContent); // Perform string replacements replaceStrings(rootNode); // Convert the modified JsonNode back into a JSON string String result = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(rootNode); logger.debug("Replacements completed successfully."); return result; } /** * Loads mappings from a YAML file. * * @param yamlFilePath The file path to the YAML mappings file. * @return A Map containing the mappings. * @throws IOException If an error occurs while reading the YAML file. */ private static Map<String, String> loadYamlMappings(String yamlFilePath) throws IOException { Yaml yaml = new Yaml(); Map<String, String> loadedMappings = new HashMap<>(); try (InputStream inputStream = new FileInputStream(yamlFilePath)) { Map<String, Object> yamlMaps = yaml.load(inputStream); if (yamlMaps == null || !yamlMaps.containsKey("mappings")) { logger.warn("The YAML file does not contain a 'mappings' key. Proceeding without replacements."); return loadedMappings; // Return empty mappings } Object mappingsObj = yamlMaps.get("mappings"); if (mappingsObj instanceof List) { List<?> mappingsList = (List<?>) mappingsObj; for (Object item : mappingsList) { if (item instanceof Map) { Map<?, ?> mapItem = (Map<?, ?>) item; Object fromObj = mapItem.get("from"); Object toObj = mapItem.get("to"); if (fromObj instanceof String && toObj instanceof String) { loadedMappings.put((String) fromObj, (String) toObj); } else { logger.warn("Invalid mapping entry: 'from' and 'to' must be strings. Skipping entry."); } } else { logger.warn("Invalid mapping format. Each mapping entry must be a map with 'from' and 'to' keys. Skipping entry."); } } } else if (mappingsObj instanceof Map) { Map<?, ?> mappingsMap = (Map<?, ?>) mappingsObj; for (Map.Entry<?, ?> entry : mappingsMap.entrySet()) { if (entry.getKey() instanceof String && entry.getValue() instanceof String) { loadedMappings.put((String) entry.getKey(), (String) entry.getValue()); } else { logger.warn("Invalid mapping entry: keys and values must be strings. Skipping entry."); } } } else { logger.warn("Unrecognized 'mappings' format in YAML file. Proceeding without replacements."); } } logger.info("Loaded {} mappings from YAML file.", loadedMappings.size()); return loadedMappings; } /** * Recursively replaces strings in a JsonNode based on the loaded mappings. * * @param node The JsonNode to process. */ private static void replaceStrings(JsonNode node) { if (node == null || mappings == null || mappings.isEmpty()) { return; } if (node.isObject()) { ObjectNode objNode = (ObjectNode) node; Iterator<Map.Entry<String, JsonNode>> fields = objNode.fields(); while (fields.hasNext()) { Map.Entry<String, JsonNode> entry = fields.next(); JsonNode childNode = entry.getValue(); if (childNode.isTextual()) { String textValue = childNode.asText(); if (mappings.containsKey(textValue)) { String replacement = mappings.get(textValue); objNode.put(entry.getKey(), replacement); logger.debug("Replaced text '{}' with '{}' in object field '{}'.", textValue, replacement, entry.getKey()); } } else { replaceStrings(childNode); } } } else if (node.isArray()) { ArrayNode arrayNode = (ArrayNode) node; for (int i = 0; i < arrayNode.size(); i++) { JsonNode element = arrayNode.get(i); if (element.isTextual()) { String textValue = element.asText(); if (mappings.containsKey(textValue)) { String replacement = mappings.get(textValue); arrayNode.set(i, new TextNode(replacement)); logger.debug("Replaced text '{}' with '{}' in array index {}.", textValue, replacement, i); } } else { replaceStrings(element); } } } // Other node types are not modified } // Example usage in the main method public static void main(String[] args) { String jsonInput = "{ \"greeting\": \"string1\", \"farewell\": \"string2\", \"nested\": { \"message\": \"string3\" }, \"array\": [\"string1\", \"hello\", \"string2\"] }"; String yamlFilePath = "org/etsi/osl/util/mappings.yaml"; // Adjust the path as needed // Set the YAML path from another class or context JsonStringReplacer.setYamlFilePath(yamlFilePath); try { // Perform the replacement String result = JsonStringReplacer.replaceJsonStrings(jsonInput); // Output the modified JSON System.out.println("Modified JSON:"); System.out.println(result); } catch (IOException e) { logger.error("An error occurred during JSON processing: {}", e.getMessage(), e); } } }
src/main/java/org/etsi/osl/util/KeycloakAuthenticator.java 0 → 100644 +175 −0 Original line number Diff line number Diff line package org.etsi.osl.util; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import java.io.IOException; import java.net.URI; import java.net.URLEncoder; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.nio.charset.StandardCharsets; import java.time.Instant; import java.util.Properties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class KeycloakAuthenticator { private static final Logger logger = LoggerFactory.getLogger(KeycloakAuthenticator.class.getName()); private final Properties config; private final HttpClient client; private final ObjectMapper objectMapper; private String currentToken; private long tokenExpiryTime; private long tokenRefreshBufferSeconds; /** * Constructs a KeycloakAuthenticator with the specified configuration file path. * * @param configFilePath The file path to the configuration properties file. * @throws IOException If there is an error loading the configuration file. */ public KeycloakAuthenticator(Properties config) throws IOException { this.config = config; this.client = HttpClient.newHttpClient(); this.objectMapper = new ObjectMapper(); setTokenRefreshBufferSeconds(); } /** * Loads the configuration properties from the specified file path. * * @param configFilePath The file path to the configuration properties file. * @return The token refresh buffer time in seconds. * @throws IOException If the configuration file cannot be read. */ private void setTokenRefreshBufferSeconds() throws IOException { // Load the token refresh buffer time, defaulting to 60 seconds if not specified String bufferSecondsStr = this.config.getProperty("token.refresh.buffer.seconds", "60"); long bufferSeconds; try { bufferSeconds = Long.parseLong(bufferSecondsStr); if (bufferSeconds < 0) { throw new NumberFormatException("Buffer seconds cannot be negative."); } } catch (NumberFormatException ex) { logger.warn("Invalid token.refresh.buffer.seconds value: " + bufferSecondsStr + ". Using default of 60 seconds."); bufferSeconds = 60; } logger.info("Token refresh buffer set to " + bufferSeconds + " seconds."); this.tokenRefreshBufferSeconds=bufferSeconds; } /** * Retrieves a valid access token. If the current token is expired or not present, * it authenticates with Keycloak to obtain a new one. * * @return A valid access token as a String. * @throws IOException If an I/O error occurs during authentication. * @throws InterruptedException If the HTTP request is interrupted. */ public synchronized String getToken() throws IOException, InterruptedException { long currentEpochSeconds = Instant.now().getEpochSecond(); if (currentToken != null && currentEpochSeconds < (tokenExpiryTime - tokenRefreshBufferSeconds)) { logger.info("Using cached token. Token expires at " + Instant.ofEpochSecond(tokenExpiryTime)); return currentToken; } else { logger.info("Cached token is missing or nearing expiration. Authenticating to obtain a new token."); return authenticateAndGetToken(); } } /** * Authenticates with Keycloak and retrieves a new access token. * * @return The new access token as a String. * @throws IOException If the authentication request fails. * @throws InterruptedException If the HTTP request is interrupted. */ private String authenticateAndGetToken() throws IOException, InterruptedException { String keycloakUrl = config.getProperty("keycloak.url"); String clientId = config.getProperty("client.id"); String clientSecret = config.getProperty("client.secret"); String username = config.getProperty("username"); String password = config.getProperty("password"); // Validate required properties if (keycloakUrl == null || clientId == null || username == null || password == null) { String errorMsg = "Missing required configuration properties."; logger.error(errorMsg); throw new IOException(errorMsg); } // Build the form data with URL encoding String form = buildFormData(clientId, clientSecret, username, password); HttpRequest request = HttpRequest.newBuilder() .uri(URI.create(keycloakUrl)) .header("Content-Type", "application/x-www-form-urlencoded") .POST(HttpRequest.BodyPublishers.ofString(form)) .build(); logger.info("Sending authentication request to Keycloak."); HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString()); if (response.statusCode() == 200) { JsonNode responseJson = objectMapper.readTree(response.body()); currentToken = responseJson.get("access_token").asText(); long expiresIn = responseJson.get("expires_in").asLong(); tokenExpiryTime = Instant.now().getEpochSecond() + expiresIn; logger.info("Authentication successful. Token obtained. Token expires in " + expiresIn + " seconds."); return currentToken; } else { String errorMsg = "Authentication failed: HTTP status " + response.statusCode() + ": " + response.body(); logger.error(errorMsg); throw new IOException(errorMsg); } } /** * Builds the URL-encoded form data for the authentication request. * * @param clientId The client ID. * @param clientSecret The client secret (optional). * @param username The username. * @param password The password. * @return The URL-encoded form data as a String. * @throws IOException If URL encoding fails. */ private String buildFormData(String clientId, String clientSecret, String username, String password) throws IOException { StringBuilder form = new StringBuilder(); form.append("client_id=").append(urlEncode(clientId)); if (clientSecret != null && !clientSecret.isEmpty()) { form.append("&client_secret=").append(urlEncode(clientSecret)); } form.append("&username=").append(urlEncode(username)); form.append("&password=").append(urlEncode(password)); form.append("&grant_type=password"); return form.toString(); } /** * URL-encodes a string using UTF-8 encoding. * * @param value The string to encode. * @return The URL-encoded string. * @throws IOException If UTF-8 encoding is not supported. */ private String urlEncode(String value) throws IOException { try { return URLEncoder.encode(value, StandardCharsets.UTF_8.toString()); } catch (Exception ex) { logger.error("URL encoding failed for value: " + value, ex); throw new IOException("URL encoding failed.", ex); } } }
src/main/java/org/etsi/osl/util/ResourceSpecificationPayloadsMaker.java 0 → 100644 +60 −0 Original line number Diff line number Diff line package org.etsi.osl.util; import org.etsi.osl.tmf.common.model.TimePeriod; import org.etsi.osl.tmf.rcm634.model.ResourceSpecification; import org.etsi.osl.tmf.rcm634.model.ResourceSpecificationCreate; import org.etsi.osl.tmf.rcm634.model.ResourceSpecificationUpdate; import java.util.ArrayList; public class ResourceSpecificationPayloadsMaker { // Change ServiceSpecificationCreate to ResourceSpecificationCreate public static ResourceSpecificationCreate createResourceSpecDataFromFile(ResourceSpecification resourceSpecFromFile) { // Parse the JSON file into a ServSpecCr object ResourceSpecificationCreate newResourceSpec = new ResourceSpecificationCreate(); newResourceSpec.setName(resourceSpecFromFile.getName()); newResourceSpec.setDescription(resourceSpecFromFile.getDescription()); //newServSpec.setAttachment(new ArrayList<>(resourceSpecFromFile.getAttachment())); newResourceSpec.setIsBundle(resourceSpecFromFile.isIsBundle()); //newServSpec.setRelatedParty(new ArrayList<>(resourceSpecFromFile.getRelatedParty())); //newServSpec.setResourceSpecification(new ArrayList<>(resourceSpecFromFile.getResourceSpecification())); //newServSpec.setServiceLevelSpecification(new ArrayList<>(resourceSpecFromFile.getServiceLevelSpecification())); //newServSpec.setServiceSpecCharacteristic(new ArrayList<>(resourceSpecFromFile.getServiceSpecCharacteristic())); //newServSpec.setServiceSpecRelationship(new ArrayList<>(resourceSpecFromFile.getServiceSpecRelationship())); newResourceSpec.setVersion(resourceSpecFromFile.getVersion()); newResourceSpec.setValidFor(new TimePeriod()); if (resourceSpecFromFile.getType() != null) { newResourceSpec.setType( resourceSpecFromFile.getType() ); } return newResourceSpec; } public static ResourceSpecificationUpdate updateResourceSpecDataFromFile(ResourceSpecification resourceSpecFromFile) { ResourceSpecificationUpdate newResourceSpecToUpdate = new ResourceSpecificationUpdate(); if (resourceSpecFromFile.getName() != null) { newResourceSpecToUpdate.setName(resourceSpecFromFile.getName()); } if (resourceSpecFromFile.getDescription() != null) { newResourceSpecToUpdate.setDescription(resourceSpecFromFile.getDescription()); } if (resourceSpecFromFile.isIsBundle() != null) { newResourceSpecToUpdate.setIsBundle(resourceSpecFromFile.isIsBundle()); } if (resourceSpecFromFile.getVersion() != null) { newResourceSpecToUpdate.setVersion(resourceSpecFromFile.getVersion()); } if (resourceSpecFromFile.getResourceSpecCharacteristic() != null) { System.out.println("ServiceSpecCharacteristic: " + resourceSpecFromFile.getResourceSpecCharacteristic()); newResourceSpecToUpdate.setResourceSpecificationCharacteristic(new ArrayList<>(resourceSpecFromFile.getResourceSpecCharacteristic())); } return newResourceSpecToUpdate; } } No newline at end of file