All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sap.cds.mt.CdsDataStoreLookup Maven / Gradle / Ivy

/*
 * ----------------------------------------------------------------
 * © 2019-2021 SAP SE or an SAP affiliate company. All rights reserved.
 * ----------------------------------------------------------------
 *
 */

package com.sap.cds.mt;

import com.google.common.base.Ticker;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.util.concurrent.UncheckedExecutionException;
import com.sap.cds.CdsDataStoreConnector;
import com.sap.cds.CdsException;
import com.sap.cds.mtx.CdsDataStoreConnectorCreator;
import com.sap.cds.mtx.impl.CacheParams;
import com.sap.cds.reflect.CdsModel;

import java.util.function.BiPredicate;
import java.util.function.Function;

/**
 * Responsible for retrieval of {@code CdsDataStoreConnectors}. For performance reasons {@code CdsDataStore}
 * connector instances are cached per tenant. The cache is synchronized with the {@code MetaDataAccessor}'s cache:
 * cache {@code CdsDataStore} entries are automatically refreshed when a cached model changes in
 * the {@code MetaDataAccessor}'s cache. To manually refresh a {@code CdsDataStore}
 * for a particular tenant the tenant's model must be refreshed or evicted at the {@code MetaDataAccessor}.
 *
 * @see com.sap.cds.mtx.MetaDataAccessor#refresh(String) 
 * @see com.sap.cds.mtx.MetaDataAccessor#evict(String) 
 */
public class CdsDataStoreLookup {
    private final BiPredicate isModelOutDated;
    private final LoadingCache tenantToConnector;

    /**
     * @param cdsDataStoreConnectorCreator factory that creates a
     *                                     {@link CdsDataStoreConnector}
     * @param isModelOutDated              predicate that takes the tenant id and
     *                                     the current model as input and decides if
     *                                     the model is out dated
     * @param cacheParams                  Parameters that control cache lifecycle
     * @param cacheTicker                  Optional ticker used by guava cache for
     *                                     testing purposes, use null for productive
     *                                     use
     */
    public CdsDataStoreLookup(CdsDataStoreConnectorCreator cdsDataStoreConnectorCreator,
                              BiPredicate isModelOutDated, CacheParams cacheParams, Ticker cacheTicker) {
        this.isModelOutDated = isModelOutDated;
        this.tenantToConnector = buildCache(cacheParams, cacheTicker, cdsDataStoreConnectorCreator::create);
    }

    /**
     * Determine a data store connector for a tenant
     *
     * @param tenantId tenant identifier
     * @return a CDS data store connector
     */
    public CdsDataStoreConnector getCdsDataStoreConnector(String tenantId) throws CdsException {
        try {
            return tenantToConnector.getUnchecked(tenantId);
        } catch (UncheckedExecutionException e) {
            throw new CdsException(e);
        }
    }

    public void evictIfOutDated(String tenantId) {
        CdsDataStoreConnector connector = getCdsDataStoreConnector(tenantId);
        if (connector != null) {
            CdsModel cdsModel = connector.reflect();
            if (isModelOutDated.test(tenantId, cdsModel)) {
                tenantToConnector.invalidate(tenantId);
            }
        }
    }

    private static LoadingCache buildCache(CacheParams params, Ticker cacheTicker,
                                                                          Function loader) {
        CacheBuilder builder = CacheBuilder.newBuilder().maximumSize(params.getMaximumSize())
                .expireAfterAccess(params.getExpirationDuration(), params.getExpirationDurationUnit());
        if (cacheTicker != null) {
            builder.ticker(cacheTicker);
        }
        return builder.build(new CacheLoader() {
            @Override
            public CdsDataStoreConnector load(String key) {
                return loader.apply(key);
            }
        });
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy