#2075 - Refactor external mapping api and use ServiceLoader

This commit is contained in:
rob bygrave committed 2020-10-10 17:12:13 +13:00
1 parent b22bffe770
commit f57db28f1c
14 files changed
+426 -136

No files matched your search

@@ -0,0 +1,70 @@
package io.ebeaninternal.server.core;
import io.ebeaninternal.server.dto.DtoNamedQueries;
import io.ebeaninternal.xmapping.api.XmapDto;
import io.ebeaninternal.xmapping.api.XmapEbean;
import io.ebeaninternal.xmapping.api.XmapRawSql;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Reads the Xml deployment information.
*/
class InternalConfigXmlMap {
private static final Logger log = LoggerFactory.getLogger(InternalConfigXmlMap.class);
private final List<XmapEbean> xmlEbeanList;
private final ClassLoader classLoader;
private final Map<Class<?>, DtoNamedQueries> dtoNamedQueries = new HashMap<>();
InternalConfigXmlMap(List<XmapEbean> xmlEbeanList, ClassLoader classLoader) {
this.xmlEbeanList = xmlEbeanList;
this.classLoader = classLoader;
initDtoMapping();
}
void initDtoMapping() {
if (xmlEbeanList != null) {
for (XmapEbean mapping : xmlEbeanList) {
List<XmapDto> dtoList = mapping.getDto();
for (XmapDto dto : dtoList) {
readDtoMapping(dto);
}
}
}
}
/**
* Return the XML deployment information for entity beans.
*/
List<XmapEbean> xmlDeployment() {
return xmlEbeanList;
}
/**
* Return the named queries for Dto beans.
*/
Map<Class<?>, DtoNamedQueries> readDtoMapping() {
return dtoNamedQueries;
}
private void readDtoMapping(XmapDto dto) {
Class<?> dtoClass;
try {
dtoClass = Class.forName(dto.getClazz(), false, classLoader);
} catch (Exception e) {
log.error("Could not load dto bean class " + dto.getClazz() + " for ebean xml entry");
return;
}
DtoNamedQueries namedQueries = dtoNamedQueries.computeIfAbsent(dtoClass, aClass -> new DtoNamedQueries());
for (XmapRawSql sql : dto.getRawSql()) {
namedQueries.addRawSql(sql.getName(), sql.getQuery());
}
}
}
@@ -1,109 +0,0 @@
package io.ebeaninternal.server.core;
import io.avaje.classpath.scanner.ClassPathScanner;
import io.avaje.classpath.scanner.Resource;
import io.ebean.config.DatabaseConfig;
import io.ebeaninternal.server.dto.DtoNamedQueries;
import io.ebeaninternal.xmlmapping.XmlMappingReader;
import io.ebeaninternal.xmlmapping.model.XmDto;
import io.ebeaninternal.xmlmapping.model.XmEbean;
import io.ebeaninternal.xmlmapping.model.XmRawSql;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Reads the Xml deployment information.
*/
class InternalConfigXmlRead {
private static final Logger log = LoggerFactory.getLogger(InternalConfigXmlRead.class);
private final DatabaseConfig config;
private final ClassLoader classLoader;
private final Map<Class<?>, DtoNamedQueries> dtoNamedQueries = new HashMap<>();
private List<XmEbean> xmlEbeanList;
InternalConfigXmlRead(DatabaseConfig config) {
this.config = config;
this.classLoader = config.getClassLoadConfig().getClassLoader();
if (config.getClassLoadConfig().isJavaxJAXBPresent()) {
init();
}
}
private void init() {
this.xmlEbeanList = XmlMappingReader.readByResourceName(classLoader, "ebean.xml");
xmlEbeanList.addAll(XmlMappingReader.readByResourceList(xmlMappingResources()));
}
private List<Resource> xmlMappingResources() {
List<ClassPathScanner> scanners = ClassPathScanners.find(config);
List<String> mappingLocations = config.getMappingLocations();
List<Resource> resourceList = new ArrayList<>();
long st = System.currentTimeMillis();
if (mappingLocations != null && !mappingLocations.isEmpty()) {
for (ClassPathScanner finder : scanners) {
for (String mappingLocation : mappingLocations) {
resourceList.addAll(finder.scanForResources(mappingLocation, resourceName -> resourceName.endsWith(".xml")));
}
}
}
long searchTime = System.currentTimeMillis() - st;
log.debug("Classpath search mappings[{}] searchTime[{}]", resourceList.size(), searchTime);
return resourceList;
}
/**
* Return the XML deployment information for entity beans.
*/
List<XmEbean> xmlDeployment() {
return xmlEbeanList;
}
/**
* Return the named queries for Dto beans.
*/
Map<Class<?>, DtoNamedQueries> readDtoMapping() {
if (xmlEbeanList != null) {
for (XmEbean mapping : xmlEbeanList) {
List<XmDto> dtoList = mapping.getDto();
for (XmDto dto : dtoList) {
readDtoMapping(dto);
}
}
}
return dtoNamedQueries;
}
private void readDtoMapping(XmDto dto) {
String dtoClassName = dto.getClazz();
Class<?> dtoClass;
try {
dtoClass = Class.forName(dtoClassName, false, classLoader);
} catch (Exception e) {
log.error("Could not load dto bean class " + dtoClassName + " for ebean xml entry");
return;
}
DtoNamedQueries namedQueries = dtoNamedQueries.computeIfAbsent(dtoClass, aClass -> new DtoNamedQueries());
for (XmRawSql sql : dto.getRawSql()) {
namedQueries.addRawSql(sql.getName(), sql.getQuery().getValue());
}
if (!dto.getNamedQuery().isEmpty()) {
log.error("Only raw-sql named queries supported for DTO beans - bean:" + dtoClass);
}
}
}
@@ -22,6 +22,7 @@ import io.ebean.event.readaudit.ReadAuditLogger;
import io.ebean.event.readaudit.ReadAuditPrepare;
import io.ebean.plugin.Plugin;
import io.ebean.plugin.SpiServer;
import io.ebeaninternal.api.DbOffline;
import io.ebeaninternal.api.ExtraMetrics;
import io.ebeaninternal.api.QueryPlanManager;
import io.ebeaninternal.api.SpiBackgroundExecutor;
@@ -33,7 +34,6 @@ import io.ebeaninternal.api.SpiLogManager;
import io.ebeaninternal.api.SpiLogger;
import io.ebeaninternal.api.SpiLoggerFactory;
import io.ebeaninternal.api.SpiProfileHandler;
import io.ebeaninternal.api.DbOffline;
import io.ebeaninternal.server.autotune.AutoTuneService;
import io.ebeaninternal.server.autotune.AutoTuneServiceProvider;
import io.ebeaninternal.server.autotune.NoAutoTuneService;
@@ -93,6 +93,8 @@ import io.ebeaninternal.server.transaction.TransactionManagerOptions;
import io.ebeaninternal.server.transaction.TransactionScopeManager;
import io.ebeaninternal.server.type.DefaultTypeManager;
import io.ebeaninternal.server.type.TypeManager;
import io.ebeaninternal.xmapping.api.XmapEbean;
import io.ebeaninternal.xmapping.api.XmapService;
import io.ebeanservice.docstore.api.DocStoreFactory;
import io.ebeanservice.docstore.api.DocStoreIntegration;
import io.ebeanservice.docstore.api.DocStoreUpdateProcessor;
@@ -101,6 +103,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -195,10 +198,11 @@ public class InternalConfiguration {
this.deployUtil = new DeployUtil(typeManager, config);
this.serverCachePlugin = initServerCachePlugin();
this.cacheManager = initCacheManager();
InternalConfigXmlRead xmlRead = new InternalConfigXmlRead(config);
this.dtoBeanManager = new DtoBeanManager(typeManager, xmlRead.readDtoMapping());
final InternalConfigXmlMap xmlMap = initExternalMapping();
this.dtoBeanManager = new DtoBeanManager(typeManager, xmlMap.readDtoMapping());
this.beanDescriptorManager = new BeanDescriptorManager(this);
Map<String, String> asOfTableMapping = beanDescriptorManager.deploy(xmlRead.xmlDeployment());
Map<String, String> asOfTableMapping = beanDescriptorManager.deploy(xmlMap.xmlDeployment());
Map<String, String> draftTableMap = beanDescriptorManager.getDraftTableMap();
beanDescriptorManager.scheduleBackgroundTrim();
this.dataTimeZone = initDataTimeZone();
@@ -206,14 +210,29 @@ public class InternalConfiguration {
this.cQueryEngine = new CQueryEngine(config, databasePlatform, binder, asOfTableMapping, draftTableMap);
}
private SpiLogManager initLogManager() {
private InternalConfigXmlMap initExternalMapping() {
final List<XmapEbean> xmEbeans = readExternalMapping();
return new InternalConfigXmlMap(xmEbeans, config.getClassLoadConfig().getClassLoader());
}
private List<XmapEbean> readExternalMapping() {
//TODO: Remove the isJavaxJAXBPresent() check once this is external module
if (!config.getClassLoadConfig().isJavaxJAXBPresent()) {
return Collections.emptyList();
}
final XmapService xmapService = config.service(XmapService.class);
if (xmapService == null) {
return Collections.emptyList();
}
return xmapService.read(config.getClassLoadConfig().getClassLoader(), config.getMappingLocations());
}
private SpiLogManager initLogManager() {
// allow plugin - i.e. capture executed SQL for testing/asserts
SpiLoggerFactory loggerFactory = config.service(SpiLoggerFactory.class);
if (loggerFactory == null) {
loggerFactory = new DLoggerFactory();
}
SpiLogger sql = loggerFactory.create("io.ebean.SQL");
SpiLogger sum = loggerFactory.create("io.ebean.SUM");
SpiLogger txn = loggerFactory.create("io.ebean.TXN");
@@ -59,12 +59,10 @@ import io.ebeaninternal.server.properties.EnhanceBeanPropertyAccess;
import io.ebeaninternal.server.type.ScalarType;
import io.ebeaninternal.server.type.ScalarTypeInteger;
import io.ebeaninternal.server.type.TypeManager;
import io.ebeaninternal.xmlmapping.model.XmAliasMapping;
import io.ebeaninternal.xmlmapping.model.XmColumnMapping;
import io.ebeaninternal.xmlmapping.model.XmEbean;
import io.ebeaninternal.xmlmapping.model.XmEntity;
import io.ebeaninternal.xmlmapping.model.XmNamedQuery;
import io.ebeaninternal.xmlmapping.model.XmRawSql;
import io.ebeaninternal.xmapping.api.XmapEbean;
import io.ebeaninternal.xmapping.api.XmapEntity;
import io.ebeaninternal.xmapping.api.XmapNamedQuery;
import io.ebeaninternal.xmapping.api.XmapRawSql;
import io.ebeanservice.docstore.api.DocStoreBeanAdapter;
import io.ebeanservice.docstore.api.DocStoreFactory;
import org.slf4j.Logger;
@@ -350,7 +348,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
/**
* Deploy returning the asOfTableMap (which is required by the SQL builders).
*/
public Map<String, String> deploy(List<XmEbean> mappings) {
public Map<String, String> deploy(List<XmapEbean> mappings) {
try {
createListeners();
readEntityDeploymentInitial();
@@ -386,19 +384,19 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
}
}
private void readXmlMapping(List<XmEbean> mappings) {
private void readXmlMapping(List<XmapEbean> mappings) {
if (mappings != null) {
ClassLoader classLoader = config.getClassLoadConfig().getClassLoader();
for (XmEbean mapping : mappings) {
List<XmEntity> entityDeploy = mapping.getEntity();
for (XmEntity deploy : entityDeploy) {
for (XmapEbean mapping : mappings) {
List<XmapEntity> entityDeploy = mapping.getEntity();
for (XmapEntity deploy : entityDeploy) {
readEntityMapping(classLoader, deploy);
}
}
}
}
private void readEntityMapping(ClassLoader classLoader, XmEntity entityDeploy) {
private void readEntityMapping(ClassLoader classLoader, XmapEntity entityDeploy) {
String entityClassName = entityDeploy.getClazz();
Class<?> entityClass;
@@ -414,25 +412,25 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
logger.error("No entity bean for ebean.xml entry " + entityClassName);
} else {
for (XmRawSql sql : entityDeploy.getRawSql()) {
for (XmapRawSql sql : entityDeploy.getRawSql()) {
RawSqlBuilder builder;
try {
builder = RawSqlBuilder.parse(sql.getQuery().getValue());
builder = RawSqlBuilder.parse(sql.getQuery());
} catch (RuntimeException e) {
builder = RawSqlBuilder.unparsed(sql.getQuery().getValue());
builder = RawSqlBuilder.unparsed(sql.getQuery());
}
for (XmColumnMapping columnMapping : sql.getColumnMapping()) {
builder.columnMapping(columnMapping.getColumn(), columnMapping.getProperty());
for (Map.Entry<String,String> columnMapping : sql.getColumnMapping().entrySet()) {
builder.columnMapping(columnMapping.getKey(), columnMapping.getValue());
}
for (XmAliasMapping aliasMapping : sql.getAliasMapping()) {
builder.tableAliasMapping(aliasMapping.getAlias(), aliasMapping.getProperty());
for (Map.Entry<String,String> aliasMapping : sql.getAliasMapping().entrySet()) {
builder.tableAliasMapping(aliasMapping.getKey(), aliasMapping.getValue());
}
info.addRawSql(sql.getName(), builder.create());
}
for (XmNamedQuery namedQuery : entityDeploy.getNamedQuery()) {
info.addNamedQuery(namedQuery.getName(), namedQuery.getQuery().getValue());
for (XmapNamedQuery namedQuery : entityDeploy.getNamedQuery()) {
info.addNamedQuery(namedQuery.getName(), namedQuery.getQuery());
}
}
}
@@ -0,0 +1,23 @@
package io.ebeaninternal.xmapping.api;
import java.util.ArrayList;
import java.util.List;
public class XmapDto {
protected final String clazz;
protected final List<XmapRawSql> rawSql = new ArrayList<>();
public XmapDto(String clazz) {
this.clazz = clazz;
}
public String getClazz() {
return clazz;
}
public List<XmapRawSql> getRawSql() {
return rawSql;
}
}
@@ -0,0 +1,19 @@
package io.ebeaninternal.xmapping.api;
import java.util.ArrayList;
import java.util.List;
public class XmapEbean {
protected final List<XmapEntity> entity = new ArrayList<>();
protected final List<XmapDto> dto = new ArrayList<>();
public List<XmapEntity> getEntity() {
return entity;
}
public List<XmapDto> getDto() {
return dto;
}
}
@@ -0,0 +1,27 @@
package io.ebeaninternal.xmapping.api;
import java.util.ArrayList;
import java.util.List;
public class XmapEntity {
protected final String clazz;
protected final List<XmapNamedQuery> namedQuery = new ArrayList<>();
protected final List<XmapRawSql> rawSql = new ArrayList<>();
public XmapEntity(String clazz) {
this.clazz = clazz;
}
public String getClazz() {
return clazz;
}
public List<XmapNamedQuery> getNamedQuery() {
return namedQuery;
}
public List<XmapRawSql> getRawSql() {
return rawSql;
}
}
@@ -0,0 +1,20 @@
package io.ebeaninternal.xmapping.api;
public class XmapNamedQuery {
protected final String name;
protected final String query;
public XmapNamedQuery(String name, String query) {
this.name = name;
this.query = query;
}
public String getName() {
return name;
}
public String getQuery() {
return query;
}
}
@@ -0,0 +1,42 @@
package io.ebeaninternal.xmapping.api;
import java.util.LinkedHashMap;
import java.util.Map;
public class XmapRawSql {
protected final String name;
protected final String query;
protected final Map<String, String> columnMapping = new LinkedHashMap<>();
protected final Map<String, String> aliasMapping = new LinkedHashMap<>();
public XmapRawSql(String name, String query) {
this.name = name;
this.query = query;
}
public void addColumnMapping(String column, String property) {
columnMapping.put(column, property);
}
public void addAliasMapping(String alias, String property) {
aliasMapping.put(alias, property);
}
public String getName() {
return name;
}
public String getQuery() {
return query;
}
public Map<String, String> getColumnMapping() {
return columnMapping;
}
public Map<String, String> getAliasMapping() {
return aliasMapping;
}
}
@@ -0,0 +1,15 @@
package io.ebeaninternal.xmapping.api;
import java.util.List;
/**
* Read and return external mapping for named queries etc.
*/
public interface XmapService {
/**
* Read and return external named queries etc.
*/
List<XmapEbean> read(ClassLoader classLoader, List<String> mappingLocations);
}
@@ -0,0 +1,66 @@
package io.ebeaninternal.xmlmapping;
import io.avaje.classpath.scanner.ClassPathScanner;
import io.avaje.classpath.scanner.ClassPathScannerFactory;
import io.avaje.classpath.scanner.Resource;
import io.ebeaninternal.xmapping.api.XmapEbean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.ServiceLoader;
/**
* Reads the Xml deployment information.
*/
class InternalConfigXmlRead {
private static final Logger log = LoggerFactory.getLogger(InternalConfigXmlRead.class);
private final ToXmapEbean to = new ToXmapEbean();
private final ClassLoader classLoader;
private final List<String> mappingLocations;
InternalConfigXmlRead(ClassLoader classLoader, List<String> mappingLocations) {
this.classLoader = classLoader;
this.mappingLocations = mappingLocations;
// if (config.getClassLoadConfig().isJavaxJAXBPresent()) {
// init();
// }
}
List<XmapEbean> read() {
List<XmapEbean> list = new ArrayList<>();
list.addAll(to.toBeans(XmlMappingReader.readByResourceName(classLoader, "ebean.xml")));
list.addAll(to.toBeans(XmlMappingReader.readByResourceList(xmlMappingResources())));
return list;
}
private List<Resource> xmlMappingResources() {
List<ClassPathScanner> scanners = scanners();
List<Resource> resourceList = new ArrayList<>();
long st = System.currentTimeMillis();
if (mappingLocations != null && !mappingLocations.isEmpty()) {
for (ClassPathScanner finder : scanners) {
for (String mappingLocation : mappingLocations) {
resourceList.addAll(finder.scanForResources(mappingLocation, resourceName -> resourceName.endsWith(".xml")));
}
}
}
long searchTime = System.currentTimeMillis() - st;
log.debug("Classpath search mappings[{}] searchTime[{}]", resourceList.size(), searchTime);
return resourceList;
}
/**
* Return the list of ClassPathScanner services using DatabaseConfig service loader.
*/
private List<ClassPathScanner> scanners() {
List<ClassPathScanner> scanners = new ArrayList<>();
for (ClassPathScannerFactory factory : ServiceLoader.load(ClassPathScannerFactory.class, classLoader)) {
scanners.add(factory.createScanner(classLoader));
}
return scanners;
}
}
@@ -0,0 +1,14 @@
package io.ebeaninternal.xmlmapping;
import io.ebeaninternal.xmapping.api.XmapEbean;
import io.ebeaninternal.xmapping.api.XmapService;
import java.util.List;
public class JaxbXmapService implements XmapService {
@Override
public List<XmapEbean> read(ClassLoader classLoader, List<String> mappingLocations) {
return new InternalConfigXmlRead(classLoader, mappingLocations).read();
}
}
@@ -0,0 +1,85 @@
package io.ebeaninternal.xmlmapping;
import io.ebeaninternal.xmapping.api.XmapDto;
import io.ebeaninternal.xmapping.api.XmapEbean;
import io.ebeaninternal.xmapping.api.XmapEntity;
import io.ebeaninternal.xmapping.api.XmapNamedQuery;
import io.ebeaninternal.xmapping.api.XmapRawSql;
import io.ebeaninternal.xmlmapping.model.XmAliasMapping;
import io.ebeaninternal.xmlmapping.model.XmColumnMapping;
import io.ebeaninternal.xmlmapping.model.XmDto;
import io.ebeaninternal.xmlmapping.model.XmEbean;
import io.ebeaninternal.xmlmapping.model.XmEntity;
import io.ebeaninternal.xmlmapping.model.XmNamedQuery;
import io.ebeaninternal.xmlmapping.model.XmRawSql;
import java.util.List;
import static java.util.stream.Collectors.toList;
public class ToXmapEbean {
public List<XmapEbean> toBeans(List<XmEbean> xmBeans) {
return xmBeans.stream()
.map(this::toBean)
.collect(toList());
}
private XmapEbean toBean(XmEbean bean) {
XmapEbean xmap = new XmapEbean();
xmap.getDto().addAll(toDto(bean.getDto()));
xmap.getEntity().addAll(toEntity(bean.getEntity()));
return xmap;
}
private List<XmapEntity> toEntity(List<XmEntity> xmEntity) {
return xmEntity.stream()
.map(this::toEntity)
.collect(toList());
}
private XmapEntity toEntity(XmEntity xmEntity) {
XmapEntity entity = new XmapEntity(xmEntity.getClazz());
for (XmNamedQuery named : xmEntity.getNamedQuery()) {
entity.getNamedQuery().add(toNamed(named));
}
for (XmRawSql xmRawSql : xmEntity.getRawSql()) {
entity.getRawSql().add(toRaw(xmRawSql));
}
return entity;
}
private XmapNamedQuery toNamed(XmNamedQuery named) {
return new XmapNamedQuery(named.getName(), named.getQuery().getValue());
}
private List<XmapDto> toDto(List<XmDto> dto) {
return dto.stream()
.map(this::toDto)
.collect(toList());
}
private XmapDto toDto(XmDto xmapDto) {
XmapDto dto = new XmapDto(xmapDto.getClazz());
dto.getRawSql().addAll(toRaw(xmapDto.getRawSql()));
return dto;
}
private List<XmapRawSql> toRaw(List<XmRawSql> rawSql) {
return rawSql.stream()
.map(this::toRaw)
.collect(toList());
}
private XmapRawSql toRaw(XmRawSql xmRawSql) {
XmapRawSql rawSql = new XmapRawSql(xmRawSql.getName(), xmRawSql.getQuery().getValue());
for (XmColumnMapping xmCol : xmRawSql.getColumnMapping()) {
rawSql.addColumnMapping(xmCol.getColumn(), xmCol.getProperty());
}
for (XmAliasMapping xmAlias : xmRawSql.getAliasMapping()) {
rawSql.addAliasMapping(xmAlias.getAlias(), xmAlias.getProperty());
}
return rawSql;
}
}
@@ -0,0 +1 @@
io.ebeaninternal.xmlmapping.JaxbXmapService