Skip to content

Instantly share code, notes, and snippets.

@sperez2-seidor
Created October 30, 2023 08:39
Show Gist options
  • Save sperez2-seidor/327f5db98d2d8368e3bb099e6a800929 to your computer and use it in GitHub Desktop.
Save sperez2-seidor/327f5db98d2d8368e3bb099e6a800929 to your computer and use it in GitHub Desktop.
Creating a new OCC Extension

With 2211 the OCC Concept was changed from Addons to Extensions.

OCC extension directory structure (new) Description
/src REST Controller classes and other related classes are located in the /src directory of OCC extension.
/resources/occ/v2/dfocc/messages Localized messages of an OCC extension are loaded from the classpath.
/lib All libraries are located in the main /lib directory.
/resources/impex ImpEx files in OCC extension aren’t loaded automatically unless they follow the configuration convention. For more information, see ImpEx Import for Essential and Project Data.
/resources/occ/v2/dfocc/web/spring Spring bean definitions of OCC extension located in /resources/occ/v2/dfocc/web/spring/dfocc-web-spring.xml file are imported into the web context of commercewebservices.

Generating an occ extension from the yocc extension template

In order to generate an occ extension from yocc extension template perform the following steps:

  1. Generate the occ extension by using extgen and the yocc extension template. The names of OCC Extensions need to end with “occ”, for example xyzocc.
➜  platform ant extgen
...
extgen:
    [input]
    [input] Please choose a template for generation.
    [input] Press [Enter] to use the default value (dffulfilmentprocess, yacceleratorfulfilmentprocess, yacceleratormarketplaceintegration, yacceleratorordermanagement, yaddon, ybackoffice, ycommercewebservices, ycommercewebservicestest, ydocumentcart, [yempty], yhacext, yocc, yoccaddon, yocctests, ysapproductconfigaddon, yacceleratorstorefront, ysmarteditmodule, yvoid, ywebservices)
yocc
    [input]
    [input] Please choose the name of your extension. It has to start with a letter followed by letters and/or numbers.
    [input] Press [Enter] to use the default value [training]
dfocc
    [input]
    [input] Please choose the package name of your extension. It has to fulfill java package name convention.
    [input] Press [Enter] to use the default value [org.training]
il.co.directfinance
     [echo] Using extension template source: /Users/serpean/y/df/hybris/bin/modules/commerce-services/yocc
   [delete] Deleting directory /Users/serpean/y/df/hybris/temp/hybris/extgen_final
   [delete] Deleting directory /Users/serpean/y/df/hybris/temp/hybris/extgen
    [mkdir] Created dir: /Users/serpean/y/df/hybris/temp/hybris/extgen
     [echo] Copying template files from /Users/serpean/y/df/hybris/bin/modules/commerce-services/yocc to /Users/serpean/y/df/hybris/temp/hybris/extgen
     [copy] Copying 69 files to /Users/serpean/y/df/hybris/temp/hybris/extgen
     [copy] Copying 69 files to /Users/serpean/y/df/hybris/temp/hybris/extgen_final
    [mkdir] Created dir: /Users/serpean/y/df/hybris/bin/custom/dfocc/lib
     [copy] Copying 58 files to /Users/serpean/y/df/hybris/bin/custom/dfocc
     [echo]
     [echo]
     [echo] 	Next steps:
     [echo]
     [echo] 1) Add your extension to your /Users/serpean/y/df/hybris/config/localextensions.xml
     [echo]
     [echo]      <extension dir="/Users/serpean/y/df/hybris/bin/custom/dfocc"/>
     [echo]
     [echo] 2) Please remove all template extensions (again) before you proceed.
     [echo]
     [echo] 3) Make sure the applicationserver is stopped before you build the extension the first time.
     [echo]
     [echo] 4) Perform 'ant' in your hybris/platform directory.
     [echo]
     [echo] 5) Restart the applicationserver
     [echo]
     [echo]

BUILD SUCCESSFUL
Total time: 34 seconds
  1. Reference the new extension dfocc in the core-customize\hybris\config\localextensions.xml file:
<extensions> 
   ... 
   <extension name="dfocc"/> 
