Polyglot persistence in Hybris 1905 : What, Why and How-To?

Polyglot persistence is the concept of using different data storage technologies to handle different data storage needs within a given software application. ~wikipedia Polyglot persistance support is introduced with Hybris 1905.

As we know that a complex business application needs can be handled in many ways and with many different programming languages and database. And each one of those may offer or may be a best fit solution to resolve different business problems. In some cases, using relational database could be a win, while in other case a NoSQL database could be a best solution.

Polyglot is term which explains that one is not rigid to just one technology/data-storage while trying to solve a business problem and can scatter and structure it across to utilize best offerings of different technology/tools available in market.

Let’s take a simple example from Hybris itself without knowing much information about Polyglot,

Polyglot persistence in Hybris 1905

In Hybris, we use relational database to store all the entities like product, cart, order, customers etc. But when it comes to support quick product search support for a huge product data, if we make a search to RDBMS (with joins and all) it certainly is a performance disaster. In this case, Solr comes to our rescue and it gives us the benefit of flat file structured and super-fast search across millions of SKUs in system. This is one of the simplest and very existing example of Polyglot persistence from very first day of hybris life where multiple data-storage/tools are use to solve a complex business problem.

Now coming back to it’s definition again, When we talk about Polyglot, that means using best fit languages/scripts/storages to solve some business problem in one application (say e-commerce website)

Now what’s new and

why Hybris 1905 release notes mentions Polyglot Persistence a big offering in new package?

Answer is…

  • Before Hybris 1905, if we wanted to use 2 different data storages (apart from RDBMS / Solr), it would take us a quite a good effort to put a stable version of it while hybris1905 version allows you to distribute your application data among many data-storages.
  • Also, with this solution, you can easily configure different data-storage units even on an Item level in Hybris system (like Cart, Promotion etc.)
  • With this offering, you don’t need to consider any changes to your back-office system to ensure adaptability and it is supported by OOB engine.

Next question arrises is that

What’s the purpose/rational of introducing this change?

Most important and simple answer is to to improve system maintenance, performance, scalability, simplified operations etc. etc. etc. We will try to understand with with following 2 examples…

Example 1 –

Carts in system is the heavily manipulated data and it also consists JOIN with many other database tables to finally show what’s visible to user. If we consider to move it to flat file / json based database, it could give huge breathing space to system.

Example 2 –

Say you need to log say every integration activity happening between hybris and any third party system; in such case there could be hundred of thousands of records generated everyday. And slowly it either you need to clean up your logging tables on quick time intervals, Or you can choose a NoSQL database to handle this big data.

Hope it is now clear on what and why polyglot persistence can help your business quite effectively if you are a Hybris practitioner.

Now comes the last part of this blog,

How to configure polyglot persistence in hybris?

Using ydocumentcart template extension – Hybris has created a new extension template named as ydocumentcart in 1905 package. One can create a custom extension using this extension as the template extension.

It has OOB configuration/code available to move Cart and related Items Objects out of RDBMS. Of-course one can extend/change as per the business need.

Using own custom extension – You can either create the related classes/configuration in a new yempty generated extension or in any of your existed custom extension as well (preferably new or customcore extension.)

How to and What to Code?

This is actually a 2 step process.

  • Implement and override interface ItemStateRepository
  • Profile related configuration in your project’s project.properties/local.properties

Below implementation is a very basic working code example. What are different objects etc in this file, I will explain in a follow up post.

Also add following entries to your project.properties / local.properties

polyglot.repository.config.<extension-name>.typeCodes=Cart
polyglot.repository.config.<extension-name>.beanName=demoInMemoryCartRepository

import de.hybris.platform.persistence.polyglot.ItemStateRepository;
 import de.hybris.platform.persistence.polyglot.model.ChangeSet;
 import de.hybris.platform.persistence.polyglot.model.Identity;
 import de.hybris.platform.persistence.polyglot.model.ItemState;
 import de.hybris.platform.persistence.polyglot.model.Key;
 import de.hybris.platform.persistence.polyglot.model.PolyglotModelFactory;
 import de.hybris.platform.persistence.polyglot.model.SingleAttributeKey;
 import de.hybris.platform.persistence.polyglot.search.FindResult;
 import de.hybris.platform.persistence.polyglot.search.StandardFindResult;
 import de.hybris.platform.persistence.polyglot.search.criteria.Criteria;
 import de.hybris.platform.persistence.polyglot.search.criteria.ItemStateComparatorCreator;
 import de.hybris.platform.persistence.polyglot.search.criteria.MatchingPredicateBuilder;
 import de.hybris.platform.persistence.polyglot.view.ItemStateView;
import java.util.Comparator;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.function.Function;
 import java.util.function.Predicate;
 import java.util.stream.Stream;
