in oap-server/oal-rt/src/main/java/org/apache/skywalking/oal/rt/util/OALClassGenerator.java [146:280]
private Class generateMetricsClass(AnalysisResult metricsStmt) throws OALCompileException {
String className = metricsClassName(metricsStmt, false);
CtClass parentMetricsClass = null;
try {
parentMetricsClass = classPool.get(METRICS_FUNCTION_PACKAGE + metricsStmt.getMetricsClassName());
} catch (NotFoundException e) {
log.error("Can't find parent class for " + className + ".", e);
throw new OALCompileException(e.getMessage(), e);
}
CtClass metricsClass = classPool.makeClass(metricsClassName(metricsStmt, true), parentMetricsClass);
try {
metricsClass.addInterface(classPool.get(WITH_METADATA_INTERFACE));
} catch (NotFoundException e) {
log.error("Can't find WithMetadata interface for " + className + ".", e);
throw new OALCompileException(e.getMessage(), e);
}
ClassFile metricsClassClassFile = metricsClass.getClassFile();
ConstPool constPool = metricsClassClassFile.getConstPool();
/**
* Create empty construct
*/
try {
CtConstructor defaultConstructor = CtNewConstructor.make("public " + className + "() {}", metricsClass);
metricsClass.addConstructor(defaultConstructor);
} catch (CannotCompileException e) {
log.error("Can't add empty constructor in " + className + ".", e);
throw new OALCompileException(e.getMessage(), e);
}
/**
* Add fields with annotations.
*
* private ${sourceField.typeName} ${sourceField.fieldName};
*/
for (SourceColumn field : metricsStmt.getFieldsFromSource()) {
try {
CtField newField = CtField.make(
"private " + field.getType()
.getName() + " " + field.getFieldName() + ";", metricsClass);
metricsClass.addField(newField);
metricsClass.addMethod(CtNewMethod.getter(field.getFieldGetter(), newField));
metricsClass.addMethod(CtNewMethod.setter(field.getFieldSetter(), newField));
AnnotationsAttribute annotationsAttribute = new AnnotationsAttribute(
constPool, AnnotationsAttribute.visibleTag);
/**
* Add @Column(name = "${sourceField.columnName}")
*/
Annotation columnAnnotation = new Annotation(Column.class.getName(), constPool);
columnAnnotation.addMemberValue("name", new StringMemberValue(field.getColumnName(), constPool));
if (field.getType().equals(String.class)) {
columnAnnotation.addMemberValue("length", new IntegerMemberValue(constPool, field.getLength()));
}
annotationsAttribute.addAnnotation(columnAnnotation);
if (field.isID()) {
// Add SeriesID = 0 annotation to ID field.
Annotation banyanSeriesIDAnnotation = new Annotation(BanyanDB.SeriesID.class.getName(), constPool);
banyanSeriesIDAnnotation.addMemberValue("index", new IntegerMemberValue(constPool, 0));
annotationsAttribute.addAnnotation(banyanSeriesIDAnnotation);
// Entity id field should enable doc values.
final var enableDocValuesAnnotation = new Annotation(ElasticSearch.EnableDocValues.class.getName(), constPool);
annotationsAttribute.addAnnotation(enableDocValuesAnnotation);
}
if (field.isGroupByCondInTopN()) {
Annotation banyanTopNAggregationAnnotation = new Annotation(BanyanDB.TopNAggregation.class.getName(), constPool);
annotationsAttribute.addAnnotation(banyanTopNAggregationAnnotation);
// If TopN, add ShardingKey to group field.
Annotation banyanShardingKeyAnnotation = new Annotation(BanyanDB.ShardingKey.class.getName(), constPool);
banyanShardingKeyAnnotation.addMemberValue("index", new IntegerMemberValue(constPool, 0));
annotationsAttribute.addAnnotation(banyanShardingKeyAnnotation);
}
newField.getFieldInfo().addAttribute(annotationsAttribute);
} catch (CannotCompileException e) {
log.error(
"Can't add field(including set/get) " + field.getFieldName() + " in " + className + ".", e);
throw new OALCompileException(e.getMessage(), e);
}
}
/**
* Generate methods
*/
for (String method : METRICS_CLASS_METHODS) {
StringWriter methodEntity = new StringWriter();
try {
configuration.getTemplate("metrics/" + method + ".ftl").process(metricsStmt, methodEntity);
metricsClass.addMethod(CtNewMethod.make(methodEntity.toString(), metricsClass));
} catch (Exception e) {
log.error("Can't generate method " + method + " for " + className + ".", e);
throw new OALCompileException(e.getMessage(), e);
}
}
/**
* Add following annotation to the metrics class
*
* at Stream(name = "${tableName}", scopeId = ${sourceScopeId}, builder = ${metricsName}Metrics.Builder.class, processor = MetricsStreamProcessor.class)
*/
AnnotationsAttribute annotationsAttribute = new AnnotationsAttribute(
constPool, AnnotationsAttribute.visibleTag);
Annotation streamAnnotation = new Annotation(Stream.class.getName(), constPool);
streamAnnotation.addMemberValue("name", new StringMemberValue(metricsStmt.getTableName(), constPool));
streamAnnotation.addMemberValue(
"scopeId", new IntegerMemberValue(constPool, metricsStmt.getFrom().getSourceScopeId()));
streamAnnotation.addMemberValue(
"builder", new ClassMemberValue(metricsBuilderClassName(metricsStmt, true), constPool));
streamAnnotation.addMemberValue("processor", new ClassMemberValue(METRICS_STREAM_PROCESSOR, constPool));
annotationsAttribute.addAnnotation(streamAnnotation);
metricsClassClassFile.addAttribute(annotationsAttribute);
Class targetClass;
try {
if (SystemUtils.isJavaVersionAtMost(JavaVersion.JAVA_1_8)) {
targetClass = metricsClass.toClass(currentClassLoader, null);
} else {
targetClass = metricsClass.toClass(MetricClassPackageHolder.class);
}
} catch (CannotCompileException e) {
log.error("Can't compile/load " + className + ".", e);
throw new OALCompileException(e.getMessage(), e);
}
log.debug("Generate metrics class, " + metricsClass.getName());
writeGeneratedFile(metricsClass, "metrics");
return targetClass;
}