[ofbiz-framework] branch trunk updated: WIP: Implemented: Added support for defining nested attributes.(OFBIZ-11902) (#231)

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

[ofbiz-framework] branch trunk updated: WIP: Implemented: Added support for defining nested attributes.(OFBIZ-11902) (#231)

grv-2
This is an automated email from the ASF dual-hosted git repository.

grv 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 fdb67ae  WIP: Implemented: Added support for defining nested attributes.(OFBIZ-11902) (#231)
fdb67ae is described below

commit fdb67aee728a86d4d196ff915fb433029e6d6e22
Author: girishvasmatkar <[hidden email]>
AuthorDate: Sat Aug 22 23:50:12 2020 +0530

    WIP: Implemented: Added support for defining nested attributes.(OFBIZ-11902) (#231)
   
    * Added nested attr definition and code to handle nested attributes
   
    * Checkstyle error fix
   
    * Fixed indentation and tabs issues
---
 framework/service/dtd/services.xsd                 | 35 +++++----
 .../java/org/apache/ofbiz/service/ModelParam.java  | 13 ++++
 .../apache/ofbiz/service/ModelServiceReader.java   | 88 ++++++++++++----------
 3 files changed, 82 insertions(+), 54 deletions(-)

diff --git a/framework/service/dtd/services.xsd b/framework/service/dtd/services.xsd
index fe0339b..2bb58b9 100644
--- a/framework/service/dtd/services.xsd
+++ b/framework/service/dtd/services.xsd
@@ -69,8 +69,8 @@ under the License.
         <xs:attribute name="action">
             <xs:annotation>
                 <xs:documentation>
-                    Specifies the HTTP method name this service can be called using REST interface. For now only POST and GET are supported.
-                    Services that have export=true and have action attribute defined can be called using REST interface.
+                    Specifies the HTTP method name this service can be called using REST interface. For now only POST and GET are supported.
+                    Services that have export=true and have action attribute defined can be called using REST interface.
                 </xs:documentation>
             </xs:annotation>
               <xs:simpleType>
@@ -99,7 +99,7 @@ under the License.
                 </xs:documentation>
             </xs:annotation>
         </xs:attribute>
-        <xs:attribute name="hideResultInLog" type="xs:boolean"
+        <xs:attribute name="hideResultInLog" type="xs:boolean"
                       default="false">
             <xs:annotation>
                 <xs:documentation>
@@ -187,7 +187,7 @@ under the License.
                       default="true">
             <xs:annotation>
                 <xs:documentation>
-                    If set to false, when the permissions failed return the failMessage as error,
+                    If set to false, when the permissions failed return the failMessage as error,
                     else continue the service and give the hand to origin service to resolve the problem.
                 </xs:documentation>
             </xs:annotation>
@@ -237,7 +237,7 @@ under the License.
     </xs:element>
     <xs:attributeGroup name="attlist.implements">
         <xs:attribute name="service" type="xs:string" use="required"/>
-        <xs:attribute name="optional" type="xs:boolean"
+        <xs:attribute name="optional" type="xs:boolean"
                       default="false">
             <xs:annotation>
                 <xs:documentation>
@@ -251,7 +251,7 @@ under the License.
             <xs:documentation>
                 Calculate and maintain an average response time for this service. Service metrics can be used
                 for monitoring and reporting.
-                
+
                 The metric works by gathering statistics until a configurable maximum is reached (number of
                 requests or elapsed time), then the average is calculated. A smoothing factor is used to
                 smooth differences between calculations.
@@ -261,28 +261,28 @@ under the License.
             <xs:attribute name="name" type="xs:string" use="required">
                 <xs:annotation>
                     <xs:documentation>
-                        Each metric must have a unique name.
+                        Each metric must have a unique name.
                     </xs:documentation>
                 </xs:annotation>
             </xs:attribute>
             <xs:attribute name="estimation-size" type="xs:string">
                 <xs:annotation>
                     <xs:documentation>
-                        Positive integer number of requests to include in the metrics calculation. Defaults to "100".
+                        Positive integer number of requests to include in the metrics calculation. Defaults to "100".
                     </xs:documentation>
                 </xs:annotation>
             </xs:attribute>
             <xs:attribute name="estimation-time" type="xs:string">
                 <xs:annotation>
                     <xs:documentation>
-                        Positive integer number of milliseconds to include in the metrics calculation. Defaults to "1000".
+                        Positive integer number of milliseconds to include in the metrics calculation. Defaults to "1000".
                     </xs:documentation>
                 </xs:annotation>
             </xs:attribute>
             <xs:attribute name="smoothing" type="xs:string">
                 <xs:annotation>
                     <xs:documentation>
-                        Positive decimal smoothing factor - used to smooth the differences between calculations. A value of "1" disables smoothing. Defaults to "0.7".
+                        Positive decimal smoothing factor - used to smooth the differences between calculations. A value of "1" disables smoothing. Defaults to "0.7".
                     </xs:documentation>
                 </xs:annotation>
             </xs:attribute>
@@ -346,6 +346,11 @@ under the License.
             <xs:sequence>
                 <xs:element minOccurs="0" maxOccurs="unbounded" ref="type-validate"/>
                 <xs:element minOccurs="0" ref="description" />
+                <xs:element minOccurs="0" maxOccurs="unbounded" ref="attribute">
+                   <xs:annotation>
+                      <xs:documentation>List, Map type attributes can have nested attributes.</xs:documentation>
+                   </xs:annotation>
+                </xs:element>
             </xs:sequence>
             <xs:attributeGroup ref="attlist.attribute"/>
         </xs:complexType>
@@ -365,9 +370,9 @@ under the License.
         <xs:attribute name="optional" type="xs:boolean" default="false"/>
         <xs:attribute name="default-value" type="xs:string">
             <xs:annotation>
-                <xs:documentation>The value specified will be used for the attribute if no value is passed in.
-                    This will only happen if it is okay to not pass a value in, so if this is set then optional will be set to true.
-                    If optional=false and this is set then the value will be overridden and with a value in default-value is will set
+                <xs:documentation>The value specified will be used for the attribute if no value is passed in.
+                    This will only happen if it is okay to not pass a value in, so if this is set then optional will be set to true.
+                    If optional=false and this is set then the value will be overridden and with a value in default-value is will set
                     optional=true anyway.
                 </xs:documentation>
             </xs:annotation>
@@ -386,7 +391,7 @@ under the License.
                     Applies only to String fields.
                     Only checked for incoming parameters/attributes (could change in the future, but this is meant for validating input from users, other systems, etc).
                     Defaults to "none" meaning no HTML is allowed (will result in an error message).
-                    If some HTML is desired then use "safe" which will follow the rules in the default custom safe policy file (CustomSafePolicy.java, see also owasp.properties).
+                    If some HTML is desired then use "safe" which will follow the rules in the default custom safe policy file (CustomSafePolicy.java, see also owasp.properties).
                     This should be safe for both internal and public users. You may want to provide your own custom safe policy file to adapt to you needs.
                     In rare cases when users are trusted or it is not a sensitive field the "any" option may be used to not check the HTML content at all.
                 </xs:documentation>
@@ -450,7 +455,7 @@ under the License.
         <xs:attribute name="allow-html" use="optional">
             <xs:annotation>
                 <xs:documentation>
-                    See the documentation on the allow-html attribute of the "attribute" element.
+                    See the documentation on the allow-html attribute of the "attribute" element.
                     Note that it is slightly different here as there is no default.
                 </xs:documentation>
             </xs:annotation>
diff --git a/framework/service/src/main/java/org/apache/ofbiz/service/ModelParam.java b/framework/service/src/main/java/org/apache/ofbiz/service/ModelParam.java
index 3db0198..d84a181 100644
--- a/framework/service/src/main/java/org/apache/ofbiz/service/ModelParam.java
+++ b/framework/service/src/main/java/org/apache/ofbiz/service/ModelParam.java
@@ -19,6 +19,7 @@
 package org.apache.ofbiz.service;
 
 import java.io.Serializable;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
@@ -94,6 +95,8 @@ public class ModelParam implements Serializable {
 
     /** Is this Parameter set internally? */
     private boolean internal = false;
+    /** Children attributes*/
+    private ArrayList<ModelParam> children = null;
 
     public ModelParam() { }
 
@@ -514,6 +517,16 @@ public class ModelParam implements Serializable {
     }
 
     /**
+     * @return the children of the attribute
+     */
+    public ArrayList<ModelParam> getChildren() {
+        if (children == null) {
+            children = new ArrayList<>();
+        }
+        return children;
+    }
+
+    /**
      * Copy default value.
      * @param param the param
      */
diff --git a/framework/service/src/main/java/org/apache/ofbiz/service/ModelServiceReader.java b/framework/service/src/main/java/org/apache/ofbiz/service/ModelServiceReader.java
index f08214e..98bd955 100644
--- a/framework/service/src/main/java/org/apache/ofbiz/service/ModelServiceReader.java
+++ b/framework/service/src/main/java/org/apache/ofbiz/service/ModelServiceReader.java
@@ -467,45 +467,7 @@ public class ModelServiceReader implements Serializable {
     private static void createAttrDefs(Element baseElement, ModelService service) {
         // Add in the defined attributes (override the above defaults if specified)
         for (Element attribute: UtilXml.childElementList(baseElement, "attribute")) {
-            ModelParam param = new ModelParam();
-
-            param.setName(UtilXml.checkEmpty(attribute.getAttribute("name")).intern());
-            param.setDescription(getCDATADef(attribute, "description"));
-            param.setType(UtilXml.checkEmpty(attribute.getAttribute("type")).intern());
-            param.setMode(UtilXml.checkEmpty(attribute.getAttribute("mode")).intern());
-            param.setEntityName(UtilXml.checkEmpty(attribute.getAttribute("entity-name")).intern());
-            param.setFieldName(UtilXml.checkEmpty(attribute.getAttribute("field-name")).intern());
-            param.setRequestAttributeName(UtilXml.checkEmpty(attribute.getAttribute("request-attribute-name")).intern());
-            param.setSessionAttributeName(UtilXml.checkEmpty(attribute.getAttribute("session-attribute-name")).intern());
-            param.setStringMapPrefix(UtilXml.checkEmpty(attribute.getAttribute("string-map-prefix")).intern());
-            param.setStringListSuffix(UtilXml.checkEmpty(attribute.getAttribute("string-list-suffix")).intern());
-            param.setFormLabel(attribute.hasAttribute("form-label") ? attribute.getAttribute("form-label").intern() : null);
-            param.setOptional("true".equalsIgnoreCase(attribute.getAttribute("optional"))); // default to true
-            param.setFormDisplay(!"false".equalsIgnoreCase(attribute.getAttribute("form-display"))); // default to false
-            param.setAllowHtml(UtilXml.checkEmpty(attribute.getAttribute("allow-html"), "none").intern()); // default to none
-
-            // default value
-            String defValue = attribute.getAttribute("default-value");
-            if (UtilValidate.isNotEmpty(defValue)) {
-                if (Debug.verboseOn()) {
-                    Debug.logVerbose("Got a default-value [" + defValue + "] for service attribute [" + service.getName() + "."
-                            + param.getName() + "]", MODULE);
-                }
-                param.setDefaultValue(defValue.intern());
-            }
-
-            // set the entity name to the default if not specified
-            if (param.getEntityName().length() == 0) {
-                param.setEntityName(service.getDefaultEntityName());
-            }
-
-            // set the field-name to the name if entity name is specified but no field-name
-            if (param.getFieldName().length() == 0 && param.getEntityName().length() > 0) {
-                param.setFieldName(param.getName());
-            }
-
-            // set the validators
-            addValidators(attribute, param);
+            ModelParam param = createAttrDef(attribute, null, service);
             service.addParam(param);
         }
 
@@ -602,6 +564,54 @@ public class ModelServiceReader implements Serializable {
         service.addParam(def);
     }
 
+    private static ModelParam createAttrDef(Element attribute, ModelParam parentParam, ModelService service) {
+        boolean hasParent = parentParam != null;
+        ModelParam param = new ModelParam();
+
+        param.setName(UtilXml.checkEmpty(attribute.getAttribute("name")).intern());
+        param.setDescription(getCDATADef(attribute, "description"));
+        param.setType(UtilXml.checkEmpty(attribute.getAttribute("type")).intern());
+        param.setMode(hasParent ? parentParam.getMode() : UtilXml.checkEmpty(attribute.getAttribute("mode")).intern()); //inherit mode from parent
+        param.setEntityName(UtilXml.checkEmpty(attribute.getAttribute("entity-name")).intern());
+        param.setFieldName(UtilXml.checkEmpty(attribute.getAttribute("field-name")).intern());
+        param.setRequestAttributeName(UtilXml.checkEmpty(attribute.getAttribute("request-attribute-name")).intern());
+        param.setSessionAttributeName(UtilXml.checkEmpty(attribute.getAttribute("session-attribute-name")).intern());
+        param.setStringMapPrefix(UtilXml.checkEmpty(attribute.getAttribute("string-map-prefix")).intern());
+        param.setStringListSuffix(UtilXml.checkEmpty(attribute.getAttribute("string-list-suffix")).intern());
+        param.setFormLabel(attribute.hasAttribute("form-label") ? attribute.getAttribute("form-label").intern() : null);
+        param.setOptional("true".equalsIgnoreCase(attribute.getAttribute("optional"))); // default to true
+        param.setFormDisplay(!"false".equalsIgnoreCase(attribute.getAttribute("form-display"))); // default to false
+        param.setAllowHtml(UtilXml.checkEmpty(attribute.getAttribute("allow-html"), "none").intern()); // default to none
+
+         // default value
+        String defValue = attribute.getAttribute("default-value");
+        if (UtilValidate.isNotEmpty(defValue)) {
+            if (Debug.verboseOn()) {
+                Debug.logVerbose("Got a default-value [" + defValue + "] for service attribute [" + service.getName() + "."
+                         + param.getName() + "]", MODULE);
+            }
+            param.setDefaultValue(defValue.intern());
+        }
+
+        // set the entity name to the default if not specified
+        if (param.getEntityName().length() == 0) {
+            param.setEntityName(service.getDefaultEntityName());
+        }
+
+        // set the field-name to the name if entity name is specified but no field-name
+        if (param.getFieldName().length() == 0 && param.getEntityName().length() > 0) {
+            param.setFieldName(param.getName());
+        }
+
+        // set the validators
+        addValidators(attribute, param);
+        for (Element child: UtilXml.childElementList(attribute, "attribute")) {
+            ModelParam childParam = createAttrDef(child, param, service);
+            param.getChildren().add(childParam);
+        }
+        return param;
+    }
+
     private static void createOverrideDefs(Element baseElement, ModelService service) {
         for (Element overrideElement: UtilXml.childElementList(baseElement, "override")) {
             String name = UtilXml.checkEmpty(overrideElement.getAttribute("name"));