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 <[email protected]>
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"));

Reply via email to