KEYCLOAK-4148 StringUtils property replacer optimization

StringUtils.getSystemPropertyAsString is used in SAML attribute
retrieval and uses StringBuffer and suboptimal regex. This optimization
gains another ~ 3 %.
This commit is contained in:
Hynek Mlnarik 2017-01-04 15:21:19 +01:00
parent 2b57b8371b
commit 862502f3ed
2 changed files with 64 additions and 26 deletions

View file

@ -59,6 +59,9 @@ public class StringUtil {
return str == null || str.isEmpty();
}
private static final Pattern PROPERTY_REPLACEMENT = Pattern.compile("(.*?)" + "\\$\\{(.*?)" + "(?:::(.*?))?\\}");
// 1: PREFIX | START 2: NAME | 3: OPTIONAL DEFAULT VALUE
/**
* <p>
* Get the system property value if the string is of the format ${sysproperty}
@ -84,37 +87,25 @@ public class StringUtil {
public static String getSystemPropertyAsString(String str) {
if (str == null)
throw logger.nullArgumentError("str");
if (str.contains("${")) {
Pattern pattern = Pattern.compile("\\$\\{([^}]+)}");
Matcher matcher = pattern.matcher(str);
StringBuffer buffer = new StringBuffer();
String sysPropertyValue = null;
Matcher m = PROPERTY_REPLACEMENT.matcher(str);
StringBuilder sb = new StringBuilder();
int lastPosition = 0;
while (m.find()) {
String propertyName = m.group(2);
String defaultValue = m.group(3);
while (matcher.find()) {
String subString = matcher.group(1);
String defaultValue = "";
// Look for default value
if (subString.contains("::")) {
int index = subString.indexOf("::");
defaultValue = subString.substring(index + 2);
subString = subString.substring(0, index);
}
sysPropertyValue = SecurityActions.getSystemProperty(subString, defaultValue);
if (sysPropertyValue.isEmpty()) {
throw logger.systemPropertyMissingError(matcher.group(1));
}else{
// sanitize the value before we use append-and-replace
sysPropertyValue = Matcher.quoteReplacement(sysPropertyValue);
}
matcher.appendReplacement(buffer, sysPropertyValue);
String sysPropertyValue = SecurityActions.getSystemProperty(propertyName, defaultValue);
if (sysPropertyValue.isEmpty()) {
throw logger.systemPropertyMissingError(propertyName);
}
matcher.appendTail(buffer);
str = buffer.toString();
sb.append(m.group(1)).append(sysPropertyValue);
lastPosition = m.end();
}
return str;
return sb.append(str.substring(lastPosition)).toString();
}
/**

View file

@ -0,0 +1,47 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.keycloak.saml.common.util;
import org.junit.Test;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.assertThat;
/**
*
* @author hmlnarik
*/
public class StringUtilTest {
public StringUtilTest() {
}
@Test
public void testGetSystemPropertyAsString() {
System.setProperty("StringUtilTest.prop1", "value1");
System.setProperty("StringUtilTest.prop2", "value2");
assertThat(StringUtil.getSystemPropertyAsString("a"), is("a"));
assertThat(StringUtil.getSystemPropertyAsString("a ${StringUtilTest.prop1}"), is("a value1"));
assertThat(
StringUtil.getSystemPropertyAsString("a" + "${StringUtilTest.prop1}" + "StringUtilTest.prop1"),
is("a" + "value1" + "StringUtilTest.prop1")
);
assertThat(
StringUtil.getSystemPropertyAsString("a" + "${StringUtilTest.prop1}" + "StringUtilTest.prop1" + "${StringUtilTest.prop2}"),
is("a" + "value1" + "StringUtilTest.prop1" + "value2")
);
assertThat(
StringUtil.getSystemPropertyAsString("a" + "${StringUtilTest.prop1}" + "StringUtilTest.prop1" + "${StringUtilTest.prop2}" + "${StringUtilTest.prop3::abc}"),
is("a" + "value1" + "StringUtilTest.prop1" + "value2" + "abc")
);
assertThat(
StringUtil.getSystemPropertyAsString("a" + "${StringUtilTest.prop1}" + "StringUtilTest.prop1" + "${StringUtilTest.prop2}" + "${StringUtilTest.prop3::abc}" + "end"),
is("a" + "value1" + "StringUtilTest.prop1" + "value2" + "abc" + "end")
);
}
}