You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ofbiz.apache.org by nm...@apache.org on 2020/03/10 13:09:26 UTC

[ofbiz-framework] branch trunk updated: Improved: Convert CommonServices.xml from mini lang to groovy (OFBIZ-11402)

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 930f4af  Improved: Convert CommonServices.xml from mini lang to groovy (OFBIZ-11402)
930f4af is described below

commit 930f4af7a223ed210415b43c04134008d41c1a82
Author: Nicolas Malin <ni...@nereide.fr>
AuthorDate: Tue Mar 10 14:09:08 2020 +0100

    Improved: Convert CommonServices.xml from mini lang to groovy
    (OFBIZ-11402)
    
    Thanks to Wiebke Pätzold for providing the patch
---
 .../common/groovyScripts/CommonServices.groovy     | 318 +++++++++++++++++++-
 framework/common/minilang/CommonServices.xml       | 330 ---------------------
 framework/common/servicedef/services.xml           |  57 ++--
 3 files changed, 337 insertions(+), 368 deletions(-)

diff --git a/framework/common/groovyScripts/CommonServices.groovy b/framework/common/groovyScripts/CommonServices.groovy
index 0740f4c..48fe0ec 100644
--- a/framework/common/groovyScripts/CommonServices.groovy
+++ b/framework/common/groovyScripts/CommonServices.groovy
@@ -17,18 +17,322 @@
  * under the License.
  */
 
+import java.math.RoundingMode
+import java.sql.Timestamp
+import org.apache.ofbiz.base.util.UtilDateTime
 import org.apache.ofbiz.base.util.UtilProperties
-import org.apache.ofbiz.base.util.UtilValidate
+import org.apache.ofbiz.common.CommonWorkers
 import org.apache.ofbiz.entity.GenericValue
 
+/**
+ * Main permission logic
+ */
+def commonGenericPermission() {
+    parameters.primaryPermission = "COMMON"
+    Map result = run service: "genericBasePermissionCheck", with: parameters
+    return result
+}
 
 /**
- * Create a KeywordThesaurus
+ * Convert UOM values
+ */
+def convertUom() {
+    // base case: if both uomIds are the same, return the original value
+    Map result = success()
+    Timestamp asOfDate
+    GenericValue uomConversion
+    RoundingMode roundingMode
+    int decimalScale
+    BigDecimal convertedValue
+
+    // setting up default parameters if not specified
+    if (!parameters.defaultRoundingMode) {
+        parameters.defaultRoundingMode = RoundingMode.HALF_EVEN
+    }
+    if (!parameters.defaultDecimalScale) {
+        parameters.defaultDecimalScale = 2
+    }
+
+    if (parameters.uomId == parameters.uomIdTo) {
+        result.convertedValue = parameters.originalValue
+        return result
+    }
+
+    asOfDate = parameters.asOfDate ?: UtilDateTime.nowTimestamp()
+
+    //first try the UomConversionDated entity
+    Map condition = [uomId: parameters.uomId,
+                     uomIdTo: parameters.uomIdTo]
+    if (parameters.purposeEnumId) {
+        condition.purposeEnumId = parameters.purposeEnumId
+    }
+
+    // sort by descending fromDate to get newest (biggest) first
+    uomConversion = from("UomConversionDated")
+            .where(condition)
+            .orderBy("-fromDate")
+            .filterByDate(asOfDate)
+            .cache()
+            .queryFirst()
+
+    // if no conversion found with specified purpose, try w/o purpose
+    if (!uomConversion) {
+        if (parameters.purposeEnumId) {
+            uomConversion = from("UomConversionDated")
+                    .where(uomId: parameters.uomId,
+                            uomIdTo: parameters.uomIdTo)
+                    .orderBy("-fromDate")
+                    .filterByDate(asOfDate)
+                    .cache()
+                    .queryFirst()
+        }
+    }
+
+    // if not found, try the uom conversion entity
+    if (!uomConversion) {
+        uomConversion = from("UomConversion").where(parameters).cache().queryOne()
+    }
+    logVerbose("using conversion factor=${uomConversion.conversionFactor}")
+
+    if (!uomConversion) {
+        // if still no uom conversion entity, then no conversion is possible
+        return error(UtilProperties.getMessage("CommonUiLabels", "CommonNoUomConversionFound", parameters.locale))
+    }
+    else {
+        // Do custom conversion, if we have customMethodId
+        if (uomConversion.customMethodId) { //custom conversion?
+            logVerbose("using custom conversion customMethodId=${uomConversion.customMethodId}")
+            Map customParms = parameters.convertUom
+            customParms.uomConversion = uomConversion
+            Map serviceResult = run service: "convertUomCustom", with: customParms
+            convertedValue = serviceResult.convertedValue
+
+            logVerbose("Custom UoM conversion returning convertedValue=${convertedValue}")
+        }
+        else { // not custom conversion
+            // do the conversion
+            if (parameters.originalValue && uomConversion.conversionFactor) {
+                convertedValue = (parameters.originalValue).multiply(BigDecimal.valueOf(uomConversion.conversionFactor))
+                convertedValue = convertedValue.setScale(15, RoundingMode.HALF_EVEN)
+            }
+        } //custom conversion?
+
+        // round result, if UomConversion[Dated] so specifies
+        decimalScale = uomConversion.decimalScale ?: parameters.defaultDecimalScale
+        roundingMode = uomConversion.roundingMode ?: parameters.defaultRoundingMode
+        if (parameters.defaultRoundingMode != roundingMode) {
+            convertedValue = convertedValue.setScale(decimalScale, roundingMode)
+        }
+    } // no UomConversion or UomConversionDated found
+
+    // all done
+    result.convertedValue = convertedValue
+    logVerbose("""Uom conversion of [${parameters.originalValue}] from [${parameters.uomId}] 
+                           to [${parameters.uomIdTo}] using conversion factor [${uomConversion.conversionFactor}],
+                           result is [${convertedValue}]""")
+
+    return result
+}
+
+// convertUomCustom: Dispatcher for calling Custom Method for UoM conversion
+/**
+ * Convert UOM values using CustomMethod
+ */
+def convertUomCustom() {
+    Map result = success()
+    Map uomConversion = parameters.uomConversion
+    String customMethodId = uomConversion.customMethodId
+    GenericValue customMethod = from("CustomMethod").where(customMethodId: customMethodId).cache().queryOne()
+    if (!customMethod?.customMethodName) {
+        return error(UtilProperties.getMessage("CommonUiLabels", "CommonNoCustomMethodName", parameters.locale))
+    } else {
+        logVerbose("calling custom method" + customMethod.customMethodName)
+        Map serviceResult = run service: customMethod.customMethodName, with: [arguments: parameters]
+        result.convertedValue = serviceResult.convertedValue
+    }
+    return result
+}
+
+/**
+ * Look up progress made in File Upload process
+ */
+def getFileUploadProgressStatus() {
+    GenericValue uploadProgressListener = parameters.uploadProgressListener
+    Map result = success()
+    if (uploadProgressListener) {
+        result.contentLength = uploadProgressListener.getContentLength
+        result.bytesRead = uploadProgressListener.getBytesRead
+        result.hasStarted = uploadProgressListener.hasStarted
+
+        result.readPercent = (result.bytesRead * 100) / result.contentLength
+    }
+    return result
+}
+
+/**
+ * Get visual theme resources
+ */
+def getVisualThemeResources() {
+    Map result = success()
+    String visualThemeId = parameters.visualThemeId
+    Map themeResources = parameters.themeResources ?: [:]
+    List resourceList = from("VisualThemeResource")
+            .where(visualThemeId: visualThemeId)
+            .orderBy("resourceTypeEnumId", "sequenceId")
+            .cache()
+            .queryList()
+    if (!resourceList) {
+        // if not found use the good old initial ofbiz theme so the system will at least start up and will be usable
+        logWarning("Could not find the ${visualThemeId} theme, reverting back to the good old OFBiz theme...")
+        visualThemeId = UtilProperties.getPropertyValue("general", "VISUAL_THEME", "FLAT_GREY")
+        resourceList = from("VisualThemeResource")
+            .where(visualThemeId: visualThemeId)
+            .orderBy("resourceTypeEnumId", "sequenceId")
+            .cache()
+            .queryList()
+    }
+    if (!resourceList) {
+        return error(UtilProperties.getMessage("CommonUiLabels", "CommonVisualThemeResourcesNotFound", parameters.locale))
+    }
+    for (GenericValue resourceRecord : resourceList) {
+        String resourceTypeEnumId = resourceRecord.resourceTypeEnumId
+        String resourceValue = resourceRecord.resourceValue
+        if (!resourceValue) {
+            logWarning(UtilProperties.getMessage("CommonUiLabels", "CommonVisualThemeInvalidRecord", parameters.locale))
+        }
+        else {
+            themeResources[resourceTypeEnumId] = [resouceTypeEnumId: resourceValue]
+        }
+    }
+    result.themeResources = themeResources
+    return result
+}
+
+/**
+ * Returns a list of country
+ */
+def getCountryList() {
+    Map result = success()
+    List countryList = []
+    List geoList = CommonWorkers.getCountryList(delegator)
+    for (GenericValue countryGeo : geoList) {
+        countryList << countryGeo.geoName + ": " + countryGeo.geoId
+    }
+    result.countryList = countryList
+    return result
+}
+
+/**
+ * set the state options for selected country
+ */
+def getAssociatedStateList() {
+    Map result = success()
+    List stateList = []
+
+    List geoList = CommonWorkers.getAssociatedStateList(delegator, parameters.countryGeoId, parameters.listOrderBy)
+    for (GenericValue stateGeo : geoList) {
+        String stateName = stateGeo.geoName + ": " + stateGeo.geoId
+        stateList << stateName
+    }
+    if (!stateList) {
+        stateList << UtilProperties.getMessage("CommonUiLabels", "CommonNoStatesProvinces", parameters.locale)
+    }
+    result.stateList = stateList
+    return result
+}
+
+/**
+ * Link Geos to another Geo
+ */
+def linkGeos() {
+    List oldGeoIds = from("GeoAssoc")
+            .where(geoId: parameters.geoId,
+                    geoAssocTypeId: parameters.geoAssocTypeId)
+            .cache()
+            .getFieldList('geoIdTo')
+    // Old list contains current values
+    for (String geoIdTo : parameters.geoIds) {
+        if (!oldGeoIds?.contains(geoIdTo)) {
+            // If it already exist, nothing to do and we keep it
+            GenericValue oldGeoAssoc = from("GeoAssoc").where(geoId: parameters.geoId, geoIdTo: geoIdTo).queryOne()
+            if (!oldGeoAssoc) {
+                // Add as it does not exist
+                GenericValue newGeoAssoc = makeValue("GeoAssoc", [
+                    geoId : parameters.geoId,
+                    geoIdTo : geoIdTo,
+                    geoAssocTypeId : parameters.geoAssocTypeId
+                ])
+                newGeoAssoc.create()
+            }
+        }
+    }
+    return success()
+}
+
+/**
+ * get related geos to a geo through a geoAssoc
  * @return
  */
