Fixing Maven-based build to properly process the component configuration properties for ONOS 2.x
Change-Id: I29c063939073852862f3c0e2f47540afe66a34aa
diff --git a/tools/package/maven-plugin/pom.xml b/tools/package/maven-plugin/pom.xml
index f9016d2..82a688f 100644
--- a/tools/package/maven-plugin/pom.xml
+++ b/tools/package/maven-plugin/pom.xml
@@ -26,7 +26,7 @@
<groupId>org.onosproject</groupId>
<artifactId>onos-maven-plugin</artifactId>
- <version>2.1-SNAPSHOT</version>
+ <version>2.1</version>
<packaging>maven-plugin</packaging>
<description>Maven plugin for packaging ONOS applications or generating
diff --git a/tools/package/maven-plugin/src/main/java/org/onosproject/maven/OnosCfgMojo.java b/tools/package/maven-plugin/src/main/java/org/onosproject/maven/OnosCfgMojo.java
index 19628f8..f8ea71c 100644
--- a/tools/package/maven-plugin/src/main/java/org/onosproject/maven/OnosCfgMojo.java
+++ b/tools/package/maven-plugin/src/main/java/org/onosproject/maven/OnosCfgMojo.java
@@ -15,10 +15,15 @@
*/
package org.onosproject.maven;
+import com.google.common.collect.Maps;
import com.thoughtworks.qdox.JavaProjectBuilder;
import com.thoughtworks.qdox.model.JavaAnnotation;
import com.thoughtworks.qdox.model.JavaClass;
import com.thoughtworks.qdox.model.JavaField;
+import com.thoughtworks.qdox.model.expression.Add;
+import com.thoughtworks.qdox.model.expression.AnnotationValue;
+import com.thoughtworks.qdox.model.expression.AnnotationValueList;
+import com.thoughtworks.qdox.model.expression.FieldRef;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
@@ -31,6 +36,9 @@
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.jar.JarEntry;
/**
* Produces ONOS component configuration catalogue resources.
@@ -39,10 +47,6 @@
@java.lang.SuppressWarnings("squid:S1148")
public class OnosCfgMojo extends AbstractMojo {
- private static final String COMPONENT = "org.apache.felix.scr.annotations.Component";
- private static final String PROPERTY = "org.apache.felix.scr.annotations.Property";
- private static final String SEP = "|";
-
/**
* The directory where the generated catalogue file will be put.
*/
@@ -59,84 +63,161 @@
public void execute() throws MojoExecutionException {
getLog().info("Generating ONOS component configuration catalogues...");
try {
- JavaProjectBuilder builder = new JavaProjectBuilder();
- builder.addSourceTree(new File(srcDirectory, "src/main/java"));
- builder.getClasses().forEach(this::processClass);
+ CfgDefGenerator gen = new CfgDefGenerator(dstDirectory, srcDirectory);
+ gen.analyze();
+ gen.generate();
} catch (Exception e) {
e.printStackTrace();
- throw e;
+ throw new MojoExecutionException("Unable to generate property catalog", e);
}
}
- private void processClass(JavaClass javaClass) {
- boolean isComponent = javaClass.getAnnotations().stream()
- .map(ja -> ja.getType().getName().equals(COMPONENT))
- .findFirst().isPresent();
- if (isComponent) {
- List<String> lines = new ArrayList<>();
- javaClass.getFields().forEach(field -> processField(lines, javaClass, field));
- if (!lines.isEmpty()) {
- writeCatalog(javaClass, lines);
+
+ private static class CfgDefGenerator {
+
+ private static final String COMPONENT = "org.osgi.service.component.annotations.Component";
+ private static final String PROPERTY = "property";
+ private static final String SEP = "|";
+ private static final String UTF_8 = "UTF-8";
+ private static final String JAVA = ".java";
+ private static final String EXT = ".cfgdef";
+ private static final String STRING = "STRING";
+ private static final String NO_DESCRIPTION = "no description provided";
+
+ private final File dstDir;
+ private final JavaProjectBuilder builder;
+
+ private final Map<String, String> constants = Maps.newHashMap();
+
+
+ private CfgDefGenerator(File dstDir, File srcDir) {
+ this.dstDir = dstDir;
+ this.builder = new JavaProjectBuilder();
+ builder.addSourceTree(new File(srcDir, "src/main/java"));
+
+// Arrays.stream(sourceFilePaths).forEach(filename -> {
+// try {
+// if (filename.endsWith(JAVA))
+// builder.addSource(new File(filename));
+// } catch (ParseException e) {
+// // When unable to parse, skip the source; leave it to javac to fail.
+// } catch (IOException e) {
+// throw new IllegalArgumentException("Unable to open file", e);
+// }
+// });
+ }
+
+ public void analyze() {
+ builder.getClasses().forEach(this::collectConstants);
+ }
+
+ private void collectConstants(JavaClass javaClass) {
+ javaClass.getFields().stream()
+ .filter(f -> f.isStatic() && f.isFinal() && !f.isPrivate())
+ .forEach(f -> constants.put(f.getName(), f.getInitializationExpression()));
+ }
+
+ public void generate() throws IOException {
+ for (JavaClass javaClass : builder.getClasses()) {
+ processClass(javaClass);
}
}
- }
- private void writeCatalog(JavaClass javaClass, List<String> lines) {
- File dir = new File(dstDirectory, javaClass.getPackageName().replace('.', '/'));
- dir.mkdirs();
+ private void processClass(JavaClass javaClass) throws IOException {
+ Optional<JavaAnnotation> annotation = javaClass.getAnnotations().stream()
+ .filter(ja -> ja.getType().getName().equals(COMPONENT))
+ .findFirst();
+ if (annotation.isPresent()) {
+ AnnotationValue property = annotation.get().getProperty(PROPERTY);
+ List<String> lines = new ArrayList<>();
+ if (property instanceof AnnotationValueList) {
+ AnnotationValueList list = (AnnotationValueList) property;
+ list.getValueList().forEach(v -> processProperty(lines, javaClass, v));
+ } else {
+ processProperty(lines, javaClass, property);
+ }
- File cfgDef = new File(dir, javaClass.getName().replace('.', '/') + ".cfgdef");
- try (FileWriter fw = new FileWriter(cfgDef);
- PrintWriter pw = new PrintWriter(fw)) {
- pw.println("# This file is auto-generated by onos-maven-plugin");
- lines.forEach(pw::println);
- } catch (IOException e) {
- System.err.println("Unable to write catalog for " + javaClass.getName());
- e.printStackTrace();
- }
- }
-
- private void processField(List<String> lines, JavaClass javaClass, JavaField field) {
- field.getAnnotations().forEach(ja -> {
- if (ja.getType().getName().equals(PROPERTY)) {
- lines.add(expand(javaClass, ja.getNamedParameter("name").toString()) +
- SEP + type(field) +
- SEP + defaultValue(javaClass, field, ja) +
- SEP + description(ja));
+ if (!lines.isEmpty()) {
+ writeCatalog(javaClass, lines);
+ }
}
- });
+ }
+
+ private void processProperty(List<String> lines, JavaClass javaClass,
+ AnnotationValue value) {
+ String s = elaborate(value);
+ String[] pex = s.split("=", 2);
+
+ if (pex.length == 2) {
+ String[] rex = pex[0].split(":", 2);
+ String name = rex[0];
+ String type = rex.length == 2 ? rex[1].toUpperCase() : STRING;
+ String def = pex[1];
+ String desc = description(javaClass, name);
+
+ if (desc != null) {
+ String line = name + SEP + type + SEP + def + SEP + desc + "\n";
+ lines.add(line);
+ }
+ }
+ }
+
+ // Retrieve description from a comment preceding the field named the same
+ // as the property or
+ // TODO: from an annotated comment.
+ private String description(JavaClass javaClass, String name) {
+ if (name.startsWith("_")) {
+ // Static property - just leave it as is, not for inclusion in the cfg defs
+ return null;
+ }
+ JavaField field = javaClass.getFieldByName(name);
+ if (field != null) {
+ String comment = field.getComment();
+ return comment != null ? comment : NO_DESCRIPTION;
+ }
+ throw new IllegalStateException("cfgdef could not find a variable named " + name + " in " + javaClass.getName());
+ }
+
+ private String elaborate(AnnotationValue value) {
+ if (value instanceof Add) {
+ return elaborate(((Add) value).getLeft()) + elaborate(((Add) value).getRight());
+ } else if (value instanceof FieldRef) {
+ return elaborate((FieldRef) value);
+ } else if (value != null) {
+ return stripped(value.toString());
+ } else {
+ return "";
+ }
+ }
+
+ private String elaborate(FieldRef field) {
+ String name = field.getName();
+ String value = constants.get(name);
+ if (value != null) {
+ return stripped(value);
+ }
+ throw new IllegalStateException("Constant " + name + " cannot be elaborated;" +
+ " value not in the same compilation context");
+ }
+
+ private String stripped(String s) {
+ return s.trim().replaceFirst("^[^\"]*\"", "").replaceFirst("\"$", "");
+ }
+
+ private void writeCatalog(JavaClass javaClass, List<String> lines) {
+ File dir = new File(dstDir, javaClass.getPackageName().replace('.', '/'));
+ dir.mkdirs();
+
+ File cfgDef = new File(dir, javaClass.getName().replace('.', '/') + ".cfgdef");
+ try (FileWriter fw = new FileWriter(cfgDef);
+ PrintWriter pw = new PrintWriter(fw)) {
+ pw.println("# This file is auto-generated by onos-maven-plugin");
+ lines.forEach(pw::println);
+ } catch (IOException e) {
+ System.err.println("Unable to write catalog for " + javaClass.getName());
+ e.printStackTrace();
+ }
+ }
+
}
-
- // TODO: Stuff below is very much hack-ish and should be redone; it works for now though.
-
- private String description(JavaAnnotation annotation) {
- String description = (String) annotation.getNamedParameter("label");
- return description.replaceAll("\" \\+ \"", "")
- .replaceFirst("^[^\"]*\"", "").replaceFirst("\"$", "");
- }
-
- private String type(JavaField field) {
- String ft = field.getType().getName().toUpperCase();
- return ft.equals("INT") ? "INTEGER" : ft;
- }
-
- private String defaultValue(JavaClass javaClass, JavaField field,
- JavaAnnotation annotation) {
- String ft = field.getType().getName().toLowerCase();
- String defValueName = ft.equals("boolean") ? "boolValue" :
- ft.equals("string") ? "value" : ft + "Value";
- Object dv = annotation.getNamedParameter(defValueName);
- return dv == null ? "" : expand(javaClass, dv.toString());
- }
-
- private String stripQuotes(String string) {
- return string.trim().replaceFirst("^[^\"]*\"", "").replaceFirst("\"$", "");
- }
-
- private String expand(JavaClass javaClass, String value) {
- JavaField field = javaClass.getFieldByName(value);
- return field == null ? stripQuotes(value) :
- stripQuotes(field.getCodeBlock().replaceFirst(".*=", "").replaceFirst(";$", ""));
- }
-
-}
+}
\ No newline at end of file