This is an automated email from the ASF dual-hosted git repository.
nmalin pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/ofbiz-framework.git
The following commit(s) were added to refs/heads/trunk by this push:
new c7f1ea4d18 Improved : Improve Uel loading (OFBIZ-13372) - Adds tests
to UEL - Added the possibility to load uel in a modular way. - separates
current UEL into thematic files. - Switched to an object structure to allow for
a description to be loaded with uel, that will be displayed in the uel screen.
c7f1ea4d18 is described below
commit c7f1ea4d18a0d996a3fcb720b61fc4b827619b4b
Author: cgaetan <[email protected]>
AuthorDate: Fri Mar 13 17:08:10 2026 +0100
Improved : Improve Uel loading (OFBIZ-13372)
- Adds tests to UEL
- Added the possibility to load uel in a modular way.
- separates current UEL into thematic files.
- Switched to an object structure to allow for a description to be loaded
with uel, that will be displayed in the uel screen.
With this you can create your customized uel library dedicate to your
plugin. Create you class that implements IUelMappingLibrary (look at
org.apache.ofbiz.base.util.string.uel.*) and load it on your
ofbiz-component.xml :
<ofbiz-component name="myplugin" ...
<uel-mapping name="my-custom-uel"
class-name="org.company.my.plugin.MyCustomUel"/>
</ofbiz-component>
---
framework/base/ofbiz-component.xml | 5 +
.../apache/ofbiz/base/test/uel/DateUelTest.groovy | 118 ++++++++
.../apache/ofbiz/base/test/uel/MathUelTest.groovy | 90 ++++++
.../apache/ofbiz/base/test/uel/MiscUelTest.groovy | 75 +++++
.../ofbiz/base/test/uel/StringUelTest.groovy | 70 +++++
.../ofbiz/base/util/string/uel/DateUel.groovy | 83 ++++++
.../ofbiz/base/util/string/uel/MathUel.groovy | 128 +++++++++
.../ofbiz/base/util/string/uel/MiscUel.groovy | 62 +++++
.../ofbiz/base/util/string/uel/StringUel.groovy | 68 +++++
.../ofbiz/base/component/ComponentConfig.java | 42 +++
.../ofbiz/base/util/string/IUelMappingLibrary.java | 31 +++
.../ofbiz/base/util/string/UelFunctions.java | 301 ++++-----------------
.../apache/ofbiz/base/util/string/UelMapping.java | 49 ++++
framework/base/testdef/basetests.xml | 18 +-
framework/webtools/config/WebtoolsUiLabels.xml | 20 ++
.../webtools/util/uel/FindAvailableUel.groovy | 37 +++
framework/webtools/template/Main.ftl | 1 +
.../webapp/webtools/WEB-INF/controller.xml | 2 +
framework/webtools/widget/MiscScreens.xml | 22 ++
framework/webtools/widget/UelForms.xml | 34 +++
20 files changed, 1004 insertions(+), 252 deletions(-)
diff --git a/framework/base/ofbiz-component.xml
b/framework/base/ofbiz-component.xml
index 8cde8e9ff9..5fceb1cad0 100644
--- a/framework/base/ofbiz-component.xml
+++ b/framework/base/ofbiz-component.xml
@@ -34,4 +34,9 @@ under the License.
<!-- load the administration server -->
<container name="admin-container" loaders="main"
class="org.apache.ofbiz.base.container.AdminServerContainer"/>
+ <!-- Load base uel methods -->
+ <uel-mapping name="date-uel"
class-name="org.apache.ofbiz.base.util.string.uel.DateUel"/>
+ <uel-mapping name="math-uel"
class-name="org.apache.ofbiz.base.util.string.uel.MathUel"/>
+ <uel-mapping name="string-uel"
class-name="org.apache.ofbiz.base.util.string.uel.StringUel"/>
+ <uel-mapping name="misc-uel"
class-name="org.apache.ofbiz.base.util.string.uel.MiscUel"/>
</ofbiz-component>
diff --git
a/framework/base/src/main/groovy/org/apache/ofbiz/base/test/uel/DateUelTest.groovy
b/framework/base/src/main/groovy/org/apache/ofbiz/base/test/uel/DateUelTest.groovy
new file mode 100644
index 0000000000..10863d1574
--- /dev/null
+++
b/framework/base/src/main/groovy/org/apache/ofbiz/base/test/uel/DateUelTest.groovy
@@ -0,0 +1,118 @@
+/*******************************************************************************
+ * 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.ofbiz.base.test.uel
+
+import org.apache.ofbiz.base.util.UtilDateTime
+import org.apache.ofbiz.base.util.string.FlexibleStringExpander
+import org.apache.ofbiz.base.util.string.UelFunctions
+import org.apache.ofbiz.service.testtools.OFBizTestCase
+
+import java.sql.Timestamp
+
+/**
+ * ./gradlew 'ofbiz -t component=base -t suitename=basetests'
+ */
+/* codenarc-disable GStringExpressionWithinString,ClosureAsLastMethodParameter
*/
+class DateUelTest extends OFBizTestCase {
+
+ DateUelTest(String name) {
+ super(name)
+ }
+
+ void testDateUel() { // codenarc-disable JUnitTestMethodWithoutAssert
+ doUelDateTest('${date:second(now, timeZone, locale)}', { Timestamp now
->
+ UtilDateTime.getSecond(now, TimeZone.getDefault(),
Locale.getDefault())
+ })
+ doUelDateTest('${date:minute(now, timeZone, locale)}', { Timestamp now
->
+ UtilDateTime.getMinute(now, TimeZone.getDefault(),
Locale.getDefault())
+ })
+ doUelDateTest('${date:hour(now, timeZone, locale)}', { Timestamp now ->
+ UtilDateTime.getHour(now, TimeZone.getDefault(),
Locale.getDefault())
+ })
+ doUelDateTest('${date:dayOfMonth(now, timeZone, locale)}', { Timestamp
now ->
+ UtilDateTime.getDayOfMonth(now, TimeZone.getDefault(),
Locale.getDefault())
+ })
+ doUelDateTest('${date:dayOfWeek(now, timeZone, locale)}', { Timestamp
now ->
+ UtilDateTime.getDayOfWeek(now, TimeZone.getDefault(),
Locale.getDefault())
+ })
+ doUelDateTest('${date:dayOfYear(now, timeZone, locale)}', { Timestamp
now ->
+ UtilDateTime.getDayOfYear(now, TimeZone.getDefault(),
Locale.getDefault())
+ })
+ doUelDateTest('${date:week(now, timeZone, locale)}', { Timestamp now ->
+ UtilDateTime.getWeek(now, TimeZone.getDefault(),
Locale.getDefault())
+ })
+ doUelDateTest('${date:month(now, timeZone, locale)}', { Timestamp now
->
+ UtilDateTime.getMonth(now, TimeZone.getDefault(),
Locale.getDefault())
+ })
+ doUelDateTest('${date:year(now, timeZone, locale)}', { Timestamp now ->
+ UtilDateTime.getYear(now, TimeZone.getDefault(),
Locale.getDefault())
+ })
+ doUelDateTest('${date:dayStart(now, timeZone, locale)}', { Timestamp
now ->
+ UtilDateTime.getDayStart(now, TimeZone.getDefault(),
Locale.getDefault())
+ })
+ doUelDateTest('${date:dayEnd(now, timeZone, locale)}', { Timestamp now
->
+ UtilDateTime.getDayEnd(now, TimeZone.getDefault(),
Locale.getDefault())
+ })
+ doUelDateTest('${date:weekStart(now, timeZone, locale)}', { Timestamp
now ->
+ UtilDateTime.getWeekStart(now, TimeZone.getDefault(),
Locale.getDefault())
+ })
+ doUelDateTest('${date:weekEnd(now, timeZone, locale)}', { Timestamp
now ->
+ UtilDateTime.getWeekEnd(now, TimeZone.getDefault(),
Locale.getDefault())
+ })
+ doUelDateTest('${date:monthStart(now, timeZone, locale)}', { Timestamp
now ->
+ UtilDateTime.getMonthStart(now, TimeZone.getDefault(),
Locale.getDefault())
+ })
+ doUelDateTest('${date:monthEnd(now, timeZone, locale)}', { Timestamp
now ->
+ UtilDateTime.getMonthEnd(now, TimeZone.getDefault(),
Locale.getDefault())
+ })
+ doUelDateTest('${date:yearStart(now, timeZone, locale)}', { Timestamp
now ->
+ UtilDateTime.getYearStart(now, TimeZone.getDefault(),
Locale.getDefault())
+ })
+ doUelDateTest('${date:yearEnd(now, timeZone, locale)}', { Timestamp
now ->
+ UtilDateTime.getYearEnd(now, TimeZone.getDefault(),
Locale.getDefault())
+ })
+ doUelDateTest('${date:dateStr(now, timeZone, locale)}', { Timestamp
now ->
+ UelFunctions.dateString(now, TimeZone.getDefault(),
Locale.getDefault())
+ })
+ doUelDateTest('${date:localizedDateStr(now, timeZone, locale)}', {
Timestamp now ->
+ UelFunctions.localizedDateString(now, TimeZone.getDefault(),
Locale.getDefault())
+ })
+ doUelDateTest('${date:localizedDateTimeStr(now, timeZone, locale)}', {
Timestamp now ->
+ UelFunctions.localizedDateTimeString(now, TimeZone.getDefault(),
Locale.getDefault())
+ })
+ doUelDateTest('${date:timeStr(now, timeZone, locale)}', { Timestamp
now ->
+ UelFunctions.timeString(now, TimeZone.getDefault(),
Locale.getDefault())
+ })
+ }
+
+ void testNowTimestampUel() {
+ FlexibleStringExpander fse =
FlexibleStringExpander.getInstance('${date:nowTimestamp()}')
+ assert (fse.expand([:]).time - UtilDateTime.nowTimestamp().time).abs()
< 15 // less than 10 ns appart
+ }
+
+ private void doUelDateTest(String uelInput, Closure uelFunction) {
+ Timestamp now = UtilDateTime.nowTimestamp()
+ Map context = [now: now,
+ timeZone: TimeZone.getDefault(),
+ locale: Locale.getDefault()]
+ FlexibleStringExpander fse =
FlexibleStringExpander.getInstance(uelInput)
+ assert fse.expand(context) == uelFunction(now)
+ }
+
+}
diff --git
a/framework/base/src/main/groovy/org/apache/ofbiz/base/test/uel/MathUelTest.groovy
b/framework/base/src/main/groovy/org/apache/ofbiz/base/test/uel/MathUelTest.groovy
new file mode 100644
index 0000000000..8cf9e7efd7
--- /dev/null
+++
b/framework/base/src/main/groovy/org/apache/ofbiz/base/test/uel/MathUelTest.groovy
@@ -0,0 +1,90 @@
+/*******************************************************************************
+ * 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.ofbiz.base.test.uel
+
+import org.apache.ofbiz.base.util.string.FlexibleStringExpander
+import org.apache.ofbiz.service.testtools.OFBizTestCase
+
+/**
+ * ./gradlew 'ofbiz -t component=base -t suitename=basetests'
+ */
+/* codenarc-disable GStringExpressionWithinString,ClosureAsLastMethodParameter
*/
+
+class MathUelTest extends OFBizTestCase {
+
+ MathUelTest(String name) { super(name) }
+
+ void testMathUel() { // codenarc-disable JUnitTestMethodWithoutAssert
+ doMathTest('${math:absDouble(a)}', [a: -0.3, b: null], { a, b ->
Math.abs(a as double) })
+ doMathTest('${math:absFloat(a)}', [a: -0.3, b: null], { a, b ->
Math.abs(a as float) })
+ doMathTest('${math:absInt(a)}', [a: -2, b: null], { a, b -> Math.abs(a
as int) })
+ doMathTest('${math:absLong(a)}', [a: -5, b: null], { a, b ->
Math.abs(a as long) })
+ doMathTest('${math:acos(a)}', [a: 0.2, b: null], { a, b ->
Math.acos(a) })
+ doMathTest('${math:asin(a)}', [a: 0.2, b: null], { a, b ->
Math.asin(a) })
+ doMathTest('${math:atan(a)}', [a: 0.2, b: null], { a, b ->
Math.atan(a) })
+ doMathTest('${math:atan2(a, b)}', [a: 0.2, b: 0.2], { a, b ->
Math.atan2(a, b) })
+ doMathTest('${math:cbrt(a)}', [a: 10, b: null], { a, b -> Math.cbrt(a)
})
+ doMathTest('${math:ceil(a)}', [a: 20, b: null], { a, b -> Math.ceil(a)
})
+ doMathTest('${math:cos(a)}', [a: 0.2, b: null], { a, b -> Math.cos(a)
})
+ doMathTest('${math:cosh(a)}', [a: 0.2, b: null], { a, b ->
Math.cosh(a) })
+ doMathTest('${math:exp(a)}', [a: 29, b: null], { a, b -> Math.exp(a) })
+ doMathTest('${math:expm1(a)}', [a: 20, b: null], { a, b ->
Math.expm1(a) })
+ doMathTest('${math:floor(a)}', [a: 23.4, b: null], { a, b ->
Math.floor(a) })
+ doMathTest('${math:hypot(a, b)}', [a: 29, b: 12], { a, b ->
Math.hypot(a, b) })
+ doMathTest('${math:IEEEremainder(a, b)}', [a: 12, b: 1.3], { a, b ->
Math.IEEEremainder(a, b) })
+ doMathTest('${math:log(a)}', [a: 20, b: null], { a, b -> Math.log(a) })
+ doMathTest('${math:log10(a)}', [a: 29, b: null], { a, b ->
Math.log10(a) })
+ doMathTest('${math:log1p(a)}', [a: 12, b: null], { a, b ->
Math.log1p(a) })
+ doMathTest('${math:maxDouble(a, b)}', [a: 12, b: 13], { a, b ->
Math.max(a as double, b as double) })
+ doMathTest('${math:maxFloat(a, b)}', [a: 2.4, b: 3.9], { a, b ->
Math.max(a as float, b as float) })
+ doMathTest('${math:maxInt(a, b)}', [a: 2.6, b: 3.7], { a, b ->
Math.max(a as int, b as int) })
+ doMathTest('${math:maxLong(a, b)}', [a: 23, b: 32], { a, b ->
Math.max(a as long, b as long) })
+ doMathTest('${math:minDouble(a, b)}', [a: 10, b: 20], { a, b ->
Math.min(a as double, b as double) })
+ doMathTest('${math:minFloat(a, b)}', [a: 1.2, b: 2.5], { a, b ->
Math.min(a as float, b as float) })
+ doMathTest('${math:minInt(a, b)}', [a: 12, b: 13], { a, b ->
Math.min(a as int, b as int) })
+ doMathTest('${math:minLong(a, b)}', [a: 24, b: 14], { a, b ->
Math.min(a as long, b as long) })
+ doMathTest('${math:pow(a, b)}', [a: 12, b: 13], { a, b -> Math.pow(a,
b) })
+ doMathTest('${math:rint(a)}', [a: 29, b: null], { a, b -> Math.rint(a)
})
+ doMathTest('${math:roundDouble(a)}', [a: 23.4, b: null], { a, b ->
Math.round(a as double) })
+ doMathTest('${math:roundFloat(a)}', [a: 12.4, b: null], { a, b ->
Math.round(a as float) })
+ doMathTest('${math:signumDouble(a)}', [a: 23, b: null], { a, b ->
Math.signum(a as double) })
+ doMathTest('${math:signumFloat(a)}', [a: 23, b: null], { a, b ->
Math.signum(a as float) })
+ doMathTest('${math:sin(a)}', [a: 12, b: null], { a, b -> Math.sin(a) })
+ doMathTest('${math:sinh(a)}', [a: 12, b: null], { a, b -> Math.sinh(a)
})
+ doMathTest('${math:sqrt(a)}', [a: 34, b: null], { a, b -> Math.sqrt(a)
})
+ doMathTest('${math:tan(a)}', [a: 13, b: null], { a, b -> Math.tan(a) })
+ doMathTest('${math:tanh(a)}', [a: 30, b: null], { a, b -> Math.tanh(a)
})
+ doMathTest('${math:toDegrees(a)}', [a: 30, b: null], { a, b ->
Math.toDegrees(a) })
+ doMathTest('${math:toRadians(a)}', [a: 12, b: null], { a, b ->
Math.toRadians(a) })
+ doMathTest('${math:ulpDouble(a)}', [a: 12, b: null], { a, b ->
Math.ulp(a as double) })
+ doMathTest('${math:ulpFloat(a)}', [a: 30, b: null], { a, b ->
Math.ulp(a as float) })
+ }
+
+ void testMathRandom() {
+ FlexibleStringExpander fse =
FlexibleStringExpander.getInstance('${math:random()}')
+ assert fse.expand([:]) instanceof Double
+ assert fse.expand([:]) != BigDecimal.ZERO
+ }
+
+ private void doMathTest(String uelInput, Map context, Closure uelFunction)
{
+ FlexibleStringExpander fse =
FlexibleStringExpander.getInstance(uelInput)
+ assert new BigDecimal(fse.expand(context)) == new
BigDecimal(uelFunction(context.a, context.b))
+ }
+
+}
diff --git
a/framework/base/src/main/groovy/org/apache/ofbiz/base/test/uel/MiscUelTest.groovy
b/framework/base/src/main/groovy/org/apache/ofbiz/base/test/uel/MiscUelTest.groovy
new file mode 100644
index 0000000000..3bbaa04b18
--- /dev/null
+++
b/framework/base/src/main/groovy/org/apache/ofbiz/base/test/uel/MiscUelTest.groovy
@@ -0,0 +1,75 @@
+/*******************************************************************************
+ * 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.ofbiz.base.test.uel
+
+import org.apache.ofbiz.base.util.string.FlexibleStringExpander
+import org.apache.ofbiz.base.util.string.UelFunctions
+import org.apache.ofbiz.service.testtools.OFBizTestCase
+
+/**
+ * ./gradlew 'ofbiz -t component=base -t suitename=basetests'
+ */
+/* codenarc-disable GStringExpressionWithinString,ClosureAsLastMethodParameter
*/
+class MiscUelTest extends OFBizTestCase {
+
+ MiscUelTest(String name) { super(name) }
+
+ void testSystemUel() { // codenarc-disable JUnitTestMethodWithoutAssert
+ // todo: Both are null, but mockito doesn't do system mock..
+ doUelSystemTest('${sys:getenv}', 'foo', { String prop ->
UelFunctions.sysGetEnv(prop) })
+ doUelSystemTest('${sys:getProperty}', 'bar', { String prop ->
UelFunctions.sysGetProp(prop) })
+ }
+
+ void testUtilSizeUel() {
+ List foo = [1, 2, 3]
+ FlexibleStringExpander fse =
FlexibleStringExpander.getInstance('${util:size(foo)}')
+ assert fse.expand([foo: foo]) == UelFunctions.getSize(foo)
+ }
+
+ void testDefaultLocaleAndTimzoneUel() {
+ FlexibleStringExpander fse =
FlexibleStringExpander.getInstance('${util:defaultLocale()}')
+ assert fse.expand([foo: 'bar']) == Locale.getDefault()
+ fse = FlexibleStringExpander.getInstance('${util:defaultTimeZone()}')
+ assert fse.expand([foo: 'bar']) == TimeZone.getDefault()
+ }
+
+ void testLabelUel() {
+ String labelFile = 'CommonEntityLabels', labelKey =
'VisualTheme.description.RAINBOWSTONE_AMBER'
+ FlexibleStringExpander fse = FlexibleStringExpander.getInstance(
+
'${util:label(\'CommonEntityLabels\',\'VisualTheme.description.RAINBOWSTONE_AMBER\',
locale)}')
+ assert fse.expand([locale: Locale.getDefault()]) ==
UelFunctions.label(labelFile, labelKey, Locale.getDefault())
+ }
+
+ private void doUelSystemTest(String uelInput, String param, Closure
uelFunction) {
+ FlexibleStringExpander fse =
FlexibleStringExpander.getInstance(uelInput)
+ assert fse.expand([:]) == uelFunction(param)
+ }
+
+// TODO: Some day
+// '${screen:id}', UelFunctions.class.getMethod("resolveCurrentScreenId",
ScreenRenderer.ScreenStack.class))
+// '${dom:readHtmlDocument}',
UelFunctions.class.getMethod("readHtmlDocument", String.class))
+// '${dom:readXmlDocument}',
UelFunctions.class.getMethod("readXmlDocument", String.class))
+// '${dom:toHtmlString}', UelFunctions.class.getMethod("toHtmlString",
Node.class, String.class, boolean.class,
+// int.class))
+// '${dom:toXmlString}', UelFunctions.class.getMethod("toXmlString",
Node.class, String.class, boolean.class,
+// boolean.class, int.class))
+// '${dom:writeXmlDocument}',
UelFunctions.class.getMethod("writeXmlDocument", String.class, Node.class,
+// String.class, boolean.class, boolean.class, int.class))
+
+}
diff --git
a/framework/base/src/main/groovy/org/apache/ofbiz/base/test/uel/StringUelTest.groovy
b/framework/base/src/main/groovy/org/apache/ofbiz/base/test/uel/StringUelTest.groovy
new file mode 100644
index 0000000000..ad24acce02
--- /dev/null
+++
b/framework/base/src/main/groovy/org/apache/ofbiz/base/test/uel/StringUelTest.groovy
@@ -0,0 +1,70 @@
+/*******************************************************************************
+ * 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.ofbiz.base.test.uel
+
+import org.apache.ofbiz.base.util.string.FlexibleStringExpander
+import org.apache.ofbiz.base.util.string.UelFunctions
+import org.apache.ofbiz.service.testtools.OFBizTestCase
+
+/**
+ * ./gradlew 'ofbiz -t component=base -t suitename=basetests'
+ */
+/* codenarc-disable GStringExpressionWithinString,ClosureAsLastMethodParameter
*/
+
+class StringUelTest extends OFBizTestCase {
+
+ StringUelTest(String name) { super(name) }
+
+ void testUelString() { // codenarc-disable JUnitTestMethodWithoutAssert
+ doStringTest('${str:endsWith(a, b)}', [a: 'dog', b: 'og', c: null],
+ { a, b, c -> UelFunctions.endsWith(a, b) })
+ doStringTest('${str:indexOf(a, b)}', [a: 'dog', b: 'og', c: null],
+ { a, b, c -> UelFunctions.indexOf(a, b) })
+ doStringTest('${str:lastIndexOf(a, b)}', [a: 'dog', b: 'og', c: null],
+ { a, b, c -> UelFunctions.lastIndexOf(a, b) })
+ doStringTest('${str:length(a)}', [a: 'dog', b: null, c: null],
+ { a, b, c -> UelFunctions.length(a) })
+ doStringTest('${str:replace(a, b, c)}', [a: 'the dog', b: 'dog', c:
'cat'],
+ { a, b, c -> UelFunctions.replace(a, b, c) })
+ doStringTest('${str:replaceAll(a, b, c)}', [a: 'the dog', b: 'dog', c:
'cat'],
+ { a, b, c -> UelFunctions.replaceAll(a, b, c) })
+ doStringTest('${str:replaceFirst(a, b, c)}', [a: 'the dog', b: 'dog',
c: 'cat'],
+ { a, b, c -> UelFunctions.replaceFirst(a, b, c) })
+ doStringTest('${str:startsWith(a, b)}', [a: 'the dog', b: 'the', c:
null],
+ { a, b, c -> UelFunctions.startsWith(a, b) })
+ doStringTest('${str:endstring(a, b)}', [a: 'the dog', b: 3, c: null],
+ { a, b, c -> UelFunctions.endString(a, b) })
+ doStringTest('${str:substring(a, b, c)}', [a: 'the dog', b: 3, c: 7],
+ { a, b, c -> UelFunctions.subString(a, b, c) })
+ doStringTest('${str:toString(a)}', [a: 'foo', b: null, c: null],
+ { a, b, c -> UelFunctions.toString(a) })
+ doStringTest('${str:toLowerCase(a)}', [a: 'FOO', b: null, c: null],
+ { a, b, c -> UelFunctions.toLowerCase(a) })
+ doStringTest('${str:toUpperCase(a)}', [a: 'foo', b: null, c: null],
+ { a, b, c -> UelFunctions.toUpperCase(a) })
+ doStringTest('${str:trim(a)}', [a: ' foo ', b: null, c: null],
+ { a, b, c -> UelFunctions.trim(a) })
+ }
+
+ private void doStringTest(String uelInput, Map context, Closure
uelFunction) {
+ FlexibleStringExpander fse =
FlexibleStringExpander.getInstance(uelInput)
+ assert fse.expand(context) == uelFunction(context.a, context.b,
context.c)
+ }
+
+}
diff --git
a/framework/base/src/main/groovy/org/apache/ofbiz/base/util/string/uel/DateUel.groovy
b/framework/base/src/main/groovy/org/apache/ofbiz/base/util/string/uel/DateUel.groovy
new file mode 100644
index 0000000000..52e410ad0c
--- /dev/null
+++
b/framework/base/src/main/groovy/org/apache/ofbiz/base/util/string/uel/DateUel.groovy
@@ -0,0 +1,83 @@
+/*******************************************************************************
+ * 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.ofbiz.base.util.string.uel
+
+import org.apache.ofbiz.base.util.UtilDateTime
+import org.apache.ofbiz.base.util.string.IUelMappingLibrary
+import org.apache.ofbiz.base.util.string.UelFunctions
+import org.apache.ofbiz.base.util.string.UelMapping
+
+import java.sql.Timestamp
+
+/**
+ * Class for importing the Date Uel
+ */
+class DateUel implements IUelMappingLibrary {
+
+ @Override
+ List<UelMapping> getUelMappingList() {
+ return [
+ new UelMapping('date:second',
UtilDateTime.getMethod('getSecond', Timestamp, TimeZone, Locale),
+ 'Returns the second value of Timestamp (0 - 59).'),
+ new UelMapping('date:minute',
UtilDateTime.getMethod('getMinute', Timestamp, TimeZone, Locale),
+ 'Returns the minute value of Timestamp (0 - 59).'),
+ new UelMapping('date:hour', UtilDateTime.getMethod('getHour',
Timestamp, TimeZone, Locale),
+ 'Returns the hour value of Timestamp (0 - 23).'),
+ new UelMapping('date:dayOfMonth',
UtilDateTime.getMethod('getDayOfMonth', Timestamp, TimeZone, Locale),
+ 'Returns the day of month value of Timestamp (1 - 31)
.'),
+ new UelMapping('date:dayOfWeek',
UtilDateTime.getMethod('getDayOfWeek', Timestamp, TimeZone, Locale),
+ 'Returns the day of week value of Timestamp (Sunday =
1, Saturday = 7).'),
+ new UelMapping('date:dayOfYear',
UtilDateTime.getMethod('getDayOfYear', Timestamp, TimeZone, Locale),
+ 'Returns the day of year value of Timestamp.'),
+ new UelMapping('date:week', UtilDateTime.getMethod('getWeek',
Timestamp, TimeZone, Locale),
+ 'Returns the week value of Timestamp.'),
+ new UelMapping('date:month',
UtilDateTime.getMethod('getMonth', Timestamp, TimeZone, Locale),
+ 'Returns the month value of Timestamp (January = 0,
December = 11).'),
+ new UelMapping('date:year', UtilDateTime.getMethod('getYear',
Timestamp, TimeZone, Locale),
+ 'Returns the year value of Timestamp.'),
+ new UelMapping('date:dayStart',
UtilDateTime.getMethod('getDayStart', Timestamp, TimeZone, Locale),
+ 'Returns Timestamp set to start of day.'),
+ new UelMapping('date:dayEnd',
UtilDateTime.getMethod('getDayEnd', Timestamp, TimeZone, Locale),
+ 'Returns Timestamp set to end of day.'),
+ new UelMapping('date:weekStart',
UtilDateTime.getMethod('getWeekStart', Timestamp, TimeZone, Locale),
+ 'Returns Timestamp set to start of week.'),
+ new UelMapping('date:weekEnd',
UtilDateTime.getMethod('getWeekEnd', Timestamp, TimeZone, Locale),
+ 'Returns Timestamp set to end of week.'),
+ new UelMapping('date:monthStart',
UtilDateTime.getMethod('getMonthStart', Timestamp, TimeZone, Locale),
+ 'Returns Timestamp set to start of month.'),
+ new UelMapping('date:monthEnd',
UtilDateTime.getMethod('getMonthEnd', Timestamp, TimeZone, Locale),
+ 'Returns Timestamp set to end of month.'),
+ new UelMapping('date:yearStart',
UtilDateTime.getMethod('getYearStart', Timestamp, TimeZone, Locale),
+ 'Returns Timestamp set to start of year.'),
+ new UelMapping('date:yearEnd',
UtilDateTime.getMethod('getYearEnd', Timestamp, TimeZone, Locale),
+ 'Returns Timestamp set to end of year.'),
+ new UelMapping('date:dateStr',
UelFunctions.getMethod('dateString', Timestamp, TimeZone, Locale),
+ 'Returns Timestamp as a date String (yyyy-mm-dd) .'),
+ new UelMapping('date:localizedDateStr',
UelFunctions.getMethod('localizedDateString', Timestamp, TimeZone, Locale),
+ 'Returns Timestamp as a date String formatted
according to the supplied locale.'),
+ new UelMapping('date:localizedDateTimeStr',
UelFunctions.getMethod('localizedDateTimeString', Timestamp, TimeZone, Locale),
+ 'Returns Timestamp as a date-time String formatted
according to the supplied locale.'),
+ new UelMapping('date:timeStr',
UelFunctions.getMethod('timeString', Timestamp, TimeZone, Locale),
+ 'Returns Timestamp as a time String (hh:mm) .'),
+ new UelMapping('date:nowTimestamp',
UtilDateTime.getMethod('nowTimestamp'),
+ 'Returns Timestamp for right now.')
+ ]
+ }
+
+}
diff --git
a/framework/base/src/main/groovy/org/apache/ofbiz/base/util/string/uel/MathUel.groovy
b/framework/base/src/main/groovy/org/apache/ofbiz/base/util/string/uel/MathUel.groovy
new file mode 100644
index 0000000000..c0b90b3e0d
--- /dev/null
+++
b/framework/base/src/main/groovy/org/apache/ofbiz/base/util/string/uel/MathUel.groovy
@@ -0,0 +1,128 @@
+/*******************************************************************************
+ * 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.ofbiz.base.util.string.uel
+
+import org.apache.ofbiz.base.util.string.IUelMappingLibrary
+import org.apache.ofbiz.base.util.string.UelMapping
+
+/**
+ * Class for importing the Math Uel
+ */
+class MathUel implements IUelMappingLibrary {
+
+ @Override
+ List<UelMapping> getUelMappingList() {
+ return [
+ new UelMapping('math:absDouble', Math.getMethod('abs', double),
+ 'Returns the absolute value of a double value'),
+ new UelMapping('math:absFloat', Math.getMethod('abs', float),
+ 'Returns the absolute value of a float value.'),
+ new UelMapping('math:absInt', Math.getMethod('abs', int),
+ 'Returns the absolute value of an int value.'),
+ new UelMapping('math:absLong', Math.getMethod('abs', long),
+ 'Returns the absolute value of a long value.'),
+ new UelMapping('math:acos', Math.getMethod('acos', double),
+ 'Returns the arc cosine of an angle, in the range of
0.0 through pi.'),
+ new UelMapping('math:asin', Math.getMethod('asin', double),
+ 'Returns the arc sine of an angle, in the range of
-pi/2 through pi/2.'),
+ new UelMapping('math:atan', Math.getMethod('atan', double),
+ 'Returns the arc tangent of an angle, in the range of
-pi/2 through pi/2.'),
+ new UelMapping('math:atan2', Math.getMethod('atan2', double,
double),
+ 'Converts rectangular coordinates (x, y) to polar (r,
theta).'),
+ new UelMapping('math:cbrt', Math.getMethod('cbrt', double),
+ 'Returns the cube root of a double value.'),
+ new UelMapping('math:ceil', Math.getMethod('ceil', double),
+ 'Returns the smallest (closest to negative infinity)
double value that is greater than or' +
+ ' equal to the argument and is equal to a
mathematical integer.'),
+ new UelMapping('math:cos', Math.getMethod('cos', double),
+ 'Returns the trigonometric cosine of an angle.'),
+ new UelMapping('math:cosh', Math.getMethod('cosh', double),
+ 'Returns the hyperbolic cosine of a double value.'),
+ new UelMapping('math:exp', Math.getMethod('exp', double),
+ "Returns Euler's number e raised to the power of a
double value."),
+ new UelMapping('math:expm1', Math.getMethod('expm1', double),
+ 'Returns ex -1.'),
+ new UelMapping('math:floor', Math.getMethod('floor', double),
+ 'Returns the largest (closest to positive infinity)
double value that is less than or equal ' +
+ 'to the argument and is equal to a
mathematical integer.'),
+ new UelMapping('math:hypot', Math.getMethod('hypot', double,
double),
+ 'Returns sqrt(x2 +y2) without intermediate overflow or
underflow.'),
+ new UelMapping('math:IEEEremainder',
Math.getMethod('IEEEremainder', double, double),
+ 'Computes the remainder operation on two arguments as
prescribed by the IEEE 754 standard.'),
+ new UelMapping('math:log', Math.getMethod('log', double),
+ 'Returns the natural logarithm (base e) of a double
value.'),
+ new UelMapping('math:log10', Math.getMethod('log10', double),
+ 'Returns the base 10 logarithm of a double value.'),
+ new UelMapping('math:log1p', Math.getMethod('log1p', double),
+ 'Returns the natural logarithm of the sum of the
argument and 1.'),
+ new UelMapping('math:maxDouble', Math.getMethod('max', double,
double),
+ 'Returns the greater of two double values.'),
+ new UelMapping('math:maxFloat', Math.getMethod('max', float,
float),
+ 'Returns the greater of two float values.'),
+ new UelMapping('math:maxInt', Math.getMethod('max', int, int),
+ 'Returns the greater of two int values.'),
+ new UelMapping('math:maxLong', Math.getMethod('max', long,
long),
+ 'Returns the greater of two long values.'),
+ new UelMapping('math:minDouble', Math.getMethod('min', double,
double),
+ 'Returns the smaller of two double values.'),
+ new UelMapping('math:minFloat', Math.getMethod('min', float,
float),
+ 'Returns the smaller of two float values.'),
+ new UelMapping('math:minInt', Math.getMethod('min', int, int),
+ 'Returns the smaller of two int values.'),
+ new UelMapping('math:minLong', Math.getMethod('min', long,
long),
+ 'Returns the smaller of two long values.'),
+ new UelMapping('math:pow', Math.getMethod('pow', double,
double),
+ 'Returns the value of the first argument raised to the
power of the second argument.'),
+ new UelMapping('math:random', Math.getMethod('random'),
+ 'Returns a double value with a positive sign, greater
than or equal to 0.0 and less than 1.0.'),
+ new UelMapping('math:rint', Math.getMethod('rint', double),
+ 'Returns the double value that is closest in value to
the argument and is equal to a' +
+ ' mathematical integer.'),
+ new UelMapping('math:roundDouble', Math.getMethod('round',
double),
+ 'Returns the closest long to the argument.'),
+ new UelMapping('math:roundFloat', Math.getMethod('round',
float),
+ 'Returns the closest int to the argument.'),
+ new UelMapping('math:signumDouble', Math.getMethod('signum',
double),
+ 'Returns the signum function of the argument; zero if
the argument is zero, 1.0 if the ' +
+ 'argument is greater than zero, -1.0 if the
argument is less than zero.'),
+ new UelMapping('math:signumFloat', Math.getMethod('signum',
float),
+ 'Returns the signum function of the argument; zero if
the argument is zero, 1.0f if the ' +
+ 'argument is greater than zero, -1.0f if the
argument is less than zero.'),
+ new UelMapping('math:sin', Math.getMethod('sin', double),
+ 'Returns the trigonometric sine of an angle.'),
+ new UelMapping('math:sinh', Math.getMethod('sinh', double),
+ 'Returns the hyperbolic sine of a double value.'),
+ new UelMapping('math:sqrt', Math.getMethod('sqrt', double),
+ 'Returns the correctly rounded positive square root of
a double value.'),
+ new UelMapping('math:tan', Math.getMethod('tan', double),
+ 'Returns the trigonometric tangent of an angle.'),
+ new UelMapping('math:tanh', Math.getMethod('tanh', double),
+ 'Returns the hyperbolic tangent of a double value.'),
+ new UelMapping('math:toDegrees', Math.getMethod('toDegrees',
double),
+ 'Converts an angle measured in radians to an
approximately equivalent angle measured in degrees.'),
+ new UelMapping('math:toRadians', Math.getMethod('toRadians',
double),
+ 'Converts an angle measured in degrees to an
approximately equivalent angle measured in radians.'),
+ new UelMapping('math:ulpDouble', Math.getMethod('ulp', double),
+ 'Returns the size of an ulp (units in the last place)
of the argument.'),
+ new UelMapping('math:ulpFloat', Math.getMethod('ulp', float),
+ 'Returns the size of an ulp (units in the last place)
of the argument.')
+ ]
+ }
+
+}
diff --git
a/framework/base/src/main/groovy/org/apache/ofbiz/base/util/string/uel/MiscUel.groovy
b/framework/base/src/main/groovy/org/apache/ofbiz/base/util/string/uel/MiscUel.groovy
new file mode 100644
index 0000000000..f03ef45c80
--- /dev/null
+++
b/framework/base/src/main/groovy/org/apache/ofbiz/base/util/string/uel/MiscUel.groovy
@@ -0,0 +1,62 @@
+/*******************************************************************************
+ * 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.ofbiz.base.util.string.uel
+
+import org.apache.ofbiz.base.util.string.IUelMappingLibrary
+import org.apache.ofbiz.base.util.string.UelFunctions
+import org.apache.ofbiz.base.util.string.UelMapping
+import org.apache.ofbiz.widget.renderer.ScreenRenderer
+import org.w3c.dom.Node
+
+/**
+ * Class for importing the various system, util, and dom Uel
+ */
+class MiscUel implements IUelMappingLibrary {
+
+ @Override
+ List<UelMapping> getUelMappingList() {
+ return [
+ new UelMapping('sys:getenv',
UelFunctions.getMethod('sysGetEnv', String),
+ 'Gets the value of the specified environment
variable.'),
+ new UelMapping('sys:getProperty',
UelFunctions.getMethod('sysGetProp', String),
+ 'Gets the system property indicated by the specified
key.'),
+ new UelMapping('util:size', UelFunctions.getMethod('getSize',
Object),
+ 'Returns the default Locale.'),
+ new UelMapping('util:defaultLocale',
Locale.getMethod('getDefault'),
+ 'Returns the default TimeZone.'),
+ new UelMapping('util:defaultTimeZone',
TimeZone.getMethod('getDefault'),
+ 'Return the label present in ressource on the given
locale.'),
+ new UelMapping('util:label', UelFunctions.getMethod('label',
String, String, Locale),
+ 'Returns the size of Maps,'),
+ new UelMapping('screen:id',
UelFunctions.getMethod('resolveCurrentScreenId', ScreenRenderer.ScreenStack),
+ 'Returns the id of the current screen, Collections,
and Strings. Invalid Object types return -1.'),
+ new UelMapping('dom:readHtmlDocument',
UelFunctions.getMethod('readHtmlDocument', String),
+ 'Reads an HTML file and returns a org.w3c.dom.Document
instance.'),
+ new UelMapping('dom:readXmlDocument',
UelFunctions.getMethod('readXmlDocument', String),
+ 'Reads an XML file and returns a org.w3c.dom.Document
instance.'),
+ new UelMapping('dom:toHtmlString',
UelFunctions.getMethod('toHtmlString', Node, String, boolean, int),
+ 'Returns a org.w3c.dom.Node as an HTML String.'),
+ new UelMapping('dom:toXmlString',
UelFunctions.getMethod('toXmlString', Node, String, boolean, boolean, int),
+ 'Returns a org.w3c.dom.Node as an XML String.'),
+ new UelMapping('dom:writeXmlDocument',
UelFunctions.getMethod('writeXmlDocument', String, Node, String, boolean,
boolean, int),
+ 'Writes a org.w3c.dom.Node to an XML file and returns
true if successful.')
+ ]
+ }
+
+}
diff --git
a/framework/base/src/main/groovy/org/apache/ofbiz/base/util/string/uel/StringUel.groovy
b/framework/base/src/main/groovy/org/apache/ofbiz/base/util/string/uel/StringUel.groovy
new file mode 100644
index 0000000000..f675edb9c1
--- /dev/null
+++
b/framework/base/src/main/groovy/org/apache/ofbiz/base/util/string/uel/StringUel.groovy
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * 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.ofbiz.base.util.string.uel
+
+import org.apache.ofbiz.base.util.string.IUelMappingLibrary
+import org.apache.ofbiz.base.util.string.UelFunctions
+import org.apache.ofbiz.base.util.string.UelMapping
+
+/**
+ * Class for importing the String Uel
+ */
+class StringUel implements IUelMappingLibrary {
+
+ @Override
+ List<UelMapping> getUelMappingList() {
+ return [
+ new UelMapping('str:endsWith',
UelFunctions.getMethod('endsWith', String, String),
+ 'Returns true if this string ends with the specified
suffix.'),
+ new UelMapping('str:indexOf',
UelFunctions.getMethod('indexOf', String, String),
+ 'Returns the index within this string of the first
occurrence of the specified substring .'),
+ new UelMapping('str:lastIndexOf',
UelFunctions.getMethod('lastIndexOf', String, String),
+ 'Returns the index within this string of the last
occurrence of the specified character.'),
+ new UelMapping('str:length', UelFunctions.getMethod('length',
String),
+ 'Returns the length of this string.'),
+ new UelMapping('str:replace',
UelFunctions.getMethod('replace', String, String, String),
+ 'Replaces each substring of this string that matches
the literal target sequence with the' +
+ ' specified literal replacement sequence.'),
+ new UelMapping('str:replaceAll',
UelFunctions.getMethod('replaceAll', String, String, String),
+ 'Replaces each substring of this string that matches
the given regular expression with the given replacement.'),
+ new UelMapping('str:replaceFirst',
UelFunctions.getMethod('replaceFirst', String, String, String),
+ 'Replaces the first substring of this string that
matches the given regular expression with the given replacement.'),
+ new UelMapping('str:startsWith',
UelFunctions.getMethod('startsWith', String, String),
+ 'Returns true if this string starts with the specified
prefix.'),
+ new UelMapping('str:endstring',
UelFunctions.getMethod('endString', String, int),
+ 'Returns a new string that is a substring of this
string. The substring begins with the' +
+ ' character at the specified index and extends
to the end of this string.'),
+ new UelMapping('str:substring',
UelFunctions.getMethod('subString', String, int, int),
+ 'Returns a new string that is a substring of this
string. The substring begins at the ' +
+ 'specified beginIndex and extends to the
character at index endIndex - 1. Thus ' +
+ 'the length of the substring is
endIndex-beginIndex.'),
+ new UelMapping('str:toString',
UelFunctions.getMethod('toString', Object),
+ 'Converts all of the characters in this String to
lower case using the rules of the default locale.'),
+ new UelMapping('str:toLowerCase',
UelFunctions.getMethod('toLowerCase', String),
+ 'Converts Object to a String - bypassing
localization.'),
+ new UelMapping('str:toUpperCase',
UelFunctions.getMethod('toUpperCase', String),
+ 'Converts all of the characters in this String to
upper case using the rules of the default locale.'),
+ new UelMapping('str:trim', UelFunctions.getMethod('trim',
String),
+ 'Returns a copy of the string, with leading and
trailing whitespace omitted.')
+ ]
+ }
+
+}
diff --git
a/framework/base/src/main/java/org/apache/ofbiz/base/component/ComponentConfig.java
b/framework/base/src/main/java/org/apache/ofbiz/base/component/ComponentConfig.java
index 3dcb13bdbd..d611a418c3 100644
---
a/framework/base/src/main/java/org/apache/ofbiz/base/component/ComponentConfig.java
+++
b/framework/base/src/main/java/org/apache/ofbiz/base/component/ComponentConfig.java
@@ -132,6 +132,16 @@ public final class ComponentConfig {
.collect(Collectors.toList());
}
+ /**
+ * Provides the list of all the keystore information available in
components.
+ * @return a list of keystore information
+ */
+ public static List<UelMappingInfo> getAllUelMappingInfo() {
+ return components()
+ .flatMap(cc -> cc.getUelMappings().stream())
+ .collect(Collectors.toList());
+ }
+
/**
* Provides the list of all the keystore information available in
components.
* @return a list of keystore information
@@ -270,6 +280,7 @@ public final class ComponentConfig {
private final List<TestSuiteInfo> testSuiteInfos;
private final List<KeystoreInfo> keystoreInfos;
private final List<WebappInfo> webappInfos;
+ private final List<UelMappingInfo> uelMappings;
private final List<ContainerConfig.Configuration> configurations;
/**
@@ -293,6 +304,7 @@ public final class ComponentConfig {
this.keystoreInfos = b.keystoreInfos;
this.webappInfos = b.webappInfos;
this.configurations = b.configurations;
+ this.uelMappings = b.uelMappings;
}
/**
@@ -311,6 +323,7 @@ public final class ComponentConfig {
private List<TestSuiteInfo> testSuiteInfos;
private List<KeystoreInfo> keystoreInfos;
private List<WebappInfo> webappInfos;
+ private List<UelMappingInfo> uelMappings;
private List<ContainerConfig.Configuration> configurations;
public Builder globalName(String name) {
@@ -373,6 +386,11 @@ public final class ComponentConfig {
return this;
}
+ public Builder uelMappings(List<UelMappingInfo> uelMappings) {
+ this.uelMappings = uelMappings;
+ return this;
+ }
+
public Builder configurations(List<ContainerConfig.Configuration>
configurations) {
this.configurations = configurations;
return this;
@@ -422,6 +440,7 @@ public final class ComponentConfig {
testSuiteInfos = collectElements(componentElement, "test-suite",
TestSuiteInfo::new);
keystoreInfos = collectElements(componentElement, "keystore",
KeystoreInfo::new);
webappInfos = collectElements(componentElement, "webapp",
WebappInfo::new);
+ uelMappings = collectElements(componentElement, "uel-mapping",
UelMappingInfo::new);
resourceLoaderInfos = UtilXml.childElementList(componentElement,
"resource-loader").stream()
.map(ResourceLoaderInfo::new)
.collect(Collectors.collectingAndThen(
@@ -523,6 +542,10 @@ public final class ComponentConfig {
return this.keystoreInfos;
}
+ private List<UelMappingInfo> getUelMappings() {
+ return this.uelMappings;
+ }
+
public Map<String, ResourceLoaderInfo> getResourceLoaderInfos() {
return this.resourceLoaderInfos;
}
@@ -762,6 +785,25 @@ public final class ComponentConfig {
}
}
+ /**
+ * An object that models a component's uel methods mapping
+ * @see <code>ofbiz-component.xsd</code>
+ */
+ public static final class UelMappingInfo extends ResourceInfo {
+ private final String name;
+ private final String className;
+
+ private UelMappingInfo(ComponentConfig componentConfig, Element
element) {
+ super(componentConfig, element);
+ this.name = element.getAttribute("name");
+ this.className = element.getAttribute("class-name");
+ }
+
+ public String getClassName() {
+ return this.className;
+ }
+ }
+
/**
* An object that models the <code><keystore></code> element.
* @see <code>ofbiz-component.xsd</code>
diff --git
a/framework/base/src/main/java/org/apache/ofbiz/base/util/string/IUelMappingLibrary.java
b/framework/base/src/main/java/org/apache/ofbiz/base/util/string/IUelMappingLibrary.java
new file mode 100644
index 0000000000..ee96cdbd3c
--- /dev/null
+++
b/framework/base/src/main/java/org/apache/ofbiz/base/util/string/IUelMappingLibrary.java
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * 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.ofbiz.base.util.string;
+
+import java.util.List;
+
+/**
+ * Interface used for loading the Uel methods.
+ * Just extend it and add an element to an ofbiz-component to add custom
methods.
+ */
+public interface IUelMappingLibrary {
+
+ List<UelMapping> getUelMappingList();
+
+}
diff --git
a/framework/base/src/main/java/org/apache/ofbiz/base/util/string/UelFunctions.java
b/framework/base/src/main/java/org/apache/ofbiz/base/util/string/UelFunctions.java
index e6438e641c..1a6b87e8ac 100644
---
a/framework/base/src/main/java/org/apache/ofbiz/base/util/string/UelFunctions.java
+++
b/framework/base/src/main/java/org/apache/ofbiz/base/util/string/UelFunctions.java
@@ -24,15 +24,20 @@ import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.sql.Timestamp;
import java.text.DateFormat;
import java.util.Collection;
-import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
import java.util.Locale;
import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
import java.util.TimeZone;
import jakarta.el.FunctionMapper;
@@ -45,6 +50,7 @@ import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamSource;
+import org.apache.ofbiz.base.component.ComponentConfig;
import org.apache.ofbiz.base.location.FlexibleLocation;
import org.apache.ofbiz.base.util.Debug;
import org.apache.ofbiz.base.util.FileUtil;
@@ -56,165 +62,28 @@ import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;
+import static
org.apache.ofbiz.base.component.ComponentConfig.getAllUelMappingInfo;
+
/**
* Implements Unified Expression Language functions.
- * <p>Built-in functions are divided into a number of
- * namespace prefixes:</p>
- * <table border="1">
- * <caption>Miscellaneous date/time functions</caption>
- * <tr><td colspan="2"><b><code>date:</code> contains miscellaneous date/time
functions</b></td></tr>
- * <tr><td><code>date:second(Timestamp, TimeZone,
Locale)</code></td><td>Returns the second value of <code>Timestamp</code> (0 -
59).</td></tr>
- * <tr><td><code>date:minute(Timestamp, TimeZone,
Locale)</code></td><td>Returns the minute value of <code>Timestamp</code> (0 -
59).</td></tr>
- * <tr><td><code>date:hour(Timestamp, TimeZone, Locale)</code></td><td>Returns
the hour value of <code>Timestamp</code> (0 - 23).</td></tr>
- * <tr><td><code>date:dayOfMonth(Timestamp, TimeZone,
Locale)</code></td><td>Returns the day of month value of <code>Timestamp</code>
(1 - 31)
- * .</td></tr>
- * <tr><td><code>date:dayOfWeek(Timestamp, TimeZone,
Locale)</code></td><td>Returns the day of week value of <code>Timestamp</code>
(Sunday = 1,
- * Saturday = 7).</td></tr>
- * <tr><td><code>date:dayOfYear(Timestamp, TimeZone,
Locale)</code></td><td>Returns the day of year value of
<code>Timestamp</code>.</td></tr>
- * <tr><td><code>date:week(Timestamp, TimeZone, Locale)</code></td><td>Returns
the week value of <code>Timestamp</code>.</td></tr>
- * <tr><td><code>date:month(Timestamp, TimeZone,
Locale)</code></td><td>Returns the month value of <code>Timestamp</code>
(January = 0, December =
- * 11).</td></tr>
- * <tr><td><code>date:year(Timestamp, TimeZone, Locale)</code></td><td>Returns
the year value of <code>Timestamp</code>.</td></tr>
- * <tr><td><code>date:dayStart(Timestamp, TimeZone,
Locale)</code></td><td>Returns <code>Timestamp</code> set to start of
day.</td></tr>
- * <tr><td><code>date:dayEnd(Timestamp, TimeZone,
Locale)</code></td><td>Returns <code>Timestamp</code> set to end of
day.</td></tr>
- * <tr><td><code>date:weekStart(Timestamp, TimeZone,
Locale)</code></td><td>Returns <code>Timestamp</code> set to start of
week.</td></tr>
- * <tr><td><code>date:weekEnd(Timestamp, TimeZone,
Locale)</code></td><td>Returns <code>Timestamp</code> set to end of
week.</td></tr>
- * <tr><td><code>date:monthStart(Timestamp, TimeZone,
Locale)</code></td><td>Returns <code>Timestamp</code> set to start of
month.</td></tr>
- * <tr><td><code>date:monthEnd(Timestamp, TimeZone,
Locale)</code></td><td>Returns <code>Timestamp</code> set to end of
month.</td></tr>
- * <tr><td><code>date:yearStart(Timestamp, TimeZone,
Locale)</code></td><td>Returns <code>Timestamp</code> set to start of
year.</td></tr>
- * <tr><td><code>date:yearEnd(Timestamp, TimeZone,
Locale)</code></td><td>Returns <code>Timestamp</code> set to end of
year.</td></tr>
- * <tr><td><code>date:dateStr(Timestamp, TimeZone,
Locale)</code></td><td>Returns <code>Timestamp</code> as a date
<code>String</code> (yyyy-mm-dd)
- * .</td></tr>
- * <tr><td><code>date:localizedDateStr(Timestamp, TimeZone,
Locale)</code></td><td>Returns <code>Timestamp</code> as a date
<code>String</code>
- * formatted according to the supplied locale.</td></tr>
- * <tr><td><code>date:dateTimeStr(Timestamp, TimeZone,
Locale)</code></td><td>Returns <code>Timestamp</code> as a date-time
<code>String</code>
- * (yyyy-mm-dd hh:mm).</td></tr>
- * <tr><td><code>date:localizedDateTimeStr(Timestamp, TimeZone,
Locale)</code></td><td>Returns <code>Timestamp</code> as a date-time
- * <code>String</code> formatted according to the supplied locale.</td></tr>
- * <tr><td><code>date:timeStr(Timestamp, TimeZone,
Locale)</code></td><td>Returns <code>Timestamp</code> as a time
<code>String</code> (hh:mm)
- * .</td></tr>
- * <tr><td><code>date:nowTimestamp()</code></td><td>Returns <code>Timestamp
</code> for right now.</td></tr>
- * <tr><td colspan="2"><b><code>math:</code> maps to
<code>java.lang.Math</code></b></td></tr>
- * <tr><td><code>math:absDouble(double)</code></td><td>Returns the absolute
value of a <code>double</code> value.</td></tr>
- * <tr><td><code>math:absFloat(float)</code></td><td>Returns the absolute
value of a <code>float</code> value.</td></tr>
- * <tr><td><code>math:absInt(int)</code></td><td>Returns the absolute value of
an <code>int</code> value.</td></tr>
- * <tr><td><code>math:absLong(long)</code></td><td>Returns the absolute value
of a <code>long</code> value.</td></tr>
- * <tr><td><code>math:acos(double)</code></td><td>Returns the arc cosine of an
angle, in the range of 0.0 through <i>pi</i>.</td></tr>
- * <tr><td><code>math:asin(double)</code></td><td>Returns the arc sine of an
angle, in the range of -<i>pi</i>/2 through <i>pi</i>/2.</td></tr>
- * <tr><td><code>math:atan(double)</code></td><td>Returns the arc tangent of
an angle, in the range of -<i>pi</i>/2 through <i>pi</i>/2.</td></tr>
- * <tr><td><code>math:atan2(double, double)</code></td><td>Converts
rectangular coordinates (<code>x</code>, <code>y</code>) to polar (r,
- * <i>theta</i>).</td></tr>
- * <tr><td><code>math:cbrt(double)</code></td><td>Returns the cube root of a
<code>double</code> value.</td></tr>
- * <tr><td><code>math:ceil(double)</code></td><td>Returns the smallest
(closest to negative infinity) <code>double</code> value that is greater
- * than or equal to the argument and is equal to a mathematical
integer.</td></tr>
- * <tr><td><code>math:cos(double)</code></td><td>Returns the trigonometric
cosine of an angle.</td></tr>
- * <tr><td><code>math:cosh(double)</code></td><td>Returns the hyperbolic
cosine of a <code>double</code> value.</td></tr>
- * <tr><td><code>math:exp(double)</code></td><td>Returns Euler's number
<i>e</i> raised to the power of a <code>double</code> value.</td></tr>
- * <tr><td><code>math:expm1(double)</code></td><td>Returns
<i>e</i><sup>x</sup> -1.</td></tr>
- * <tr><td><code>math:floor(double)</code></td><td>Returns the largest
(closest to positive infinity) <code>double</code> value that is less than
- * or equal to the argument and is equal to a mathematical integer.</td></tr>
- * <tr><td><code>math:hypot(double, double)</code></td><td>Returns
sqrt(<i>x</i><sup>2</sup> +<i>y</i><sup>2</sup>) without intermediate
- * overflow or underflow.</td></tr>
- * <tr><td><code>math:IEEEremainder(double, double)</code></td><td>Computes
the remainder operation on two arguments as prescribed by the IEEE 754
- * standard.</td></tr>
- * <tr><td><code>math:log(double)</code></td><td>Returns the natural logarithm
(base <i>e</i>) of a <code>double</code> value.</td></tr>
- * <tr><td><code>math:log10(double)</code></td><td>Returns the base 10
logarithm of a <code>double</code> value.</td></tr>
- * <tr><td><code>math:log1p(double)</code></td><td>Returns the natural
logarithm of the sum of the argument and 1.</td></tr>
- * <tr><td><code>math:maxDouble(double, double)</code></td><td>Returns the
greater of two <code>double</code> values.</td></tr>
- * <tr><td><code>math:maxFloat(float, float)</code></td><td>Returns the
greater of two <code>float</code> values.</td></tr>
- * <tr><td><code>math:maxInt(int, int)</code></td><td>Returns the greater of
two <code>int</code> values.</td></tr>
- * <tr><td><code>math:maxLong(long, long)</code></td><td>Returns the greater
of two <code>long</code> values.</td></tr>
- * <tr><td><code>math:minDouble(double, double)</code></td><td>Returns the
smaller of two <code>double</code> values.</td></tr>
- * <tr><td><code>math:minFloat(float, float)</code></td><td>Returns the
smaller of two <code>float</code> values.</td></tr>
- * <tr><td><code>math:minInt(int, int)</code></td><td>Returns the smaller of
two <code>int</code> values.</td></tr>
- * <tr><td><code>math:minLong(long, long)</code></td><td>Returns the smaller
of two <code>long</code> values.</td></tr>
- * <tr><td><code>math:pow(double, double)</code></td><td>Returns the value of
the first argument raised to the power of the second argument.</td></tr>
- * <tr><td><code>math:random()</code></td><td>Returns a <code>double</code>
value with a positive sign, greater than or equal to <code>0.0</code>
- * and less than <code>1.0</code>.</td></tr>
- * <tr><td><code>math:rint(double)</code></td><td>Returns the
<code>double</code> value that is closest in value to the argument and is equal
to a
- * mathematical integer.</td></tr>
- * <tr><td><code>math:roundDouble(double)</code></td><td>Returns the closest
<code>long</code> to the argument.</td></tr>
- * <tr><td><code>math:roundFloat(float)</code></td><td>Returns the closest
<code>int</code> to the argument.</td></tr>
- * <tr><td><code>math:signumDouble(double)</code></td><td>Returns the signum
function of the argument; zero if the argument is zero, 1.0 if the
- * argument is greater than zero, -1.0 if the argument is less than
zero.</td></tr>
- * <tr><td><code>math:signumFloat(float)</code></td><td>Returns the signum
function of the argument; zero if the argument is zero, 1.0f if the
- * argument is greater than zero, -1.0f if the argument is less than
zero.</td></tr>
- * <tr><td><code>math:sin(double)</code></td><td>Returns the trigonometric
sine of an angle.</td></tr>
- * <tr><td><code>math:sinh(double)</code></td><td>Returns the hyperbolic sine
of a <code>double</code> value.</td></tr>
- * <tr><td><code>math:sqrt(double)</code></td><td>Returns the correctly
rounded positive square root of a <code>double</code> value.</td></tr>
- * <tr><td><code>math:tan(double)</code></td><td>Returns the trigonometric
tangent of an angle.</td></tr>
- * <tr><td><code>math:tanh(double)</code></td><td>Returns the hyperbolic
tangent of a <code>double</code> value.</td></tr>
- * <tr><td><code>math:toDegrees(double)</code></td><td>Converts an angle
measured in radians to an approximately equivalent angle measured in
- * degrees.</td></tr>
- * <tr><td><code>math:toRadians(double)</code></td><td>Converts an angle
measured in degrees to an approximately equivalent angle measured in
- * radians.</td></tr>
- * <tr><td><code>math:ulpDouble(double)</code></td><td>Returns the size of an
ulp (units in the last place) of the argument.</td></tr>
- * <tr><td><code>math:ulpFloat(float)</code></td><td>Returns the size of an
ulp (units in the last place) of the argument.</td></tr>
- * <tr><td colspan="2"><b><code>str:</code> maps to
<code>java.lang.String</code></b></td></tr>
- * <tr><td><code>str:endsWith(String, String)</code></td><td>Returns
<code>true</code> if this string ends with the specified suffix.</td></tr>
- * <tr><td><code>str:indexOf(String, String)</code></td><td>Returns the index
within this string of the first occurrence of the specified substring
- * .</td></tr>
- * <tr><td><code>str:lastIndexOf(String, String)</code></td><td>Returns the
index within this string of the last occurrence of the specified
- * character.</td></tr>
- * <tr><td><code>str:length(String)</code></td><td>Returns the length of this
string.</td></tr>
- * <tr><td><code>str:replace(String, String, String)</code></td><td>Replaces
each substring of this string that matches the literal target sequence
- * with the specified literal replacement sequence.</td></tr>
- * <tr><td><code>str:replaceAll(String, String,
String)</code></td><td>Replaces each substring of this string that matches the
given regular
- * expression with the given replacement.</td></tr>
- * <tr><td><code>str:replaceFirst(String, String,
String)</code></td><td>Replaces the first substring of this string that matches
the given regular
- * expression with the given replacement.</td></tr>
- * <tr><td><code>str:startsWith(String, String)</code></td><td>Returns
<code>true</code> if this string starts with the specified prefix.</td></tr>
- * <tr><td><code>str:endstring(String, int)</code></td><td>Returns a new
string that is a substring of this string. The substring begins with the
- * character at the specified index and extends to the end of this
string.</td></tr>
- * <tr><td><code>str:substring(String, int, int)</code></td><td>Returns a new
string that is a substring of this string. The substring begins at
- * the specified beginIndex and extends to the character at index endIndex -
1. Thus the length of the substring is endIndex-beginIndex.</td></tr>
- * <tr><td><code>str:toLowerCase(String)</code></td><td>Converts all of the
characters in this String to lower case using the rules of the default
- * locale.</td></tr>
- * <tr><td><code>str:toString(Object)</code></td><td>Converts
<code>Object</code> to a <code>String</code> - bypassing localization.</td></tr>
- * <tr><td><code>str:toUpperCase(String)</code></td><td>Converts all of the
characters in this String to upper case using the rules of the default
- * locale.</td></tr>
- * <tr><td><code>str:trim(String)</code></td><td>Returns a copy of the string,
with leading and trailing whitespace omitted.</td></tr>
- * <tr><td colspan="2"><b><code>sys:</code> maps to
<code>java.lang.System</code></b></td></tr>
- * <tr><td><code>sys:getenv(String)</code></td><td>Gets the value of the
specified environment variable.</td></tr>
- * <tr><td><code>sys:getProperty(String)</code></td><td>Gets the system
property indicated by the specified key.</td></tr>
- * <tr><td colspan="2"><b><code>util:</code> contains miscellaneous utility
functions</b></td></tr>
- * <tr><td><code>util:defaultLocale()</code></td><td>Returns the default
<code>Locale</code>.</td></tr>
- * <tr><td><code>util:defaultTimeZone()</code></td><td>Returns the default
<code>TimeZone</code>.</td></tr>
- * <tr><td><code>util:label(String, String, Locale)</code></td><td>Return the
label present in ressource on the given locale.</td></tr>
- * <tr><td><code>util:size(Object)</code></td><td>Returns the size of
<code>Maps</code>,
- * <tr><td><code>screen:id(ScreenStack)</code></td><td>Returns the id of the
current screen,
- * <code>Collections</code>, and <code>Strings</code>. Invalid
<code>Object</code> types return -1.</td></tr>
- * <tr><td colspan="2"><b><code>dom:</code> contains
<code>org.w3c.dom.*</code> functions</b></td></tr>
- * <tr><td><code>dom:readHtmlDocument(String)</code></td><td>Reads an HTML
file and returns a <code>org.w3c.dom.Document</code> instance.</td></tr>
- * <tr><td><code>dom:readXmlDocument(String)</code></td><td>Reads an XML file
and returns a <code>org.w3c.dom.Document</code> instance.</td></tr>
- * <tr><td><code>dom:toHtmlString(Node, String encoding, boolean indent, int
indentAmount)</code></td><td>Returns a <code>org.w3c.dom.Node</code>
- * as an HTML <code>String</code>.</td></tr>
- * <tr><td><code>dom:toXmlString(Node, String encoding, boolean
omitXmlDeclaration, boolean indent, int indentAmount)</code></td><td>Returns a
- * <code>org.w3c.dom.Node</code> as an XML <code>String</code>.</td></tr>
- * <tr><td><code>dom:writeXmlDocument(String, Node, String encoding, boolean
omitXmlDeclaration, boolean indent, int indentAmount)
- * </code></td><td>Writes a <code>org.w3c.dom.Node</code> to an XML file and
returns <code>true</code> if successful.</td></tr>
- * </table>
+ * <p>The uel functions mappings are defined in the
<code>ofbiz-component</code> files. An example can
+ * be found in the base component of the framework.</p>
*/
public class UelFunctions {
protected static final Functions FUNCTION_MAPPER = new Functions();
public static final String MODULE = UelFunctions.class.getName();
+ public UelFunctions() { }
+
/**
* Returns a <code>FunctionMapper</code> instance.
* @return <code>FunctionMapper</code> instance
*/
- public static FunctionMapper getFunctionMapper() {
+ public static Functions getFunctionMapper() {
return FUNCTION_MAPPER;
}
- /**
- * Add a function to OFBiz's built-in UEL functions.
- */
- public static synchronized void setFunction(String prefix, String
localName, Method method) {
- FUNCTION_MAPPER.functionMap.put(prefix + ":" + localName, method);
- }
-
public static String dateString(Timestamp stamp, TimeZone timeZone, Locale
locale) {
DateFormat dateFormat =
UtilDateTime.toDateFormat(UtilDateTime.getDateFormat(), timeZone, locale);
dateFormat.setTimeZone(timeZone);
@@ -468,119 +337,51 @@ public class UelFunctions {
return null;
}
- protected static class Functions extends FunctionMapper {
- private final Map<String, Method> functionMap = new HashMap<>();
+ protected static final class Functions extends FunctionMapper {
+ private Set<UelMapping> functionList = new HashSet<>();
public Functions() {
- try {
- this.functionMap.put("date:second",
UtilDateTime.class.getMethod("getSecond", Timestamp.class, TimeZone.class,
Locale.class));
- this.functionMap.put("date:minute",
UtilDateTime.class.getMethod("getMinute", Timestamp.class, TimeZone.class,
Locale.class));
- this.functionMap.put("date:hour",
UtilDateTime.class.getMethod("getHour", Timestamp.class, TimeZone.class,
Locale.class));
- this.functionMap.put("date:dayOfMonth",
UtilDateTime.class.getMethod("getDayOfMonth", Timestamp.class, TimeZone.class,
Locale.class));
- this.functionMap.put("date:dayOfWeek",
UtilDateTime.class.getMethod("getDayOfWeek", Timestamp.class, TimeZone.class,
Locale.class));
- this.functionMap.put("date:dayOfYear",
UtilDateTime.class.getMethod("getDayOfYear", Timestamp.class, TimeZone.class,
Locale.class));
- this.functionMap.put("date:week",
UtilDateTime.class.getMethod("getWeek", Timestamp.class, TimeZone.class,
Locale.class));
- this.functionMap.put("date:month",
UtilDateTime.class.getMethod("getMonth", Timestamp.class, TimeZone.class,
Locale.class));
- this.functionMap.put("date:year",
UtilDateTime.class.getMethod("getYear", Timestamp.class, TimeZone.class,
Locale.class));
- this.functionMap.put("date:dayStart",
UtilDateTime.class.getMethod("getDayStart", Timestamp.class, TimeZone.class,
Locale.class));
- this.functionMap.put("date:dayEnd",
UtilDateTime.class.getMethod("getDayEnd", Timestamp.class, TimeZone.class,
Locale.class));
- this.functionMap.put("date:weekStart",
UtilDateTime.class.getMethod("getWeekStart", Timestamp.class, TimeZone.class,
Locale.class));
- this.functionMap.put("date:weekEnd",
UtilDateTime.class.getMethod("getWeekEnd", Timestamp.class, TimeZone.class,
Locale.class));
- this.functionMap.put("date:monthStart",
UtilDateTime.class.getMethod("getMonthStart", Timestamp.class, TimeZone.class,
Locale.class));
- this.functionMap.put("date:monthEnd",
UtilDateTime.class.getMethod("getMonthEnd", Timestamp.class, TimeZone.class,
Locale.class));
- this.functionMap.put("date:yearStart",
UtilDateTime.class.getMethod("getYearStart", Timestamp.class, TimeZone.class,
Locale.class));
- this.functionMap.put("date:yearEnd",
UtilDateTime.class.getMethod("getYearEnd", Timestamp.class, TimeZone.class,
Locale.class));
- this.functionMap.put("date:dateStr",
UelFunctions.class.getMethod("dateString", Timestamp.class, TimeZone.class,
Locale.class));
- this.functionMap.put("date:localizedDateStr",
UelFunctions.class.getMethod("localizedDateString", Timestamp.class,
TimeZone.class,
- Locale.class));
- this.functionMap.put("date:localizedDateTimeStr",
UelFunctions.class.getMethod("localizedDateTimeString", Timestamp.class,
- TimeZone.class, Locale.class));
- this.functionMap.put("date:timeStr",
UelFunctions.class.getMethod("timeString", Timestamp.class, TimeZone.class,
Locale.class));
- this.functionMap.put("date:nowTimestamp",
UtilDateTime.class.getMethod("nowTimestamp"));
- this.functionMap.put("math:absDouble",
Math.class.getMethod("abs", double.class));
- this.functionMap.put("math:absFloat",
Math.class.getMethod("abs", float.class));
- this.functionMap.put("math:absInt",
Math.class.getMethod("abs", int.class));
- this.functionMap.put("math:absLong",
Math.class.getMethod("abs", long.class));
- this.functionMap.put("math:acos", Math.class.getMethod("abs",
double.class));
- this.functionMap.put("math:asin", Math.class.getMethod("asin",
double.class));
- this.functionMap.put("math:atan", Math.class.getMethod("atan",
double.class));
- this.functionMap.put("math:atan2", Math.class.getMethod("max",
double.class, double.class));
- this.functionMap.put("math:cbrt", Math.class.getMethod("cbrt",
double.class));
- this.functionMap.put("math:ceil", Math.class.getMethod("ceil",
double.class));
- this.functionMap.put("math:cos", Math.class.getMethod("cos",
double.class));
- this.functionMap.put("math:cosh", Math.class.getMethod("cosh",
double.class));
- this.functionMap.put("math:exp", Math.class.getMethod("exp",
double.class));
- this.functionMap.put("math:expm1",
Math.class.getMethod("expm1", double.class));
- this.functionMap.put("math:floor",
Math.class.getMethod("floor", double.class));
- this.functionMap.put("math:hypot",
Math.class.getMethod("hypot", double.class, double.class));
- this.functionMap.put("math:IEEEremainder",
Math.class.getMethod("IEEEremainder", double.class, double.class));
- this.functionMap.put("math:log", Math.class.getMethod("log",
double.class));
- this.functionMap.put("math:log10",
Math.class.getMethod("log10", double.class));
- this.functionMap.put("math:log1p",
Math.class.getMethod("log1p", double.class));
- this.functionMap.put("math:maxDouble",
Math.class.getMethod("max", double.class, double.class));
- this.functionMap.put("math:maxFloat",
Math.class.getMethod("max", float.class, float.class));
- this.functionMap.put("math:maxInt",
Math.class.getMethod("max", int.class, int.class));
- this.functionMap.put("math:maxLong",
Math.class.getMethod("max", long.class, long.class));
- this.functionMap.put("math:minDouble",
Math.class.getMethod("min", double.class, double.class));
- this.functionMap.put("math:minFloat",
Math.class.getMethod("min", float.class, float.class));
- this.functionMap.put("math:minInt",
Math.class.getMethod("min", int.class, int.class));
- this.functionMap.put("math:minLong",
Math.class.getMethod("min", long.class, long.class));
- this.functionMap.put("math:pow", Math.class.getMethod("pow",
double.class, double.class));
- this.functionMap.put("math:random",
Math.class.getMethod("random"));
- this.functionMap.put("math:rint", Math.class.getMethod("rint",
double.class));
- this.functionMap.put("math:roundDouble",
Math.class.getMethod("round", double.class));
- this.functionMap.put("math:roundFloat",
Math.class.getMethod("round", float.class));
- this.functionMap.put("math:signumDouble",
Math.class.getMethod("signum", double.class));
- this.functionMap.put("math:signumFloat",
Math.class.getMethod("signum", float.class));
- this.functionMap.put("math:sin", Math.class.getMethod("sin",
double.class));
- this.functionMap.put("math:sinh", Math.class.getMethod("sinh",
double.class));
- this.functionMap.put("math:sqrt", Math.class.getMethod("sqrt",
double.class));
- this.functionMap.put("math:tan", Math.class.getMethod("tan",
double.class));
- this.functionMap.put("math:tanh", Math.class.getMethod("tanh",
double.class));
- this.functionMap.put("math:toDegrees",
Math.class.getMethod("toDegrees", double.class));
- this.functionMap.put("math:toRadians",
Math.class.getMethod("toRadians", double.class));
- this.functionMap.put("math:ulpDouble",
Math.class.getMethod("ulp", double.class));
- this.functionMap.put("math:ulpFloat",
Math.class.getMethod("ulp", float.class));
- this.functionMap.put("str:endsWith",
UelFunctions.class.getMethod("endsWith", String.class, String.class));
- this.functionMap.put("str:indexOf",
UelFunctions.class.getMethod("indexOf", String.class, String.class));
- this.functionMap.put("str:lastIndexOf",
UelFunctions.class.getMethod("lastIndexOf", String.class, String.class));
- this.functionMap.put("str:length",
UelFunctions.class.getMethod("length", String.class));
- this.functionMap.put("str:replace",
UelFunctions.class.getMethod("replace", String.class, String.class,
String.class));
- this.functionMap.put("str:replaceAll",
UelFunctions.class.getMethod("replaceAll", String.class, String.class,
String.class));
- this.functionMap.put("str:replaceFirst",
UelFunctions.class.getMethod("replaceFirst", String.class, String.class,
String.class));
- this.functionMap.put("str:startsWith",
UelFunctions.class.getMethod("startsWith", String.class, String.class));
- this.functionMap.put("str:endstring",
UelFunctions.class.getMethod("endString", String.class, int.class));
- this.functionMap.put("str:substring",
UelFunctions.class.getMethod("subString", String.class, int.class, int.class));
- this.functionMap.put("str:toString",
UelFunctions.class.getMethod("toString", Object.class));
- this.functionMap.put("str:toLowerCase",
UelFunctions.class.getMethod("toLowerCase", String.class));
- this.functionMap.put("str:toUpperCase",
UelFunctions.class.getMethod("toUpperCase", String.class));
- this.functionMap.put("str:trim",
UelFunctions.class.getMethod("trim", String.class));
- this.functionMap.put("sys:getenv",
UelFunctions.class.getMethod("sysGetEnv", String.class));
- this.functionMap.put("sys:getProperty",
UelFunctions.class.getMethod("sysGetProp", String.class));
- this.functionMap.put("util:size",
UelFunctions.class.getMethod("getSize", Object.class));
- this.functionMap.put("util:defaultLocale",
Locale.class.getMethod("getDefault"));
- this.functionMap.put("util:defaultTimeZone",
TimeZone.class.getMethod("getDefault"));
- this.functionMap.put("util:label",
UelFunctions.class.getMethod("label", String.class, String.class,
Locale.class));
- this.functionMap.put("screen:id",
UelFunctions.class.getMethod("resolveCurrentScreenId",
ScreenRenderer.ScreenStack.class));
- this.functionMap.put("dom:readHtmlDocument",
UelFunctions.class.getMethod("readHtmlDocument", String.class));
- this.functionMap.put("dom:readXmlDocument",
UelFunctions.class.getMethod("readXmlDocument", String.class));
- this.functionMap.put("dom:toHtmlString",
UelFunctions.class.getMethod("toHtmlString", Node.class, String.class,
boolean.class,
- int.class));
- this.functionMap.put("dom:toXmlString",
UelFunctions.class.getMethod("toXmlString", Node.class, String.class,
boolean.class,
- boolean.class, int.class));
- this.functionMap.put("dom:writeXmlDocument",
UelFunctions.class.getMethod("writeXmlDocument", String.class, Node.class,
- String.class, boolean.class, boolean.class,
int.class));
- } catch (NoSuchMethodException | NullPointerException |
SecurityException e) {
- Debug.logError(e, "Error while initializing
UelFunctions.Functions instance", MODULE);
- }
+ this.functionList = loadUelFromComponents();
if (Debug.verboseOn()) {
- Debug.logVerbose("UelFunctions.Functions loaded " +
this.functionMap.size() + " functions", MODULE);
+ Debug.logVerbose("UelFunctions.Functions loaded " +
this.functionList.size() + " functions", MODULE);
}
}
/** resolve function */
@Override
public Method resolveFunction(String prefix, String localName) {
- return functionMap.get(prefix + ":" + localName);
+ Optional<UelMapping> uelCandidate = functionList.stream()
+ .filter(uelMapping -> Objects.equals(uelMapping.getKey(),
prefix + ":" + localName))
+ .findFirst();
+ return uelCandidate.map(UelMapping::getMethod).orElse(null);
+ }
+
+ private Set<UelMapping> loadUelFromComponents() {
+ List<ComponentConfig.UelMappingInfo> uelsMappingInfo =
getAllUelMappingInfo();
+ Set<UelMapping> uelMappings = new HashSet<>();
+
+ uelsMappingInfo.forEach(uelMappingInfo -> {
+ String className = uelMappingInfo.getClassName();
+ IUelMappingLibrary mapping = null;
+ Class<?> lClass;
+ ClassLoader classLoader =
Thread.currentThread().getContextClassLoader();
+ try {
+ lClass = classLoader.loadClass(className);
+ mapping = (IUelMappingLibrary)
lClass.getDeclaredConstructor().newInstance();
+ } catch (ClassNotFoundException | InvocationTargetException |
InstantiationException
+ | IllegalAccessException | NoSuchMethodException e) {
+ Debug.logError(e, "Error while initializing
UelFunctions.Functions instance", MODULE);
+ }
+ if (mapping == null) {
+ return;
+ }
+ uelMappings.addAll(mapping.getUelMappingList());
+ });
+ return uelMappings;
+ }
+
+ public Set<UelMapping> getUelFunctions() {
+ return this.functionList;
}
}
+
}
diff --git
a/framework/base/src/main/java/org/apache/ofbiz/base/util/string/UelMapping.java
b/framework/base/src/main/java/org/apache/ofbiz/base/util/string/UelMapping.java
new file mode 100644
index 0000000000..d647fe76ea
--- /dev/null
+++
b/framework/base/src/main/java/org/apache/ofbiz/base/util/string/UelMapping.java
@@ -0,0 +1,49 @@
+package org.apache.ofbiz.base.util.string;
+
+import java.lang.reflect.Method;
+
+/**
+ * Small Uel utility class
+ */
+public final class UelMapping {
+
+ /**
+ * The key of this Uel, often composed by a domain and a name separated by
a column
+ */
+ private final String myKey;
+
+ /**
+ * The method that is called by the Uel
+ */
+ private final Method myMethod;
+
+ /**
+ * The description of the Uel that will be displayed in the Uel screen
+ */
+ private final String myDescription;
+
+ public UelMapping(String key, Method method) {
+ myKey = key;
+ myMethod = method;
+ myDescription = "No description";
+ }
+
+ public UelMapping(String key, Method method, String description) {
+ myKey = key;
+ myMethod = method;
+ myDescription = description;
+ }
+
+ public String getKey() {
+ return myKey;
+ }
+
+ public Method getMethod() {
+ return myMethod;
+ }
+
+ public String getDescription() {
+ return myDescription;
+ }
+
+}
diff --git a/framework/base/testdef/basetests.xml
b/framework/base/testdef/basetests.xml
index 661302cf02..81b1638abd 100644
--- a/framework/base/testdef/basetests.xml
+++ b/framework/base/testdef/basetests.xml
@@ -18,9 +18,23 @@
-->
<test-suite suite-name="basetests"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-
xsi:noNamespaceSchemaLocation="http://ofbiz.apache.org/dtds/test-suite.xsd">
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+
xsi:noNamespaceSchemaLocation="http://ofbiz.apache.org/dtds/test-suite.xsd">
<test-case case-name="basesimpletests">
<junit-test-suite class-name="org.apache.ofbiz.base.test.SimpleTests"/>
</test-case>
+
+ <test-case case-name="uel-date-tests">
+ <junit-test-suite
class-name="org.apache.ofbiz.base.test.uel.DateUelTest"/>
+ </test-case>
+ <test-case case-name="uel-math-tests">
+ <junit-test-suite
class-name="org.apache.ofbiz.base.test.uel.MathUelTest"/>
+ </test-case>
+ <test-case case-name="uel-string-tests">
+ <junit-test-suite
class-name="org.apache.ofbiz.base.test.uel.StringUelTest"/>
+ </test-case>
+ <test-case case-name="uel-misc-tests">
+ <junit-test-suite
class-name="org.apache.ofbiz.base.test.uel.MiscUelTest"/>
+ </test-case>
+
</test-suite>
diff --git a/framework/webtools/config/WebtoolsUiLabels.xml
b/framework/webtools/config/WebtoolsUiLabels.xml
index 6edef76fa0..00443a0220 100644
--- a/framework/webtools/config/WebtoolsUiLabels.xml
+++ b/framework/webtools/config/WebtoolsUiLabels.xml
@@ -880,6 +880,10 @@
<value xml:lang="zh">异步</value>
<value xml:lang="zh-TW">非同步</value>
</property>
+ <property key="WebtoolsAvailableUelMethods">
+ <value xml:lang="en">Available UEL Methods</value>
+ <value xml:lang="fr">Fonctions UEL disponibles</value>
+ </property>
<property key="WebtoolsBackToCacheMaintenance">
<value xml:lang="de">Zurück zur Cache-Wartung</value>
<value xml:lang="en">Back to Cache Maintenance</value>
@@ -5688,6 +5692,22 @@
<value xml:lang="zh">全部</value>
<value xml:lang="zh-TW">全部</value>
</property>
+ <property key="WebtoolsUelKeyString">
+ <value xml:lang="en">Uel string key</value>
+ <value xml:lang="fr">Clef de l'Uel</value>
+ </property>
+ <property key="WebtoolsUelMethodClass">
+ <value xml:lang="en">Uel Method class</value>
+ <value xml:lang="fr">Methode appelée par l'Uel</value>
+ </property>
+ <property key="WebtoolsUelMethodParams">
+ <value xml:lang="en">Uel method params</value>
+ <value xml:lang="fr">Paramètres de la methode Uel</value>
+ </property>
+ <property key="WebtoolsUelDescription">
+ <value xml:lang="en">Uel description</value>
+ <value xml:lang="fr">Description de l'Uel</value>
+ </property>
<property key="WebtoolsUnCheckAll">
<value xml:lang="de">Keine auswählen</value>
<value xml:lang="en">Un-Check All</value>
diff --git
a/framework/webtools/src/main/groovy/org/apache/ofbiz/webtools/util/uel/FindAvailableUel.groovy
b/framework/webtools/src/main/groovy/org/apache/ofbiz/webtools/util/uel/FindAvailableUel.groovy
new file mode 100644
index 0000000000..d64fff2e7c
--- /dev/null
+++
b/framework/webtools/src/main/groovy/org/apache/ofbiz/webtools/util/uel/FindAvailableUel.groovy
@@ -0,0 +1,37 @@
+/*
+ * 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.ofbiz.webtools.util.uel
+
+import org.apache.ofbiz.base.util.UtilMisc
+import org.apache.ofbiz.base.util.string.UelFunctions
+import org.apache.ofbiz.base.util.string.UelMapping
+
+List uelList = []
+Set<UelMapping> uelMap = UelFunctions.getFunctionMapper().getUelFunctions()
+uelMap.each { mapping ->
+ uelList << [
+ uelKeyString: mapping.key,
+ uelMethodClass: mapping.method.getDeclaringClass(),
+ uelMethodParams:
mapping.method.getParameterTypes()*.getName().join(', '),
+ uelDescription: mapping.description ?: 'Uel has no description'
+ ]
+}
+
+context.uelList = (parameters.sortField) ? UtilMisc.sortMaps(uelList,
[parameters.sortField]) : uelList
+
diff --git a/framework/webtools/template/Main.ftl
b/framework/webtools/template/Main.ftl
index 4df797bc4d..e683f42b14 100644
--- a/framework/webtools/template/Main.ftl
+++ b/framework/webtools/template/Main.ftl
@@ -99,6 +99,7 @@ under the License.
<#if security.hasPermission("PORTALPAGE_ADMIN", session)>
<li><a
href="<@ofbizUrl>FindGeo</@ofbizUrl>">${uiLabelMap.WebtoolsGeoManagement}</a></li>
<li><a
href="<@ofbizUrl>WebtoolsLayoutDemo</@ofbizUrl>">${uiLabelMap.WebtoolsLayoutDemo}</a></li>
+ <li><a
href="<@ofbizUrl>AvailableUelList</@ofbizUrl>">${uiLabelMap.WebtoolsAvailableUelMethods}</a></li>
</#if>
<#if security.hasPermission("ENUM_STATUS_MAINT", session)>
<#--
diff --git a/framework/webtools/webapp/webtools/WEB-INF/controller.xml
b/framework/webtools/webapp/webtools/WEB-INF/controller.xml
index 375dd08768..a2499a9204 100644
--- a/framework/webtools/webapp/webtools/WEB-INF/controller.xml
+++ b/framework/webtools/webapp/webtools/WEB-INF/controller.xml
@@ -635,6 +635,7 @@ under the License.
<request-map uri="WebtoolsLayoutDemoCsv"><security https="true"
auth="true"/><response name="success" type="view"
value="WebtoolsLayoutDemoCsv"/></request-map>
<request-map uri="WebtoolsLayoutDemoXls"><security https="true"
auth="true"/><response name="success" type="view"
value="WebtoolsLayoutDemoXls"/></request-map>
+ <request-map uri="AvailableUelList"><security https="true"
auth="true"/><response name="success" type="view"
value="AvailableUelList"/></request-map>
<!-- end of request mappings -->
<!-- View Mappings -->
@@ -743,5 +744,6 @@ under the License.
<view-map name="WebtoolsLayoutDemoCsv" type="screencsv"
page="component://webtools/widget/MiscScreens.xml#WebtoolsLayoutDemoText"
content-type="text/csv"/>
<view-map name="WebtoolsLayoutDemoXls" type="screenxls"
page="component://webtools/widget/MiscScreens.xml#WebtoolsLayoutDemoText"
content-type="application/vnd.ms-excel"/>
+ <view-map name="AvailableUelList" type="screen"
page="component://webtools/widget/MiscScreens.xml#AvailableUelList"/>
<!-- end of view mappings -->
</site-conf>
diff --git a/framework/webtools/widget/MiscScreens.xml
b/framework/webtools/widget/MiscScreens.xml
index 48c69516c7..965eeea806 100644
--- a/framework/webtools/widget/MiscScreens.xml
+++ b/framework/webtools/widget/MiscScreens.xml
@@ -239,4 +239,26 @@ under the License.
</widgets>
</section>
</screen>
+
+ <screen name="AvailableUelList">
+ <section>
+ <actions>
+ <script
location="component://webtools/src/main/groovy/org/apache/ofbiz/webtools/util/uel/FindAvailableUel.groovy"/>
+ </actions>
+ <widgets>
+ <decorator-screen name="main-decorator"
location="${parameters.mainDecoratorLocation}">
+ <decorator-section name="body">
+ <section>
+ <widgets>
+ <screenlet
title="${uiLabelMap.WebtoolsAvailableUelMethods}">
+ <include-form name="ListUel"
location="component://webtools/widget/UelForms.xml"/>
+ </screenlet>
+ </widgets>
+ </section>
+ </decorator-section>
+ </decorator-screen>
+ </widgets>
+ </section>
+ </screen>
+
</screens>
diff --git a/framework/webtools/widget/UelForms.xml
b/framework/webtools/widget/UelForms.xml
new file mode 100644
index 0000000000..e2150226ed
--- /dev/null
+++ b/framework/webtools/widget/UelForms.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+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.
+-->
+
+<forms xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns="http://ofbiz.apache.org/Widget-Form"
+ xsi:schemaLocation="http://ofbiz.apache.org/Widget-Form
http://ofbiz.apache.org/dtds/widget-form.xsd">
+
+ <grid name="ListUel" list-name="uelList" paginate-target="AvailableUelList"
+ separate-columns="true" odd-row-style="alternate-row"
default-table-style="basic-table hover-bar"
+ header-row-style="header-row-2">
+ <field name="uelKeyString" title="${uiLabelMap.WebtoolsUelKeyString}"
sort-field="true"><display/></field>
+ <field name="uelMethodClass"
title="${uiLabelMap.WebtoolsUelMethodClass}"
sort-field="true"><display/></field>
+ <field name="uelMethodParams"
title="${uiLabelMap.WebtoolsUelMethodParams}"
sort-field="true"><display/></field>
+ <field name="uelDescription"
title="${uiLabelMap.WebtoolsUelDescription}"
sort-field="true"><display/></field>
+ </grid>
+
+</forms>