package org.radargun; import java.lang.annotation.Annotation; import java.util.HashMap; import java.util.Map; import org.radargun.config.Definition; import org.radargun.config.InitHelper; import org.radargun.config.PropertyHelper; import org.radargun.logging.Log; import org.radargun.logging.LogFactory; import org.radargun.utils.Utils; /** * Helper class, the only function is instantiating and initializing the service. * * @author Radim Vansa <rvansa@redhat.com> */ public final class ServiceHelper { private static final Log log = LogFactory.getLog(ServiceHelper.class); private static final String SERVICE_PROPERTY_PREFIX = "service."; private static String currentPlugin; private static String currentConfigName; private static int currentSlaveIndex; private ServiceHelper() {} public static String getPlugin() { return currentPlugin; } public static String getConfigName() { return currentConfigName; } public static int getSlaveIndex() { return currentSlaveIndex; } /** * As we expect only one service at time to be running on one node, this sets current * plugin, configuration name and slave index that can be later retrieved, e.g. in some * init method (annotated by {@link org.radargun.config.Init}) that would not be able * to retrieve this information in another way. * * @param plugin * @param configName * @param slaveIndex */ public static void setServiceContext(String plugin, String configName, int slaveIndex) { currentPlugin = plugin; currentConfigName = configName; currentSlaveIndex = slaveIndex; } /** * Instantiates the service, looking up file plugin.properties for the service name * (in form of service./service name/ /service class/ * The service class must have public no-arg constructor. * Then, sets up all properties declared on the service (and its superclasses). * Finally calls any methods of the class annotated by {@link org.radargun.config.Init @Init}. * * Don't forget to call {@link #setServiceContext(String, String, int)} before calling this method. */ public static Object createService(String plugin, String service, Map<String, Definition> properties, Map<String, String> extras) { String serviceClassName = Utils.getPluginProperty(plugin, SERVICE_PROPERTY_PREFIX + service); if (serviceClassName == null) { throw new IllegalStateException(String.format("Cannot find service %s for plugin %s", service, plugin)); } Class<?> serviceClazz = null; try { serviceClazz = Class.forName(serviceClassName); } catch (Throwable t) { throw new IllegalArgumentException("Cannot load class " + serviceClassName + " from plugin " + plugin, t); } boolean isService = false; for (Annotation annotation : serviceClazz.getDeclaredAnnotations()) { if (annotation.annotationType().equals(Service.class)) { isService = true; } } if (!isService) { throw new IllegalArgumentException("Class " + serviceClassName + " is not declared as a Service"); } Object instance; try { instance = serviceClazz.newInstance(); } catch (Exception e) { throw new RuntimeException("Cannot instantiate service " + serviceClassName, e); } // The properties are evaluated only on the slave, using the extras (such as ${slave.index} etc...) Map<String, String> backupExtras = new HashMap<String, String>(); for (Map.Entry<String, String> extra : extras.entrySet()) { backupExtras.put(extra.getKey(), System.getProperty(extra.getKey())); System.setProperty(extra.getKey(), extra.getValue()); } PropertyHelper.setPropertiesFromDefinitions(instance, properties, false, true); for (Map.Entry<String, String> backup : backupExtras.entrySet()) { System.setProperty(backup.getKey(), backup.getValue() == null ? "" : backup.getValue()); } InitHelper.init(instance); return instance; } public static Map<String, Class<?>> loadServices(String plugin) { Map<String, Class<?>> services = new HashMap<>(); java.util.Properties properties = Utils.getPluginProperties(plugin); for (String property : properties.stringPropertyNames()) { if (!property.startsWith(SERVICE_PROPERTY_PREFIX)) continue; String name = property.substring(property.indexOf('.') + 1); String clazzName = properties.getProperty(property); try { Class<?> clazz = Class.forName(clazzName); services.put(name, clazz); } catch (ClassNotFoundException e) { log.warn("Failed to load class " + clazzName, e); } } return services; } }