/** * This software is licensed to you under the Apache License, Version 2.0 (the * "Apache License"). * * LinkedIn's contributions are made under the Apache License. If you contribute * to the Software, the contributions will be deemed to have been made under the * Apache License, unless you expressly indicate otherwise. Please do not make any * contributions that would be inconsistent with the Apache License. * * You may obtain a copy of the Apache License at http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, this software * distributed under the Apache License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the Apache * License for the specific language governing permissions and limitations for the * software governed under the Apache License. * * © 2012 LinkedIn Corp. All Rights Reserved. */ package com.senseidb.plugin; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.IdentityHashMap; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import org.apache.commons.configuration.Configuration; import com.browseengine.bobo.facets.FacetHandler; import com.browseengine.bobo.facets.RuntimeFacetHandlerFactory; public class SenseiPluginRegistry { public static final String FACET_CONF_PREFIX = "sensei.custom.facets"; private Map<String, PluginHolder> pluginsByPrefix = new LinkedHashMap<String, PluginHolder>(); private Map<String, PluginHolder> pluginsByNames = new LinkedHashMap<String, PluginHolder>(); private List<PluginHolder> plugins = new ArrayList<PluginHolder>(); private Configuration configuration; private static Map<Configuration, SenseiPluginRegistry> cachedRegistries = new IdentityHashMap<Configuration, SenseiPluginRegistry>(); private SenseiPluginRegistry() { } public static synchronized SenseiPluginRegistry get(Configuration conf) { return cachedRegistries.get(conf); } public static String getNameByPrefix(String prefix) { if (prefix != null) { if (prefix.contains(".")) return prefix.substring(prefix.lastIndexOf(".") + 1); else return prefix; } return null; } public static synchronized SenseiPluginRegistry build(Configuration conf) { if (cachedRegistries.containsKey(conf)) { return cachedRegistries.get(conf); } SenseiPluginRegistry ret = new SenseiPluginRegistry(); ret.configuration = conf; Iterator keysIterator = conf.getKeys(); while (keysIterator.hasNext()) { String key = (String) keysIterator.next(); if (key.endsWith(".class")) { String prefix = key.substring(0, key.indexOf(".class")); String pluginName = getNameByPrefix(prefix); String pluginCLass = conf.getString(key); ret.plugins.add(new PluginHolder(ret, pluginCLass, pluginName, prefix)); } if (key.endsWith(".instance")) { String prefix = key.substring(0, key.indexOf(".instance")); String pluginName = getNameByPrefix(prefix); Object pluginInstance = conf.getProperty(key); ret.plugins.add(new PluginHolder(ret, pluginInstance, pluginName, prefix)); } } for (PluginHolder pluginHolder : ret.plugins) { ret.pluginsByPrefix.put(pluginHolder.fullPrefix, pluginHolder); ret.pluginsByNames.put(pluginHolder.pluginName, pluginHolder); Iterator propertyIterator = conf.getKeys(pluginHolder.fullPrefix); while (propertyIterator.hasNext()) { String propertyName = (String) propertyIterator.next(); if (propertyName.endsWith(".class")) { continue; } String property = propertyName; if (propertyName.contains(pluginHolder.fullPrefix)) { property = propertyName.substring(pluginHolder.fullPrefix.length() + 1); } pluginHolder.properties.put(property, conf.getProperty(propertyName).toString()); } } cachedRegistries.put(conf, ret); return ret; } public <T> T getBeanByName(String name, Class<T> type) { PluginHolder holder = pluginsByNames.get(name); if (holder == null) { return null; } return (T) holder.getInstance(); } public <T> List<T> getBeansByType(Class<T> type) { List<T> ret = new ArrayList<T>(); for (PluginHolder pluginHolder : plugins) { if (pluginHolder.getInstance() != null && type.isAssignableFrom(pluginHolder.getInstance().getClass())) { ret.add((T) pluginHolder.getInstance()); } } return ret; } public <T> Map<String,T> getNamedBeansByType(Class<T> type) { Map<String, T> ret = new HashMap<String, T>(); for (PluginHolder pluginHolder : plugins) { if (pluginHolder.getInstance() != null && type.isAssignableFrom(pluginHolder.getInstance().getClass())) { ret.put(pluginHolder.pluginName, (T) pluginHolder.getInstance()); } } return ret; } public List<?> getBeansByPrefix(String prefix) { List<Object> ret = new ArrayList<Object>(); for (PluginHolder pluginHolder : plugins) { if (pluginHolder.getInstance() != null && pluginHolder.fullPrefix.startsWith(prefix)) { ret.add(pluginHolder.getInstance()); } } return ret; } public FacetHandler<?> getFacet(String name) { for (Object handlerObject : resolveBeansByListKey(FACET_CONF_PREFIX, Object.class)) { if (!(handlerObject instanceof FacetHandler)) { continue; } FacetHandler handler = (FacetHandler) handlerObject; if (handler.getName().equals(name)) { return handler; } } return null; } public RuntimeFacetHandlerFactory getRuntimeFacet(String name) { for (Object handlerObject : resolveBeansByListKey(FACET_CONF_PREFIX, Object.class)) { if (!(handlerObject instanceof RuntimeFacetHandlerFactory)) { continue; } RuntimeFacetHandlerFactory handler = (RuntimeFacetHandlerFactory) handlerObject; if (handler.getName().equals(name)) { return handler; } } return null; } public <T> T getBeanByFullPrefix(String fullPrefix, Class<T> type) { PluginHolder holder = pluginsByPrefix.get(fullPrefix); if (holder == null) { return null; } return (T) holder.getInstance(); } public <T> List<T> resolveBeansByListKey(String paramKey, Class<T> returnedClass) { if (!paramKey.endsWith(".list")) { paramKey = paramKey + ".list"; } List<T> ret = new ArrayList<T>(); String strList = configuration.getString(paramKey); if (strList == null) { return new ArrayList<T>(); } String[] keys = strList.split(","); if (keys == null || keys.length == 0) { return null; } for (String key : keys) { if (key.trim().length() == 0) { continue; } Object bean = getBeanByName(key.trim(), Object.class); if (bean == null) { bean = getBeanByFullPrefix(key.trim(), Object.class); } if (bean == null) { throw new IllegalStateException("the bean with name " + key + " couldn't be found"); } if (bean instanceof Collection) { ret.addAll((Collection) bean); } else { ret.add((T) bean); } } return ret; } public synchronized void start() { for (PluginHolder pluginHolder : plugins) { Object instance = pluginHolder.getInstance(); if (instance instanceof SenseiPlugin) { ((SenseiPlugin) instance).start(); } } } public synchronized void stop() { for (PluginHolder pluginHolder : plugins) { Object instance = pluginHolder.getInstance(); if (instance instanceof SenseiPlugin) { ((SenseiPlugin) instance).stop(); } } pluginsByPrefix.clear(); pluginsByNames.clear(); plugins.clear(); cachedRegistries.remove(configuration); configuration = null; } public Configuration getConfiguration() { return configuration; } }