RandomGeneratorFactory.java
/*
* Copyright 2000-2014 Namics AG. All rights reserved.
*/
package com.namics.commons.random.generator;
import com.namics.commons.random.support.reflections.ReflectionsInitializer;
import org.reflections.Reflections;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Modifier;
import java.util.Comparator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
/**
* Factory to manage custom {@link RandomGenerator} instances and provide easy resolving facilities.
*
* @author aschaefer
* @since 20.02.14 16:07
*/
public abstract class RandomGeneratorFactory {
private static final Logger LOG = LoggerFactory.getLogger(RandomGeneratorFactory.class);
/**
* Initially only default {@link RandomGenerator}s
* in package <code>com.namics.commons.random.generator.basic</code> are registered.
*/
public static final String DEFAULT_SCAN_PACKAGE = "com.namics.commons.random.generator.basic";
private static final Map<String, Reflections> PACKAGE_REFLECTIONS = new TreeMap<>();
private static final Map<Class<?>, RandomGenerator> generators = new TreeMap<>(Comparator.comparing(Class::getName));
static {
ReflectionsInitializer.init();
addRandomGenerators(DEFAULT_SCAN_PACKAGE);
}
/**
* Registers {@link com.namics.commons.random.generator.RandomGenerator} implementations found in the package provided.
*
* @param scanpackage package to scan for implementation of {@link RandomGenerator} to be registered.
*/
public static void addRandomGenerators(String scanpackage) {
if (!PACKAGE_REFLECTIONS.containsKey(scanpackage)) {
LOG.debug("Scan package {}", scanpackage);
Reflections reflections = new Reflections(scanpackage);
PACKAGE_REFLECTIONS.put(scanpackage, reflections);
Set<Class<? extends RandomGenerator>> randomGenerators = reflections.getSubTypesOf(RandomGenerator.class);
for (Class<? extends RandomGenerator> generatorClazz : randomGenerators) {
addRandomGenerator(generatorClazz);
}
}
}
/**
* Create and register an instance of the {@link RandomGenerator} implementation.
*
* @param generatorClazz {@link RandomGenerator} implementation to register.
*/
public static void addRandomGenerator(Class<? extends RandomGenerator> generatorClazz) {
try {
if (!Modifier.isAbstract(generatorClazz.getModifiers())) {
RandomGenerator generator = generatorClazz.newInstance();
addRandomGenerator(generator);
}
} catch (InstantiationException | IllegalAccessException | NoClassDefFoundError e) {
LOG.warn("Could not add generator {} {}", generatorClazz, e.toString());
}
}
/**
* Register the instance of the {@link RandomGenerator} implementation.
*
* @param generator {@link RandomGenerator} implementations instance to register.
*/
public static void addRandomGenerator(RandomGenerator<?> generator) {
for (Class<?> type : generator.supportedTypes()) {
generators.put(type, generator);
}
}
/**
* Try to resolve a generator for the requested type.
* Tries to load a {@link RandomGenerator} instance of known generators.
* Tries to scan package of SupportedType for {@link RandomGenerator<SupportedType>} implementations,
* registers them and returns the instance if an implementation is found.
* If no suitable {@link RandomGenerator<SupportedType>} is found, <code>null</code> is returned
*
* @param supportedType Type to find a suitable generator for.
* @param <SupportedType> Type to find a suitable generator for.
* @return suitable generator if found, null else.
*/
public static <SupportedType> RandomGenerator<SupportedType> generator(Class<SupportedType> supportedType) {
RandomGenerator resolved = generators.get(supportedType);
if (resolved == null && supportedType != null && Class.class != supportedType && supportedType.getPackage() != null) {
String supportedTypePackage = supportedType.getPackage().getName();
if (!PACKAGE_REFLECTIONS.containsKey(supportedTypePackage)) {
LOG.debug("No generator for class {}, scan its package {} for generator", supportedType, supportedTypePackage);
addRandomGenerators(supportedTypePackage);
resolved = generators.get(supportedType);
}
}
return resolved;
}
/**
* Try to resolve a generator for the requested type.
* Tries to load a {@link RandomGenerator} instance of known generators.
* Tries to scan package of SupportedType for {@link RandomGenerator<SupportedType>} implementations,
* registers them and returns the instance if an implementation is found.
* If no suitable {@link RandomGenerator<SupportedType>} is found, <code>null</code> is returned
*
* @param supportedType Name of the type to find a suitable generator for.
* @param <SupportedType> Type to find a suitable generator for.
* @return suitable generator if found, null else.
*/
public static <SupportedType> RandomGenerator<SupportedType> generator(String supportedType) {
try {
return (RandomGenerator<SupportedType>) generator(Class.forName(supportedType));
} catch (ClassNotFoundException e) {
return null;
}
}
}