blob: b706f287ff898299f1531ecca0bdd0d11b9ba146 [file] [log] [blame]
Thomas Vachuska8c8b0372015-03-10 11:11:24 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2015-present Open Networking Foundation
Thomas Vachuska8c8b0372015-03-10 11:11:24 -07003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.maven;
17
Thomas Vachuskad6f88c62019-03-30 10:37:36 -070018import com.google.common.collect.Maps;
Thomas Vachuska8c8b0372015-03-10 11:11:24 -070019import com.thoughtworks.qdox.JavaProjectBuilder;
20import com.thoughtworks.qdox.model.JavaAnnotation;
21import com.thoughtworks.qdox.model.JavaClass;
22import com.thoughtworks.qdox.model.JavaField;
Thomas Vachuskad6f88c62019-03-30 10:37:36 -070023import com.thoughtworks.qdox.model.expression.Add;
24import com.thoughtworks.qdox.model.expression.AnnotationValue;
25import com.thoughtworks.qdox.model.expression.AnnotationValueList;
26import com.thoughtworks.qdox.model.expression.FieldRef;
Thomas Vachuska8c8b0372015-03-10 11:11:24 -070027import org.apache.maven.plugin.AbstractMojo;
28import org.apache.maven.plugin.MojoExecutionException;
29import org.apache.maven.plugins.annotations.LifecyclePhase;
30import org.apache.maven.plugins.annotations.Mojo;
31import org.apache.maven.plugins.annotations.Parameter;
32
33import java.io.File;
34import java.io.FileWriter;
35import java.io.IOException;
36import java.io.PrintWriter;
37import java.util.ArrayList;
38import java.util.List;
Thomas Vachuskad6f88c62019-03-30 10:37:36 -070039import java.util.Map;
40import java.util.Optional;
41import java.util.jar.JarEntry;
Thomas Vachuska8c8b0372015-03-10 11:11:24 -070042
43/**
44 * Produces ONOS component configuration catalogue resources.
45 */
46@Mojo(name = "cfg", defaultPhase = LifecyclePhase.GENERATE_RESOURCES)
Ray Milkey4fd3ceb2015-12-10 14:43:08 -080047@java.lang.SuppressWarnings("squid:S1148")
Thomas Vachuska8c8b0372015-03-10 11:11:24 -070048public class OnosCfgMojo extends AbstractMojo {
49
Thomas Vachuska8c8b0372015-03-10 11:11:24 -070050 /**
51 * The directory where the generated catalogue file will be put.
52 */
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -070053 @Parameter(defaultValue = "${basedir}")
Thomas Vachuska8c8b0372015-03-10 11:11:24 -070054 protected File srcDirectory;
55
56 /**
57 * The directory where the generated catalogue file will be put.
58 */
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -070059 @Parameter(defaultValue = "${project.build.outputDirectory}")
Thomas Vachuska8c8b0372015-03-10 11:11:24 -070060 protected File dstDirectory;
61
62 @Override
63 public void execute() throws MojoExecutionException {
64 getLog().info("Generating ONOS component configuration catalogues...");
65 try {
Thomas Vachuskad6f88c62019-03-30 10:37:36 -070066 CfgDefGenerator gen = new CfgDefGenerator(dstDirectory, srcDirectory);
67 gen.analyze();
68 gen.generate();
Thomas Vachuska8c8b0372015-03-10 11:11:24 -070069 } catch (Exception e) {
70 e.printStackTrace();
Thomas Vachuskad6f88c62019-03-30 10:37:36 -070071 throw new MojoExecutionException("Unable to generate property catalog", e);
Thomas Vachuska8c8b0372015-03-10 11:11:24 -070072 }
73 }
74
Thomas Vachuskad6f88c62019-03-30 10:37:36 -070075
Carmelo Casconeafdddc12019-07-15 18:51:32 -070076 private class CfgDefGenerator {
Thomas Vachuskad6f88c62019-03-30 10:37:36 -070077
78 private static final String COMPONENT = "org.osgi.service.component.annotations.Component";
79 private static final String PROPERTY = "property";
80 private static final String SEP = "|";
81 private static final String UTF_8 = "UTF-8";
82 private static final String JAVA = ".java";
83 private static final String EXT = ".cfgdef";
84 private static final String STRING = "STRING";
85 private static final String NO_DESCRIPTION = "no description provided";
86
87 private final File dstDir;
88 private final JavaProjectBuilder builder;
89
90 private final Map<String, String> constants = Maps.newHashMap();
91
92
93 private CfgDefGenerator(File dstDir, File srcDir) {
94 this.dstDir = dstDir;
95 this.builder = new JavaProjectBuilder();
96 builder.addSourceTree(new File(srcDir, "src/main/java"));
97
98// Arrays.stream(sourceFilePaths).forEach(filename -> {
99// try {
100// if (filename.endsWith(JAVA))
101// builder.addSource(new File(filename));
102// } catch (ParseException e) {
103// // When unable to parse, skip the source; leave it to javac to fail.
104// } catch (IOException e) {
105// throw new IllegalArgumentException("Unable to open file", e);
106// }
107// });
108 }
109
110 public void analyze() {
111 builder.getClasses().forEach(this::collectConstants);
112 }
113
114 private void collectConstants(JavaClass javaClass) {
115 javaClass.getFields().stream()
116 .filter(f -> f.isStatic() && f.isFinal() && !f.isPrivate())
117 .forEach(f -> constants.put(f.getName(), f.getInitializationExpression()));
118 }
119
120 public void generate() throws IOException {
121 for (JavaClass javaClass : builder.getClasses()) {
122 processClass(javaClass);
Thomas Vachuska8c8b0372015-03-10 11:11:24 -0700123 }
124 }
Thomas Vachuska8c8b0372015-03-10 11:11:24 -0700125
Thomas Vachuskad6f88c62019-03-30 10:37:36 -0700126 private void processClass(JavaClass javaClass) throws IOException {
127 Optional<JavaAnnotation> annotation = javaClass.getAnnotations().stream()
128 .filter(ja -> ja.getType().getName().equals(COMPONENT))
129 .findFirst();
130 if (annotation.isPresent()) {
131 AnnotationValue property = annotation.get().getProperty(PROPERTY);
132 List<String> lines = new ArrayList<>();
133 if (property instanceof AnnotationValueList) {
134 AnnotationValueList list = (AnnotationValueList) property;
135 list.getValueList().forEach(v -> processProperty(lines, javaClass, v));
136 } else {
137 processProperty(lines, javaClass, property);
138 }
Thomas Vachuska8c8b0372015-03-10 11:11:24 -0700139
Thomas Vachuskad6f88c62019-03-30 10:37:36 -0700140 if (!lines.isEmpty()) {
141 writeCatalog(javaClass, lines);
142 }
Thomas Vachuska8c8b0372015-03-10 11:11:24 -0700143 }
Thomas Vachuskad6f88c62019-03-30 10:37:36 -0700144 }
145
146 private void processProperty(List<String> lines, JavaClass javaClass,
147 AnnotationValue value) {
148 String s = elaborate(value);
149 String[] pex = s.split("=", 2);
150
151 if (pex.length == 2) {
152 String[] rex = pex[0].split(":", 2);
153 String name = rex[0];
154 String type = rex.length == 2 ? rex[1].toUpperCase() : STRING;
155 String def = pex[1];
156 String desc = description(javaClass, name);
157
158 if (desc != null) {
Carmelo Casconeafdddc12019-07-15 18:51:32 -0700159 String line = name + SEP + type + SEP + def + SEP + desc;
160 getLog().info("Processing property " + line + " ...");
161 lines.add(line + "\n");
Thomas Vachuskad6f88c62019-03-30 10:37:36 -0700162 }
163 }
164 }
165
166 // Retrieve description from a comment preceding the field named the same
167 // as the property or
168 // TODO: from an annotated comment.
169 private String description(JavaClass javaClass, String name) {
170 if (name.startsWith("_")) {
171 // Static property - just leave it as is, not for inclusion in the cfg defs
172 return null;
173 }
174 JavaField field = javaClass.getFieldByName(name);
175 if (field != null) {
176 String comment = field.getComment();
177 return comment != null ? comment : NO_DESCRIPTION;
178 }
179 throw new IllegalStateException("cfgdef could not find a variable named " + name + " in " + javaClass.getName());
180 }
181
182 private String elaborate(AnnotationValue value) {
183 if (value instanceof Add) {
184 return elaborate(((Add) value).getLeft()) + elaborate(((Add) value).getRight());
185 } else if (value instanceof FieldRef) {
186 return elaborate((FieldRef) value);
187 } else if (value != null) {
188 return stripped(value.toString());
189 } else {
190 return "";
191 }
192 }
193
194 private String elaborate(FieldRef field) {
195 String name = field.getName();
196 String value = constants.get(name);
197 if (value != null) {
198 return stripped(value);
199 }
200 throw new IllegalStateException("Constant " + name + " cannot be elaborated;" +
201 " value not in the same compilation context");
202 }
203
204 private String stripped(String s) {
205 return s.trim().replaceFirst("^[^\"]*\"", "").replaceFirst("\"$", "");
206 }
207
208 private void writeCatalog(JavaClass javaClass, List<String> lines) {
209 File dir = new File(dstDir, javaClass.getPackageName().replace('.', '/'));
210 dir.mkdirs();
211
212 File cfgDef = new File(dir, javaClass.getName().replace('.', '/') + ".cfgdef");
213 try (FileWriter fw = new FileWriter(cfgDef);
214 PrintWriter pw = new PrintWriter(fw)) {
215 pw.println("# This file is auto-generated by onos-maven-plugin");
216 lines.forEach(pw::println);
217 } catch (IOException e) {
218 System.err.println("Unable to write catalog for " + javaClass.getName());
219 e.printStackTrace();
220 }
221 }
222
Thomas Vachuska8c8b0372015-03-10 11:11:24 -0700223 }
Thomas Vachuskad6f88c62019-03-30 10:37:36 -0700224}