@@ -, +, @@ --- ...heticResponseTimeDistributionGraphConsumer.java | 20 +++--- .../impl/TransactionsPerSecondGraphConsumer.java | 7 +- .../org/apache/jorphan/text/BooleanFormatter.java | 46 +++++++++++++ .../org/apache/jorphan/text/CombinedFormatter.java | 46 +++++++++++++ .../org/apache/jorphan/text/NoOpFormatter.java | 28 ++++++++ .../apache/jorphan/text/PreCompiledFormatter.java | 24 +++++++ .../jorphan/text/PreCompiledFormatterBuilder.java | 79 ++++++++++++++++++++++ .../org/apache/jorphan/text/SimpleFormatter.java | 26 +++++++ .../org/apache/jorphan/text/StaticFormatter.java | 39 +++++++++++ .../org/apache/jorphan/text/StringFormatter.java | 45 ++++++++++++ .../jorphan/text/PreCompiledFormatterSpec.groovy | 50 ++++++++++++++ 11 files changed, 397 insertions(+), 13 deletions(-) create mode 100644 src/jorphan/org/apache/jorphan/text/BooleanFormatter.java create mode 100644 src/jorphan/org/apache/jorphan/text/CombinedFormatter.java create mode 100644 src/jorphan/org/apache/jorphan/text/NoOpFormatter.java create mode 100644 src/jorphan/org/apache/jorphan/text/PreCompiledFormatter.java create mode 100644 src/jorphan/org/apache/jorphan/text/PreCompiledFormatterBuilder.java create mode 100644 src/jorphan/org/apache/jorphan/text/SimpleFormatter.java create mode 100644 src/jorphan/org/apache/jorphan/text/StaticFormatter.java create mode 100644 src/jorphan/org/apache/jorphan/text/StringFormatter.java create mode 100644 test/src/org/apache/jorphan/text/PreCompiledFormatterSpec.groovy --- a/src/core/org/apache/jmeter/report/processor/graph/impl/SyntheticResponseTimeDistributionGraphConsumer.java +++ a/src/core/org/apache/jmeter/report/processor/graph/impl/SyntheticResponseTimeDistributionGraphConsumer.java @@ -17,23 +17,24 @@ */ package org.apache.jmeter.report.processor.graph.impl; -import java.text.MessageFormat; import java.util.Arrays; import java.util.HashMap; import java.util.Map; import org.apache.jmeter.report.core.Sample; -import org.apache.jmeter.report.processor.ListResultData; -import org.apache.jmeter.report.processor.MapResultData; -import org.apache.jmeter.report.processor.SumAggregatorFactory; -import org.apache.jmeter.report.processor.ValueResultData; import org.apache.jmeter.report.processor.graph.AbstractGraphConsumer; import org.apache.jmeter.report.processor.graph.AbstractSeriesSelector; import org.apache.jmeter.report.processor.graph.CountValueSelector; import org.apache.jmeter.report.processor.graph.GraphKeysSelector; import org.apache.jmeter.report.processor.graph.GroupInfo; import org.apache.jmeter.report.processor.graph.SeriesData; +import org.apache.jmeter.report.processor.ListResultData; +import org.apache.jmeter.report.processor.MapResultData; +import org.apache.jmeter.report.processor.SumAggregatorFactory; +import org.apache.jmeter.report.processor.ValueResultData; import org.apache.jmeter.util.JMeterUtils; +import org.apache.jorphan.text.PreCompiledFormatter; +import org.apache.jorphan.text.PreCompiledFormatterBuilder; /** * The class SyntheticResponseTimeDistributionGraphConsumer provides a graph to visualize @@ -44,9 +45,12 @@ import org.apache.jmeter.util.JMeterUtils; public class SyntheticResponseTimeDistributionGraphConsumer extends AbstractGraphConsumer { private static final String FAILED_LABEL = JMeterUtils.getResString("response_time_distribution_failed_label"); - private static final MessageFormat SATISFIED_LABEL = new MessageFormat(JMeterUtils.getResString("response_time_distribution_satisfied_label")); - private static final MessageFormat TOLERATED_LABEL = new MessageFormat(JMeterUtils.getResString("response_time_distribution_tolerated_label")); - private static final MessageFormat UNTOLERATED_LABEL = new MessageFormat(JMeterUtils.getResString("response_time_distribution_untolerated_label")); + private static final PreCompiledFormatter SATISFIED_LABEL = PreCompiledFormatterBuilder.build( + JMeterUtils.getResString("response_time_distribution_satisfied_label")); + private static final PreCompiledFormatter TOLERATED_LABEL = PreCompiledFormatterBuilder.build( + JMeterUtils.getResString("response_time_distribution_tolerated_label")); + private static final PreCompiledFormatter UNTOLERATED_LABEL = PreCompiledFormatterBuilder.build( + JMeterUtils.getResString("response_time_distribution_untolerated_label")); private static final String SERIE_COLOR_PROPERTY = "color"; private static final String SATISFIED_COLOR = "#9ACD32"; private static final String TOLERATED_COLOR = "yellow"; --- a/src/core/org/apache/jmeter/report/processor/graph/impl/TransactionsPerSecondGraphConsumer.java +++ a/src/core/org/apache/jmeter/report/processor/graph/impl/TransactionsPerSecondGraphConsumer.java @@ -39,7 +39,6 @@ import org.apache.jmeter.report.processor.graph.TimeStampKeysSelector; public class TransactionsPerSecondGraphConsumer extends AbstractOverTimeGraphConsumer { - private static final String STATUS_SERIES_FORMAT = "%s-%s"; private static final String SUCCESS_SERIES_SUFFIX = "success"; private static final String FAILURE_SERIES_SUFFIX = "failure"; @@ -72,10 +71,8 @@ public class TransactionsPerSecondGraphConsumer extends @Override public Iterable select(Sample sample) { - String label = String.format(STATUS_SERIES_FORMAT, - sample.getName(), - sample.getSuccess() ? SUCCESS_SERIES_SUFFIX - : FAILURE_SERIES_SUFFIX); + String success = sample.getSuccess() ? SUCCESS_SERIES_SUFFIX : FAILURE_SERIES_SUFFIX; + String label = sample.getName() + "-" + success; return Arrays.asList(label); } }, --- a/src/jorphan/org/apache/jorphan/text/BooleanFormatter.java +++ a/src/jorphan/org/apache/jorphan/text/BooleanFormatter.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jorphan.text; + +import java.util.function.Function; + +public class BooleanFormatter implements SimpleFormatter { + + Function transformer; + + public BooleanFormatter() { + this(s -> s); + } + + public BooleanFormatter(Function transformer) { + this.transformer = transformer; + } + + @Override + public void format(StringBuilder sb, Object arg) { + String valueAsString = arg instanceof Boolean ? String.valueOf(arg) : "true"; + sb.append(transformer.apply(arg == null ? "false" : valueAsString)); + } + + @Override + public int argsNeeded() { + return 1; + } + +} --- a/src/jorphan/org/apache/jorphan/text/CombinedFormatter.java +++ a/src/jorphan/org/apache/jorphan/text/CombinedFormatter.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jorphan.text; + +import java.util.List; + +public class CombinedFormatter implements PreCompiledFormatter { + + private List formatters; + + public CombinedFormatter(List formatters) { + this.formatters = formatters; + } + + @Override + public String format(Object... args) { + StringBuilder sb = new StringBuilder(); + int index = 0; + for (SimpleFormatter f : formatters) { + if (f.argsNeeded() > 0) { + f.format(sb, args[index]); + } else { + f.format(sb, null); + } + index += f.argsNeeded(); + } + return sb.toString(); + } + +} --- a/src/jorphan/org/apache/jorphan/text/NoOpFormatter.java +++ a/src/jorphan/org/apache/jorphan/text/NoOpFormatter.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jorphan.text; + +public class NoOpFormatter implements PreCompiledFormatter { + + @Override + public String format(Object... args) { + return ""; + } + +} --- a/src/jorphan/org/apache/jorphan/text/PreCompiledFormatter.java +++ a/src/jorphan/org/apache/jorphan/text/PreCompiledFormatter.java @@ -0,0 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jorphan.text; + +public interface PreCompiledFormatter { + + public String format(Object... args); +} --- a/src/jorphan/org/apache/jorphan/text/PreCompiledFormatterBuilder.java +++ a/src/jorphan/org/apache/jorphan/text/PreCompiledFormatterBuilder.java @@ -0,0 +1,79 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jorphan.text; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class PreCompiledFormatterBuilder { + + private PreCompiledFormatterBuilder() { + // hide publicly + } + + private static Map availableFormatters; + static { + availableFormatters = new HashMap<>(); + availableFormatters.put("s", new StringFormatter()); + availableFormatters.put("S", new StringFormatter(String::toUpperCase)); + availableFormatters.put("b", new BooleanFormatter()); + availableFormatters.put("B", new BooleanFormatter(String::toUpperCase)); + availableFormatters.put("%", new StaticFormatter("%")); + availableFormatters.put("n", new StaticFormatter("\n")); + } + + private static Pattern formatPattern = Pattern.compile("%(\\w)"); + + public static PreCompiledFormatter build(String format) { + List f = new ArrayList<>(); + Matcher matcher = formatPattern.matcher(format); + while (matcher.find()) { + StringBuffer buf = new StringBuffer(); + matcher.appendReplacement(buf, + Matcher.quoteReplacement("")); + String prefix = buf.toString(); + if (prefix.length() > 0) { + f.add(new StaticFormatter(prefix)); + } + if (availableFormatters.containsKey(matcher.group(1))) { + f.add(availableFormatters.get(matcher.group(1))); + } else { + throw new IllegalArgumentException("No formatter available for %" + matcher.group(1) + " in [" + format + "]"); + } + } + String tailString = extractTail(matcher); + if (!tailString.isEmpty()) { + f.add(new StaticFormatter(tailString)); + } + if (f.isEmpty()) { + return new NoOpFormatter(); + } + return new CombinedFormatter(f); + } + + private static String extractTail(Matcher matcher) { + StringBuffer buf = new StringBuffer(); + matcher.appendTail(buf); + return buf.toString(); + } +} --- a/src/jorphan/org/apache/jorphan/text/SimpleFormatter.java +++ a/src/jorphan/org/apache/jorphan/text/SimpleFormatter.java @@ -0,0 +1,26 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jorphan.text; + +public interface SimpleFormatter { + + public void format(StringBuilder sb, Object arg); + + public int argsNeeded(); +} --- a/src/jorphan/org/apache/jorphan/text/StaticFormatter.java +++ a/src/jorphan/org/apache/jorphan/text/StaticFormatter.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jorphan.text; + +public class StaticFormatter implements SimpleFormatter { + + private final String text; + + public StaticFormatter(final String text) { + this.text = text; + } + + @Override + public void format(StringBuilder sb, Object arg) { + sb.append(text); + } + + @Override + public int argsNeeded() { + return 0; + } + +} --- a/src/jorphan/org/apache/jorphan/text/StringFormatter.java +++ a/src/jorphan/org/apache/jorphan/text/StringFormatter.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jorphan.text; + +import java.util.function.Function; + +public class StringFormatter implements SimpleFormatter { + + Function transform; + + public StringFormatter() { + this(s -> s); + } + + public StringFormatter(Function transform) { + this.transform = transform; + } + + @Override + public void format(StringBuilder sb, Object arg) { + sb.append(transform.apply(arg == null ? "null" : arg.toString())); + } + + @Override + public int argsNeeded() { + return 1; + } + +} --- a/test/src/org/apache/jorphan/text/PreCompiledFormatterSpec.groovy +++ a/test/src/org/apache/jorphan/text/PreCompiledFormatterSpec.groovy @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jorphan.io + +import org.apache.jorphan.text.PreCompiledFormatter +import org.apache.jorphan.text.PreCompiledFormatterBuilder +import spock.lang.Specification +import spock.lang.Unroll + +@Unroll +class PreCompiledFormatterSpec extends Specification { + + def "empty format gives an empty string"() { + given: + def sut = PreCompiledFormatterBuilder.build("") + expect: + sut.format() == "" + } + + def "formats are the same as String.format"() { + given: + def sut = PreCompiledFormatterBuilder.build(format) + Object[] args = allArgs.toArray(new Object[0]) + expect: + sut.format(args) == String.format(format, args) + where: + format | allArgs + "Hello, %s!" | ['World'] + "%s-%s" | [42, 23] + "%s => %S" | ['aBc', 'aBc'] + "%s => %b" | [true, true] + } + +} --