import com.hybriscx.demo.polyglot.customer.repository.DemoInMemoryCartRepository.ModificationChangeSet;
/**
  *
  */
 public class DemoInMemoryCartRepository implements ItemStateRepository
 {
private final ConcurrentHashMap<Identity, SimpleState> inMemory = new ConcurrentHashMap<>();
private final Function<Criteria, MatchingPredicateBuilder> predicateBuilderProvider = MatchingPredicateBuilder::new;


@Override
public ChangeSet beginCreation(final Identity id)
{
    return new CreationChangeSet(id);
}

@Override
public FindResult find(final Criteria criteria)
{
    final MatchingPredicateBuilder builder = predicateBuilderProvider.apply(criteria);
    final Predicate<ItemStateView> matchingPredicate = builder.getPredicate();
    final Comparator<ItemStateView> cmp = ItemStateComparatorCreator.getItemStateComparator(criteria);
    final Stream<ItemStateView> stream = inMemory.values().stream().map(ItemStateView.class::cast).filter(matchingPredicate)
            .sorted(cmp);

    return StandardFindResult.buildFromStream(stream).withCriteria(criteria).build();
}

@Override
public ItemState get(final Identity id)
{
    return inMemory.get(id);
}

@Override
public void remove(final ItemState state)
{
    inMemory.remove(state.get(PolyglotModelFactory.pk()));
}

@Override
public void store(final ChangeSet changeSet)
{
    if (changeSet instanceof CreationChangeSet)
  {
        final CreationChangeSet creation = (CreationChangeSet) changeSet;
        inMemory.putIfAbsent(creation.id, new SimpleState(creation.id, creation.initialValues));
        return;
  }

    if (changeSet instanceof ModificationChangeSet)
    {
        final ModificationChangeSet modification = (ModificationChangeSet) changeSet;
        final SimpleState currentState = inMemory.get(modification.id);
        inMemory.replace(modification.id, currentState);
        return;
    }
}


static class CreationChangeSet implements ChangeSet
{
    final Identity id;
    final Map<SingleAttributeKey, Object> initialValues = new HashMap<>();

    public CreationChangeSet(final Identity id)
    {
        this.id = id;
        initialValues.put(PolyglotModelFactory.pk(), id);
        initialValues.put(PolyglotModelFactory.version(), Long.valueOf(0));
    }

    @Override
    public void set(final SingleAttributeKey key, final Object value)
    {
        initialValues.put(key, value);
    }

}

static class ModificationChangeSet implements ChangeSet
{
    final Identity id;
    long baselineVersion;
    final Map<SingleAttributeKey, Object> valuesToModify = new HashMap<>();

    public ModificationChangeSet(final SimpleState itemState)
    {
        id = itemState.get(PolyglotModelFactory.pk());
        baselineVersion = itemState.get(PolyglotModelFactory.version());
    }

    @Override
    public void set(final SingleAttributeKey key, final Object value)
    {
        valuesToModify.put(key, value);
    }
}
}
class SimpleState implements ItemState
 {
private final Map<SingleAttributeKey, Object> values;
private final Identity id;
private final long version;


/**
 * @return the version
 */
public long getVersion()
{
    return version;
}

/**
 * @return the id
 */
public Identity getId()
{
    return id;
}

public SimpleState(final Identity id, final Map<SingleAttributeKey, Object> values)
{
    this.id = id;
    this.version = 1;
    this.values = values;
}

@Override
public <T> T get(final Key key)
{
    return (T) values.get(key);
}

@Override
public ChangeSet beginModification()
{
    return new ModificationChangeSet(this);
}
}

Thanks for taking out time and reading it. Hope you liked my article on Polyglot persistence in Hybris 1905? and you can use it for your work.

Related Posts

For queries of if you want me to cover specific topic, please use comments section below. Thank once again. Cheers!! 🙂

If you are interested in learning Hybris back-office customization concepts and tricks, read my blog at http://www.hybriscx.com/category/backoffice/

Also, if you are looking for some real time code examples, check my GitHub repository @ https://github.com/gupta1vipin/

2200cookie-checkPolyglot persistence in Hybris 1905 : What, Why and How-To?

3 thoughts on “Polyglot persistence in Hybris 1905 : What, Why and How-To?

  • how polyglot handles the many to many relations. As the relation has separate table. Where do need to have this relation table either in main Database or polyglot database? Please confirm.

    • Dear Siddesh – I would need a little more understanding of the background of your question. If we talk about hybris polyglot persistence and table creation, one would still need to use standard itemtype and relation tags to define many to many relationships in items.xml file. And when it comes to decide where (which db) you want to keep related data, it should be more depending upon the type of item and the business operations need on that. For example, if you are choosing a flat file db, there you would want your data to be persisted as a normal json object without any direct relation as in a rotational database. Give me a little more detail on usecase and I might be able to givemore constructive answer. Thanks again for your timr to read the blog

Leave a Reply

Your email address will not be published.