Product Data Synchronization Between Solr and SAP Commerce (hybris)

Requirement : The product data in SAP Commerce (Hybris) is always synchronized with the information stored in Solr.

This means that any updates or changes made to product details in Solr are automatically reflected in SAP Commerce(Hybris) Database. It works by:

  1. Fetching product details (like product code, stock status, EAN, and manufacturer name) from Solr.
  2. Checking if the product already exists in the SAP Commerce database.
  3. If the product exists, it updates the existing record.
  4. If the product does not exist, it creates a new record in the database.

This process ensures that the product information in SAP Commerce remains synchronized with the product data from Solr.

Step 1: Define the Custom Item Type SolrExtractedItemType in /samplecore/resources/samplecore-items.xml
You need to create a custom item type that will hold the product information fetched from Solr, such as the product code, stock status, EAN, and manufacturer name
<itemtype code="SolrExtractedItemType" autocreate="true" generate="true">
    <deployment table="solrextractedtypes" typecode="15800" />
    <attributes>
        <attribute qualifier="productCode" type="java.lang.String">
            <description>Product Code</description>
            <modifiers read="true" write="true" search="true" unique="true" />
            <persistence type="property" />
        </attribute>
        <attribute qualifier="inStockFlag" type="java.lang.Boolean">
            <description>Stock Flag of the Product</description>
            <modifiers read="true" write="true" search="true" />
            <persistence type="property" />
        </attribute>
        <attribute qualifier="ean" type="java.lang.String">
            <description>EAN of the product</description>
            <modifiers read="true" write="true" search="true" />
            <persistence type="property" />
        </attribute>
        <attribute qualifier="manufacturerName" type="java.lang.String">
            <description>Name of manufacturer</description>
            <modifiers read="true" write="true" search="true" />
            <persistence type="property" />
        </attribute>
    </attributes>
</itemtype>

Step 2: Do ant all command in platform

Step 3: Create a DAO for Fetching Data from Solr

In this step, we will create the SolrProductDataUpdaterDao interface, which will define the method to fetch an existing SolrExtractedItemTypeModel based on productCode.

Location: /samplecore/src/com/hybris/sample/core/solr/product/attributes/SolrProductDataUpdaterDao.java
package com.hybris.sample.core.solr.product.attributes;
import de.hybris.platform.servicelayer.internal.dao.Dao;
import com.hybris.sample.core.model.SolrExtractedItemTypeModel;

public interface SolrProductDataUpdaterDao extends Dao {
    SolrExtractedItemTypeModel findExistingSolrExtractedItem(String productCode);
    }
  
Step 4: In this step, we will implement the DefaultSolrProductDataUpdaterDao class, which implements the SolrProductDataUpdaterDao interface and defines the method to fetch an existing SolrExtractedItemTypeModel based on productCode.
Location: /samplecore/src/com/hybris/sample/core/solr/product/attributes/DefaultSolrProductDataUpdaterDao.java
package com.hybris.sample.core.solr.product.attributes;
import de.hybris.platform.servicelayer.search.FlexibleSearchQuery;
import de.hybris.platform.servicelayer.search.FlexibleSearchService;
import de.hybris.platform.servicelayer.search.SearchResult;
import javax.annotation.Resource;

public class DefaultSolrProductDataUpdaterDao implements SolrProductDataUpdaterDao {
    private static final String GET_EXISTINGITEMS_BY_PRODUCTCODE = 
        "SELECT{" + SolrExtractedItemTypeModel.PK + "} FROM {" + SolrExtractedItemTypeModel._TYPECODE + "} WHERE {" + SolrExtractedItemTypeModel.PRODUCTCODE + "} = ?productCode";

    @Resource
    private FlexibleSearchService flexibleSearchService;

    @Override
    public SolrExtractedItemTypeModel findExistingSolrExtractedItem(
        final String productCode) {
        FlexibleSearchQuery query = new FlexibleSearchQuery(GET_EXISTINGITEMS_BY_PRODUCTCODE);
        query.addQueryParameter("productCode", productCode);
        SearchResult<SolrExtractedItemTypeModel> searchResult = flexibleSearchService.search(query);
        return searchResult.getCount() > 0 ? searchResult.getResult().get(0) : null;
    }
}
  

Step 5: Configure the SolrProductDataUpdaterDao in samplecore-spring.xml
Location: /samplecore/resources/samplecore-spring.xml
<alias name="defaultSolrProductDataUpdaterDao" alias="productDataUpdater" />
<bean id="defaultSolrProductDataUpdaterDao" class="com.hybris.sample.core.solr.product.attributes.impl.DefaultSolrProductDataUpdaterDao" />

Step 6: Create the Solr Data Fetching Job
Location:/samplecore/src/com/hybris/sample/core/job/SolrProductDataUpdaterJob.java
package com.hybris.sample.core.job;
import de.hybris.platform.cronjob.enums.CronJobResult;
import de.hybris.platform.cronjob.enums.CronJobStatus;
import de.hybris.platform.cronjob.model.CronJobModel;
import de.hybris.platform.servicelayer.cronjob.AbstractJobPerformable;
import de.hybris.platform.servicelayer.cronjob.PerformResult;
import de.hybris.platform.servicelayer.model.ModelService;

import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;

import javax.annotation.Resource;
import javax.net.ssl.SSLContext;

import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.HttpClient;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.ssl.SSLContexts;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.impl.HttpSolrClient;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;

import com.hybris.sample.core.model.SolrExtractedItemTypeModel;
import com.hybris.sample.core.solr.product.attributes.SolrProductDataUpdaterDao;

