/* * Seldon -- open source prediction engine * ======================================= * Copyright 2011-2015 Seldon Technologies Ltd and Rummble Ltd (http://www.seldon.io/) * ********************************************************************************************** * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ********************************************************************************************** */ package io.seldon.api.state; import io.seldon.plugins.PluginProvider; import io.seldon.plugins.PluginService; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import javax.annotation.PostConstruct; import org.apache.log4j.Logger; import org.springframework.beans.BeansException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component; import com.fasterxml.jackson.databind.ObjectMapper; @Component public class PluginConfigStore implements ApplicationContextAware,ClientConfigUpdateListener { protected static Logger logger = Logger.getLogger(PredictionAlgorithmStore.class.getName()); private static final String PLUGIN_KEY = "plugins"; private ConcurrentMap<String, List<PluginProvider>> pluginStore = new ConcurrentHashMap<>(); private final ClientConfigHandler configHandler; private ApplicationContext applicationContext; @Autowired public PluginConfigStore(ClientConfigHandler configHandler) { this.configHandler = configHandler; } @PostConstruct private void init(){ logger.info("Initializing..."); configHandler.addListener(this); } public List<PluginProvider> retrievePlugins(String client) { return pluginStore.get(client); } private PluginProvider toPluginProvider(Plugin plugin) { PluginService service = applicationContext.getBean(plugin.name, PluginService.class); Map<String, String> config = toConfigMap(plugin.config); return new PluginProvider(service,plugin.config ==null ? new HashMap<String, String>(): config , plugin.service); } @Override public void configUpdated(String client, String configKey,String configValue) { if (configKey.equals(PLUGIN_KEY)){ logger.info("Received new plugin config for "+ client+": "+ configValue); try { ObjectMapper mapper = new ObjectMapper(); List<PluginProvider> plugins = new ArrayList<>(); PluginConfig config = mapper.readValue(configValue, PluginConfig.class); for (Plugin plugin : config.plugins) { PluginProvider strategy = toPluginProvider(plugin); plugins.add(strategy); } pluginStore.put(client, plugins); logger.info("Successfully added new plugin config for "+client); } catch (IOException | BeansException e) { logger.error("Couldn't update plugin for client " +client, e); } } } @Override public void configRemoved(String client, String configKey) { if (configKey.equals(PLUGIN_KEY)){ pluginStore.remove(client); logger.info("Removed client "+client); } } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; StringBuilder builder= new StringBuilder("Available algorithms: \n"); for (PluginService inc : applicationContext.getBeansOfType(PluginService.class).values()){ builder.append('\t'); builder.append(inc.getClass()); builder.append('\n'); } logger.info(builder.toString()); } private Map<String, String> toConfigMap(List<ConfigItem> config) { Map<String, String> configMap = new HashMap<>(); if (config==null) return configMap; for (ConfigItem item : config){ configMap.put(item.name,item.value); } return configMap; } public static class PluginConfig { public List<Plugin> plugins; } public static class Plugin { public String name; public String service; public List<ConfigItem> config; } public static class ConfigItem { public String name; public String value; } }