+def getRelatedGeos() {
+    Map result = success()
+    List geoList = from("GeoAssoc")
+            .where(geoId: parameters.geoId, geoAssocTypeId: parameters.geoAssocTypeId)
+            .getFieldList('geoIdTo')
+    if (!geoList) {
+        geoList << "____"
+    }
+    result.geoList = geoList
+    return result
+}
 
-def createKeywordThesaurus() {
+/**
+ * Returns true if an UomConversion record exists
+ */
+def checkUomConversion() {
+    Map result = success()
+    result.exist = from("UomConversion").where(uomId: parameters.uomId, uomIdTo: parameters.uomIdTo).queryCount() == 1
+    return result
+}
+
+/**
+ * Returns true if an UomConversionDated record exists
+ */
+def checkUomConversionDated() {
+    Map result = success()
+    Map condition = [
+        uomId: parameters.uomId,
+        uomIdTo: parameters.uomIdTo
+    ]
+    if (parameters.purposeEnumId) {
+        condition.purposeEnumId = parameters.purposeEnumId
+    }
+    result.exist = from("UomConversion").where(condition).filterByDate().queryCount() == 1
+    return result
+}
+
+def getServerTimestamp() {
+    Map result = success()
+    result.serverTimestamp = UtilDateTime.nowTimestamp()
+    return result
+}
+
+def getServerTimeZone() {
+    Map result = success()
+    result.serverTimeZone = TimeZone.getDefault().toZoneId()
+    return result
+}
+
+def getServerTimestampAsLong() {
+    Map result = success()
+    result.serverTimestamp = UtilDateTime.nowTimestamp().getTime()
+    return result
+}
 
+/**
+ * Create a KeywordThesaurus
+ * @return
+ */
+def createKeywordThesaurus() {
     GenericValue newEntity = makeValue("KeywordThesaurus", parameters)
     newEntity.enteredKeyword = newEntity.enteredKeyword.toLowerCase()
     newEntity.alternateKeyword = newEntity.alternateKeyword.toLowerCase()
@@ -40,16 +344,12 @@ def createKeywordThesaurus() {
  * Delete a complete Entry KeywordThesaurus
  * @return
  */
-
 def deleteKeywordThesaurus() {
-
     GenericValue newEntity = makeValue("KeywordThesaurus")
     newEntity.enteredKeyword = parameters.enteredKeyword
-    if (UtilValidate.isNotEmpty(parameters.alternateKeyword)) {
+    if (parameters.alternateKeyword) {
         newEntity.alternateKeyword = parameters.alternateKeyword
     }
-
     delegator.removeByAnd("KeywordThesaurus", newEntity)
-
     return success()
-}
+}
\ No newline at end of file
diff --git a/framework/common/minilang/CommonServices.xml b/framework/common/minilang/CommonServices.xml
deleted file mode 100644
index 51d465a..0000000
--- a/framework/common/minilang/CommonServices.xml
+++ /dev/null
@@ -1,330 +0,0 @@
-<?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.
--->
-
-<simple-methods xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-        xmlns="http://ofbiz.apache.org/Simple-Method" xsi:schemaLocation="http://ofbiz.apache.org/Simple-Method http://ofbiz.apache.org/dtds/simple-methods.xsd">
-    <simple-method method-name="commonGenericPermission" short-description="Main permission logic">
-        <set field="primaryPermission" value="COMMON"/>
-        <call-simple-method method-name="genericBasePermissionCheck" xml-resource="component://common/minilang/permission/CommonPermissionServices.xml"/>
-    </simple-method>
-
-    <!-- Uom Conversion service -->
-    <simple-method method-name="createUomConversionDated" short-description="Create a new dated UOM conversion entity">
-        <make-value entity-name="UomConversionDated" value-field="newEntity"/>
-        <set-pk-fields map="parameters" value-field="newEntity"/>
-        <set-nonpk-fields map="parameters" value-field="newEntity"/>
-        <create-value value-field="newEntity"/>
-    </simple-method>
-
-    <simple-method method-name="convertUom" short-description="Convert UOM values" login-required="false">
-        <!-- base case: if both uomIds are the same, return the original value -->
-        <if-compare-field field="parameters.uomId" to-field="parameters.uomIdTo" operator="equals">
-            <field-to-result field="parameters.originalValue" result-name="convertedValue"/>
-            <return/>
-        </if-compare-field>
-
-        <if-empty field="parameters.asOfDate">
-            <now-timestamp field="nowTimestamp"/>
-            <set field="asOfDate" from-field="nowTimestamp"/>
-            <else>
-                <set field="asOfDate" from-field="parameters.asOfDate"/>
-            </else>
-        </if-empty>
-
-        <!-- first try the UomConversionDated entity -->
-        <entity-condition entity-name="UomConversionDated" list="uomConversions" use-cache="true">
-            <condition-list combine="and">
-                <condition-expr field-name="uomId" from-field="parameters.uomId"/>
-                <condition-expr field-name="uomIdTo" from-field="parameters.uomIdTo"/>
-                <condition-expr field-name="purposeEnumId" operator="equals" from-field="parameters.purposeEnumId" ignore-if-empty="true"/>
-                <condition-expr field-name="fromDate" operator="less-equals" from-field="asOfDate"/>
-                <condition-list combine="or">
-                    <condition-expr field-name="thruDate" operator="greater-equals" from-field="asOfDate"/>
-                    <condition-expr field-name="thruDate" operator="equals" from-field="nullField"/>
-                </condition-list>
-            </condition-list>
-            <!-- sort by descending fromDate to get newest (biggest) first -->
-            <order-by field-name="-fromDate"/>
-        </entity-condition>
-        <first-from-list list="uomConversions" entry="uomConversion"/>
-
-        <!-- if no conversion found with specified purpose, try w/o purpose -->
-        <if-empty field="uomConversion">
-            <if-not-empty field="parameters.purposeEnumId">
-                <entity-condition entity-name="UomConversionDated" list="uomConversions" use-cache="true">
-                    <condition-list combine="and">
-                        <condition-expr field-name="uomId" from-field="parameters.uomId"/>
-                        <condition-expr field-name="uomIdTo" from-field="parameters.uomIdTo"/>
-                        <condition-expr field-name="fromDate" operator="less-equals" from-field="asOfDate"/>
-                        <condition-list combine="or">
-                            <condition-expr field-name="thruDate" operator="greater-equals" from-field="asOfDate"/>
-                            <condition-expr field-name="thruDate" operator="equals" from-field="nullField"/>
-                        </condition-list>
-                    </condition-list>
-                    <order-by field-name="-fromDate"/>
-                </entity-condition>
-                <first-from-list list="uomConversions" entry="uomConversion"/>
-            </if-not-empty>
-        </if-empty>
-        <!-- if not found, try the uom conversion entity -->
-        <if-empty field="uomConversion">
-            <entity-one entity-name="UomConversion" value-field="uomConversion" auto-field-map="true" use-cache="true"/>
-        </if-empty>
-        <log level="verbose" message="using conversion factor=${uomConversion.conversionFactor}"/>
-
-        <if-empty field="uomConversion">
-            <!-- if still no uom conversion entity, then no conversion is possible -->
-            <add-error><fail-property resource="CommonUiLabels" property="CommonNoUomConversionFound"/></add-error>
-            <check-errors/>
-        <else>
-            <!-- Do custom conversion, if we have customMethodId -->
-            <if-not-empty field="uomConversion.customMethodId">  <!-- custom conversion? -->
-                <log level="verbose" message="using custom conversion customMethodId=${uomConversion.customMethodId}"/>
-                <set-service-fields service-name="convertUomCustom" map="parameters" to-map="customParms"/>
-                <set field="customParms.uomConversion" from-field="uomConversion"/>
-                <call-service service-name="convertUomCustom" in-map-name="customParms">
-                    <result-to-field result-name="convertedValue"/>
-                </call-service>
-                <log level="verbose" message="Custom UoM conversion returning convertedValue=${convertedValue}"/>
-            <else>  <!-- not custom conversion -->
-                <!-- do the conversion -->
-                <calculate field="convertedValue" type="BigDecimal" decimal-scale="15">
-                    <calcop operator="multiply">
-                        <calcop operator="get" field="parameters.originalValue"/>
-                        <calcop operator="get" field="uomConversion.conversionFactor"/>
-                    </calcop>
-                </calculate>
-            </else>
-            </if-not-empty>  <!-- custom conversion? -->
-
-            <!-- round result, if UomConversion[Dated] so specifies -->
-            <set field="roundingMode" from-field="uomConversion.roundingMode" default-value="${parameters.defaultRoundingMode}"/>
-            <set field="decimalScale" from-field="uomConversion.decimalScale" default-value="${parameters.defaultDecimalScale}"/>
-            <if-not-empty field="roundingMode">
-                <calculate field="roundedValue" type="BigDecimal" decimal-scale="${decimalScale}" rounding-mode="${roundingMode}">
-                    <calcop operator="get" field="convertedValue"/>
-                </calculate>
-                <set field="convertedValue" from-field="roundedValue"/>
-            </if-not-empty>
-        </else>
-        </if-empty>  <!-- no UomConversion or UomConversionDated found -->
-
-        <!-- all done -->
-        <field-to-result field="convertedValue"/>
-
-        <log level="verbose" message="Uom conversion of [${parameters.originalValue}] from [${parameters.uomId}] to [${parameters.uomIdTo}] using conversion factor [${uomConversion.conversionFactor}], result is [${convertedValue}]"/>
-    </simple-method>
-
-    <!-- convertUomCustom: Dispatcher for calling Custom Method for UoM conversion -->
-    <simple-method method-name="convertUomCustom" short-description="Convert UOM values using CustomMethod" login-required="false">
-        <set field="customMethodId" from-field="parameters.uomConversion.customMethodId"/>
-        <entity-one entity-name="CustomMethod" value-field="customMethod" auto-field-map="true" use-cache="true"/>
-
-        <if-empty field="customMethod.customMethodName">
-            <add-error> <fail-property resource="CommonUiLabels" property="CommonNoCustomMethodName"/> </add-error>
-            <check-errors/>
-        <else>
-            <log level="verbose" message="calling custom method ${customMethod.customMethodName}"/>
-            <set field="args.arguments" from-field="parameters"/>
-            <call-service service-name="${customMethod.customMethodName}" in-map-name="args">
-                <result-to-result result-name="convertedValue"/>
-            </call-service>
-        </else>
-        </if-empty>
-    </simple-method>
-
-    <simple-method method-name="getFileUploadProgressStatus" short-description="Look up progress made in File Upload process">
-        <set field="uploadProgressListener" from-field="parameters.uploadProgressListener"/>
-        <if-not-empty field="uploadProgressListener">
-            <call-object-method obj-field="uploadProgressListener" method-name="getContentLength" ret-field="parameters.contentLength"/>
-            <field-to-result field="parameters.contentLength" result-name="contentLength"/>
-            <call-object-method obj-field="uploadProgressListener" method-name="getBytesRead" ret-field="parameters.bytesRead"/>
-            <field-to-result field="parameters.bytesRead" result-name="bytesRead"/>
-            <call-object-method obj-field="uploadProgressListener" method-name="hasStarted" ret-field="parameters.hasStarted"/>
-            <field-to-result field="parameters.hasStarted" result-name="hasStarted"/>
-            <script>groovy:
-                contentLength = parameters.get("contentLength")
-                bytesRead = parameters.get("bytesRead")
-                int readPercent = (bytesRead* 100)/contentLength
-                parameters.put("readPercent", readPercent)
-            </script>
-            <field-to-result field="parameters.readPercent" result-name="readPercent"/>
-            <field-to-result field="parameters.hasStarted" result-name="hasStarted"/>
-        </if-not-empty>
-    </simple-method>
-
-    <simple-method method-name="getVisualThemeResources" short-description="Get visual theme resources" login-required="false">
-        <set field="visualThemeId" from-field="parameters.visualThemeId"/>
-        <set field="themeResources" from-field="parameters.themeResources"/>
-        <entity-condition entity-name="VisualThemeResource" list="resourceList" use-cache="true">
-            <condition-expr field-name="visualThemeId" from-field="visualThemeId"/>
-            <order-by field-name="resourceTypeEnumId"/>
-            <order-by field-name="sequenceId"/>
-        </entity-condition>
-        <if-empty field="resourceList">
-            <!-- if not found use the good old initial ofbiz theme so the system will at least start up and will be usable -->
-            <log level="error" message="Could not find the '${visualThemeId}' theme, reverting back to the good old OFBiz theme..."></log>
-            <entity-condition entity-name="VisualThemeResource" list="resourceList" use-cache="true">
-                <condition-expr field-name="visualThemeId" value="FLAT_GREY"/>
-                <order-by field-name="resourceTypeEnumId"/>
-                <order-by field-name="sequenceId"/>
-            </entity-condition>
-        </if-empty>
-        <if-empty field="resourceList">
-            <add-error><fail-property resource="CommonUiLabels" property="CommonVisualThemeResourcesNotFound"/></add-error>
-            <check-errors/>
-        </if-empty>
-        <iterate list="resourceList" entry="resourceRecord">
-            <set field="resourceTypeEnumId" from-field="resourceRecord.resourceTypeEnumId"/>
-            <set field="resourceValue" from-field="resourceRecord.resourceValue"/>
-            <if-empty field="resourceValue">
-                <property-to-field field="warningMsg" property="CommonVisualThemeInvalidRecord" resource="CommonUiLabels"/>
-                <log level="warning" message="${warningMsg}"/>
-                <else>
-                    <set field="themeResources[resourceTypeEnumId][]" from-field="resourceValue"/>
-                </else>
-            </if-empty>
-        </iterate>
-        <field-to-result field="themeResources"/>
-    </simple-method>
-
-    <simple-method method-name="getCountryList" short-description="Returns a list of country" login-required="false">
-        <call-class-method method-name="getCountryList" class-name="org.apache.ofbiz.common.CommonWorkers" ret-field="geoList">
-            <field field="delegator" type="org.apache.ofbiz.entity.Delegator"/>
-        </call-class-method>
-        <iterate list="geoList" entry="countryGeo">
-            <set field="countryName" value="${countryGeo.geoName}: ${countryGeo.geoId}"/>
-            <field-to-list list="countryList" field="countryName"/>
-        </iterate>
-        <field-to-result field="countryList"/>
-    </simple-method>
-
-    <simple-method method-name="getAssociatedStateList" short-description="set the state options for selected country" login-required="false">
-        <set field="countryGeoId" from-field="parameters.countryGeoId"/>
-        <set field="listOrderBy" from-field="parameters.listOrderBy"/>
-        <call-class-method method-name="getAssociatedStateList" class-name="org.apache.ofbiz.common.CommonWorkers" ret-field="geoList">
-            <field field="delegator" type="org.apache.ofbiz.entity.Delegator"/>
-            <field field="countryGeoId" type="String"/>
-            <field field="listOrderBy" type="String"/>
-        </call-class-method>
-        <iterate list="geoList" entry="stateGeo">
-            <set field="stateName" value="${stateGeo.geoName}: ${stateGeo.geoId}"/>
-            <field-to-list list="stateList" field="stateName"/>
-        </iterate>
-        <if-empty field="stateList">
-            <property-to-field resource="CommonUiLabels" property="CommonNoStatesProvinces" field="noOptions"/>
-            <field-to-list list="stateList" field="noOptions"/>
-        </if-empty>
-        <field-to-result field="stateList"/>
-    </simple-method>
-
-    <simple-method method-name="linkGeos" short-description="Link Geos to another Geo">
-        <entity-and entity-name="GeoAssoc" list="geoAssocs">
-            <field-map field-name="geoId" from-field="parameters.geoId"/>
-            <field-map field-name="geoAssocTypeId" from-field="parameters.geoAssocTypeId"/>
-        </entity-and>
-        <set field="oldGeoIds" value="${groovy:org.apache.ofbiz.entity.util.EntityUtil.getFieldListFromEntityList(geoAssocs, 'geoIdTo', true);}"/>
-        <!-- Old list contains current values -->
-        <iterate list="parameters.geoIds" entry="geoIdTo">
-            <if-compare-field field="oldGeoIds" operator="contains" to-field="geoIdTo">
-                <!-- Yes, nothing to do, it already exists and we keep it -->
-                <else> 
-                    <entity-one entity-name="GeoAssoc" value-field="oldGeoAssoc">
-                        <field-map field-name="geoId" from-field="parameters.geoId"/>
-                        <field-map field-name="geoIdTo" from-field="geoIdTo"/>
-                    </entity-one>
-                    <if-empty field="oldGeoAssoc">
-                        <!-- Add as it does not exist -->
-                        <make-value entity-name="GeoAssoc" value-field="newGeoAssoc"/>
-                        <set field="newGeoAssoc.geoId" from-field="parameters.geoId"/>
-                        <set field="newGeoAssoc.geoIdTo" from-field="geoIdTo"/>
-                        <set field="newGeoAssoc.geoAssocTypeId" from-field="parameters.geoAssocTypeId"/>
-                        <create-value value-field="newGeoAssoc"/>
-                    </if-empty>
-                </else>
-            </if-compare-field>
-        </iterate>
-        <check-errors/>
-    </simple-method>
-
-    <simple-method method-name="getRelatedGeos" short-description="get related geos to a geo through a geoAssoc" login-required="false">
-        <entity-and entity-name="GeoAssoc" list="geoAssoc">
-            <field-map field-name="geoId" from-field="parameters.geoId"/>
-            <field-map field-name="geoAssocTypeId" from-field="parameters.geoAssocTypeId"/>
-        </entity-and>
-        <if-empty field="geoAssoc">
-            <set field="noOptions" value="____"/>
-            <field-to-list list="geoList" field="noOptions"/>
-            <else>
-                <iterate list="geoAssoc" entry="geo">
-                    <field-to-list list="geoList" field="geo.geoIdTo"/>
-                </iterate>
-            </else>
-        </if-empty>
-        <field-to-result field="geoList"/>
-    </simple-method>
-
-    <simple-method method-name="checkUomConversion" short-description="Returns true if an UomConversion record exists">
-        <entity-one entity-name="UomConversion" value-field="uomConversion">
-            <field-map field-name="uomId" from-field="parameters.uomId"/>
-            <field-map field-name="uomIdTo" from-field="parameters.uomIdTo"/>
-        </entity-one>
-        <if-not-empty field="uomConversion">
-            <set field="exist" value="true" type="Boolean"/>
-            <else>
-                <set field="exist" value="false" type="Boolean"/>
-            </else>
-        </if-not-empty>
-        <field-to-result field="exist"/>
-    </simple-method>
-
-    <simple-method method-name="checkUomConversionDated" short-description="Returns true if an UomConversionDated record exists">
-         <entity-condition entity-name="UomConversionDated" list="uomConversions" filter-by-date="true">
-            <condition-list>
-                <condition-expr field-name="uomId" operator="equals" from-field="parameters.uomId"/>
-                <condition-expr field-name="uomIdTo" operator="equals" from-field="parameters.uomIdTo"/>
-                <condition-expr field-name="purposeEnumId" operator="equals" from-field="parameters.purposeEnumId" ignore-if-empty="true"/>
-            </condition-list>
-        </entity-condition>
-        <if-not-empty field="uomConversions">
-            <set field="exist" value="true" type="Boolean"/>
-            <else>
-                <set field="exist" value="false" type="Boolean"/>
-            </else>
-        </if-not-empty>
-        <field-to-result field="exist"/>
-    </simple-method>
-
-    <simple-method method-name="getServerTimestamp" login-required="false">
-        <now field="serverTimestamp" type="java.sql.Timestamp"/>
-        <field-to-result field="serverTimestamp"/>
-    </simple-method>
-
-    <simple-method method-name="getServerTimeZone" login-required="false">
-        <set field="serverTimeZone" value="${util:defaultTimeZone()}" type="String"/>
-        <field-to-result field="serverTimeZone"/>
-    </simple-method>
-
-    <simple-method method-name="getServerTimestampAsLong" login-required="false">
-        <now field="serverTimestamp" type="java.lang.Long"/>
-        <field-to-result field="serverTimestamp"/>
-    </simple-method>
-
-</simple-methods>
diff --git a/framework/common/servicedef/services.xml b/framework/common/servicedef/services.xml
index f99fa64..87554d5 100644
--- a/framework/common/servicedef/services.xml
+++ b/framework/common/servicedef/services.xml
@@ -25,8 +25,8 @@ under the License.
     <version>1.0</version>
 
     <!-- Common Permission Service -->
-    <service name="commonGenericPermission" engine="simple"
-        location="component://common/minilang/CommonServices.xml" invoke="commonGenericPermission">
+    <service name="commonGenericPermission" engine="groovy"
+        location="component://common/groovyScripts/CommonServices.groovy" invoke="commonGenericPermission">
         <implements service="permissionInterface"/>
     </service>
 
@@ -303,14 +303,13 @@ under the License.
     </service>
 
     <!-- Uom conversion service -->
-    <service name="createUomConversionDated" default-entity-name="UomConversionDated" engine="simple"
-            location="component://common/minilang/CommonServices.xml" invoke="createUomConversionDated" auth="true">
+    <service name="createUomConversionDated" default-entity-name="UomConversionDated" engine="entity-auto" invoke="create" auth="true">
         <description>Create a new dated UOM converesion entity</description>
         <auto-attributes include="pk" mode="IN" optional="false"/>
         <auto-attributes include="nonpk" mode="IN" optional="true"/>
     </service>
-    <service name="convertUom" default-entity-name="UomConversion" engine="simple"
-            location="component://common/minilang/CommonServices.xml" invoke="convertUom" auth="false">
+    <service name="convertUom" default-entity-name="UomConversion" engine="groovy"
+            location="component://common/groovyScripts/CommonServices.groovy" invoke="convertUom" auth="false">
         <description>Make a unit of measure conversion, first using UomConversionDated, then with UomConversion</description>
         <auto-attributes include="pk" mode="IN" optional="false"/>
         <attribute name="asOfDate" mode="IN" type="Timestamp" optional="true"/>
@@ -321,8 +320,8 @@ under the License.
         <attribute name="defaultDecimalScale" mode="IN" type="Long" optional="true"/>
         <attribute name="defaultRoundingMode" mode="IN" type="String" optional="true"/>
     </service>
-    <service name="convertUomCustom" default-entity-name="UomConversion" engine="simple"
-            location="component://common/minilang/CommonServices.xml" invoke="convertUomCustom" auth="false">
+    <service name="convertUomCustom" default-entity-name="UomConversion" engine="groovy"
+            location="component://common/groovyScripts/CommonServices.groovy" invoke="convertUomCustom" auth="false">
         <description>Make a unit of measure conversion, using CustomMethod entity</description>
         <auto-attributes include="pk" mode="IN" optional="false"/>
         <attribute name="originalValue" mode="IN" type="BigDecimal" optional="false"/>
@@ -331,16 +330,16 @@ under the License.
         <attribute name="convertedValue" mode="OUT" type="BigDecimal" optional="true"/>
     </service>
     
-    <service name="checkUomConversion" engine="simple" default-entity-name="UomConversion"
-        location="component://common/minilang/CommonServices.xml" invoke="checkUomConversion">
+    <service name="checkUomConversion" engine="groovy" default-entity-name="UomConversion"
+        location="component://common/groovyScripts/CommonServices.groovy" invoke="checkUomConversion">
         <description>Returns true if an UomConversion record exists</description>
         <permission-service service-name="commonGenericPermission" main-action="VIEW"/>
         <auto-attributes include="pk" mode="IN"/>
         <attribute name="exist" mode="OUT" type="Boolean"/>
     </service>
     
-    <service name="checkUomConversionDated" engine="simple" default-entity-name="UomConversionDated"
-        location="component://common/minilang/CommonServices.xml" invoke="checkUomConversionDated">
+    <service name="checkUomConversionDated" engine="groovy" default-entity-name="UomConversionDated"
+        location="component://common/groovyScripts/CommonServices.groovy" invoke="checkUomConversionDated">
         <description>Returns true if an UomConversionDated record exists</description>
         <permission-service service-name="commonGenericPermission" main-action="VIEW"/>
         <auto-attributes include="pk" mode="IN"/>
@@ -348,7 +347,7 @@ under the License.
     </service>
     
     
-    <service name="getFileUploadProgressStatus" engine="simple" location="component://common/minilang/CommonServices.xml" invoke="getFileUploadProgressStatus" auth="false">
+    <service name="getFileUploadProgressStatus" engine="groovy" location="component://common/groovyScripts/CommonServices.groovy" invoke="getFileUploadProgressStatus" auth="false">
         <description>Look up progress made in File Upload process</description>
         <attribute name="uploadProgressListener" mode="IN" type="org.apache.ofbiz.webapp.event.FileUploadProgressListener" optional="true"/>
         <attribute name="contentLength" mode="OUT" type="Long" optional="true"/>
@@ -529,8 +528,8 @@ under the License.
     </service>
 
     <!-- Visual theme services -->
-    <service name="getVisualThemeResources" engine="simple"
-            location="component://common/minilang/CommonServices.xml" invoke="getVisualThemeResources">
+    <service name="getVisualThemeResources" engine="groovy"
+            location="component://common/groovyScripts/CommonServices.groovy" invoke="getVisualThemeResources">
         <description>Get a visual theme resources Map. Call with visualThemeId String,
             and optional themeResources Map. Returns themeResources Map - a
             Map of Lists, where the resourceTypeEnumId is the key and the value
@@ -752,27 +751,27 @@ under the License.
         <permission-service service-name="commonGenericPermission" main-action="DELETE"/>
         <auto-attributes include="pk" mode="IN" optional="false"/>
     </service>
-    <service name="linkGeos" engine="simple" auth="true"
-        location="component://common/minilang/CommonServices.xml" invoke="linkGeos">
+    <service name="linkGeos" engine="groovy" auth="true"
+        location="component://common/groovyScripts/CommonServices.groovy" invoke="linkGeos">
         <description>Link Geos to another Geo</description>
         <permission-service service-name="commonGenericPermission" main-action="CREATE"/>
         <attribute name="geoIds" type="List" mode="IN" optional="true"/>
         <attribute name="geoId" type="String" mode="IN"/>
         <attribute name="geoAssocTypeId" type="String" mode="IN"/>
     </service>
-    <service name="getRelatedGeos" engine="simple" auth="false"
-        location="component://common/minilang/CommonServices.xml" invoke="getRelatedGeos">
+    <service name="getRelatedGeos" engine="groovy" auth="false"
+        location="component://common/groovyScripts/CommonServices.groovy" invoke="getRelatedGeos">
         <attribute name="geoId" mode="IN" type="String"/>
         <attribute name="geoAssocTypeId" mode="IN" type="String"/>
         <attribute name="geoList" mode="OUT" type="java.util.List"/>
     </service>
-    <service name="getCountryList" engine="simple" auth="false"
-        location="component://common/minilang/CommonServices.xml" invoke="getCountryList">
+    <service name="getCountryList" engine="groovy" auth="false"
+        location="component://common/groovyScripts/CommonServices.groovy" invoke="getCountryList">
         <description>Get a list of country and associated states from Geo</description>
         <attribute name="countryList" mode="OUT" type="java.util.List"/>
     </service>
-    <service name="getAssociatedStateList" engine="simple" auth="false"
-        location="component://common/minilang/CommonServices.xml" invoke="getAssociatedStateList">
+    <service name="getAssociatedStateList" engine="groovy" auth="false"
+        location="component://common/groovyScripts/CommonServices.groovy" invoke="getAssociatedStateList">
         <attribute name="countryGeoId" mode="IN" type="String" optional="false"/>
         <attribute name="listOrderBy" mode="IN" type="String" optional="true"/>
         <attribute name="stateList" mode="OUT" type="java.util.List"/>
@@ -803,18 +802,18 @@ under the License.
         <auto-attributes include="pk" mode="IN" optional="false"/>
     </service>
     
-    <service name="getServerTimestamp" engine="simple" auth="false"
-        location="component://common/minilang/CommonServices.xml" invoke="getServerTimestamp">
+    <service name="getServerTimestamp" engine="groovy" auth="false"
+        location="component://common/groovyScripts/CommonServices.groovy" invoke="getServerTimestamp">
         <attribute name="serverTimestamp" mode="OUT" type="Timestamp"/>
     </service>
     
-    <service name="getServerTimeZone" engine="simple" auth="false"
-        location="component://common/minilang/CommonServices.xml" invoke="getServerTimeZone">
+    <service name="getServerTimeZone" engine="groovy" auth="false"
+        location="component://common/groovyScripts/CommonServices.groovy" invoke="getServerTimeZone">
         <attribute name="serverTimeZone" mode="OUT" type="String"/>
     </service>
     
-    <service name="getServerTimestampAsLong" engine="simple" auth="false"
-        location="component://common/minilang/CommonServices.xml" invoke="getServerTimestampAsLong">
+    <service name="getServerTimestampAsLong" engine="groovy" auth="false"
+        location="component://common/groovyScripts/CommonServices.groovy" invoke="getServerTimestampAsLong">
         <attribute name="serverTimestamp" mode="OUT" type="Long"/>
     </service>