blob: e51380e1b330c6a6c65a61be468aae1e358981f8 [file] [log] [blame]
package org.apache.karaf.boot.karaf.impl;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic.Kind;
import javax.tools.FileObject;
import javax.tools.StandardLocation;
import java.io.CharArrayWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.Writer;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import org.apache.karaf.util.tracker.annotation.Managed;
import org.apache.karaf.util.tracker.annotation.ProvideService;
import org.apache.karaf.util.tracker.annotation.RequireService;
import org.apache.karaf.util.tracker.annotation.Services;
public class KarafProcessor extends AbstractProcessor {
boolean hasRun;
public KarafProcessor() {
}
@Override
public Set<String> getSupportedAnnotationTypes() {
Set<String> set = new HashSet<String>();
set.add(Services.class.getName());
set.add(Managed.class.getName());
return set;
}
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
List<String> instructions = new ArrayList<>();
Properties props = new Properties();
for (Element elem : roundEnv.getElementsAnnotatedWith(Services.class)) {
for (AnnotationMirror mirror : elem.getAnnotationMirrors()) {
if (Services.class.getName().equals(((TypeElement) mirror.getAnnotationType().asElement()).getQualifiedName().toString())) {
Map<String, Object> values = getAnnotationValues(mirror);
if (values.containsKey("provides")) {
for (AnnotationMirror p : (List<AnnotationMirror>) values.get("provides")) {
Map<String, Object> pv = getAnnotationValues(p);
String n = pv.get("value").toString();
instructions.add("Provide-Capability: osgi.service;effective:=active;objectClass=" + n);
}
}
if (values.containsKey("requires")) {
for (AnnotationMirror r : (List<AnnotationMirror>) values.get("requires")) {
Map<String, Object> rv = getAnnotationValues(r);
String value = rv.get("value").toString();
String filter = (String) rv.getOrDefault("filter", "");
boolean opt = ((Boolean) rv.getOrDefault("optional", false));
String fltWithClass = combine(filter, "(objectClass=" + value + ")");
instructions.add("Require-Capability: osgi.service;effective:=active;filter:=\"" + fltWithClass + "\"");
props.setProperty(value, filter);
}
}
}
}
instructions.add("Bundle-Activator: " + ((TypeElement) elem).getQualifiedName().toString());
Managed managed = elem.getAnnotation(Managed.class);
if (managed != null) {
props.setProperty("pid", managed.value());
}
String name = "OSGI-INF/karaf-tracker/" + ((TypeElement) elem).getQualifiedName().toString();
try (OutputStream os = processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", name).openOutputStream()) {
props.store(os, null);
} catch (IOException e) {
processingEnv.getMessager().printMessage(Kind.ERROR, "Error writing to " + name + ": " + e.getMessage());
}
}
instructions.add("Private-Package: org.apache.karaf.util.tracker");
instructions.add("PREPEND-Import-Package: !org.apache.karaf.util.tracker.annotation");
if (!hasRun) {
hasRun = true;
// Add the Karaf embedded package
try (PrintWriter w = appendResource("META-INF/org.apache.karaf.boot.bnd")) {
for (String instr : instructions) {
w.println(instr);
}
} catch (Exception e) {
processingEnv.getMessager().printMessage(Kind.ERROR, "Error writing to META-INF/org.apache.karaf.boot.bnd: " + e.getMessage());
}
}
return true;
}
private Map<String, Object> getAnnotationValues(AnnotationMirror mirror) {
Map<String, Object> map = new HashMap<>();
for (Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> entry : mirror.getElementValues().entrySet()) {
map.put(entry.getKey().getSimpleName().toString(), entry.getValue().getValue());
}
return map;
}
private String combine(String filter1, String filter2) {
if (filter1!=null && !filter1.isEmpty()) {
return "(&" + filter2 + filter1 + ")";
} else {
return filter2;
}
}
private PrintWriter appendResource(String resource) throws IOException {
try {
FileObject o = processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", resource);
return new PrintWriter(o.openWriter());
} catch (Exception e) {
try {
FileObject o = processingEnv.getFiler().getResource(StandardLocation.CLASS_OUTPUT, "", resource);
CharArrayWriter baos = new CharArrayWriter();
try (Reader r = o.openReader(true)) {
char[] buf = new char[4096];
int l;
while ((l = r.read(buf)) > 0) {
baos.write(buf, 0, l);
}
}
o.delete();
o = processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", resource);
Writer w = o.openWriter();
w.write(baos.toCharArray());
return new PrintWriter(w);
} catch (Exception e2) {
e2.addSuppressed(e);
e2.printStackTrace();
throw e2;
}
}
}
}