(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
- 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; } }
- 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:
- 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.
- public JSONObject executeConfigBasedBean
(String beanClassName, String profileName, String responseFormat, Map<String, Object> paramOverrideMap) throws ExceptionThis 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.
- 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.
- public JSONObject executeConfigBasedCommand
(String pCmdInterfaceName, String profileName, String responseFormat, String storeId, Map<String, Object> paramOverrideMap) throws ExceptionThis 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.
- 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>
- Configuration-based controller command and data bean mapping framework
The configuration-based controller command and data bean mapping framework allows the activation of data beans or the running of controller commands using REST services. The framework significantly reduces the amount of custom code necessary. It provides a way to describe what inputs and outputs are required from a data bean or controller command through a mapping file. A mapping file represents one data bean or controller command. It is further subdivided into profiles, allowing multiple REST resources with different properties to work on the same data bean or controller command. The custom code required to write a resource handler for a single REST resource can be as simple as a single line. The input mapping, type casting, activation, running, and responses are all handled by the framework. To help produce a custom mapping file and handler, a generator tool is provided (restClassicSampleGen), further reducing the effort of creating custom REST resources.- Customizing the configuration-based controller command and data bean mapping framework
WebSphere Commerce uses REST calls for some data beans by default. They are configured with mapping profiles that map REST input parameters to data bean or controller command setter-methods, and data bean or controller command getter-methods to REST output parameters. To customize this behavior, we must either create new mappings, or extend the default mappings.