Thursday, March 10, 2016

Creating Custom REST Handler from Controller Command and Data Bean – WCS 7 FEP 8

Introduction
------------------
WCS 7 FEP 8 supports the creation of configuration based controller commands which reduces the coding effort by having the mapping file in the system.The input and output of the databean and controller command invocation is controlled by the mapping file itself.

In FEP7, the resource handler extends AbstractClassicResourceHandler to invoke controller commands and data beans whereas in FEP8, it extends the AbstractConfigBasedClassicHandler which provides the configuration support required.

Please follow the below 4 steps to create the custom REST handler-

1)  Create Handler
Create the com.mycompany.commerce.order.rest.handler.MyOrderHandler by exteding the com.ibm.commerce.rest.classic.core.AbstractConfigBasedClassicHandler class (which provides the required configuration support) under WebSphereCommerceServerExtensionsLogic project.

a) Below method retrieves the Order information using OrderDataBean-
    @GET
    @Path("/byId/{orderId}")
    public Response getOrderById(
            @PathParam("storeId") String storeId,
            @PathParam("orderId") String orderId) {
        Response finalResponse = null;
 
        String responseFormat = getParameterValue(PARAMETER_RESPONSE_FORMAT, MediaTypeHelper.FORMAT_JSON, false);
        String profileName = getParameterValue(PARAMETER_PROFILE_NAME, "MyCompany_Store_Details", false, false);
        finalResponse = prepareAndValidate(storeId, RESOURCE_NAME, GET_METHOD, request, responseFormat);
        if (finalResponse == null) {
            Map<String, Object> paramOverrideMap = new HashMap<String, Object>();
            paramOverrideMap.put(PARAMETER_ORDER_ID, orderId);
            finalResponse = executeConfigBasedBeanWithContext(OrderDataBean.class.getName(), profileName, responseFormat, paramOverrideMap);
        } 
        return finalResponse;
    }

executeConfigBasedBeanWithContext loads configuration related to the data bean involved placed under the Rest.war/WEB-INF/beanmapping/ or Rest.war/WEB-INF/beanmapping-ext/ folder.
  
b) This below method can be used to add an item-
    @Path("/@current/item")
    @Consumes("application/json")
    @PUT
    public Response addItem(@PathParam("storeId") String storeId,
            @QueryParam("responseFormat") String responseFormat)
            throws Exception {
        Response finalResponse = prepareAndValidate(storeId, "myorder", POST_METHOD, request, responseFormat);
        if (finalResponse == null) {
            try {
                throwRestExceptionIfErrorsAreDetected();
                
                String cmdRefKey = OrderItemAddCmd.NAME;
                TypedProperty requestProperties = initializeRequestPropertiesFromRequestMap(responseFormat);
                if (!requestProperties.containsKey(ECConstants.EC_URL)) {
                    requestProperties.put(ECConstants.EC_URL, ECConstants.EC_URL);
                }
    
                finalResponse = executeControllerCommandWithContext(storeId, cmdRefKey, requestProperties,responseFormat, HttpStatus.CREATED);
            }
            catch (Exception e) {
                finalResponse = handleException(responseFormat, e, "addItem");
            }
        }
        return finalResponse;
    }
  
2)  Register Handler
Register the new handler class by making an entry inside the Rest.war/WEB-INF/config/resources-ext.properties file, add the full qualified name of the custom handler class such as com.mycompany.commerce.order.rest.handler.OrderHandler

3)  Mapping
Create the beanmapping-ext folder under Rest.war/WEB-INF/config folder and place the custom configuration files inside it which is com.ibm.commerce.order.beans.OrderDataBean.xml.

For getOrderById() method, I placed the below com.ibm.commerce.order.beans.OrderDataBean.xml under Rest.war/WEB-INF/beanmapping-ext/ folder-
   
    <?xml version="1.0" encoding="UTF-8"?>
    <bean>
        <profiles>
            <profile name="MyCompany_Store_Details">
                <inputs>
                    <input methodName="setOrderId" inputName="orderId" />
                </inputs>
                <outputs>
                    <output methodName="getPaymentInfo" outputName="paymentInfo" />
                    <output methodName="getOrderItemDataBeans" outputName="orderItemDataBeans">  
                        <output methodName="getShippingMode" outputName="shippingMode">
                            <output methodName="getCarrier" outputName="carrier"/>
                            <output methodName="getCode" outputName="code"/>
                            <output methodName="getShippingModeId" outputName="shippingModeId"/>
                            <output methodName="getShippingModeIdInEJBType" outputName="shippingModeId"/>
                            <output methodName="getStoreEntityIdInEJBType" outputName="storeEntityId"/>
                        </output>
                        <output methodName="getShippingModeId" outputName="shippingModeId"/> 
                    </output>               
                </outputs>
            </profile>
        </profiles>
    </bean>

Each data bean has a separate configuration file associated with it which can be found under Rest.war/WEB-INF/beanmapping/<fullyQualifedBeanName.xml>. The framework merges the custom and default bean mappings for the same bean, giving precedence to the custom configuration.

Each configuration file defines multiple profiles for a bean. Each profile contains a set of inputs and outputs. The input maps a request parameter to a corresponding setter method on the bean. The output maps a response data to the getter method on the bean.

4) Testing
In order to test the customization, we can use any REST plugin e.g. RESTClient in firefox.
Additionally, while testing the order response please make sure that we are logged in into the site and we are querying for the order which is related to the logged in user otherwise we will be getting the user authority exception like below-
"The user does not have the authority to run this command "com.ibm.commerce.order.beans.OrderDataBean"

URLs- 
http://localhost/wcs/resources/store/{storeId}/myorder/byId/{orderId}
http://localhost/wcs/resources/store/{storeId}/myorder/@current/item

3 comments:

  1. Great Explaination!!

    ReplyDelete
  2. Hi Nipun,

    I followed the same approach. But, getting the error message as "The system cannot find any method in the ResponseImpl class that supports GET"

    I have followed the exact steps mentioned in https://www.ibm.com/support/knowledgecenter/en/SSZLC2_7.0.0/com.ibm.commerce.webservices.doc/tasks/twvrestcreating_util.htm

    Let me know, if you have faced the same kind of issue

    ReplyDelete