Jacques,

what was the measured difference between the method call to the Java method and 
the service call to the Java implementation?

Jacopo

On Oct 29, 2014, at 5:37 PM, [email protected] wrote:

> Author: jleroux
> Date: Wed Oct 29 16:37:40 2014
> New Revision: 1635192
> 
> URL: http://svn.apache.org/r1635192
> Log:
> The storeOrder service, implemented by the OrderService.createOrder() method, 
> synchronously calls the countProductQuantityOrdered service implemented in 
> Minilang. OOTB, the countProductQuantityOrdered service is only called by the 
> storeOrder service implementation. It's called inside a loop on orderItems.
> 
> While intentionally load testing a custom project with JMeter on a weak 
> m1.small AWS machine, I noticed the overhead of the service call for each 
> order item iteration was significant on this slow machine. With only 30 
> concurrent users the process was blocked by  a timeout on the 
> countProductQuantityOrdered service.
> 
> I then decided to transform the minilang code into an 
> OrderService.countProductQuantityOrdered() method that can be directly called 
> inside OrderService.createOrder() and also implements the 
> countProductQuantityOrdered service. Hence it avoids the overhead of the  
> minilang service calls in loop while still providing a 
> countProductQuantityOrdered service for possible external uses. For that I 
> moved the definition from Product component to Order component to avoid the 
> hard coded dependency of Order to Product. I then did not cross issues with 
> the same load test.
> 
> I also added a test for the countProductQuantityOrdered service by adding an 
> order item of a virtual product (GZ-1006-1) in SalesOrderTest.
> 
> Modified:
>    ofbiz/trunk/applications/order/servicedef/services.xml
>    ofbiz/trunk/applications/order/src/org/ofbiz/order/order/OrderServices.java
>    ofbiz/trunk/applications/order/src/org/ofbiz/order/test/SalesOrderTest.java
>    ofbiz/trunk/applications/product/servicedef/services.xml
> 
> Modified: ofbiz/trunk/applications/order/servicedef/services.xml
> URL: 
> http://svn.apache.org/viewvc/ofbiz/trunk/applications/order/servicedef/services.xml?rev=1635192&r1=1635191&r2=1635192&view=diff
> ==============================================================================
> --- ofbiz/trunk/applications/order/servicedef/services.xml (original)
> +++ ofbiz/trunk/applications/order/servicedef/services.xml Wed Oct 29 
> 16:37:40 2014
> @@ -1147,4 +1147,11 @@ under the License.
>         <auto-attributes mode="IN" entity-name="OrderItemGroupOrder" 
> include="pk" optional="false"/>
>     </service>
> 
> +    <service name="countProductQuantityOrdered" engine="java"
> +        location="org.ofbiz.order.order.OrderServices" 
> invoke="countProductQuantityOrdered" auth="true">
> +        <description>count Product Quantity Ordered</description>
> +        <attribute name="productId" type="String" mode="IN" 
> optional="false"/>
> +        <attribute name="quantity" type="BigDecimal" mode="IN" 
> optional="false"/>
> +    </service>
> +    
> </services>
> 
> Modified: 
> ofbiz/trunk/applications/order/src/org/ofbiz/order/order/OrderServices.java
> URL: 
> http://svn.apache.org/viewvc/ofbiz/trunk/applications/order/src/org/ofbiz/order/order/OrderServices.java?rev=1635192&r1=1635191&r2=1635192&view=diff
> ==============================================================================
> --- 
> ofbiz/trunk/applications/order/src/org/ofbiz/order/order/OrderServices.java 
> (original)
> +++ 
> ofbiz/trunk/applications/order/src/org/ofbiz/order/order/OrderServices.java 
> Wed Oct 29 16:37:40 2014
> @@ -280,15 +280,10 @@ public class OrderServices {
>                     normalizedItemQuantities.put(currentProductId, 
> currentQuantity.add(orderItem.getBigDecimal("quantity")));
>                 }
> 
> -                try {
> -                    // count product ordered quantities
> -                    // run this synchronously so it will run in the same 
> transaction
> -                    dispatcher.runSync("countProductQuantityOrdered", 
> UtilMisc.<String, Object>toMap("productId", currentProductId, "quantity", 
> orderItem.getBigDecimal("quantity"), "userLogin", userLogin));
> -                } catch (GenericServiceException e1) {
> -                    Debug.logError(e1, "Error calling 
> countProductQuantityOrdered service", module);
> -                    return 
> ServiceUtil.returnError(UtilProperties.getMessage(resource_error,
> -                            
> "OrderErrorCallingCountProductQuantityOrderedService",locale) + 
> e1.toString());
> -                }
> +                Map<String, Object> countContext = new HashMap<String, 
> Object>();
> +                countContext.put("productId", currentProductId);
> +                countContext.put("quantity", 
> orderItem.getBigDecimal("quantity"));
> +                countProductQuantityOrdered(ctx, countContext);
>             }
>         }
> 
> @@ -1152,6 +1147,54 @@ public class OrderServices {
> 
>         return successResult;
>     }
> +    
> +    public static Map<String, Object> 
> countProductQuantityOrdered(DispatchContext ctx, Map<String, Object> context) 
> {
> +        Delegator delegator = ctx.getDelegator();
> +        Locale locale = (Locale) context.get("locale");
> +        List<GenericValue> productCalculatedInfoList = null;
> +        GenericValue productCalculatedInfo = null;
> +        String productId = (String) context.get("productId");
> +        BigDecimal quantity = (BigDecimal) context.get("quantity");
> +        try {
> +            productCalculatedInfoList = 
> delegator.findByAnd("ProductCalculatedInfo", UtilMisc.toMap("productId", 
> productId), null, false);
> +            if (UtilValidate.isEmpty(productCalculatedInfoList)) {
> +                productCalculatedInfo = 
> delegator.makeValue("ProductCalculatedInfo");
> +                productCalculatedInfo.set("productId", productId);
> +                productCalculatedInfo.set("totalQuantityOrdered", quantity);
> +                productCalculatedInfo.create();
> +            } else {
> +                productCalculatedInfo = productCalculatedInfoList.get(0);
> +                BigDecimal totalQuantityOrdered = 
> productCalculatedInfo.getBigDecimal("totalQuantityOrdered");
> +                if (totalQuantityOrdered == null) {
> +                    productCalculatedInfo.set("totalQuantityOrdered", 
> quantity);
> +                } else {
> +                    productCalculatedInfo.set("totalQuantityOrdered", 
> totalQuantityOrdered.add(quantity));
> +                }
> +            }
> +            productCalculatedInfo.store();
> +        } catch (GenericEntityException e) {
> +            Debug.logError(e, "Error calling countProductQuantityOrdered 
> service", module);
> +            return 
> ServiceUtil.returnError(UtilProperties.getMessage(resource_error,
> +                    
> "OrderErrorCallingCountProductQuantityOrderedService",locale) + e.toString());
> +
> +        }
> +        
> +        String virtualProductId = null;
> +        try {
> +            GenericValue product = delegator.findOne("Product", 
> UtilMisc.toMap("productId", productId), true);
> +            virtualProductId = ProductWorker.getVariantVirtualId(product);
> +        } catch (GenericEntityException e) {
> +            Debug.logError(e, "Error calling countProductQuantityOrdered 
> service", module);
> +            return 
> ServiceUtil.returnError(UtilProperties.getMessage(resource_error,
> +                    
> "OrderErrorCallingCountProductQuantityOrderedService",locale) + e.toString());
> +        }
> +        
> +        if (UtilValidate.isNotEmpty(virtualProductId)) {
> +            context.put("productId", virtualProductId);
> +            countProductQuantityOrdered(ctx, context);
> +        }
> +        return ServiceUtil.returnSuccess();
> +    }            
> 
>     public static void reserveInventory(Delegator delegator, LocalDispatcher 
> dispatcher, GenericValue userLogin, Locale locale, List<GenericValue> 
> orderItemShipGroupInfo, List<String> dropShipGroupIds, Map<String, 
> GenericValue> itemValuesBySeqId, String orderTypeId, String productStoreId, 
> List<String> resErrorMessages) throws GeneralException {
>         boolean isImmediatelyFulfilled = false;
> @@ -1729,7 +1772,7 @@ public class OrderServices {
>                 if (UtilValidate.isNotEmpty(orderItemSeqId)) {
>                     createOrderAdjContext.put("orderItemSeqId", 
> orderItemSeqId);
>                 } else {
> -                     createOrderAdjContext.put("orderItemSeqId", "_NA_");
> +                    createOrderAdjContext.put("orderItemSeqId", "_NA_");
>                 }
>                 createOrderAdjContext.put("shipGroupSeqId", "_NA_");
>                 createOrderAdjContext.put("description", "Tax adjustment due 
> to order change");
> @@ -5787,4 +5830,4 @@ public class OrderServices {
> 
>         return ServiceUtil.returnSuccess();
>     }
> -}
> \ No newline at end of file
> +}
> 
> Modified: 
> ofbiz/trunk/applications/order/src/org/ofbiz/order/test/SalesOrderTest.java
> URL: 
> http://svn.apache.org/viewvc/ofbiz/trunk/applications/order/src/org/ofbiz/order/test/SalesOrderTest.java?rev=1635192&r1=1635191&r2=1635192&view=diff
> ==============================================================================
> --- 
> ofbiz/trunk/applications/order/src/org/ofbiz/order/test/SalesOrderTest.java 
> (original)
> +++ 
> ofbiz/trunk/applications/order/src/org/ofbiz/order/test/SalesOrderTest.java 
> Wed Oct 29 16:37:40 2014
> @@ -114,8 +114,16 @@ public class SalesOrderTest extends OFBi
>         orderItem.set("unitPrice", new BigDecimal("38.4"));
>         orderItem.set("unitListPrice", new BigDecimal("48.0"));
>         orderItem.set("statusId", "ITEM_CREATED");
> -
>         orderItems.add(orderItem);
> +        
> +        orderItem = delegator.makeValue("OrderItem", 
> UtilMisc.toMap("orderItemSeqId", "00002", "orderItemTypeId", 
> "PRODUCT_ORDER_ITEM", "prodCatalogId", "DemoCatalog", "productId", 
> "GZ-1006-1", "quantity", BigDecimal.ONE, "selectedAmount", BigDecimal.ZERO));
> +        orderItem.set("isPromo", "N");
> +        orderItem.set("isModifiedPrice", "N");
> +        orderItem.set("unitPrice", new BigDecimal("1.99"));
> +        orderItem.set("unitListPrice", new BigDecimal("5.99"));
> +        orderItem.set("statusId", "ITEM_CREATED");
> +        orderItems.add(orderItem);
> +        
>         ctx.put("orderItems", orderItems);
> 
>         List<GenericValue> orderTerms = FastList.newInstance();
> 
> Modified: ofbiz/trunk/applications/product/servicedef/services.xml
> URL: 
> http://svn.apache.org/viewvc/ofbiz/trunk/applications/product/servicedef/services.xml?rev=1635192&r1=1635191&r2=1635192&view=diff
> ==============================================================================
> --- ofbiz/trunk/applications/product/servicedef/services.xml (original)
> +++ ofbiz/trunk/applications/product/servicedef/services.xml Wed Oct 29 
> 16:37:40 2014
> @@ -175,13 +175,7 @@ under the License.
>         <attribute name="productId" type="String" mode="IN" optional="false"/>
>         <attribute name="weight" type="Long" mode="IN" optional="true"/>
>     </service>
> -    <service name="countProductQuantityOrdered" engine="simple"
> -                
> location="component://product/script/org/ofbiz/product/product/ProductServices.xml"
>  invoke="countProductQuantityOrdered" auth="true">
> -        <description>count Product Quantity Ordered</description>
> -        <attribute name="productId" type="String" mode="IN" 
> optional="false"/>
> -        <attribute name="quantity" type="BigDecimal" mode="IN" 
> optional="false"/>
> -    </service>
> -
> +    
>     <service name="createProductReview" engine="simple"
>             
> location="component://product/script/org/ofbiz/product/product/ProductServices.xml"
>  invoke="createProductReview" auth="true">
>         <description>Create a product review entity</description>
> 
> 

Reply via email to