</extensions>

Extending the REST API

To expose new calls, you need to define a Controller class with the appropriate methods. A Controller should be created in the /src directory. If it is created in package: dfocc.controllers (for example il.co.directfinance.dfocc.controllers then it is automatically added to Commerce Web Services Spring web context.

@Controller 
@RequestMapping(value = "/{baseSiteId}/newResource") 
public class NewController 
{ 
    @RequestMapping(method = RequestMethod.GET) 
    @ResponseBody 
    public NewResourceWsDTO getNewResource() 
    { 
        return new NewResourceWsDTO("newSampleResource"); 
    } 
} 

After reference the new occ extension xyzocc with such defined controller, rebuild SAP Commerce.

Then it should be possible to call the following request: https://localhost:9002/occ/v2/{baseSiteId}/newResource

Override a specific Endpoint

To Override a specific Endpoint you can use the Annotation @de.hybris.platform.commerceservices.request.mapping.annotation.RequestMappingOverride

on a Custom Endpoint (with the same Mapping) to replace the Orginal one.

@RequestMappingOverride should be used to override an identical @RequestMapping annotation.

It will however not work correctly in a situation where the original request mapping supports two HTTP methods and you will try to override only one of them:

  • request mapping for original method = @RequestMapping(value = "/current/addresses/default/{id}", method = { RequestMethod.PUT, RequestMethod.POST } )

  • request mapping for method, which should override original = @RequestMapping(value = "/current/addresses/default/{id}", method = RequestMethod.PUT )

Even example below is considered as different mapping :

  • request mapping for original method = @RequestMapping(value = "/{productCode}", method = RequestMethod.GET)

  • request mapping for method, which should override original = @RequestMapping(value = "/{productId}", method = RequestMethod.GET)

In such cases methods will not be overridden and error "Ambiguous handler methods..." will appear during request (not during platform start up)

If multiple Extensions with the same Mappings exists you will be able to define the priority via Property. The method with the Highest Priority will be used.

You can use b2bocc as reference or eview the example of overwrite the get address endpoint:

requestMappingOverride.il.co.directfinance.dfocc.controllers.ExtendedCustomersController.updateDefaultAddress.priority

If there is no property defined in the properties file, the priority value is set to zero.

Example:

  • @RequestMappingOverride(priorityProperty="dfocc.updateDefaultAddress.priority") - here the priority value is read from the df.updateDefaultAddress.priority property.
  • @RequestMappingOverride - here the priority value is read from requestMappingOverride.<className>.<methodName>.priority property (e.g. requestMappingOverride.il.co.directfinance.dfzocc.controllers.ExtAddressCustomersController.updateDefaultAddress.priority).

Overriding the Request Mapping Example: !ExtendedCustomerController

This example will override the following OCC API:

Method: PUT

URL: htps://localhost:9002/occ/v2/{baseSiteId}/users/{userId}/addresses/{addressId}

Authentication: OAUTH token for client

Response Code: 401

Response Bdoy:

{
  "errors": [
    {
      "message": "Access is denied",
      "type": "AccessDeniedError"
    }
  ]
}

Description: Failed to update the address if the OCC API is override.

References:

/**
* Controller which extends Customer Resources
*/
@Controller
@RequestMapping(value = "/{baseSiteId}/users/{userId}")
@Api(tags = "Extended User")
public class ExtAddressCustomersController
{
……
/**
* This is example of overriding existing request mapping. Annotation {@link RequestMappingOverride} allows override
* existing request mapping, defined by {@link RequestMapping} annotation.
*/
@Secured({ "ROLE_CUSTOMERGROUP" })
@RequestMapping(value = "/addresses/{addressId}", method =
RequestMethod.PUT, consumes = { MediaType.APPLICATION_JSON_VALUE,
MediaType.APPLICATION_XML_VALUE })
@ResponseStatus(HttpStatus.OK)
@ApiBaseSiteIdAndUserIdParam
@RequestMappingOverride
public void replaceAddress(@PathVariable final String addressId, @RequestBody final AddressWsDTO address)
{
throw new AccessDeniedException("Access is denied");
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment