Handle Url Encoding Attributes like a Boss !

Hi,

In this post, I will show you step by step how to customize SAP Cx for a new URL encoding attribute.

Problem

Instead of having /en /jp /ru in the storefront URL, we want to get something like /mystring1, /mystring2 and /mystring3 while :

  • /mystring1 is mapped to /en but not shown in the url
  • /mystring2 is mapped to /jp but not shown in the url
  • /mystring3 is mapped to /ru but not shown in the url

Solution

1/ Customize the data model to add mappping in cms site level :

<collectiontypes>
  ...
  <collectiontype code="ExtraLanguages" elementtype="ExtraLanguage" autocreate="true"
    generate="true"
    type="list"/>
...
</collectiontypes>
<itemtype code="ExtraLanguage" autocreate="true" generate="true">
  <deployment table="ExtraLanguage" typecode="32024"/>
  <attributes>
    <attribute qualifier="isoCode" type="java.lang.String">
      <persistence type="property"/>
      <description>language iso code (en, jp, ru,etc...)</description>
      <modifiers unique="true"/>
    </attribute>
    <attribute qualifier="value" type="java.lang.String">
      <persistence type="property"/>
      <description>mapped string (mystring1, mystring2, mystring3,etc...)</description>
    </attribute>
  </attributes>
</itemtype>
<itemtype code="CMSSite" autocreate="false" generate="false">
...
<attribute qualifier="extraLanguages" type="ExtraLanguages">
<persistence type="property"/>
</attribute>
...
</attributes>
</itemtype>

2/ Create a new class that inherited de.hybris.platform.acceleratorservices. urlencoder.attributes.impl.AbstractUrlEncodingAttributeManager

/**
 * The goal behind this class is to override the default hybris behaviour for language attribute manager.
 */
public class DefaultExtraLanguageAttributeManager extends AbstractUrlEncodingAttributeManager {

  private ExtraLanguageService extraLanguageService;

  @Override
  public Collection<String> getAllAvailableValues()
  {
    Collection<String> extraLanguages;

    return extraLanguageService.getAvailableExtraLanguages();
  }

  @Override
  public void updateAndSyncForAttrChange(final String value)
  {
    if (isValid(value))
    {
      getStoreSessionService().setCurrentLanguage(extraLanguageService.getIsoCodeForExtraLanguage(value));
    }
  }

  @Override
  public String getDefaultValue()
  {
    return extraLanguageService.getExtraLanguageForIsoCode(getCommerceCommonI18NService().getDefaultLanguage().getIsocode());
  }

  @Override
  public String getCurrentValue()
  {
    return extraLanguageService.getExtraLanguageForIsoCode(getCommerceCommonI18NService().getCurrentLanguage().getIsocode());
  }


  @Override
  public String getAttributeValueForEmail(final BusinessProcessModel businessProcessModel)
  {
    String extraIsoCode = StringUtils.EMPTY;

    if (businessProcessModel instanceof StoreFrontCustomerProcessModel)
    {
      extraIsoCode = ((StoreFrontCustomerProcessModel) businessProcessModel).getLanguage().getIsocode();
    }
    else if (businessProcessModel instanceof OrderProcessModel)
    {
      extraIsoCode = ((OrderProcessModel) businessProcessModel).getOrder().getLanguage().getIsocode();
    }
    else if (businessProcessModel instanceof ConsignmentProcessModel
        && ((ConsignmentProcessModel) businessProcessModel).getConsignment().getOrder() instanceof OrderModel)
    {
      extraIsoCode = ((OrderModel) ((ConsignmentProcessModel) businessProcessModel).getConsignment().getOrder()).getLanguage()
          .getIsocode();
    }
    else if (businessProcessModel instanceof ReturnProcessModel)
    {
      extraIsoCode = ((ReturnProcessModel) businessProcessModel).getReturnRequest().getOrder().getLanguage().getIsocode();
    }

    if(extraIsoCode.isEmpty()){
      extraIsoCode = getDefaultValue();
    }

    return extraLanguageService.getExtraLanguageForIsoCode(extraIsoCode);
  }

  public void setExtraLanguageService(
      ExtraLanguageService extraLanguageService) {
    this.extraLanguageService = extraLanguageService;
  }

 

**
 * @author boufnichel
 */
public class DefaultExtraLanguageService implements ExtraLanguageService {

    private CMSSiteService cmsSiteService;

    @Override
    public Collection<String> getAvailableExtraLanguages() {
        List<String> availableExtraLanguages = new ArrayList<>();
        CMSSiteModel currentSite = cmsSiteService.getCurrentSite();
        currentSite.getExtraLanguages()
                .stream()
                .forEach(extraLanguage -> availableExtraLanguages.add(extraLanguage.getValue()));
        return availableExtraLanguages;
    }

    @Override
    public String getIsoCodeForExtraLanguage(String extraLanguage) {
        CMSSiteModel currentSite = cmsSiteService.getCurrentSite();
        ExtraLanguageModel searchResult = currentSite.getExtraLanguages()
                .stream()
                .filter(extraLanguageModel -> extraLanguageModel.getValue().equals(extraLanguage))
                .findFirst()
                .orElse(null);
        return searchResult != null ? searchResult.getIsoCode() : StringUtils.EMPTY;
    }

