From 0ea81a9b922584ce9bd50dd05939cce344b85be2 Mon Sep 17 00:00:00 2001 From: Jonathan Austin Date: Mon, 9 Sep 2024 15:28:38 +1000 Subject: [PATCH 01/10] Pickup latest qa-parent 1.0.21 --- CHANGELOG.md | 1 + pom.xml | 2 +- wcomponents-core/spotbugs-exclude-filter.xml | 5 +++++ .../bordertech/wcomponents/examples/TextDuplicator.java | 5 +++-- .../examples/layout/GridLayoutOptionsExample.java | 2 +- .../wcomponents/examples/table/FilterableTableExample.java | 4 ++-- 6 files changed, 13 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 35710e4d0..55d4f17d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # Change log ## Release in-progress +* Pickup latest qa-parent 1.0.21 ### API Changes ### Enhancements diff --git a/pom.xml b/pom.xml index 6895933ce..88fd3258a 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ com.github.bordertech.common qa-parent - 1.0.20 + 1.0.21 diff --git a/wcomponents-core/spotbugs-exclude-filter.xml b/wcomponents-core/spotbugs-exclude-filter.xml index ff0016a2b..1e622dce1 100644 --- a/wcomponents-core/spotbugs-exclude-filter.xml +++ b/wcomponents-core/spotbugs-exclude-filter.xml @@ -47,6 +47,11 @@ + + + + + diff --git a/wcomponents-examples/src/main/java/com/github/bordertech/wcomponents/examples/TextDuplicator.java b/wcomponents-examples/src/main/java/com/github/bordertech/wcomponents/examples/TextDuplicator.java index ab0a076c8..78a1520bb 100755 --- a/wcomponents-examples/src/main/java/com/github/bordertech/wcomponents/examples/TextDuplicator.java +++ b/wcomponents-examples/src/main/java/com/github/bordertech/wcomponents/examples/TextDuplicator.java @@ -43,6 +43,7 @@ public TextDuplicator(final String name) { /** * Add the controls to the UI. + * * @param labelText the text to show in the duplicator field's label. */ private void setupUI(final String labelText) { @@ -63,7 +64,7 @@ private void setupUI(final String labelText) { /** * An action implementation which duplicates the text in the text field. */ - private class DuplicateAction implements Action { + private final class DuplicateAction implements Action { /** * Executes the action which duplicates the text. @@ -83,7 +84,7 @@ public void execute(final ActionEvent event) { /** * An action implementation which clears the text in the text field. */ - private class ClearAction implements Action { + private final class ClearAction implements Action { /** * Executes the action which clears the text. diff --git a/wcomponents-examples/src/main/java/com/github/bordertech/wcomponents/examples/layout/GridLayoutOptionsExample.java b/wcomponents-examples/src/main/java/com/github/bordertech/wcomponents/examples/layout/GridLayoutOptionsExample.java index 9fe040172..041f9abbd 100755 --- a/wcomponents-examples/src/main/java/com/github/bordertech/wcomponents/examples/layout/GridLayoutOptionsExample.java +++ b/wcomponents-examples/src/main/java/com/github/bordertech/wcomponents/examples/layout/GridLayoutOptionsExample.java @@ -213,7 +213,7 @@ public void preparePaintComponent(final Request request) { * * @author Steve Harney */ - private class ControlFieldLayout extends WFieldLayout { + private final class ControlFieldLayout extends WFieldLayout { /** * {@inheritDoc} diff --git a/wcomponents-examples/src/main/java/com/github/bordertech/wcomponents/examples/table/FilterableTableExample.java b/wcomponents-examples/src/main/java/com/github/bordertech/wcomponents/examples/table/FilterableTableExample.java index 7b0c9d1eb..8f5a9ad09 100755 --- a/wcomponents-examples/src/main/java/com/github/bordertech/wcomponents/examples/table/FilterableTableExample.java +++ b/wcomponents-examples/src/main/java/com/github/bordertech/wcomponents/examples/table/FilterableTableExample.java @@ -320,7 +320,7 @@ private void buildFilterSubMenu(final WMenu menu, final int column) { * @author Mark Reeves */ @SuppressWarnings("serial") - private class FilterAction implements Action { + private final class FilterAction implements Action { /** * {@inheritDoc} @@ -338,7 +338,7 @@ public void execute(final ActionEvent event) { * @author Mark Reeves */ @SuppressWarnings("serial") - private class ClearFilterAction implements Action { + private final class ClearFilterAction implements Action { /** * {@inheritDoc} From 88cc711b681ced3ab3ff57408844719e33631459 Mon Sep 17 00:00:00 2001 From: Jonathan Austin Date: Mon, 9 Sep 2024 15:30:24 +1000 Subject: [PATCH 02/10] Turn on dependency checking for theme module --- wcomponents-theme/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wcomponents-theme/pom.xml b/wcomponents-theme/pom.xml index f2f5dc933..b522509ea 100755 --- a/wcomponents-theme/pom.xml +++ b/wcomponents-theme/pom.xml @@ -25,7 +25,7 @@ v16.14.1 8.5.0 v1.22.19 - true + true wcomponents-theme From 408e72f6f56bf32c44afc34958251fb353938823 Mon Sep 17 00:00:00 2001 From: Jonathan Austin Date: Tue, 10 Sep 2024 10:14:21 +1000 Subject: [PATCH 03/10] Removed dependency commons-htttpclient:3.0 due to security issue and added its URI percent encoding functionality to WebUtilities that is no longer provided in the latest version. --- CHANGELOG.md | 3 + wcomponents-core/pom.xml | 3 +- .../bordertech/wcomponents/WebUtilities.java | 134 +++++++++++++++++- 3 files changed, 134 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 55d4f17d9..c5a7b5884 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ ## Release in-progress * Pickup latest qa-parent 1.0.21 +* Removed dependency commons-htttpclient:3.0 due to a criticial security issue. HttpClient was only used by WebUtilities to percent encode URLs. + However, the latest version no longer provides the URI class that provided this functionality. + To provide the legacy functinality the encoding logic was put into WebUtilities. ### API Changes ### Enhancements diff --git a/wcomponents-core/pom.xml b/wcomponents-core/pom.xml index 87880bf58..cee82670e 100755 --- a/wcomponents-core/pom.xml +++ b/wcomponents-core/pom.xml @@ -238,11 +238,12 @@ 2.10.1 - + commons-httpclient commons-httpclient 3.1 + test diff --git a/wcomponents-core/src/main/java/com/github/bordertech/wcomponents/WebUtilities.java b/wcomponents-core/src/main/java/com/github/bordertech/wcomponents/WebUtilities.java index 357b3e44e..b01c058da 100755 --- a/wcomponents-core/src/main/java/com/github/bordertech/wcomponents/WebUtilities.java +++ b/wcomponents-core/src/main/java/com/github/bordertech/wcomponents/WebUtilities.java @@ -17,11 +17,11 @@ import java.io.StringWriter; import java.io.Writer; import java.net.URLConnection; +import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; import java.util.Date; import java.util.Map; import java.util.concurrent.atomic.AtomicLong; -import org.apache.commons.httpclient.URI; -import org.apache.commons.httpclient.util.URIUtil; import org.apache.commons.lang3.text.translate.AggregateTranslator; import org.apache.commons.lang3.text.translate.CharSequenceTranslator; import org.apache.commons.lang3.text.translate.CodePointTranslator; @@ -298,18 +298,142 @@ public static String encodeUrl(final String urlStr) { * @return the URL percent encoded */ public static String percentEncodeUrl(final String urlStr) { + if (Util.empty(urlStr)) { return urlStr; } try { // Avoid double encoding - String decode = URIUtil.decode(urlStr); - URI uri = new URI(decode, false); - return uri.getEscapedURIReference(); + String tmp = URLDecoder.decode(urlStr, StandardCharsets.UTF_8.name()); + // Encode as per legacy HttpClient URI class for backward compatability + String encoded = percentEncodeUrlLegacy(tmp); + // Check URL is valid + java.net.URI uri = new java.net.URI(encoded); + return uri.toString(); } catch (Exception e) { + throw new IllegalStateException("Could not percent encode URL [" + urlStr + "]", e); + } + } + + /** + * Percent encode a URL as per the HTTPClient URI class that handled unescaped URLs. + * + * @param urlStr the unescaped URL to encode + * @return the URL percent encoded + */ + private static String percentEncodeUrlLegacy(final String urlStr) { + + if (Util.empty(urlStr)) { return urlStr; } + + String tmp = urlStr.trim(); + + int at = 0; + int length = tmp.length(); + + StringBuilder url = new StringBuilder(); + + // Handle path + if (at < length) { + // Check for first delim (query or fragment) + int next = tmp.indexOf("?"); + if (next == -1) { + next = tmp.indexOf("#"); + } + // No delims + if (next == -1) { + next = length; + } + String path = tmp.substring(0, next); + url.append(path); + at = next; + } + + // Handle Query + if (at >= 0 && at + 1 < length && tmp.charAt(at) == '?') { + int next = tmp.indexOf('#', at + 1); + if (next == -1) { + next = tmp.length(); + } + String query = escapeForUrlLegacy(tmp.substring(at + 1, next)); + url.append("?").append(query); + at = next; + } + + // Handle Fragment + if (at >= 0 && at + 1 <= length && tmp.charAt(at) == '#') { + String fragment; + if (at + 1 == length) { + fragment = ""; + } else { + fragment = escapeForUrlLegacy(tmp.substring(at + 1)); + } + url.append("#").append(fragment); + } + return url.toString(); + } + + /** + * Escapes the given string as per the legacy HttpClient URI class. + * + * @param input the String to escape. + * @return an escaped copy of the string. + */ + private static String escapeForUrlLegacy(final String input) { + if (input == null || input.length() == 0) { + return input; + } + + final StringBuilder buffer = new StringBuilder(input.length() * 2); // worst-case + char[] characters = input.toCharArray(); + + for (int i = 0, len = input.length(); i < len; ++i) { + final char ch = characters[i]; + + // Unreserved chars from HTTPClient V3.1 URI + if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9') + || ch == '-' + || ch == '_' + || ch == '.' + || ch == '!' + || ch == '~' + || ch == '*' + || ch == '\'' + || ch == '(' + || ch == ')') { + buffer.append(ch); + // Reserved chars from HTTPClient V3.1 URI + } else if (ch == ';' + || ch == '/' + || ch == '?' + || ch == ':' + || ch == '@' + || ch == '&' + || ch == '=' + || ch == '+' + || ch == '$' + || ch == ',') { + buffer.append(ch); + } else if (ch <= 127) { // Other ASCII characters must be escaped + final String hexString = Integer.toHexString(ch).toUpperCase(); + if (hexString.length() == 1) { + buffer.append("%0").append(hexString); + } else { + buffer.append('%').append(hexString); + } + } else if (ch <= 0x07FF) { // Other non-ASCII chars must be UTF-8 encoded + buffer.append('%').append(Integer.toHexString(0xc0 | (ch >> 6)).toUpperCase()); + buffer.append('%').append(Integer.toHexString(0x80 | (ch & 0x3F)).toUpperCase()); + } else { + buffer.append('%').append(Integer.toHexString(0xe0 | (ch >> 12)).toUpperCase()); + buffer.append('%').append(Integer.toHexString(0x80 | ((ch >> 6) & 0x3F)).toUpperCase()); + buffer.append('%').append(Integer.toHexString(0x80 | (ch & 0x3F)).toUpperCase()); + } + } + + return buffer.toString(); } /** From 15c80daaf52b797535da2ef7cd4b8104666a8d30 Mon Sep 17 00:00:00 2001 From: Jonathan Austin Date: Tue, 10 Sep 2024 10:47:28 +1000 Subject: [PATCH 04/10] Removed the encodeURL and percentEncodeUrl from WebUtilities as encoding full URLs is unsafe and unreliable and should be done while constructing the URL. --- CHANGELOG.md | 7 +- wcomponents-core/pom.xml | 8 - .../bordertech/wcomponents/WebUtilities.java | 163 ------------------ .../wcomponents/WebUtilities_Test.java | 100 ----------- 4 files changed, 4 insertions(+), 274 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c5a7b5884..e854a6423 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,9 +2,10 @@ ## Release in-progress * Pickup latest qa-parent 1.0.21 -* Removed dependency commons-htttpclient:3.0 due to a criticial security issue. HttpClient was only used by WebUtilities to percent encode URLs. - However, the latest version no longer provides the URI class that provided this functionality. - To provide the legacy functinality the encoding logic was put into WebUtilities. +* Removed dependency commons-htttpclient:3.0 due to a security issue. HttpClient was only used by WebUtilities to + percent encode URLs. However, the latest version no longer provides the URI class that provided this functionality. + As encoding full URLs is unsafe and unreliable and should be done while constructing the URL, the encodeURL + and percentEncodeUrl methods have been removed from WebUtilities. ### API Changes ### Enhancements diff --git a/wcomponents-core/pom.xml b/wcomponents-core/pom.xml index cee82670e..d9fc0805b 100755 --- a/wcomponents-core/pom.xml +++ b/wcomponents-core/pom.xml @@ -238,14 +238,6 @@ 2.10.1 - - - commons-httpclient - commons-httpclient - 3.1 - test - - diff --git a/wcomponents-core/src/main/java/com/github/bordertech/wcomponents/WebUtilities.java b/wcomponents-core/src/main/java/com/github/bordertech/wcomponents/WebUtilities.java index b01c058da..512501bbe 100755 --- a/wcomponents-core/src/main/java/com/github/bordertech/wcomponents/WebUtilities.java +++ b/wcomponents-core/src/main/java/com/github/bordertech/wcomponents/WebUtilities.java @@ -17,8 +17,6 @@ import java.io.StringWriter; import java.io.Writer; import java.net.URLConnection; -import java.net.URLDecoder; -import java.nio.charset.StandardCharsets; import java.util.Date; import java.util.Map; import java.util.concurrent.atomic.AtomicLong; @@ -275,167 +273,6 @@ public static WComponent getTop(final WComponent comp) { return top; } - /** - * Encode URL for XML. - * - * @param urlStr the URL to escape - * @return the URL percent encoded - */ - public static String encodeUrl(final String urlStr) { - if (Util.empty(urlStr)) { - return urlStr; - } - // Percent Encode - String percentEncode = percentEncodeUrl(urlStr); - // XML Enocde - return encode(percentEncode); - } - - /** - * Percent encode a URL to include in HTML. - * - * @param urlStr the URL to escape - * @return the URL percent encoded - */ - public static String percentEncodeUrl(final String urlStr) { - - if (Util.empty(urlStr)) { - return urlStr; - } - - try { - // Avoid double encoding - String tmp = URLDecoder.decode(urlStr, StandardCharsets.UTF_8.name()); - // Encode as per legacy HttpClient URI class for backward compatability - String encoded = percentEncodeUrlLegacy(tmp); - // Check URL is valid - java.net.URI uri = new java.net.URI(encoded); - return uri.toString(); - } catch (Exception e) { - throw new IllegalStateException("Could not percent encode URL [" + urlStr + "]", e); - } - } - - /** - * Percent encode a URL as per the HTTPClient URI class that handled unescaped URLs. - * - * @param urlStr the unescaped URL to encode - * @return the URL percent encoded - */ - private static String percentEncodeUrlLegacy(final String urlStr) { - - if (Util.empty(urlStr)) { - return urlStr; - } - - String tmp = urlStr.trim(); - - int at = 0; - int length = tmp.length(); - - StringBuilder url = new StringBuilder(); - - // Handle path - if (at < length) { - // Check for first delim (query or fragment) - int next = tmp.indexOf("?"); - if (next == -1) { - next = tmp.indexOf("#"); - } - // No delims - if (next == -1) { - next = length; - } - String path = tmp.substring(0, next); - url.append(path); - at = next; - } - - // Handle Query - if (at >= 0 && at + 1 < length && tmp.charAt(at) == '?') { - int next = tmp.indexOf('#', at + 1); - if (next == -1) { - next = tmp.length(); - } - String query = escapeForUrlLegacy(tmp.substring(at + 1, next)); - url.append("?").append(query); - at = next; - } - - // Handle Fragment - if (at >= 0 && at + 1 <= length && tmp.charAt(at) == '#') { - String fragment; - if (at + 1 == length) { - fragment = ""; - } else { - fragment = escapeForUrlLegacy(tmp.substring(at + 1)); - } - url.append("#").append(fragment); - } - return url.toString(); - } - - /** - * Escapes the given string as per the legacy HttpClient URI class. - * - * @param input the String to escape. - * @return an escaped copy of the string. - */ - private static String escapeForUrlLegacy(final String input) { - if (input == null || input.length() == 0) { - return input; - } - - final StringBuilder buffer = new StringBuilder(input.length() * 2); // worst-case - char[] characters = input.toCharArray(); - - for (int i = 0, len = input.length(); i < len; ++i) { - final char ch = characters[i]; - - // Unreserved chars from HTTPClient V3.1 URI - if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9') - || ch == '-' - || ch == '_' - || ch == '.' - || ch == '!' - || ch == '~' - || ch == '*' - || ch == '\'' - || ch == '(' - || ch == ')') { - buffer.append(ch); - // Reserved chars from HTTPClient V3.1 URI - } else if (ch == ';' - || ch == '/' - || ch == '?' - || ch == ':' - || ch == '@' - || ch == '&' - || ch == '=' - || ch == '+' - || ch == '$' - || ch == ',') { - buffer.append(ch); - } else if (ch <= 127) { // Other ASCII characters must be escaped - final String hexString = Integer.toHexString(ch).toUpperCase(); - if (hexString.length() == 1) { - buffer.append("%0").append(hexString); - } else { - buffer.append('%').append(hexString); - } - } else if (ch <= 0x07FF) { // Other non-ASCII chars must be UTF-8 encoded - buffer.append('%').append(Integer.toHexString(0xc0 | (ch >> 6)).toUpperCase()); - buffer.append('%').append(Integer.toHexString(0x80 | (ch & 0x3F)).toUpperCase()); - } else { - buffer.append('%').append(Integer.toHexString(0xe0 | (ch >> 12)).toUpperCase()); - buffer.append('%').append(Integer.toHexString(0x80 | ((ch >> 6) & 0x3F)).toUpperCase()); - buffer.append('%').append(Integer.toHexString(0x80 | (ch & 0x3F)).toUpperCase()); - } - } - - return buffer.toString(); - } - /** * Escapes the given string to make it presentable in a URL. This follows RFC 3986, with some extensions for UTF-8. * diff --git a/wcomponents-core/src/test/java/com/github/bordertech/wcomponents/WebUtilities_Test.java b/wcomponents-core/src/test/java/com/github/bordertech/wcomponents/WebUtilities_Test.java index 33c73d424..d4b8fd57d 100755 --- a/wcomponents-core/src/test/java/com/github/bordertech/wcomponents/WebUtilities_Test.java +++ b/wcomponents-core/src/test/java/com/github/bordertech/wcomponents/WebUtilities_Test.java @@ -11,7 +11,6 @@ import java.util.List; import java.util.Map; import org.junit.Assert; -import org.apache.commons.httpclient.util.URIUtil; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; @@ -594,92 +593,6 @@ public void testRenderToHtmlWithXML() { String output = WebUtilities.renderWithTransformToHTML(new MockRequest(), text, false); Assert.assertEquals("Invalid html output with XML", TransformXMLTestHelper.EXPECTED, output); } - @Test - public void testEscapeUrlBasic() { - String in = "http://test.com"; - Assert.assertEquals("Basic url not escaped correctly", in, WebUtilities.percentEncodeUrl(in)); - } - - @Test - public void testEscapeUrlBasic2() { - String in = "http://test.com/"; - Assert.assertEquals("Basic url not escaped correctly", in, WebUtilities.percentEncodeUrl(in)); - } - - @Test - public void testEscapeUrlBasicParameters() { - String in = "http://test.com?a=foo"; - Assert.assertEquals("Basic url not escaped correctly", in, WebUtilities.percentEncodeUrl(in)); - } - - @Test - public void testEscapeUrlBasicParameters2() { - String parms = "a=foo&b=g h j"; - String in = "http://test.com?" + parms; - String out = "http://test.com?" + encodeQuery(parms); - Assert.assertEquals("Basic url not escaped correctly", out, WebUtilities.percentEncodeUrl(in)); - } - - @Test - public void testEscapeUrlBasicParameters3() { - String parms = "a=foo&b=<>{{}}"; - String in = "http://test.com?" + parms; - String out = "http://test.com?" + encodeQuery(parms); - Assert.assertEquals("Basic url not escaped correctly", out, WebUtilities.percentEncodeUrl(in)); - } - - @Test - public void testEscapeUrlRelBasic() { - String in = "rel/"; - Assert.assertEquals("Basic url not escaped correctly", in, WebUtilities.percentEncodeUrl(in)); - } - - @Test - public void testEscapeUrlRelBasicParameters() { - String in = "rel?a=foo"; - Assert.assertEquals("Basic url not escaped correctly", in, WebUtilities.percentEncodeUrl(in)); - } - - @Test - public void testEscapeUrlRelBasicParameters2() { - String parms = "a=foo&b=g h j"; - String in = "rel?" + parms; - String out = "rel?" + encodeQuery(parms); - Assert.assertEquals("Basic url not escaped correctly", out, WebUtilities.percentEncodeUrl(in)); - } - - @Test - public void testEscapeUrlRelBasicParameters3() { - String parms = "a=foo&b=<>{{}}"; - String in = "rel?" + parms; - String out = "rel?" + encodeQuery(parms); - Assert.assertEquals("Basic url not escaped correctly", out, WebUtilities.percentEncodeUrl(in)); - } - - @Test - public void testEscapeUrlRef() { - String in = "#REF1"; - Assert.assertEquals("Basic Reference not escaped correctly", in, WebUtilities.percentEncodeUrl(in)); - } - - @Test - public void testEscapeUrlRef2() { - String in = "rel?#REF1"; - Assert.assertEquals("Basic Reference not escaped correctly", in, WebUtilities.percentEncodeUrl(in)); - } - - @Test - public void testEscapeUrlRef3() { - String in = "rel?a=foo#REF1"; - Assert.assertEquals("Basic Reference not escaped correctly", in, WebUtilities.percentEncodeUrl(in)); - } - - @Test - public void testEncodeUrl() { - String in = "http://test.com?a=foo&b=<>{}#REF1"; - String out = "http://test.com?a=foo&b=%3C%3E%7B%7D#REF1"; - Assert.assertEquals("Encoded URL not correct", out, WebUtilities.encodeUrl(in)); - } // @Test // public void testContainsBrackets() { @@ -764,19 +677,6 @@ public void testDoubleDecodeBracketsWithNoMatches() { Assert.assertEquals("Double decode brackets not correct", out, WebUtilities.doubleDecodeBrackets(in)); } - /** - * - * @param input the query string input - * @return the percent encoded query string - */ - private String encodeQuery(final String input) { - try { - return URIUtil.encodeQuery(input); - } catch (Exception e) { - throw new IllegalStateException("Could not encode input string [" + input + "]."); - } - } - /** * Generates a range of characters. * @param from The first character in the range (must be > 0). From 34716e99150eea0ab68080723402a2f099d660a4 Mon Sep 17 00:00:00 2001 From: Jonathan Austin Date: Tue, 10 Sep 2024 14:29:54 +1000 Subject: [PATCH 05/10] Update ExampleSeleniumTest to pass latest pmd rules --- .../wcomponents/test/example/ExampleSeleniumTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wcomponents-test-lib/src/main/java/com/github/bordertech/wcomponents/test/example/ExampleSeleniumTest.java b/wcomponents-test-lib/src/main/java/com/github/bordertech/wcomponents/test/example/ExampleSeleniumTest.java index f3d9e76bd..ddcffa0c0 100755 --- a/wcomponents-test-lib/src/main/java/com/github/bordertech/wcomponents/test/example/ExampleSeleniumTest.java +++ b/wcomponents-test-lib/src/main/java/com/github/bordertech/wcomponents/test/example/ExampleSeleniumTest.java @@ -319,7 +319,7 @@ WButton getClearButton() { /** * An extension of the text duplicator example which exposes the fields. */ - private static class TextDuplicatorWithGetters extends TextDuplicator { + private static final class TextDuplicatorWithGetters extends TextDuplicator { /** * @return the text field. From 2150bde3202a6a4f48a8faeaafad1da47f882a67 Mon Sep 17 00:00:00 2001 From: Jonathan Austin Date: Tue, 10 Sep 2024 15:56:23 +1000 Subject: [PATCH 06/10] Update project dependencies to current versions --- CHANGELOG.md | 1 + pom.xml | 43 ++++++++++++++++++++++++-------- wcomponents-core/pom.xml | 14 +++++------ wcomponents-examples-lde/pom.xml | 2 +- wcomponents-examples/pom.xml | 2 +- wcomponents-test-lib/pom.xml | 7 +----- wcomponents-xslt/pom.xml | 4 +-- 7 files changed, 45 insertions(+), 28 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e854a6423..5ac0d59f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ percent encode URLs. However, the latest version no longer provides the URI class that provided this functionality. As encoding full URLs is unsafe and unreliable and should be done while constructing the URL, the encodeURL and percentEncodeUrl methods have been removed from WebUtilities. +* Update project dependencies to current versions ### API Changes ### Enhancements diff --git a/pom.xml b/pom.xml index 88fd3258a..7bbea89db 100644 --- a/pom.xml +++ b/pom.xml @@ -92,12 +92,12 @@ org.slf4j slf4j-api - 2.0.12 + 2.0.16 org.slf4j slf4j-simple - 2.0.12 + 2.0.16 @@ -105,7 +105,7 @@ commons-logging commons-logging - 1.3.0 + 1.3.4 commons-collections @@ -115,7 +115,7 @@ commons-io commons-io - 2.15.1 + 2.16.1 commons-lang @@ -125,17 +125,17 @@ org.apache.commons commons-lang3 - 3.14.0 + 3.17.0 org.apache.commons commons-compress - 1.26.1 + 1.27.1 commons-codec commons-codec - 1.16.1 + 1.17.1 xml-apis @@ -173,17 +173,38 @@ org.apache.httpcomponents.core5 httpcore5 - 5.2.4 + 5.2.5 org.apache.httpcomponents.core5 httpcore5-h2 - 5.2.4 + 5.2.5 com.google.guava guava - 33.1.0-jre + 33.3.0-jre + + + com.google.errorprone + error_prone_annotations + 2.31.0 + + + + + + + + org.owasp.antisamy + antisamy + 1.6.8 + + + + net.sourceforge.htmlunit + neko-htmlunit + 2.70.0 @@ -267,7 +288,7 @@ org.apache.ant ant - 1.10.12 + 1.10.15 diff --git a/wcomponents-core/pom.xml b/wcomponents-core/pom.xml index d9fc0805b..293c1cf65 100755 --- a/wcomponents-core/pom.xml +++ b/wcomponents-core/pom.xml @@ -235,16 +235,12 @@ com.google.code.gson gson - 2.10.1 + 2.11.0 - - - org.owasp.antisamy antisamy - 1.6.8 org.apache.xmlgraphics @@ -256,6 +252,10 @@ xercesImpl runtime + + net.sourceforge.htmlunit + neko-htmlunit + @@ -267,13 +267,13 @@ com.github.spullara.mustache.java compiler - 0.9.11 + 0.9.14 org.apache.tika tika-core - 2.9.1 + 2.9.2 diff --git a/wcomponents-examples-lde/pom.xml b/wcomponents-examples-lde/pom.xml index 71e886b6a..5856d2fb7 100755 --- a/wcomponents-examples-lde/pom.xml +++ b/wcomponents-examples-lde/pom.xml @@ -60,7 +60,7 @@ org.apache.maven.plugins maven-shade-plugin - 3.2.1 + 3.6.0 package diff --git a/wcomponents-examples/pom.xml b/wcomponents-examples/pom.xml index 5c9010ffc..b7e9cf891 100755 --- a/wcomponents-examples/pom.xml +++ b/wcomponents-examples/pom.xml @@ -61,7 +61,7 @@ commons-validator commons-validator - 1.8.0 + 1.9.0 diff --git a/wcomponents-test-lib/pom.xml b/wcomponents-test-lib/pom.xml index 31ed5c7c1..18bffb2a0 100755 --- a/wcomponents-test-lib/pom.xml +++ b/wcomponents-test-lib/pom.xml @@ -68,7 +68,7 @@ io.github.bonigarcia webdrivermanager - 5.7.0 + 5.9.2 @@ -83,11 +83,6 @@ compile - - org.apache.httpcomponents - httpclient - 4.5.14 - diff --git a/wcomponents-xslt/pom.xml b/wcomponents-xslt/pom.xml index fb46bcce2..d39b64ca1 100644 --- a/wcomponents-xslt/pom.xml +++ b/wcomponents-xslt/pom.xml @@ -25,7 +25,7 @@ maven-assembly-plugin - 3.3.0 + 3.7.1 package @@ -77,7 +77,7 @@ net.sf.saxon Saxon-HE - 11.3 + 12.5 From 26454e7bce5552073e50e6997fe3f731301bebdd Mon Sep 17 00:00:00 2001 From: Jonathan Austin Date: Tue, 10 Sep 2024 16:14:54 +1000 Subject: [PATCH 07/10] Update theme dependencies to current versions --- CHANGELOG.md | 1 + wcomponents-theme/package.json | 12 ++++++------ wcomponents-theme/pom.xml | 4 ++-- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5ac0d59f9..777d98165 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ As encoding full URLs is unsafe and unreliable and should be done while constructing the URL, the encodeURL and percentEncodeUrl methods have been removed from WebUtilities. * Update project dependencies to current versions +* Update theme dependencies to current versions ### API Changes ### Enhancements diff --git a/wcomponents-theme/package.json b/wcomponents-theme/package.json index ca862446e..4e3987d69 100644 --- a/wcomponents-theme/package.json +++ b/wcomponents-theme/package.json @@ -27,16 +27,16 @@ "target": "target" }, "dependencies": { - "dojo": "1.15.3", + "dojo": "1.17.3", "fabric": "3.4.0", "getusermedia-js": "1.0.0", - "i18next": "23.5.1", + "i18next": "23.14.0", "mailcheck": "1.1.1", "mustache": "2.3.0", - "promise-polyfill": "8.1.3", - "requirejs": "2.3.6", - "sprintf-js": "1.1.2", - "tinymce": "6.3.1" + "promise-polyfill": "8.3.0", + "requirejs": "2.3.7", + "sprintf-js": "1.1.3", + "tinymce": "6.8.4" }, "devDependencies": { "@babel/cli": "7.20.7", diff --git a/wcomponents-theme/pom.xml b/wcomponents-theme/pom.xml index b522509ea..df39aa9ac 100755 --- a/wcomponents-theme/pom.xml +++ b/wcomponents-theme/pom.xml @@ -32,7 +32,7 @@ maven-assembly-plugin - 3.3.0 + 3.7.1 package @@ -51,7 +51,7 @@ com.github.eirslett frontend-maven-plugin - 1.8.0 + 1.15.0 ${basedir} From fe3572b37819c715b302ffa63eb64902d2c800e7 Mon Sep 17 00:00:00 2001 From: Jonathan Austin Date: Tue, 10 Sep 2024 16:33:06 +1000 Subject: [PATCH 08/10] Remove owasp suppression files --- owasp-jetty-suppression.xml | 32 ------------------- owasp-velocity-suppression.xml | 7 ---- wcomponents-bundle/pom.xml | 4 --- wcomponents-core/pom.xml | 1 - wcomponents-examples-lde/pom.xml | 1 - wcomponents-examples/pom.xml | 1 - wcomponents-lde/pom.xml | 1 - wcomponents-test-lib/pom.xml | 1 - .../test-lib-owasp-suppression.xml | 18 ----------- 9 files changed, 66 deletions(-) delete mode 100644 owasp-jetty-suppression.xml delete mode 100644 owasp-velocity-suppression.xml delete mode 100644 wcomponents-test-lib/test-lib-owasp-suppression.xml diff --git a/owasp-jetty-suppression.xml b/owasp-jetty-suppression.xml deleted file mode 100644 index 00b44ac79..000000000 --- a/owasp-jetty-suppression.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - CVE-2017-7656 - - - - CVE-2019-10241 - - - - CVE-2019-10247 - - - - CVE-2017-7658 - - - - CVE-2017-9735 - - - - CVE-2017-7657 - - - - CVE-2019-10247 - - diff --git a/owasp-velocity-suppression.xml b/owasp-velocity-suppression.xml deleted file mode 100644 index 7c92268e7..000000000 --- a/owasp-velocity-suppression.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - CVE-2020-13936 - - diff --git a/wcomponents-bundle/pom.xml b/wcomponents-bundle/pom.xml index f2e8b3d1c..c2abd1c7c 100755 --- a/wcomponents-bundle/pom.xml +++ b/wcomponents-bundle/pom.xml @@ -22,10 +22,6 @@ and client-side artefacts. - - ${project.parent.basedir}/owasp-velocity-suppression.xml - - com.github.bordertech.wcomponents diff --git a/wcomponents-core/pom.xml b/wcomponents-core/pom.xml index 293c1cf65..5b3abdbbd 100755 --- a/wcomponents-core/pom.xml +++ b/wcomponents-core/pom.xml @@ -20,7 +20,6 @@ ${basedir}/spotbugs-exclude-filter.xml - ${project.parent.basedir}/owasp-velocity-suppression.xml diff --git a/wcomponents-examples-lde/pom.xml b/wcomponents-examples-lde/pom.xml index 5856d2fb7..963204a45 100755 --- a/wcomponents-examples-lde/pom.xml +++ b/wcomponents-examples-lde/pom.xml @@ -31,7 +31,6 @@ ${basedir}/checkstyle-exclude.xml - ${project.parent.basedir}/owasp-jetty-suppression.xml,${project.parent.basedir}/owasp-velocity-suppression.xml diff --git a/wcomponents-examples/pom.xml b/wcomponents-examples/pom.xml index b7e9cf891..fca08ac24 100755 --- a/wcomponents-examples/pom.xml +++ b/wcomponents-examples/pom.xml @@ -47,7 +47,6 @@ ${basedir}/pmd-excludes.properties true - ${project.parent.basedir}/owasp-velocity-suppression.xml diff --git a/wcomponents-lde/pom.xml b/wcomponents-lde/pom.xml index 41fa413c4..25d0deed2 100755 --- a/wcomponents-lde/pom.xml +++ b/wcomponents-lde/pom.xml @@ -30,7 +30,6 @@ ${basedir}/spotbugs-exclude-filter.xml - ${project.parent.basedir}/owasp-jetty-suppression.xml,${project.parent.basedir}/owasp-velocity-suppression.xml diff --git a/wcomponents-test-lib/pom.xml b/wcomponents-test-lib/pom.xml index 18bffb2a0..d8113868c 100755 --- a/wcomponents-test-lib/pom.xml +++ b/wcomponents-test-lib/pom.xml @@ -16,7 +16,6 @@ ${basedir}/spotbugs-exclude-filter.xml - ${project.parent.basedir}/owasp-jetty-suppression.xml,${basedir}/test-lib-owasp-suppression.xml,${project.parent.basedir}/owasp-velocity-suppression.xml 3.141.59 diff --git a/wcomponents-test-lib/test-lib-owasp-suppression.xml b/wcomponents-test-lib/test-lib-owasp-suppression.xml deleted file mode 100644 index c8bc29693..000000000 --- a/wcomponents-test-lib/test-lib-owasp-suppression.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - CVE-2018-10237 - - - - CVE-2015-2156 - - - - CVE-2014-3488 - - From 5094c8827ff77459ec1402eb69d345cae0dc93ba Mon Sep 17 00:00:00 2001 From: Jonathan Austin Date: Fri, 13 Sep 2024 16:57:26 +1000 Subject: [PATCH 09/10] Fixed bug in DefaultInternalConfiguration subset method that was not removing the prefix key of the matched properties and was not behaving as described in the interface javadoc. --- CHANGELOG.md | 3 ++ .../util/DefaultInternalConfiguration.java | 29 +++++++++----- .../DefaultInternalConfiguration_Test.java | 40 +++++++++++++++++++ ...faultInternalConfiguration_Test.properties | 4 ++ 4 files changed, 66 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 777d98165..2ee0b4151 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,9 @@ and percentEncodeUrl methods have been removed from WebUtilities. * Update project dependencies to current versions * Update theme dependencies to current versions +* Fixed bug in DefaultInternalConfiguration subset method that was not removing the prefix key of the matched properties + in the returned Configuration. The subset method now uses the SubsetConfiguration class to implement the correct + behaviour as described in the subset method interface javadoc. ### API Changes ### Enhancements diff --git a/wcomponents-core/src/main/java/com/github/bordertech/wcomponents/util/DefaultInternalConfiguration.java b/wcomponents-core/src/main/java/com/github/bordertech/wcomponents/util/DefaultInternalConfiguration.java index c69cadfa2..e0f1ca9ae 100755 --- a/wcomponents-core/src/main/java/com/github/bordertech/wcomponents/util/DefaultInternalConfiguration.java +++ b/wcomponents-core/src/main/java/com/github/bordertech/wcomponents/util/DefaultInternalConfiguration.java @@ -27,8 +27,9 @@ import java.util.Stack; import java.util.StringTokenizer; import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationMap; import org.apache.commons.configuration.ConversionException; -import org.apache.commons.configuration.MapConfiguration; +import org.apache.commons.configuration.SubsetConfiguration; /** *

