(Developer)

Create REST services using the configuration-based controller command and data bean mapping framework

We can create REST services using the configuration-based controller command and data bean mapping framework. It helps create REST services and automates mappings using the restClassicSampleGen utility.


Procedure

  1. Create your resource handler, following the specified format as a base. The following sample resource handler accepts two resources. One gets CatalogEntry data from a data bean, and the other updates a CatalogEntry with a command:

      import java.util.logging.Logger;
      
      import javax.ws.rs.GET;
      import javax.ws.rs.POST;
      import javax.ws.rs.Path;
      import javax.ws.rs.PathParam;
      import javax.ws.rs.Produces;
      import javax.ws.rs.QueryParam;
      import javax.ws.rs.core.MediaType;
      import javax.ws.rs.core.Response;
      
      import com.ibm.commerce.beans.DataBean;
      import com.ibm.commerce.catalog.beans.CatalogEntryDataBean;
      import com.ibm.commerce.catalogmanagement.commands.CatalogEntryUpdateCmd;
      import com.ibm.commerce.command.ControllerCommand;
      import com.ibm.commerce.foundation.logging.LoggingHelper;
      import com.ibm.commerce.rest.classic.core.AbstractConfigBasedClassicHandler;
      
      /**
      * This is a very simple REST handler that extends the configuration-based REST
      * classic handler. It demonstrates how to create REST resources based on a
      * {@link DataBean} and a {@link ControllerCommand} with minimal coding, as all
      * the input/output information is stored in a configuration mapping file.
      * 
      */
      
      @Path("store/{storeId}/sample")
      public class SampleCatalogEntryClassicRestHandler extends AbstractConfigBasedClassicHandler
      {
        /**
        * IBM Copyright notice field.
        */
        public static final String COPYRIGHT = com.ibm.commerce.copyright.IBMCopyright.SHORT_COPYRIGHT;
        
        private static final String CLASSNAME = RestClassicDataBeanHandler.class.getName();
        
        private static final Logger LOGGER = LoggingHelper.getLogger(RestClassicDataBeanHandler.class);
        
        private static final String RESOURCE_NAME = "sample";
        
        /*
        * (non-Javadoc)
        * @see com.ibm.commerce.foundation.rest.resourcehandler.IResourceHandler#getResourceName()
        */
        @Override
        public String getResourceName()
        {
          return RESOURCE_NAME;
        }
        
        /**
        * Used with WC to instantiate handler.
        */
        public SampleCatalogEntryClassicRestHandler()
        {
          super();
        }
        
        /**
        * A sample REST GET that executes the {@link CatalogEntryDataBean} based on
        * the request parameters and profile specified.
        * 
        * @param storeId
        * @param responseFormat
        * @param profileName
        * @param catalogEntryID
        * @return the response
        */
        @GET
        @Path("catalogEntry")
        @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, 
        MediaType.APPLICATION_XHTML_XML, MediaType.APPLICATION_ATOM_XML })
        public Response processRequest(
        @PathParam("storeId") String storeId,
        @QueryParam("responseFormat") String responseFormat,
        @QueryParam("profileName") String profileName,
        @QueryParam("catalogEntryID") String catalogEntryID)
        {
          final String METHODNAME = "processRequest(String storeId, String profileName, 
          String responseFormat, String catalogEntryID) ";
          boolean entryExitTraceEnabled = LoggingHelper.isEntryExitTraceEnabled(LOGGER);
          if (entryExitTraceEnabled)
          {
            Object[] objArr = new Object[] { storeId, profileName, responseFormat, catalogEntryID };
            LOGGER.entering(CLASSNAME, METHODNAME, objArr);
          }
          
          Response result = executeConfigBasedBeanWithContext(CatalogEntryDataBean.class.getName(), 
          profileName, responseFormat, null);
          
          if (entryExitTraceEnabled)
          {
            LOGGER.exiting(CLASSNAME, METHODNAME, result);
          }
          
          return result;
        }
        
        /**
        * A sample REST POST that executes the {@link CatalogEntryUpdateCmd} based on
        * the request parameters and profile specified.
        * 
        * @param storeId
        * @param responseFormat
        * @param profileName
        * @return the response
        */
        @POST
        @Path("catalogEntryUpdate")
        @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, 
        MediaType.APPLICATION_XHTML_XML, MediaType.APPLICATION_ATOM_XML })
        public Response processRequest(@PathParam("storeId") String storeId,
        @QueryParam(value = "responseFormat") String responseFormat,
        @QueryParam(value = "profileName") String profileName)
        {
          final String METHODNAME = "processRequest(String storeId, String profileName, 
          String responseFormat) ";
          boolean entryExitTraceEnabled = LoggingHelper.isEntryExitTraceEnabled(LOGGER);
          if (entryExitTraceEnabled)
          {
            Object[] objArr = new Object[] { storeId, profileName, responseFormat };
            LOGGER.entering(CLASSNAME, METHODNAME, objArr);
          }
          
          Response result = executeConfigBasedCommandWithContext(CatalogEntryUpdateCmd.class.getName(), 
          profileName, responseFormat, storeId, null);
          
          if (entryExitTraceEnabled)
          {
            LOGGER.exiting(CLASSNAME, METHODNAME, result);
          }
        
          return result;
        } 
      }

  2. Decide which entry point class (data bean or controller command) we want to use in your resource handler.

    REST calls typically require a handler that contains an entry point into the configuration-based classic handler class. The following entry points are available by default:

    1. public Response executeConfigBasedBeanWithContext
      (String beanClassName, String profileName, String responseFormat, Map<String, Object> paramOverrideMap)

      This method sets up the {@link BusinessContextService} start request, then delegates to {@link #executeConfigBasedBean(String, String, String, Map)}, and finally ends BCS the request. The following parameters are available by default:

        beanClassName
        The data bean class name.

        profileName
        The profile name for the data bean in the configuration.

        responseFormat
        The response format to use for generating the result.

        paramOverrideMap
        Defines any parameters to add or override from the request object associated to this handler.
        Typically used if there are path parameters or entity data we want included when it maps the query parameters with the input for the command.
        The key must be a string. The value can be any type object.
        The value can be null.

    2. public JSONObject executeConfigBasedBean
      (String beanClassName, String profileName, String responseFormat, Map<String, Object> paramOverrideMap) throws Exception

      This method processes a data bean request using the configuration-based profile mappings. It assumes that the {@link BusinessContextService} is dealt with by the caller.

      The input parameters are automatically completed based on any path parameters specified in the URL, followed by any query parameters.

      An override map can be provided to inject more parameters or override preexisting parameters. The following parameters are available by default:

        beanClassName
        The data bean class name.

        profileName
        The profile name for the data bean in the configuration.

        responseFormat
        The response format to use for generating the result.

        paramOverrideMap
        Defines any parameters to add or override from the request object associated to this handler.
        Typically used if there are path parameters or entity data we want included when it maps the query parameters with the input for the command.
        The key must be a string. The value can be any type object.
        The value can be null.

    3. public Response executeConfigBasedCommandWithContext
      (String commandInterfaceName, String profileName, String responseFormat, String storeId, Map<String, Object> paramOverrideMap)

      This method sets up the {@link BusinessContextService} start request, then delegates to * {@link #executeControllerCommand(String, String, TypedProperty, String)}, and finally ends BCS the request. The following parameters are available by default:

        commandInterfaceName
        The controller command interface name.

        profileName
        The profile name for the controller command in the configuration.

        responseFormat
        The response format to use for generating the result.

        paramOverrideMap
        Defines any parameters to add or override from the request object associated to this handler.
        Typically used if there are path parameters or entity data we want included when it maps the query parameters with the input for the command.
        The key must be a string. The value can be any type object.
        The value can be null.

    4. public JSONObject executeConfigBasedCommand
      (String pCmdInterfaceName, String profileName, String responseFormat, String storeId, Map<String, Object> paramOverrideMap) throws Exception

      This method processes a controller command request using the configuration-based profile mappings. It assumes that the {@link BusinessContextService} is dealt with by the caller.

      The input parameters are automatically completed based on any path parameters specified in the URL, followed by any parameters that are found in the request body.

      An override map can be provided to inject more parameters or override preexisting parameters.

      Although the store ID is specified in the method call, it is not automatically included in the list of parameters provided to populate the setters of the command. We must explicitly add it to the override map, or have it included with the URL path parameters or request body.

        pCmdInterfaceName
        The controller command interface name.

        profileName
        The profile name for the controller command in the configuration.

        responseFormat
        The response format to use for generating the result.

        storeId
        The store ID.

        paramOverrideMap
        Defines any parameters to add or override from the request object associated to this handler.
        Typically used if there are path parameters or entity data we want included when it maps the query parameters with the input for the command.
        The key must be a string. The value can be any type object.
        The value can be null.

  3. Create the XML mapping files, either using the restClassicSampleGen utility, or manually:

    • Recommended: Using the restClassicSampleGen utility:

      Go to the WCDE_installdir\bin directory and run the utility:

      restClassicSampleGen.bat searchType=searchType basePackage=basePackage locationType=locationType location=location outputDir=outputDir classTypes=classTypes inputPrefix=inputPrefix sampleDepth=sampleDepth additionalClassPath=additionalClassPath Where:

        searchType
        Use ABSOLUTE when explicitly stating the classes to generate mappings for.
        Use PATTERN to find classes that match the specified Java regular expression patterns.
        Default is ABSOLUTE.

        basePackage
        The base Java package (excluding final period) to generate mappings for.
        Default is ''.

        locationType
        Use FILE to specify that a file is used containing line-separated entries of either Java regular expression patterns, or explicit classes in com/example/MyClass.java format.
        Use DIRECT if directly specifying a Java regular expression pattern or class name.
        Default is DIRECT.

        location
        If the locationType FILE was specified, it is the path to the file.
        If the locationType DIRECT was specified, it is the actual Java regular expression or explicit class.

        outputDir
        The output directory. The directory is created if it does not exist. Subdirectories are created for each class type generated.

        classTypes
        One or more of the comma-separated values DATABEAN, CONTROLLERCOMMAND, and ALL.
        Default is ALL.

        inputPrefix
        Specifies characters to prefix input parameters with in the mapping file.
        Default is ''.

        sampleDepth
        The depth of mappings to create when recursively traversing the classes.
        Default is 3.

        additionalClassPath
        Specifies extra JAR files and directories to include to locate classes, which are separated with ;.

      Note:

      • If spaces are used in any of the property values, we must surround the entire property and value with quotations. For example, "property1=value 1".

      • Predefined values such as ABSOLUTE are case-insensitive.

      For example:

      • To generate a mapping for the specified data bean:

          restClassicSampleGen.bat location=com.ibm.commerce.catalog.beans.AttributeFloatValueDataBean 
           outputDir=C:/Temp/ClassicSamples

      • To generate mappings for data beans only, starting from the base package com.example.myclasses, specifying a pattern directly as a property, and prefixing all input parameters with q:

          restClassicSampleGen.bat searchType=pattern basePackage=com.example.myclasses classTypes=DATABEAN 
          "location=.*" inputPrefix=q outputDir=C:/Temp/ClassicSamples

      • To generate the classes specified in a file, with a mapping depth of 1. Then, adding a JAR file and directory to the class path to locate the classes:

          restClassicSampleGen.bat locationType=file "location=C:/users/admin/mapping list.txt" 
          sampleDepth=1 "additionalClassPath=c:/lib/MyJar.jar;c:/classdir" outputDir=c:/users/admin/samples

      Ensure that the utility runs successfully. Check the WCDE_installdir\logs\restclassic.log file for details.

    • Otherwise, to manually create the XML mapping files, create mapping files that resemble the following samples, and save them in the following locations:

        Rest.war/WebContent/WEB-INF/config/beanMapping-ext
        The directory to publish new data beans, or extend the existing data beans.

        Rest.war/WebContent/WEB-INF/config/commandMapping-ext
        The directory to publish new controller commands, or extend the existing controller commands.

      Sample data bean mapping file (com.ibm.commerce.catalog.beans.CatalogEntryDataBean.xml):

        <?xml version="1.0" encoding="UTF-8"?>
        <bean>
           <profiles>
              <profile name="sample">
                 <inputs>
                    <input inputName="associationType" methodName="setAssociationType"/>
                    <input inputName="attachmentUsage" methodName="setAttachmentUsage"/>
                    <input inputName="availabilityDate" methodName="setAvailabilityDate"/>
                    <input inputName="baseItemId" methodName="setBaseItemId"/>
                    <input inputName="buyable" methodName="setBuyable"/>
                    <input inputName="catalogEntryID" methodName="setCatalogEntryID"/>
                    <input inputName="compactProperties" methodName="setCompactProperties"/>
                    <input inputName="description" methodName="setDescription"/>
                    <input inputName="discontinueDate" methodName="setDiscontinueDate"/>
                    <input inputName="endDate" methodName="setEndDate"/>
                    <input inputName="endOfServiceDate" methodName="setEndOfServiceDate"/>
                    <input inputName="field1" methodName="setField1"/>
                    <input inputName="field2" methodName="setField2"/>
                    <input inputName="field3" methodName="setField3"/>
                    <input inputName="field4" methodName="setField4"/>
                    <input inputName="field5" methodName="setField5"/>
                    <input inputName="initKey_catalogEntryReferenceNumber" 
                     methodName="setInitKey_catalogEntryReferenceNumber"/>
                    <input inputName="itemspc_id" methodName="setItemspc_id"/>
                    <input inputName="language_id" methodName="setLanguage_id"/>
                    <input inputName="lastOrderDate" methodName="setLastOrderDate"/>
                    <input inputName="lastUpdate" methodName="setLastUpdate"/>
                    <input inputName="manufacturerName" methodName="setManufacturerName"/>
                    <input inputName="manufacturerPartNumber" 
                     methodName="setManufacturerPartNumber"/>
                    <input inputName="markForDelete" methodName="setMarkForDelete"/>
                    <input inputName="memberId" methodName="setMemberId"/>
                    <input inputName="oid" methodName="setOid"/>
                    <input inputName="onAuction" methodName="setOnAuction"/>
                    <input inputName="onSpecial" methodName="setOnSpecial"/>
                    <input inputName="partNumber" methodName="setPartNumber"/>
                    <input inputName="shipping" methodName="setShipping"/>
                    <input inputName="startDate" methodName="setStartDate"/>
                    <input inputName="state" methodName="setState"/>
                    <input inputName="url" methodName="setUrl"/>
                 </inputs>
                 <outputs>
                    <output methodName="getApplicableContractIds" 
                     outputName="applicableContractIds"/>
                    <output methodName="getAvailabilityDate" outputName="availabilityDate"/>
                    <output methodName="getAvailabilityDay" outputName="availabilityDay"/>
                    <output methodName="getAvailabilityMonth" outputName="availabilityMonth"/>
                    <output methodName="getAvailabilityYear" outputName="availabilityYear"/>
                    <output methodName="getBaseItemIdInEJBType" outputName="baseItemId"/>
                    <output methodName="getBuyableInEJBType" outputName="buyable"/>
                    <output methodName="getCatalogEntryID" outputName="catalogEntryID"/>
                    <output methodName="getCatalogEntryReferenceNumberInEJBType" 
                     outputName="catalogEntryReferenceNumber"/>
                    <output methodName="getDiscontinueDate" outputName="discontinueDate"/>
                    <output methodName="getDiscontinueDay" outputName="discontinueDay"/>
                    <output methodName="getDiscontinueMonth" outputName="discontinueMonth"/>
                    <output methodName="getDiscontinueYear" outputName="discontinueYear"/>
                    <output methodName="getEndDate" outputName="endDate"/>
                    <output methodName="getEndDay" outputName="endDay"/>
                    <output methodName="getEndMonth" outputName="endMonth"/>
                    <output methodName="getEndOfServiceDate" outputName="endOfServiceDate"/>
                    <output methodName="getEndOfServiceDay" outputName="endOfServiceDay"/>
                    <output methodName="getEndOfServiceMonth" outputName="endOfServiceMonth"/>
                    <output methodName="getEndOfServiceYear" outputName="endOfServiceYear"/>
                    <output methodName="getEndYear" outputName="endYear"/>
                    <output methodName="getField1InEJBType" outputName="field1"/>
                    <output methodName="getField2InEJBType" outputName="field2"/>
                    <output methodName="getField3InEJBType" outputName="field3"/>
                    <output methodName="getField4" outputName="field4"/>
                    <output methodName="getField5" outputName="field5"/>
                    <output methodName="getFormattedAvailabilityDate" 
                     outputName="formattedAvailabilityDate"/>
                    <output methodName="getFormattedDiscontinueDate" 
                     outputName="formattedDiscontinueDate"/>
                    <output methodName="getFormattedEndDate" 
                     outputName="formattedEndDate"/>
                    <output methodName="getFormattedEndOfServiceDate" 
                     outputName="formattedEndOfServiceDate"/>
                    <output methodName="getFormattedLastOrderDate" 
                     outputName="formattedLastOrderDate"/>
                    <output methodName="getFormattedStartDate" 
                     outputName="formattedStartDate"/>
                    <output methodName="isAnyMerchandisingAssociated" 
                     outputName="isAnyMerchandisingAssociated"/>
                    <output methodName="isBundle" outputName="isBundle"/>
                    <output methodName="isCalculatedContractPriced" 
                     outputName="isCalculatedContractPriced"/>
                    <output methodName="isCatalogEntryAllowedPriceRanges" 
                     outputName="isCatalogEntryAllowedPriceRanges"/>
                    <output methodName="isDynamicKit" outputName="isDynamicKit"/>
                    <output methodName="isItem" outputName="isItem"/>
                    <output methodName="isListPriced" outputName="isListPriced"/>
                    <output methodName="isMerchandisingAssociated" 
                     outputName="isMerchandisingAssociated"/>
                    <output methodName="isPackage" outputName="isPackage"/>
                    <output methodName="isProduct" outputName="isProduct"/>
                    <output methodName="getItemspc_idInEJBType" outputName="itemspc_id"/>
                    <output methodName="getLanguage_idInEJBType" outputName="language_id"/>
                    <output methodName="getLastOrderDate" outputName="lastOrderDate"/>
                    <output methodName="getLastOrderDay" outputName="lastOrderDay"/>
                    <output methodName="getLastOrderMonth" outputName="lastOrderMonth"/>
                    <output methodName="getLastOrderYear" outputName="lastOrderYear"/>
                    <output methodName="getLastUpdateInEJBType" outputName="lastUpdate"/>
                    <output methodName="getManufacturerName" outputName="manufacturerName"/>
                    <output methodName="getManufacturerPartNumber" 
                     outputName="manufacturerPartNumber"/>
                    <output methodName="getMarkForDeleteInEJBType" 
                     outputName="markForDelete"/>
                    <output methodName="getMemberIdInEJBType" outputName="memberId"/>
                    <output methodName="getObjectPath" outputName="objectPath"/>
                    <output methodName="getOid" outputName="oid"/>
                    <output methodName="getOnAuctionInEJBType" outputName="onAuction"/>
                    <output methodName="getOnSpecialInEJBType" outputName="onSpecial"/>
                    <output methodName="getParentCatalogEntryIds" 
                     outputName="parentCatalogEntryIds"/>
                    <output methodName="getPartNumber" outputName="partNumber"/>
                    <output methodName="getStartDate" outputName="startDate"/>
                    <output methodName="getStartDay" outputName="startDay"/>
                    <output methodName="getStartMonth" outputName="startMonth"/>
                    <output methodName="getStartYear" outputName="startYear"/>
                    <output methodName="getState" outputName="state"/>
                    <output methodName="getType" outputName="type"/>
                    <output methodName="getUrl" outputName="url"/>
                 </outputs>
              </profile>
           </profiles>
        </bean>

      Sample controller command mapping file (com.ibm.commerce.catalogmanagement.commands.CatalogEntryUpdateCmd.xml):

        <?xml version="1.0" encoding="UTF-8"?>
        <command>
           <profiles>
              <profile name="sample">
                 <inputs>
                    <input inputName="URL" methodName="setURL"/>
                    <input inputName="XMLdetail" methodName="setXMLdetail"/>
                    <input inputName="auxdescription1" methodName="setAuxdescription1"/>
                    <input inputName="auxdescription2" methodName="setAuxdescription2"/>
                    <input inputName="availabilityDate" methodName="setAvailabilityDate"/>
                    <input inputName="availabilitydate" methodName="setAvailabilitydate"/>
                    <input inputName="available" methodName="setAvailable"/>
                    <input inputName="buyable" methodName="setBuyable"/>
                    <input inputName="catEntURL" methodName="setCatEntURL"/>
                    <input inputName="catentryId" methodName="setCatentryId"/>
                    <input inputName="descLanguage" methodName="setDescLanguage"/>
                    <input inputName="discontinueDate" methodName="setDiscontinueDate"/>
                    <input inputName="endDate" methodName="setEndDate"/>
                    <input inputName="endOfServiceDate" methodName="setEndOfServiceDate"/>
                    <input inputName="expirationdate" methodName="setExpirationdate"/>
                    <input inputName="field1" methodName="setField1"/>
                    <input inputName="field2" methodName="setField2"/>
                    <input inputName="field3" methodName="setField3"/>
                    <input inputName="field4" methodName="setField4"/>
                    <input inputName="field5" methodName="setField5"/>
                    <input inputName="fullimage" methodName="setFullimage"/>
                    <input inputName="keyword" methodName="setKeyword"/>
                    <input inputName="lastOrderDate" methodName="setLastOrderDate"/>
                    <input inputName="longdescription" methodName="setLongdescription"/>
                    <input inputName="markfordelete" methodName="setMarkfordelete"/>
                    <input inputName="memberId" methodName="setMemberId"/>
                    <input inputName="mfname" methodName="setMfname"/>
                    <input inputName="mfpartnumber" methodName="setMfpartnumber"/>
                    <input inputName="name" methodName="setName"/>
                    <input inputName="onauction" methodName="setOnauction"/>
                    <input inputName="onspecial" methodName="setOnspecial"/>
                    <input inputName="partnumber" methodName="setPartnumber"/>
                    <input inputName="published" methodName="setPublished"/>
                    <input inputName="shortdescription" methodName="setShortdescription"/>
                    <input inputName="startDate" methodName="setStartDate"/>
                    <input inputName="thumbnail" methodName="setThumbnail"/>
                 </inputs>
                 <outputs>
                    <output methodName="getCatentryId" outputName="catentryId"/>
                    <output methodName="getPartnumber" outputName="partnumber"/>
                 </outputs>
              </profile>
           </profiles>
        </command>