    @Override
    public String getExtraLanguageForIsoCode(String isoCode) {
        CMSSiteModel currentSite = cmsSiteService.getCurrentSite();
        ExtraLanguageModel searchResult = currentSite.getExtraLanguages()
                .stream()
                .filter(extraLanguageModel -> extraLanguageModel.getIsoCode().equals(isoCode))
                .findFirst()
                .orElse(null);
        return searchResult != null ? searchResult.getValue() : StringUtils.EMPTY;
    }


    public void setCmsSiteService(CMSSiteService cmsSiteService) {
        this.cmsSiteService = cmsSiteService;
    }


}

3/ Override the default de.hybris.platform.acceleratorservices.urlencoder.impl.DefaultUrlEncoderService bean to use the new encoding url attribute ‘extralanguage’

<alias name="customUrlEncoderService" alias="urlEncoderService"/>
<bean id="customUrlEncoderService"
  class="de.hybris.platform.acceleratorservices.urlencoder.impl.DefaultUrlEncoderService">
  <property name="sessionService" ref="sessionService"/>
  <property name="cmsSiteService" ref="cmsSiteService"/>
  <property name="urlEncodingAttributeManagerMap">
    <map>
      <entry key="currency" value-ref="currencyAttributeManager"/>     
      <entry key="storefront" value-ref="storeFrontAttributeManager"/>
      <entry key="extralanguage" value-ref="extraLanguageAttributeManager"/>
    </map>
  </property>
</bean>

4/ Update the *-site.impex to be imported during update/init system

$siteUid = mysite

# Insert extra language mapping
INSERT_UPDATE ExtraLanguage; &xlangId; isoCode[unique = true]; value
                           ; en ; en  ; mystring1
                           ; jp ; jp  ; mystring2
                           ; ru ; ru  ; mystring3

# CMS Site
INSERT_UPDATE CMSSite; uid[unique = true]; extraLanguages(&xlangId);urlEncodingAttributes
; $siteUid ;en,jp,ru;extralanguage

5/ Update strofront logic with the new changes, and especially the accelerator StoreSessionController class

/**
 * Controller for store session. Used to change the session language, currency and experience
 * level.
 */
@Controller
@RequestMapping("/_s")
public class StoreSessionController extends AbstractController {

  
...

  @Resource(name = "extraLanguageRedirectStrategy")
  private RedirectionStrategy redirectionStrategy;


  
 ...
  @RequestMapping(value = "/language", method =
      {RequestMethod.GET, RequestMethod.POST})
  public String selectLanguage(@RequestParam("code") final String isoCode,
      final HttpServletRequest request) {
    final String previousLanguage = storeSessionFacade.getCurrentLanguage().getIsocode();
    storeSessionFacade.setCurrentLanguage(isoCode);
    if (!userFacade.isAnonymousUser()) {
      userFacade.syncSessionLanguage();
    } 
    return redirectionStrategy.calculateRedirectUrl(
        request, previousLanguage,
        storeSessionFacade.getCurrentLanguage().getIsocode());
  }
...
}
/**
 *
 * @author boufnichel
 *
 */
public class ExtraLanguageRedirectStrategy implements RedirectionStrategy {

  private ExtraLanguageService extraLanguageService;

  @Override
  public String calculateRedirectUrl(final HttpServletRequest request,
      final String old, final String current) {

    String extractedOld = extractLanguage(old);
    String extractedCurrent = extractLanguage(current);

    final String originalReferer = (String) request.getSession()
        .getAttribute(StorefrontFilter.ORIGINAL_REFERER);

    if (StringUtils.isNotBlank(originalReferer)) {

      if(originalReferer.contains(extractedOld)){

        return AbstractController.REDIRECT_PREFIX + StringUtils
            .replace(originalReferer, "/" + extractedOld + "/", "/" + extractedCurrent + "/");

      } else {

        String redirectUrl = AbstractController.REDIRECT_PREFIX + originalReferer;

        if(originalReferer.endsWith("/")){

          redirectUrl += extractedCurrent + "/";

        } else {

          redirectUrl += "/" + extractedCurrent + "/";

        }

        return redirectUrl;
      }

    }

    String referer = StringUtils
        .remove(request.getRequestURL().toString(), request.getServletPath());
    if (!StringUtils.endsWith(referer, "/")) {
      referer = referer + "/";
    }
    if (referer != null && !referer.isEmpty() && StringUtils.contains(referer, "/" + old + "/")) {
      return AbstractController.REDIRECT_PREFIX + StringUtils.replace(referer, "/" + old + "/", "/" + current + "/");
    }
    return AbstractController.REDIRECT_PREFIX + referer;
  }

  private String extractLanguage(String language) {
    return extraLanguageService.getExtraLanguageForIsoCode(language);
  }

  public void setExtraLanguageService(
      ExtraLanguageService extraLanguageService) {
    this.extraLanguageService = extraLanguageService;
  }

}

6/ Dont forget to add the spring beans 😉

 

Tagged

1 thought on “Handle Url Encoding Attributes like a Boss !

Leave a Reply

Your email address will not be published. Required fields are marked *