@@ -86,7 +87,7 @@ final class DefaultInternalConfiguration implements Configuration { * Parameters with this prefix will be dumped into the System parameters. This feature is for handling recalcitrant * 3rd party software only - not for general use!!! */ - private static final String SYSTEM_PARAMETERS_PREFIX = "bordertech.wcomponents.parameters.system."; + private static final String SYSTEM_PARAMETERS_PREFIX = "bordertech.wcomponents.parameters.system"; // ----------------------------------------------------------------------------------------------------------------- // State used during loading of parameters @@ -94,7 +95,7 @@ final class DefaultInternalConfiguration implements Configuration { * The messages logged during loading of the configuration. We can't depend on a logging framework to log errors, as * this class is typically used to configure the logging. */ - private final StringBuffer messages = new StringBuffer(); + private final StringBuilder messages = new StringBuilder(); /** * The resource being loaded. This is used for the relative form of resource loading. @@ -156,9 +157,7 @@ protected DefaultInternalConfiguration(final String resourceName) { initialiseInstanceVariables(); loadTop(resourceName); - // Now perform variable substitution. - do { - } while (substitute()); + handleLoadedProperties(); } /** @@ -264,6 +263,14 @@ private void load() { load(System.getProperties(), "System Properties", true); } + handleLoadedProperties(); + } + + /** + * Handle processing the loaded properties. + */ + private void handleLoadedProperties() { + // Now perform variable substitution. do { // Do nothing while loop @@ -279,8 +286,8 @@ private void load() { clearMessages(); // Now move any parameters with the system parameters prefix into the real system parameters. - Properties systemProperties = getSubProperties(SYSTEM_PARAMETERS_PREFIX, true); - System.getProperties().putAll(systemProperties); + Configuration subset = subset(SYSTEM_PARAMETERS_PREFIX); + System.getProperties().putAll(new ConfigurationMap(subset)); } /** @@ -315,7 +322,7 @@ protected String getDebuggingInfo() { // Okay } - StringBuffer info = new StringBuffer(); + StringBuilder info = new StringBuilder(); info.append("----Parameters start----"); info.append(codesourceStr); @@ -630,7 +637,9 @@ private void clearMessages() { * @param prefix the prefix of the parameter keys which should be included. * @param truncate if true, the prefix is truncated in the returned properties. * @return the properties sub-set, may be empty. + * @deprecated Use {@link #subset(java.lang.String)} instead */ + @Deprecated public Properties getSubProperties(final String prefix, final boolean truncate) { String cacheKey = truncate + prefix; Properties sub = subcontextCache.get(cacheKey); @@ -1416,6 +1425,6 @@ public void setProperty(final String key, final Object value) { */ @Override public Configuration subset(final String prefix) { - return new MapConfiguration(getSubProperties(prefix, false)); + return new SubsetConfiguration(this, prefix, "."); } } diff --git a/wcomponents-core/src/test/java/com/github/bordertech/wcomponents/util/DefaultInternalConfiguration_Test.java b/wcomponents-core/src/test/java/com/github/bordertech/wcomponents/util/DefaultInternalConfiguration_Test.java index 50362d87b..35fc79f62 100755 --- a/wcomponents-core/src/test/java/com/github/bordertech/wcomponents/util/DefaultInternalConfiguration_Test.java +++ b/wcomponents-core/src/test/java/com/github/bordertech/wcomponents/util/DefaultInternalConfiguration_Test.java @@ -5,7 +5,9 @@ import java.util.Arrays; import java.util.List; import java.util.Properties; +import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConversionException; +import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -65,10 +67,18 @@ public class DefaultInternalConfiguration_Test { @Before public void loadProperties() { + clearProperties(); config = new DefaultInternalConfiguration( "com/github/bordertech/wcomponents/util/DefaultInternalConfiguration_Test.properties"); } + @After + public void clearProperties(){ + // Clear test system properties + System.getProperties().remove("testSystem1"); + System.getProperties().remove("testSystem2"); + } + @Test public void testSimpleProperties() { Assert.assertNull("Missing properties should be null", config.get( @@ -350,6 +360,36 @@ public void testGetProperties() { assertPropertyEquals("key3", "value3", props); } + @Test + public void testSubset() { + + // Setup properties to test behaviour as described in subset javadoc + config.addProperty("testprefix.number", "1"); + config.addProperty("testprefix.string", "Apache"); + config.addProperty("testprefixed.foo", "bar"); + config.addProperty("testprefix", "Jakarta"); + + // Create subset + Configuration subset = config.subset("testprefix"); + + // Check subset keys exist + Assert.assertTrue("Should contain number key", subset.containsKey("number")); + Assert.assertTrue("Should contain string key", subset.containsKey("string")); + Assert.assertFalse("Should not contain foo key", subset.containsKey("foo")); + Assert.assertTrue("Should contain empty key", subset.containsKey("")); + // Check values + Assert.assertEquals("Invalid number key value", "1", subset.getProperty("number")); + Assert.assertEquals("Invalid string key value", "Apache", subset.getProperty("string")); + Assert.assertEquals("Invalid empty key value", "Jakarta", subset.getProperty("")); + } + + @Test + public void testSystemParameters(){ + // Check system properties were loaded + Assert.assertEquals("Invalid value for system key testSystem1", "foo", System.getProperties().getProperty("testSystem1")); + Assert.assertEquals("Invalid value for system key testSystem2", "bar", System.getProperties().getProperty("testSystem2")); + } + /** * Asserts that the configuration contains the given key/value. * diff --git a/wcomponents-core/src/test/resources/com/github/bordertech/wcomponents/util/DefaultInternalConfiguration_Test.properties b/wcomponents-core/src/test/resources/com/github/bordertech/wcomponents/util/DefaultInternalConfiguration_Test.properties index d888a7032..fcd15b81e 100755 --- a/wcomponents-core/src/test/resources/com/github/bordertech/wcomponents/util/DefaultInternalConfiguration_Test.properties +++ b/wcomponents-core/src/test/resources/com/github/bordertech/wcomponents/util/DefaultInternalConfiguration_Test.properties @@ -66,3 +66,7 @@ includeAfter=com/github/bordertech/wcomponents/util/DefaultInternalConfiguration # This property is defined in the includeAfter but redefined here. The includeAfter definition should be effective. test.definedAfterIncludeAfter=mainValue + +# Test loading system properties +bordertech.wcomponents.parameters.system.testSystem1 = foo +bordertech.wcomponents.parameters.system.testSystem2 = bar From 3c02544339b5d4b8634d6f8d0f053b5e34dbfee7 Mon Sep 17 00:00:00 2001 From: Jonathan Austin Date: Fri, 13 Sep 2024 17:26:57 +1000 Subject: [PATCH 10/10] Update velocity from 1.5 to 2.3 and include support for backward compatability. --- CHANGELOG.md | 7 +++ wcomponents-core/pom.xml | 6 +- .../template/VelocityCacheImpl.java | 20 ++----- .../template/VelocityRendererImpl.java | 28 ++++----- .../util/ConfigurationProperties.java | 44 ++++++++++++++ .../velocity/VelocityEngineFactory.java | 29 ++++------ .../wcomponents/velocity/VelocityLogger.java | 57 ------------------- .../bordertech/wcomponents/web.properties | 22 +++++++ 8 files changed, 108 insertions(+), 105 deletions(-) delete mode 100755 wcomponents-core/src/main/java/com/github/bordertech/wcomponents/velocity/VelocityLogger.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ee0b4151..cc4984b33 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,13 @@ * Fixed bug in DefaultInternalConfiguration subset method that was not removing the prefix key of the matched properties in the returned Configuration. The subset method now uses the SubsetConfiguration class to implement the correct behaviour as described in the subset method interface javadoc. +* Updated velocity version from 1.5 to 2.3 due to security vulnerabilities. + * Removed the custom VelocityLogger class as version 2.3 now uses SLF4J. + * Version 2.3 allows for backward compatability properties to be set for version 1.5 and 1.7. The VeloctityRenderImpl + and VelocityEngineFactory classes have been updated to set these properties by default. This can be disabled by setting + runtime property "bordertech.wcomponents.velocity.backward17.enabled=false". These backward compatability properties + use a prefix of "bt.velocity.backward17.*" in web.properties. Refer to https://velocity.apache.org/engine/2.3/upgrading.html. + * Additional velocity initilisation properties can also be set by using runtime properties with the prefix "bt.velocity.app.*". ### API Changes ### Enhancements diff --git a/wcomponents-core/pom.xml b/wcomponents-core/pom.xml index 5b3abdbbd..cc64abf08 100755 --- a/wcomponents-core/pom.xml +++ b/wcomponents-core/pom.xml @@ -207,9 +207,9 @@ - velocity - velocity - 1.5 + org.apache.velocity + velocity-engine-core + 2.3 diff --git a/wcomponents-core/src/main/java/com/github/bordertech/wcomponents/template/VelocityCacheImpl.java b/wcomponents-core/src/main/java/com/github/bordertech/wcomponents/template/VelocityCacheImpl.java index 35609d0f1..69e45bd9d 100644 --- a/wcomponents-core/src/main/java/com/github/bordertech/wcomponents/template/VelocityCacheImpl.java +++ b/wcomponents-core/src/main/java/com/github/bordertech/wcomponents/template/VelocityCacheImpl.java @@ -25,42 +25,32 @@ public class VelocityCacheImpl implements ResourceCache { */ private static final String CACHE_NAME = "wc-velocity-templates"; - /** - * {@inheritDoc} - */ @Override public void initialize(final RuntimeServices rs) { // Do nothing } - /** - * {@inheritDoc} - */ + @Override + public void clear() { + getCache().clear(); + } + @Override public Resource get(final Object resourceKey) { return getCache().get(resourceKey); } - /** - * {@inheritDoc} - */ @Override public Resource put(final Object resourceKey, final Resource resource) { getCache().put(resourceKey, resource); return resource; } - /** - * {@inheritDoc} - */ @Override public Resource remove(final Object resourceKey) { return getCache().getAndRemove(resourceKey); } - /** - * {@inheritDoc} - */ @Override public Iterator enumerateKeys() { return getCache().iterator(); diff --git a/wcomponents-core/src/main/java/com/github/bordertech/wcomponents/template/VelocityRendererImpl.java b/wcomponents-core/src/main/java/com/github/bordertech/wcomponents/template/VelocityRendererImpl.java index 2edef7986..bb57c1ca3 100644 --- a/wcomponents-core/src/main/java/com/github/bordertech/wcomponents/template/VelocityRendererImpl.java +++ b/wcomponents-core/src/main/java/com/github/bordertech/wcomponents/template/VelocityRendererImpl.java @@ -7,6 +7,7 @@ import com.github.bordertech.wcomponents.util.SystemException; import java.io.Writer; import java.util.Map; +import java.util.Properties; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.velocity.Template; @@ -14,6 +15,7 @@ import org.apache.velocity.app.VelocityEngine; import org.apache.velocity.exception.ResourceNotFoundException; import org.apache.velocity.runtime.RuntimeConstants; +import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader; /** * Velocity template renderer. @@ -119,32 +121,32 @@ public void renderInline(final String templateInline, final Map */ public static synchronized VelocityEngine getVelocityEngine() { if (engine == null) { - VelocityEngine newEngine = new VelocityEngine(); + Properties props = new Properties(); // Class Loader - newEngine.addProperty("resource.loader", "class"); - newEngine.addProperty("class.resource.loader.class", - "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader"); + props.setProperty("resource.loader", "class"); + props.setProperty("class.resource.loader.class", ClasspathResourceLoader.class.getName()); // Caching if (isCaching()) { - newEngine.addProperty("class.resource.loader.cache", "true"); - newEngine.addProperty(RuntimeConstants.RESOURCE_MANAGER_CACHE_CLASS, - "com.github.bordertech.wcomponents.template.VelocityCacheImpl"); + props.setProperty("class.resource.loader.cache", "true"); + props.setProperty(RuntimeConstants.RESOURCE_MANAGER_CACHE_CLASS, VelocityCacheImpl.class.getName()); } else { - newEngine.addProperty("class.resource.loader.cache", "false"); + props.setProperty("class.resource.loader.cache", "false"); } - // Logging - newEngine.addProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS, - "com.github.bordertech.wcomponents.velocity.VelocityLogger"); + // Backwards compatability properties (if enabled) + if (ConfigurationProperties.isVelocityBackwardCompatability17Enabled()) { + props.putAll(ConfigurationProperties.getVelocityBackwardCompatability17Properties()); + } + // Project custom properties (if set) + props.putAll(ConfigurationProperties.getVelocityCustomProperties()); try { - newEngine.init(); + engine = new VelocityEngine(props); } catch (Exception ex) { throw new SystemException("Failed to configure VelocityEngine", ex); } - engine = newEngine; } return engine; diff --git a/wcomponents-core/src/main/java/com/github/bordertech/wcomponents/util/ConfigurationProperties.java b/wcomponents-core/src/main/java/com/github/bordertech/wcomponents/util/ConfigurationProperties.java index bc0cb8006..c2abecb87 100644 --- a/wcomponents-core/src/main/java/com/github/bordertech/wcomponents/util/ConfigurationProperties.java +++ b/wcomponents-core/src/main/java/com/github/bordertech/wcomponents/util/ConfigurationProperties.java @@ -1,8 +1,10 @@ package com.github.bordertech.wcomponents.util; import java.text.MessageFormat; +import java.util.Map; import java.util.Properties; import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationMap; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; @@ -329,6 +331,21 @@ public final class ConfigurationProperties { */ public static final String VELOCITY_MACRO_LIBRARY = "bordertech.wcomponents.velocity.macroLibrary"; + /** + * The flag indicating whether to load backward comptability properties for velocity version 1.7. + */ + public static final String VELOCITY_BACKWARD_COMPATABILITY_17_ENABLED = "bordertech.wcomponents.velocity.backward17.enabled"; + + /** + * The parameters prefix for backward compatability properties for velocity version 1.7. + */ + public static final String VELOCITY_BACKWARD_COMPATABILITY_17_PROPERTIES_PREFIX = "bt.velocity.backward17"; + + /** + * The parameters prefix for custom velocity properties. + */ + public static final String VELOCITY_CUSTOM_PROPERTIES_PREFIX = "bt.velocity.app"; + /** * Whether to perform server-side XSLT. * @@ -1165,6 +1182,33 @@ public static boolean getDeveloperVelocityDebug() { return get().getBoolean(DEVELOPER_VELOCITY_DEBUG, false); } + /** + * The flag indicating whether to load backward compatability properties for velocity version 1.7. + * + * @return the parameter value, or true if not set + */ + public static boolean isVelocityBackwardCompatability17Enabled() { + return get().getBoolean(VELOCITY_BACKWARD_COMPATABILITY_17_ENABLED, true); + } + + /** + * The map of backward compatability properties for velocity version 1.7 prefixed with {@link #VELOCITY_BACKWARD_COMPATABILITY_17_PROPERTIES_PREFIX}. + * + * @return the map of backward compatability properties. + */ + public static Map getVelocityBackwardCompatability17Properties() { + return new ConfigurationMap(get().subset(VELOCITY_BACKWARD_COMPATABILITY_17_PROPERTIES_PREFIX)); + } + + /** + * The optional map of custom properties for velocity prefixed with {@link #VELOCITY_CUSTOM_PROPERTIES_PREFIX}. + * + * @return the map of custom properties for velocity. + */ + public static Map getVelocityCustomProperties() { + return new ConfigurationMap(get().subset(VELOCITY_CUSTOM_PROPERTIES_PREFIX)); + } + /* **************************** * LDE PROPERTIES - used for running the LDE. * *****************************/ diff --git a/wcomponents-core/src/main/java/com/github/bordertech/wcomponents/velocity/VelocityEngineFactory.java b/wcomponents-core/src/main/java/com/github/bordertech/wcomponents/velocity/VelocityEngineFactory.java index ab17b7b52..9042241c2 100755 --- a/wcomponents-core/src/main/java/com/github/bordertech/wcomponents/velocity/VelocityEngineFactory.java +++ b/wcomponents-core/src/main/java/com/github/bordertech/wcomponents/velocity/VelocityEngineFactory.java @@ -10,6 +10,7 @@ import org.apache.commons.logging.LogFactory; import org.apache.velocity.app.VelocityEngine; import org.apache.velocity.runtime.RuntimeConstants; +import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader; /** * A wrapper for the creation of a (singleton) VelocityEngine, using runtime {@link Config configuration} parameters for @@ -53,7 +54,6 @@ public static synchronized VelocityEngine getVelocityEngine() { String fileTemplates = ConfigurationProperties.getVelocityFileTemplates(); boolean cacheTemplates = ConfigurationProperties.getVelocityCacheTemplates(); - VelocityEngine newEngine = new VelocityEngine(); Properties props = new Properties(); // Configure the velocity template differently according to whether we are in @@ -61,32 +61,30 @@ public static synchronized VelocityEngine getVelocityEngine() { if (fileTemplates != null && !"".equals(fileTemplates)) { // Source mode LOG.info("Velocity engine running in source mode from " + fileTemplates); - props.setProperty("resource.loader", "file,class"); props.setProperty("file.resource.loader.path", fileTemplates); props.setProperty("file.resource.loader.cache", "false"); props.setProperty("file.resource.loader.modificationCheckInterval", "2"); - props.setProperty("class.resource.loader.cache", "false"); props.setProperty("class.resource.loader.modificationCheckInterval", "2"); - - props.setProperty("class.resource.loader.class", - "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader"); + props.setProperty("class.resource.loader.class", ClasspathResourceLoader.class.getName()); } else { String cache = String.valueOf(cacheTemplates); - props.setProperty("class.resource.loader.cache", cache); props.setProperty("resource.loader", "class"); - props.setProperty("class.resource.loader.class", - "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader"); + props.setProperty("class.resource.loader.cache", cache); + props.setProperty("class.resource.loader.class", ClasspathResourceLoader.class.getName()); } - // Setup commons logging for velocity - props.setProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS, - "com.github.bordertech.wcomponents.velocity.VelocityLogger"); - // Set up access to the common velocity macros. props.setProperty(RuntimeConstants.VM_LIBRARY, ConfigurationProperties.getVelocityMacroLibrary()); + // Backwards compatability properties + if (ConfigurationProperties.isVelocityBackwardCompatability17Enabled()) { + props.putAll(ConfigurationProperties.getVelocityBackwardCompatability17Properties()); + } + // Project properties (if set) + props.putAll(ConfigurationProperties.getVelocityCustomProperties()); + try { if (LOG.isInfoEnabled()) { // Dump properties @@ -94,13 +92,10 @@ public static synchronized VelocityEngine getVelocityEngine() { props.list(new PrintWriter(writer)); LOG.info("Configuring velocity with the following properties...\n" + writer); } - - newEngine.init(props); + engine = new VelocityEngine(props); } catch (Exception ex) { throw new SystemException("Failed to configure VelocityEngine", ex); } - - engine = newEngine; } return engine; diff --git a/wcomponents-core/src/main/java/com/github/bordertech/wcomponents/velocity/VelocityLogger.java b/wcomponents-core/src/main/java/com/github/bordertech/wcomponents/velocity/VelocityLogger.java deleted file mode 100755 index 9252dac19..000000000 --- a/wcomponents-core/src/main/java/com/github/bordertech/wcomponents/velocity/VelocityLogger.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.github.bordertech.wcomponents.velocity; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.velocity.runtime.RuntimeServices; -import org.apache.velocity.runtime.log.LogSystem; - -/** - * Allows the velocity engine to use the commons logging used by WComponents. - * - * @author Jonathan Austin - * @since 1.0.0 - */ -public class VelocityLogger implements LogSystem { - - /** - * The logger instance for this class. - */ - private static final Log LOG = LogFactory.getLog(VelocityLogger.class); - - /** - * @param rsvc the velocity runtime services - * @throws Exception if problem configuring logger - */ - @Override - public void init(final RuntimeServices rsvc) throws Exception { - // Do no extra configuration - } - - /** - * Log velocity engine messages. - * - * @param level severity level - * @param message complete error message - */ - @Override - public void logVelocityMessage(final int level, final String message) { - switch (level) { - case LogSystem.WARN_ID: - LOG.warn(message); - break; - case LogSystem.INFO_ID: - LOG.info(message); - break; - case LogSystem.DEBUG_ID: - LOG.debug(message); - break; - case LogSystem.ERROR_ID: - LOG.error(message); - break; - default: - LOG.debug(message); - break; - } - } - -} diff --git a/wcomponents-core/src/main/resources/com/github/bordertech/wcomponents/web.properties b/wcomponents-core/src/main/resources/com/github/bordertech/wcomponents/web.properties index 0d48b231d..a2972613f 100755 --- a/wcomponents-core/src/main/resources/com/github/bordertech/wcomponents/web.properties +++ b/wcomponents-core/src/main/resources/com/github/bordertech/wcomponents/web.properties @@ -112,3 +112,25 @@ bordertech.wcomponents.template.renderer.plaintext =com.github.bordertech.wcomp bordertech.wcomponents.plaintext.cache.enabled = true bordertech.wcomponents.handlebars.cache.enabled = true bordertech.wcomponents.velocity.cache.enabled = true + +# Enable backward compatability properties for velocity 1.7 "bt.velocity.backward17.*" to be loaded +bordertech.wcomponents.velocity.backward17.enabled=true + +## Velocity 1.7 properties +# Refer to https://velocity.apache.org/engine/2.3/upgrading.html +# No automatic conversion of methods arguments +bt.velocity.backward17.introspector.conversion_handler.class = none +# Use backward compatible space gobbling +bt.velocity.backward17.parser.space_gobbling = bc +# Have #if($foo) only returns false if $foo is false or null +bt.velocity.backward17.directive.if.empty_check = false +# Allow '-' in identifiers (since 2.1) +bt.velocity.backward17.parser.allow_hyphen_in_identifiers = true +# Enable backward compatibility mode for Velocimacros +bt.velocity.backward17.velocimacro.enable_bc_mode = true +# When using an invalid reference handler, also include quiet references (since 2.2) +bt.velocity.backward17.event_handler.invalid_references.quiet = true +# When using an invalid reference handler, also include null references (since 2.2) +bt.velocity.backward17.event_handler.invalid_references.null = true +# When using an invalid reference handler, also include tested references (since 2.2) +bt.velocity.backward17.event_handler.invalid_references.tested = true