in linkis-public-enhancements/linkis-datasource/linkis-datasource-manager/server/src/main/java/org/apache/linkis/metadata/query/server/loader/MetaClassLoaderManager.java [88:264]
public BiFunction<String, Object[], Object> getInvoker(String dsType) throws ErrorException {
boolean needToLoad = true;
MetaServiceInstance serviceInstance = metaServiceInstances.get(dsType);
if (Objects.nonNull(serviceInstance)) {
Integer expireTimeInSec = INSTANCE_EXPIRE_TIME.getValue();
// Lazy load
needToLoad =
Objects.nonNull(expireTimeInSec)
&& expireTimeInSec > 0
&& (serviceInstance.initTimeStamp
+ TimeUnit.MILLISECONDS.convert(expireTimeInSec, TimeUnit.SECONDS))
< System.currentTimeMillis();
}
if (needToLoad) {
MetaServiceInstance finalServiceInstance1 = serviceInstance;
boolean isContains = CacheConfiguration.MYSQL_RELATIONSHIP_LIST.getValue().contains(dsType);
String finalBaseType = isContains ? MYSQL_BASE_DIR : dsType;
serviceInstance =
metaServiceInstances.compute(
dsType,
(key, instance) -> {
if (null != instance && !Objects.equals(finalServiceInstance1, instance)) {
return instance;
}
String lib = LIB_DIR.getValue();
String stdLib = lib.endsWith("/") ? lib.replaceAll(".$", "") : lib;
String componentLib = stdLib + "/" + finalBaseType;
LOG.info(
"Start to load/reload meta instance of data source type: ["
+ dsType
+ "] from library dir:"
+ componentLib);
ClassLoader parentClassLoader = MetaClassLoaderManager.class.getClassLoader();
ClassLoader metaClassLoader =
classLoaders.computeIfAbsent(
dsType,
(type) -> {
try {
return new URLClassLoader(
getJarsUrlsOfPath(componentLib).toArray(new URL[0]),
parentClassLoader);
} catch (Exception e) {
LOG.error(
"Cannot init the classloader of type: ["
+ dsType
+ "] in library path: ["
+ componentLib
+ "]",
e);
return null;
}
});
if (Objects.isNull(metaClassLoader)) {
throw new MetaRuntimeException(
MessageFormat.format(ERROR_IN_CREATING.getErrorDesc(), dsType), null);
}
String expectClassName = null;
if (dsType.length() > 0) {
String converDsType = dsType;
try {
if (MapUtils.isNotEmpty(databaseRelationship)
&& databaseRelationship.containsKey(dsType)) {
String value = MapUtils.getString(databaseRelationship, dsType);
if (StringUtils.isNotBlank(value)
&& CacheConfiguration.MYSQL_RELATIONSHIP_LIST
.getValue()
.contains(value)) {
converDsType = value;
}
}
} catch (Exception e) {
LOG.warn("dsType conver failed: {}", dsType);
}
String prefix =
converDsType.substring(0, 1).toUpperCase() + converDsType.substring(1);
expectClassName = String.format(META_CLASS_NAME, prefix);
}
Class<? extends BaseMetadataService> metaServiceClass =
searchForLoadMetaServiceClass(metaClassLoader, expectClassName, true);
if (Objects.isNull(metaServiceClass)) {
throw new MetaRuntimeException(
MessageFormat.format(INIT_META_SERVICE.getErrorDesc(), dsType), null);
}
BaseMetadataService metadataService =
MetadataUtils.loadMetaService(metaServiceClass, metaClassLoader);
if (metadataService instanceof AbstractCacheMetaService) {
LOG.info("Invoke the init() method in meta service for type: [" + dsType + "]");
((AbstractCacheMetaService<?>) metadataService).init();
}
return new MetaServiceInstance(metadataService, metaClassLoader);
});
}
Method[] childMethods = serviceInstance.methods;
MetaServiceInstance finalServiceInstance = serviceInstance;
return (String m, Object... args) -> {
ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(finalServiceInstance.metaClassLoader);
List<Method> methodsMatched =
Arrays.stream(childMethods)
.filter(
eachMethod -> {
if (eachMethod.getName().equals(m)) {
Class<?>[] parameterType = eachMethod.getParameterTypes();
if (parameterType.length == args.length) {
for (int i = 0; i < parameterType.length; i++) {
if (Objects.nonNull(args[i])) {
boolean matches =
parameterType[i].isAssignableFrom(args[i].getClass())
|| ((args[i].getClass().isPrimitive()
|| parameterType[i].isPrimitive())
&& MetadataUtils.getPrimitive(args[i].getClass())
== MetadataUtils.getPrimitive(parameterType[i]));
if (!matches) {
return false;
}
}
}
return true;
}
}
return false;
})
.collect(Collectors.toList());
if (methodsMatched.isEmpty()) {
String type = null;
if (Objects.nonNull(args)) {
type =
Arrays.stream(args)
.map(arg -> Objects.nonNull(arg) ? arg.getClass().toString() : "null")
.collect(Collectors.joining(","));
}
String message =
"Unknown method: [ name: "
+ m
+ ", type: ["
+ type
+ "]] for meta service instance: ["
+ finalServiceInstance.getServiceInstance().toString()
+ "]";
LOG.warn(message);
throw new MetaRuntimeException(message, null);
} else if (methodsMatched.size() > 1) {
LOG.warn(
"Find multiple matched methods with name: ["
+ m
+ "] such as: \n"
+ methodsMatched.stream()
.map(
method ->
method.getName() + ":" + Arrays.toString(method.getParameterTypes()))
.collect(Collectors.joining("\n"))
+ "\n in meta service instance: ["
+ finalServiceInstance.getServiceInstance().toString()
+ "], will choose the first one");
}
return methodsMatched.get(0).invoke(finalServiceInstance.serviceInstance, args);
} catch (Exception e) {
Throwable t = e;
// UnWrap the Invocation target exception
while (t instanceof InvocationTargetException) {
t = t.getCause();
}
String message =
"Fail to invoke method: ["
+ m
+ "] in meta service instance: ["
+ finalServiceInstance.serviceInstance.toString()
+ "]";
LOG.warn(message, t);
throw new MetaRuntimeException(message, t);
} finally {
Thread.currentThread().setContextClassLoader(currentClassLoader);
}
};
}