public class SolrProductDataUpdaterJob extends AbstractJobPerformable<CronJobModel>
{
    // Solr query constants
    private static final String SOLR_QUERY = "*:*";
    private static final String SOLR_URL = "https://localhost:8983/solr/master_electronics_Product_default";
    private static final String SOLR_USERNAME = "solradmin";
    private static final String SOLR_PASSWORD = "admin123";

    @Resource
    private SolrProductDataUpdaterDao productDataUpdaterDao;

    @Resource
    private ModelService modelService;

    private SolrClient solrClient;

    @Override
    public PerformResult perform(final CronJobModel job)
    {
        try
        {
            // Initialize the HttpClient for Solr connection
            solrClient = new HttpSolrClient.Builder(SOLR_URL).withHttpClient(createHttpClient(SOLR_USERNAME, SOLR_PASSWORD)).build();
        }
        catch (final Exception e)
        {
            e.printStackTrace();
            return new PerformResult(CronJobResult.FAILURE, CronJobStatus.FINISHED);
        }

        final SolrQuery solrQuery = new SolrQuery();
        solrQuery.setQuery(SOLR_QUERY);
        solrQuery.setFilterQueries("catalogVersion:Online");

        solrQuery.addField("code_string");
        solrQuery.addField("inStockFlag_boolean");
        solrQuery.addField("ean_string");
        solrQuery.addField("manufacturerName_text");

        int start = 0;
        final int pageSize = 100;

        while (true)
        {
            solrQuery.setStart(start);
            solrQuery.setRows(pageSize);

            QueryResponse response = null;
            try
            {
                response = solrClient.query(solrQuery);
            }
            catch (final Exception e)
            {
                e.printStackTrace();
                return new PerformResult(CronJobResult.FAILURE, CronJobStatus.FINISHED);
            }

            final SolrDocumentList results = response.getResults();
            if (!results.isEmpty())
            {
                for (final SolrDocument document : results)
                {
                    final String productCode = document.getFieldValue("code_string").toString();
                    final SolrExtractedItemTypeModel existingItem = productDataUpdaterDao.findExistingSolrExtractedItem(productCode);
                    if (existingItem != null)
                    {
                        existingItem.setInStockFlag((Boolean) document.getFieldValue("inStockFlag_boolean"));
                        existingItem.setEan((String) document.getFieldValue("ean_string"));
                        existingItem.setManufacturerName((String) document.getFieldValue("manufacturerName_text"));
                        modelService.save(existingItem);
                    }
                    else
                    {
                        final SolrExtractedItemTypeModel solrExtractedItemTypeModel = modelService.create(SolrExtractedItemTypeModel.class);
                        solrExtractedItemTypeModel.setProductCode(productCode);
                        solrExtractedItemTypeModel.setInStockFlag((Boolean) document.getFieldValue("inStockFlag_boolean"));
                        solrExtractedItemTypeModel.setEan((String) document.getFieldValue("ean_string"));
                        solrExtractedItemTypeModel.setManufacturerName((String) document.getFieldValue("manufacturerName_text"));
                        modelService.save(solrExtractedItemTypeModel);
                    }
                }
            }

            // Check if there are fewer results than page size, if so, stop
            if (results.size() < pageSize)
            {
                break;
            }
            start += pageSize;
        }

        // Return successful job completion
        return new PerformResult(CronJobResult.SUCCESS, CronJobStatus.FINISHED);
    }

    // Creates a HttpClient with SSL and HTTP Basic Authentication for Solr.
    private HttpClient createHttpClient(final String solrUsername, final String solrPassword)
            throws KeyManagementException, NoSuchAlgorithmException, KeyStoreException
    {
        final SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(new TrustStrategy()
        {
            @Override
            public boolean isTrusted(final java.security.cert.X509Certificate[] chain, final String authType)
            {
                return true;
            }
        }).build();

        final BasicCredentialsProvider provider = new BasicCredentialsProvider();
        final UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(solrUsername, solrPassword);
        provider.setCredentials(AuthScope.ANY, credentials);

        return HttpClientBuilder.create().setSSLContext(sslContext).setDefaultCredentialsProvider(provider).build();
    }
}
  

Step 7: Create Spring Bean for the Job

Location:/samplecore/resources/samplecore-spring.xml

<bean id="solrProductDataUpdaterJob"class="com.hybris.sample.core.job.SolrProductDataUpdaterJob"/>

Step 8: Do ant all command in platform,make server up after that update hac by just selecting samplecore extension (check only Update running system)

Step 9: Run ServicelayerJob and CronJob Impexes in Hac
INSERT_UPDATE ServicelayerJob ; code[unique=true]         ; springId                 
                              ; solrProductDataUpdaterJob ; solrProductDataUpdaterJob
        

INSERT_UPDATE CronJob ; code[unique=true]             ; job(code)                 ; sessionLanguage(isocode) ; sessionCurrency(isocode)
                      ; solrProductDataUpdaterCronJob ; solrProductDataUpdaterJob ; en                       ; EUR
        

Step 10: First let see how we are retrieving product information from solr
Open Solr Admin: Im passing catalogVersion:"Online" in FilterQuery and code_string,inStockFlag_boolean,ean_string,manufacturerName_text in FilterList ,here we can see total no of doc count is 185
Step 10: Open Backoffice and run Cronjob ,Check the type SolrExtractedItemType

Comments

Anonymous said…
Great Content
Anonymous said…
This post is very useful.
Sandhya said…
Thanks for sharing, very useful, keep sharing
Anonymous said…
Thanks for sharing, very informative
Anonymous said…
Very useful content

Popular posts from this blog

Latest SAP Commerce (Hybris) Interview Questions

Steps to Install SAP Commerce Cloud 2211/Install SAP Hybris 2105 to 2211

OCC Webservices in SAP Commerce(hybris) 2211 using YOCC template – Part 1