Skip to content

Commit

Permalink
Add the capability to render file fragments into config.xml
Browse files Browse the repository at this point in the history
  • Loading branch information
codepitbull committed Jan 23, 2025
1 parent dd413ec commit 39aab57
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import com.hivemq.configuration.entity.listener.UDPListenerEntity;
import com.hivemq.configuration.entity.listener.WebsocketListenerEntity;
import com.hivemq.exceptions.UnrecoverableException;
import com.hivemq.util.FileFragmentUtil;
import org.jetbrains.annotations.NotNull;
import com.hivemq.util.EnvVarUtil;
import org.apache.commons.io.FileUtils;
Expand Down Expand Up @@ -266,6 +267,7 @@ public void writeConfigToXML(final @NotNull Writer writer) {
//replace environment variable placeholders
String configFileContent = new String(Files.readAllBytes(configFile.toPath()), StandardCharsets.UTF_8);
configFileContent = EnvVarUtil.replaceEnvironmentVariablePlaceholders(configFileContent);
configFileContent = FileFragmentUtil.replaceFragmentPlaceHolders(configFileContent);
final ByteArrayInputStream is =
new ByteArrayInputStream(configFileContent.getBytes(StandardCharsets.UTF_8));
final StreamSource streamSource = new StreamSource(is);
Expand Down
4 changes: 1 addition & 3 deletions hivemq-edge/src/main/java/com/hivemq/util/EnvVarUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.inject.Singleton;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

Expand All @@ -30,7 +29,6 @@
*
* @author Christoph Schäbel
*/
@Singleton
public class EnvVarUtil {

private static final Logger log = LoggerFactory.getLogger(EnvVarUtil.class);
Expand All @@ -55,7 +53,7 @@ public class EnvVarUtil {
}

/**
* Replaces placeholders like '${VAR_NAME}' and '${ENV:VAR_NAME}' with the according environment variables.
* Replaces placeholders like '${ENV:VAR_NAME}' with the according environment variables.
*
* @param text the text which contains placeholders (or not)
* @return the text with all the placeholders replaced
Expand Down
84 changes: 84 additions & 0 deletions hivemq-edge/src/main/java/com/hivemq/util/FileFragmentUtil.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package com.hivemq.util;

import com.hivemq.exceptions.UnrecoverableException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class FileFragmentUtil {
private static final Logger log = LoggerFactory.getLogger(EnvVarUtil.class);

private static final @NotNull String FRAGMENT_VAR_PATTERN = "\\$\\{FRAGMENT:(.*)}";

/**
* Load a file fragment
*
* @param path the path where the fragment is located
* @return return the content of the fragment
*/
public static @Nullable String getFragment(final @NotNull String path) {
try {
return Files.readString(Path.of(path), StandardCharsets.UTF_8);
} catch (IOException e) {
log.error("Unable to load fragment from {}", path, e);
}
return null;
}

/**
* Replaces fragment markers like '${FRAGMENT:VAR_NAME}' with the according fragment loaded from the filesystem.
*
* @param text the text which contains placeholders (or not)
* @return the text with all the placeholders replaced
* @throws UnrecoverableException if a fragment used in a placeholder can't be loaded
*/
public static @NotNull String replaceFragmentPlaceHolders(final @NotNull String text) {

final StringBuffer resultString = new StringBuffer();

final Matcher matcher = Pattern.compile(FRAGMENT_VAR_PATTERN)
.matcher(text);

while (matcher.find()) {

if (matcher.groupCount() < 1) {
//this should never happen as we declared 1 groups in the ENV_VAR_PATTERN
log.warn("Found unexpected fragment variable placeholder in config.xml");
matcher.appendReplacement(resultString, "");
continue;
}

final String fragmentPath = matcher.group(1);

final String replacement = getFragment(fragmentPath);

if (replacement == null) {
log.error("Fragment {} for HiveMQ config.xml can't be loaded.", fragmentPath);
throw new UnrecoverableException(false);
}

//sets replacement for this match
matcher.appendReplacement(resultString, escapeReplacement(replacement));

}

//adds everything except the replacements to the string buffer
matcher.appendTail(resultString);

return resultString.toString();
}

private static @NotNull String escapeReplacement(final @NotNull String replacement) {
return replacement
.replace("\\", "\\\\")
.replace("$", "\\$");
}
}
4 changes: 2 additions & 2 deletions hivemq-edge/src/test/java/com/hivemq/util/EnvVarUtilTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,12 @@ public void test_replaceEnvironmentVariablePlaceholders() throws Exception {
setTempEnvVars(Map.of("VALUE1", "value$1", "VALUE2", "2", "VALUE3", "value-_/!\"\\'3!§%&/()=?`*,;.:[]|{}"));

final String testString =
"<test1><test2 id=\"VALUE1\"><test3>${ENV:VALUE1}</test3><test4>${ENV:VALUE2}</test4><test5>${ENV:VALUE3}</test5></test2></test1>";
"<test1><test2 id=\"VALUE1\"><test3>${ENV:VALUE1}${FRAGMENT:FRAGGY}</test3><test4>${ENV:VALUE2}</test4><test5>${ENV:VALUE3}</test5></test2></test1>";

final String result = EnvVarUtil.replaceEnvironmentVariablePlaceholders(testString);

final String expected =
"<test1><test2 id=\"VALUE1\"><test3>value$1</test3><test4>2</test4><test5>value-_/!\"\\'3!§%&/()=?`*,;.:[]|{}</test5></test2></test1>";
"<test1><test2 id=\"VALUE1\"><test3>value$1${FRAGMENT:FRAGGY}</test3><test4>2</test4><test5>value-_/!\"\\'3!§%&/()=?`*,;.:[]|{}</test5></test2></test1>";

assertEquals(expected, result);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.hivemq.util;

import org.junit.jupiter.api.Test;

import java.nio.file.Files;
import java.nio.file.Path;

import static org.assertj.core.api.Assertions.assertThat;

public class FileFragmentUtilTest {

@Test
public void testRender() throws Exception {
final Path fragment = Files.createTempFile("fragment", ".xml");

Files.writeString(fragment, "THE FRAGMENT");
final String fragmented = "<hallo>${FRAGMENT:" + fragment.toFile() + "}</hallo>";
final String resolved = FileFragmentUtil.replaceFragmentPlaceHolders(fragmented);

assertThat(resolved).isEqualTo("<hallo>THE FRAGMENT</hallo>");
}
}

0 comments on commit 39aab57

Please sign in to comment.