/* * * This file is part of the Hesperides distribution. * * (https://github.com/voyages-sncf-technologies/hesperides) * * Copyright (c) 2016 VSCT. * * * * Hesperides is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as * * published by the Free Software Foundation, version 3. * * * * Hesperides is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ package com.vsct.dt.hesperides.templating.modules.cache; import com.vsct.dt.hesperides.storage.EventStore; import com.vsct.dt.hesperides.storage.HesperidesSnapshotItem; import com.vsct.dt.hesperides.templating.modules.AbstractModulesAggregate; import com.vsct.dt.hesperides.templating.modules.Module; import com.vsct.dt.hesperides.templating.modules.ModuleKey; import com.vsct.dt.hesperides.templating.modules.event.ModuleContainer; import com.vsct.dt.hesperides.templating.modules.exception.ModuleNotFoundInDatabaseException; import com.vsct.dt.hesperides.templating.modules.template.Template; import com.vsct.dt.hesperides.templating.modules.template.event.AbstractTemplateCacheLoader; import com.vsct.dt.hesperides.templating.modules.virtual.VirtualModulesAggregate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.*; /** * Created by emeric_martineau on 15/01/2016. */ public class ModuleCacheLoader extends AbstractTemplateCacheLoader<ModuleKey, ModuleContainer> implements ModuleStoragePrefixInterface { private interface Callback { void moduleFound(Module module, AbstractModulesAggregate modulesAggregate); } /** * Logger. */ private static final Logger LOGGER = LoggerFactory.getLogger(ModuleCacheLoader.class); @Override protected Logger getLogger() { return LOGGER; } /** * Constructor. * * @param store store of event */ public ModuleCacheLoader(final EventStore store, final long nbEventBeforePersiste) { super(store, nbEventBeforePersiste); } @Override protected ModuleContainer createEventBuilder() { return new ModuleContainer(); } @Override protected String getObjectLoadName() { return "module"; } @Override public ModuleContainer load(final ModuleKey moduleKey) throws ModuleNotFoundInDatabaseException { LOGGER.debug("Load module with key '{}'.", moduleKey); // Redis key pattern to search all application platform final String redisKey = generateDbKey(moduleKey); // First seach last snapshot final HesperidesSnapshotItem hesperidesSnapshotItem = getStore().findLastSnapshot(redisKey); ModuleContainer moduleContainer; if (hesperidesSnapshotItem == null || hesperidesSnapshotItem.getCurrentNbEvents() < hesperidesSnapshotItem.getNbEvents()) { // Module builder moduleContainer = createEventBuilder(); final VirtualModulesAggregate virtualModulesAggregate = new VirtualModulesAggregate(getStore()); virtualModulesAggregate.replay(redisKey); virtualModulesAggregate.getModule(moduleKey); // Warning : must never return null ! final Optional<Module> module = virtualModulesAggregate.getModule(moduleKey); updateModuleContainer(moduleKey, moduleContainer, virtualModulesAggregate, module); } else { moduleContainer = (ModuleContainer) hesperidesSnapshotItem.getSnapshot(); if (hesperidesSnapshotItem.getCurrentNbEvents() > hesperidesSnapshotItem.getNbEvents()) { final VirtualModulesAggregate virtualModulesAggregate = new VirtualModulesAggregate(getStore(), moduleContainer.getModule(), moduleContainer.loadAllTemplate()); virtualModulesAggregate.replay(redisKey, hesperidesSnapshotItem.getNbEvents(), hesperidesSnapshotItem.getCurrentNbEvents()); final Optional<Module> module = virtualModulesAggregate.getModule(moduleKey); updateModuleContainer(moduleKey, moduleContainer, virtualModulesAggregate, module); } } // Can't return null !!!! return moduleContainer; } /** * Update module container. * * @param moduleKey * @param moduleContainer * @param virtualModulesAggregate * @param module * @throws ModuleNotFoundInDatabaseException */ private void updateModuleContainer(final ModuleKey moduleKey, final ModuleContainer moduleContainer, final VirtualModulesAggregate virtualModulesAggregate, final Optional<Module> module) throws ModuleNotFoundInDatabaseException { if (module.isPresent()) { moduleContainer.setModule(module.get()); final List<Template> templates = virtualModulesAggregate.getAllTemplates(moduleKey); if (templates != null) { templates.stream().forEach(t -> moduleContainer.addTemplate(t)); } } else { throw new ModuleNotFoundInDatabaseException(); } } /** * Return list of modules. * * @return list of modules */ public List<Module> getAllModules() { return getAllModules(null); } /** * Retrieve module key with redis key. * * @param virtualModulesAggregate * @param redisKey * @return */ private Collection<Module> findModuleKey(final VirtualModulesAggregate virtualModulesAggregate, final String redisKey) { virtualModulesAggregate.clear(); virtualModulesAggregate.replay(redisKey); return virtualModulesAggregate.getAllModules(); } /** * Store object in snapshot. * * @param moduleKey key of cache (same as cache.get(K)) * @param object object */ public void saveSnapshot(final ModuleKey moduleKey, final ModuleContainer object) { // Don't store snapshot of release, cause release contain only one event if (moduleKey.isWorkingCopy()) { final String redisKey = generateDbKey(moduleKey); // Now store snapshot getStore().storeSnapshot(redisKey, object, getNbEventBeforePersiste()); } } /** * Store object in snapshot. * * @param moduleKey key of cache (same as cache.get(K)) * @param object object */ public void forceSaveSnapshot(final ModuleKey moduleKey, final ModuleContainer object, final long nbEvent) { // Don't store snapshot of release, cause release contain only one event if (moduleKey.isWorkingCopy()) { final String redisKey = generateDbKey(moduleKey); // Now store snapshot getStore().createSnapshot(redisKey, object, nbEvent); } } /** * Return list of modules. * * @return list of modules */ private List<Module> getAllModules(final Callback callback) { LOGGER.debug("Load all modules from store."); // Redis key pattern to search all application platform final String redisKey = String.format("%s-*", getStreamPrefix()); // All application module redis key. final Set<String> modules = getStore().getStreamsLike(redisKey); // List of platform return by method final List<Module> listModule = new ArrayList<>(modules.size()); // Module key Collection<Module> moduleList; final VirtualModulesAggregate virtualModulesAggregate = new VirtualModulesAggregate(getStore()); for (String moduleRedisKey : modules) { LOGGER.debug("Load module from store associate with key '{}'.", moduleRedisKey); moduleList = findModuleKey(virtualModulesAggregate, moduleRedisKey); if (moduleList.size() > 0) { listModule.addAll(moduleList); if (callback != null) { moduleList.stream().forEach(m -> callback.moduleFound(m, virtualModulesAggregate)); } } } LOGGER.debug("All modules are loaded."); // Can't return null !!!! return listModule; } /** * Return list of modules. * * @return list of modules */ @Override public List<Template> getAllTemplates() { final List<Template> listTemplates = new ArrayList<>(); getAllModules((m, ma) -> listTemplates.addAll(ma.getAllTemplates(m.getKey())) ); // Can't return null !!!! return listTemplates; } }