-
Notifications
You must be signed in to change notification settings - Fork 612
/
JGroupsComponentProcessor.java
118 lines (107 loc) · 5.15 KB
/
JGroupsComponentProcessor.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
package org.infinispan.component.processor.external;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.time.Instant;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.DeclaredType;
import org.infinispan.external.JGroupsProtocolComponent;
import org.jgroups.annotations.ManagedAttribute;
import org.jgroups.conf.ClassConfigurator;
import org.jgroups.protocols.RED;
import org.jgroups.stack.Protocol;
import org.kohsuke.MetaInfServices;
/**
* @since 14.0
**/
@SupportedSourceVersion(SourceVersion.RELEASE_8)
@SupportedAnnotationTypes("org.infinispan.external.JGroupsProtocolComponent")
@MetaInfServices(Processor.class)
public class JGroupsComponentProcessor extends AbstractProcessor {
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
for (TypeElement annotation : annotations) {
for (Element element : roundEnv.getElementsAnnotatedWith(annotation)) {
JGroupsProtocolComponent component = element.getAnnotation(JGroupsProtocolComponent.class);
DeclaredType typeMirror = (DeclaredType) element.asType();
TypeElement type = (TypeElement) typeMirror.asElement();
String fqcn = type.getQualifiedName().toString();
int lastDot = fqcn.lastIndexOf('.');
String packageName = fqcn.substring(0, lastDot);
try (PrintWriter w = new PrintWriter(processingEnv.getFiler().createSourceFile(packageName + '.' + component.value()).openWriter())) {
generate(w, packageName, component.value());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
return true;
}
public void generate(PrintWriter w, String packageName, String className) throws IOException {
w.printf("package %s;%n", packageName);
w.println("import java.util.ArrayList;");
w.println("import java.util.Collection;");
w.println("import java.util.HashMap;");
w.println("import java.util.List;");
w.println("import java.util.Map;");
w.println("import java.util.function.Function;");
w.println("import javax.annotation.Generated;");
w.println("import static org.infinispan.factories.impl.MBeanMetadata.AttributeMetadata;");
w.println("import org.jgroups.stack.Protocol;");
w.println();
w.printf("@Generated(value = \"%s\", date = \"%s\")%n", getClass().getName(), Instant.now().toString());
w.printf("public class %s {%n", className);
w.println(" public static final Map<Class<? extends Protocol>, Collection<AttributeMetadata>> PROTOCOL_METADATA = new HashMap<>();");
w.printf(" private %s() {}%n", className);
w.println(" static {");
w.println(" List<AttributeMetadata> attributes;");
for (short id = 0; id < 256; id++) {
Class<?> protocol = ClassConfigurator.getProtocol(id);
addProtocol(protocol, w);
}
// RED protocol does not have an ID (maybe a bug?)
// Add it manually if an ID is not found.
if (ClassConfigurator.getProtocolId(RED.class) == 0) {
addProtocol(RED.class, w);
}
w.println(" }");
w.println("}");
w.println();
w.flush();
w.close();
}
private static void addProtocol(Class<?> protocol, PrintWriter w) {
if (protocol == null || !Protocol.class.isAssignableFrom(protocol)) {
return;
}
boolean hasAttributes = false;
for (Method method : protocol.getMethods()) {
ManagedAttribute annotation = method.getAnnotation(ManagedAttribute.class);
if (annotation != null && !Modifier.isStatic(method.getModifiers()) && method.getParameterCount() == 0 && isNumber(method.getReturnType())) {
if (!hasAttributes) {
w.println(" attributes = new ArrayList<>();");
hasAttributes = true;
}
w.printf(" attributes.add(new AttributeMetadata(\"%s\", \"%s\", false, false, \"%s\",\n" +
" false, (Function<%s, ?>) %s::%s, null));%n",
method.getName(), annotation.description().replace('"', '\''), method.getReturnType().getName(), protocol.getName(), protocol.getName(), method.getName());
}
}
if (hasAttributes) {
// only put the protocol in PROTOCOL_METADATA if we have something to store there
w.printf(" PROTOCOL_METADATA.put(%s.class, attributes);%n", protocol.getName());
}
}
private static boolean isNumber(Class<?> type) {
return short.class == type || byte.class == type || long.class == type || int.class == type || float.class == type || double.class == type || Number.class.isAssignableFrom(type);
}
}