
com.aerospike.mapper.tools.AbstractBuilder Maven / Gradle / Ivy
package com.aerospike.mapper.tools;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import javax.validation.constraints.NotNull;
import org.apache.commons.lang3.StringUtils;
import com.aerospike.client.AerospikeException;
import com.aerospike.client.Log;
import com.aerospike.client.policy.BatchPolicy;
import com.aerospike.client.policy.Policy;
import com.aerospike.client.policy.QueryPolicy;
import com.aerospike.client.policy.ScanPolicy;
import com.aerospike.mapper.annotations.AerospikeRecord;
import com.aerospike.mapper.tools.ClassCache.PolicyType;
import com.aerospike.mapper.tools.configuration.ClassConfig;
import com.aerospike.mapper.tools.configuration.Configuration;
import com.aerospike.mapper.tools.utils.TypeUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
public abstract class AbstractBuilder {
private final T mapper;
private List> classesToPreload = null;
protected AbstractBuilder(T mapper) {
this.mapper = mapper;
}
/**
* Add in a custom type converter. The converter must have methods which implement the ToAerospike and FromAerospike annotation.
*
* @param converter The custom converter
* @return this object
*/
public AbstractBuilder addConverter(Object converter) {
GenericTypeMapper typeMapper = new GenericTypeMapper(converter);
TypeUtils.addTypeMapper(typeMapper.getMappedClass(), typeMapper);
return this;
}
public AbstractBuilder preLoadClasses(Class>... clazzes) {
if (classesToPreload == null) {
classesToPreload = new ArrayList<>();
}
classesToPreload.addAll(Arrays.asList(clazzes));
return this;
}
public String getPackageName(Class> clazz) {
Class> c;
if (clazz.isArray()) {
c = clazz.getComponentType();
} else {
c = clazz;
}
String pn;
if (c.isPrimitive()) {
pn = "java.lang";
} else {
String cn = c.getName();
int dot = cn.lastIndexOf('.');
pn = (dot != -1) ? cn.substring(0, dot).intern() : "";
}
return pn;
}
public AbstractBuilder preLoadClassesFromPackage(Class> classInPackage) {
return preLoadClassesFromPackage(getPackageName(classInPackage));
}
public AbstractBuilder preLoadClassesFromPackage(String thePackage) {
Set> clazzes = findAllClassesUsingClassLoader(thePackage);
for (Class> thisClazz : clazzes) {
// Only add classes with the AerospikeRecord annotation.
if (thisClazz.getAnnotation(AerospikeRecord.class) != null) {
this.preLoadClass(thisClazz);
}
}
return this;
}
// See https://www.baeldung.com/java-find-all-classes-in-package
private Set> findAllClassesUsingClassLoader(String packageName) {
InputStream stream = ClassLoader.getSystemClassLoader()
.getResourceAsStream(packageName.replaceAll("[.]", "/"));
BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
return reader.lines().filter(line -> line.endsWith(".class")).map(line -> getClass(line, packageName))
.collect(Collectors.toSet());
}
private Class> getClass(String className, String packageName) {
try {
return Class.forName(packageName + "." + className.substring(0, className.lastIndexOf('.')));
} catch (ClassNotFoundException ignored) {
}
return null;
}
public AbstractBuilder preLoadClass(Class> clazz) {
if (classesToPreload == null) {
classesToPreload = new ArrayList<>();
}
classesToPreload.add(clazz);
return this;
}
public AbstractBuilder withConfigurationFile(File file) throws IOException {
return this.withConfigurationFile(file, false);
}
public AbstractBuilder withConfigurationFile(File file, boolean allowsInvalid) throws IOException {
ObjectMapper objectMapper = new ObjectMapper(new YAMLFactory());
Configuration configuration = objectMapper.readValue(file, Configuration.class);
this.loadConfiguration(configuration, allowsInvalid);
return this;
}
public AbstractBuilder withConfigurationFile(InputStream ios) throws IOException {
return this.withConfigurationFile(ios, false);
}
public AbstractBuilder withConfigurationFile(InputStream ios, boolean allowsInvalid) throws IOException {
ObjectMapper objectMapper = new ObjectMapper(new YAMLFactory());
Configuration configuration = objectMapper.readValue(ios, Configuration.class);
this.loadConfiguration(configuration, allowsInvalid);
return this;
}
public AbstractBuilder withConfiguration(String configurationYaml) throws JsonProcessingException {
return this.withConfiguration(configurationYaml, false);
}
public AbstractBuilder withConfiguration(String configurationYaml, boolean allowsInvalid) throws JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper(new YAMLFactory());
Configuration configuration = objectMapper.readValue(configurationYaml, Configuration.class);
this.loadConfiguration(configuration, allowsInvalid);
return this;
}
public AbstractBuilder withClassConfigurations(ClassConfig classConfig, ClassConfig ...classConfigs) {
Configuration configuration = new Configuration();
configuration.add(classConfig);
for (ClassConfig thisConfig : classConfigs) {
configuration.add(thisConfig);
}
ClassCache.getInstance().addConfiguration(configuration);
return this;
}
private void loadConfiguration(@NotNull Configuration configuration, boolean allowsInvalid) {
for (ClassConfig config : configuration.getClasses()) {
try {
String name = config.getClassName();
if (StringUtils.isBlank(name)) {
throw new AerospikeException("Class with blank name in configuration file");
} else {
try {
Class.forName(config.getClassName());
} catch (ClassNotFoundException e) {
throw new AerospikeException("Cannot find a class with name " + name);
}
}
} catch (RuntimeException re) {
if (allowsInvalid) {
Log.warn("Ignoring issue with configuration: " + re.getMessage());
} else {
throw re;
}
}
}
ClassCache.getInstance().addConfiguration(configuration);
}
public static class AeroPolicyMapper {
private final AbstractBuilder builder;
private final Policy policy;
private final PolicyType policyType;
public AeroPolicyMapper(AbstractBuilder builder, PolicyType policyType, Policy policy) {
this.builder = builder;
this.policyType = policyType;
this.policy = policy;
}
public AbstractBuilder forClasses(Class>... classes) {
for (Class> thisClass : classes) {
ClassCache.getInstance().setSpecificPolicy(policyType, thisClass, policy);
}
return builder;
}
public AbstractBuilder forThisOrChildrenOf(Class> clazz) {
ClassCache.getInstance().setChildrenPolicy(this.policyType, clazz, this.policy);
return builder;
}
public AbstractBuilder forAll() {
ClassCache.getInstance().setDefaultPolicy(policyType, policy);
return builder;
}
}
public AeroPolicyMapper withReadPolicy(Policy policy) {
return new AeroPolicyMapper<>(this, PolicyType.READ, policy);
}
public AeroPolicyMapper withWritePolicy(Policy policy) {
return new AeroPolicyMapper<>(this, PolicyType.WRITE, policy);
}
public AeroPolicyMapper withBatchPolicy(BatchPolicy policy) {
return new AeroPolicyMapper<>(this, PolicyType.BATCH, policy);
}
public AeroPolicyMapper withScanPolicy(ScanPolicy policy) {
return new AeroPolicyMapper<>(this, PolicyType.SCAN, policy);
}
public AeroPolicyMapper withQueryPolicy(QueryPolicy policy) {
return new AeroPolicyMapper<>(this, PolicyType.QUERY, policy);
}
public T build() {
if (classesToPreload != null) {
for (Class> clazz : classesToPreload) {
ClassCache.getInstance().loadClass(clazz, this.mapper);
}
}
return this.mapper;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy