2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.controller.config.yangjmxgenerator.plugin;
10 import com.google.common.base.Predicate;
11 import com.google.common.collect.Collections2;
12 import com.google.common.collect.Lists;
13 import com.google.common.collect.Maps;
14 import com.google.common.collect.Sets;
15 import com.google.common.io.Files;
16 import org.apache.commons.io.FileUtils;
17 import org.apache.maven.plugin.logging.Log;
18 import org.apache.maven.project.MavenProject;
19 import org.eclipse.jdt.core.JavaCore;
20 import org.eclipse.jdt.core.compiler.IProblem;
21 import org.eclipse.jdt.core.dom.AST;
22 import org.eclipse.jdt.core.dom.ASTParser;
23 import org.eclipse.jdt.core.dom.ASTVisitor;
24 import org.eclipse.jdt.core.dom.CompilationUnit;
25 import org.eclipse.jdt.core.dom.FieldDeclaration;
26 import org.eclipse.jdt.core.dom.MethodDeclaration;
27 import org.eclipse.jdt.core.dom.NormalAnnotation;
28 import org.eclipse.jdt.core.dom.PackageDeclaration;
29 import org.eclipse.jdt.core.dom.TypeDeclaration;
30 import org.junit.Before;
31 import org.junit.Test;
32 import org.opendaylight.controller.config.api.DependencyResolver;
33 import org.opendaylight.controller.config.api.DependencyResolverFactory;
34 import org.opendaylight.controller.config.api.DynamicMBeanWithInstance;
35 import org.opendaylight.controller.config.api.annotations.Description;
36 import org.opendaylight.controller.config.api.annotations.RequireInterface;
37 import org.opendaylight.controller.config.api.annotations.ServiceInterfaceAnnotation;
38 import org.opendaylight.controller.config.spi.Module;
39 import org.opendaylight.controller.config.spi.ModuleFactory;
40 import org.opendaylight.controller.config.yangjmxgenerator.ConfigConstants;
41 import org.opendaylight.controller.config.yangjmxgenerator.PackageTranslatorTest;
42 import org.opendaylight.controller.config.yangjmxgenerator.ServiceInterfaceEntryTest;
43 import org.osgi.framework.BundleContext;
44 import org.xml.sax.ErrorHandler;
45 import org.xml.sax.InputSource;
46 import org.xml.sax.SAXException;
47 import org.xml.sax.SAXParseException;
49 import javax.xml.parsers.DocumentBuilder;
50 import javax.xml.parsers.DocumentBuilderFactory;
52 import java.io.IOException;
53 import java.nio.charset.Charset;
54 import java.util.ArrayList;
55 import java.util.Arrays;
56 import java.util.Collection;
57 import java.util.Collections;
58 import java.util.HashMap;
59 import java.util.HashSet;
60 import java.util.List;
64 import static org.hamcrest.CoreMatchers.equalTo;
65 import static org.hamcrest.CoreMatchers.is;
66 import static org.junit.Assert.assertEquals;
67 import static org.junit.Assert.assertNotNull;
68 import static org.junit.Assert.assertThat;
69 import static org.junit.Assert.assertTrue;
70 import static org.junit.Assert.assertFalse;
71 import static org.junit.Assert.fail;
72 import static org.junit.matchers.JUnitMatchers.containsString;
73 import static org.mockito.Matchers.any;
74 import static org.mockito.Mockito.mock;
75 import static org.mockito.Mockito.doNothing;
76 import static org.mockito.Mockito.doReturn;
78 public class JMXGeneratorTest extends AbstractGeneratorTest {
80 JMXGenerator jmxGenerator;
82 protected final HashMap<String, String> map = Maps.newHashMap();
83 protected File outputBaseDir;
84 File generatedResourcesDir;
86 private static final List<String> expectedModuleFileNames = ServiceInterfaceEntryTest
87 .toFileNames("[AbstractAsyncEventBusModule.java, AbstractAsyncEventBusModuleFactory.java, " +
88 "AbstractDynamicThreadPoolModule.java, AbstractDynamicThreadPoolModuleFactory.java, " +
89 "AbstractEventBusModule.java, AbstractEventBusModuleFactory.java, " +
90 "AbstractNamingThreadFactoryModule.java, AbstractNamingThreadFactoryModuleFactory.java, " +
91 "AsyncEventBusModule.java, AsyncEventBusModuleFactory.java, AsyncEventBusModuleMXBean.java, " +
92 "AsyncEventBusRuntimeMXBean.java, AsyncEventBusRuntimeRegistration.java, " +
93 "AsyncEventBusRuntimeRegistrator.java, DynamicThreadPoolModule.java, " +
94 "DynamicThreadPoolModuleFactory.java, DynamicThreadPoolModuleMXBean.java, " +
95 "DynamicThreadPoolRuntimeMXBean.java, DynamicThreadPoolRuntimeRegistration.java, " +
96 "DynamicThreadPoolRuntimeRegistrator.java, EventBusModule.java, EventBusModuleFactory.java, " +
97 "EventBusModuleMXBean.java, EventRuntimeMXBean.java, EventRuntimeRegistration.java, " +
98 "InnerStreamList.java, NamingThreadFactoryModule.java, NamingThreadFactoryModuleFactory.java, " +
99 "NamingThreadFactoryModuleMXBean.java, NamingThreadFactoryRuntimeMXBean.java, NamingThreadFactoryRuntimeRegistration.java, NamingThreadFactoryRuntimeRegistrator.java, Peer.java, StreamRuntimeMXBean.java, StreamRuntimeRegistration.java, ThreadRuntimeMXBean.java, ThreadRuntimeRegistration.java, ThreadStreamRuntimeMXBean.java, ThreadStreamRuntimeRegistration.java]");
101 private static final List<String> expectedBGPNames = ServiceInterfaceEntryTest
102 .toFileNames("[AbstractBgpListenerImplModule.java, " + "AbstractBgpListenerImplModuleFactory.java, " +
103 "BgpListenerImplModule.java, " + "BgpListenerImplModuleFactory.java, " +
104 "BgpListenerImplModuleMXBean.java, Peers.java]");
106 private static final List<String> expectedNetconfNames = ServiceInterfaceEntryTest
107 .toFileNames("[AbstractNetconfTestImplModule.java, " + "AbstractNetconfTestImplModuleFactory.java, " +
108 "AbstractTestImplModule.java, " + "AbstractTestImplModuleFactory.java, " +
109 "AutoCloseableServiceInterface.java, " + "ComplexDtoBInner.java, ComplexList.java, Deep.java, " +
110 "DtoA.java, DtoA1.java, DtoAInner.java, DtoAInnerInner.java, DtoB.java, DtoC.java," + "NetconfTestImplModule.java, NetconfTestImplModuleFactory.java," + "NetconfTestImplModuleMXBean.java, Peer.java, SimpleList.java, TestImplModule.java, " + "TestImplModuleFactory.java," + " TestImplModuleMXBean.java" + "]");
111 private static final List<String> expectedTestFiles = ServiceInterfaceEntryTest
112 .toFileNames("[AbstractNetconfTestFileImplModule.java, AbstractNetconfTestFileImplModuleFactory.java, " +
113 "AbstractNetconfTestFiles1ImplModule.java, AbstractNetconfTestFiles1ImplModuleFactory.java, " +
114 "AbstractTestFileImplModule.java, AbstractTestFileImplModuleFactory.java, " +
115 "AbstractTestFiles1ImplModule.java, AbstractTestFiles1ImplModuleFactory.java, DtoA.java, " +
116 "DtoA.java, NetconfTestFileImplModuleMXBean.java, NetconfTestFileImplRuntimeMXBean.java, " +
117 "NetconfTestFileImplRuntimeRegistration.java, NetconfTestFileImplRuntimeRegistrator.java, " +
118 "NetconfTestFiles1ImplModule.java, NetconfTestFiles1ImplModuleFactory.java, " +
119 "NetconfTestFiles1ImplModuleMXBean.java, NetconfTestFiles1ImplRuntimeMXBean.java, " +
120 "NetconfTestFiles1ImplRuntimeRegistration.java, NetconfTestFiles1ImplRuntimeRegistrator.java, TestFileImplModule.java, TestFileImplModuleFactory.java, TestFileImplModuleMXBean.java, TestFileImplRuntimeMXBean.java, TestFileImplRuntimeRegistration.java, TestFileImplRuntimeRegistrator.java, TestFiles1ImplModule.java, TestFiles1ImplModuleFactory.java, TestFiles1ImplModuleMXBean.java, TestFiles1ImplRuntimeMXBean.java, TestFiles1ImplRuntimeRegistration.java, TestFiles1ImplRuntimeRegistrator.java]");
121 private static final List<String> expectedAllFileNames = ServiceInterfaceEntryTest
122 .toFileNames("[AbstractAsyncEventBusModule.java, AbstractAsyncEventBusModuleFactory.java, " +
123 "AbstractBgpListenerImplModule.java, AbstractBgpListenerImplModuleFactory.java, " +
124 "AbstractDynamicThreadPoolModule.java, AbstractDynamicThreadPoolModuleFactory.java, " +
125 "AbstractEventBusModule.java, AbstractEventBusModuleFactory.java, " +
126 "AbstractNamingThreadFactoryModule.java, AbstractNamingThreadFactoryModuleFactory.java, " +
127 "AbstractNetconfTestFileImplModule.java, AbstractNetconfTestFileImplModuleFactory.java, " +
128 "AbstractNetconfTestFiles1ImplModule.java, AbstractNetconfTestFiles1ImplModuleFactory.java, " +
129 "AbstractNetconfTestImplModule.java, AbstractNetconfTestImplModuleFactory.java, " +
130 "AbstractTestFileImplModule.java, AbstractTestFileImplModuleFactory.java, " +
131 "AbstractTestFiles1ImplModule.java, AbstractTestFiles1ImplModuleFactory.java, " +
132 "AbstractTestImplModule.java, AbstractTestImplModuleFactory.java, AsyncEventBusModule.java, " +
133 "AsyncEventBusModuleFactory.java, AsyncEventBusModuleMXBean.java, " +
134 "AsyncEventBusRuntimeMXBean.java, AsyncEventBusRuntimeRegistration.java, " +
135 "AsyncEventBusRuntimeRegistrator.java, AutoCloseableServiceInterface.java, " +
136 "BgpListenerImplModule.java, BgpListenerImplModuleFactory.java, BgpListenerImplModuleMXBean.java," +
137 " BgpListenerImplRuntimeMXBean.java, BgpListenerImplRuntimeRegistration.java, " +
138 "BgpListenerImplRuntimeRegistrator.java, ComplexDtoBInner.java, ComplexList.java, Deep.java, " +
139 "DtoA.java, DtoA.java, DtoA.java, DtoA1.java, DtoAInner.java, DtoAInnerInner.java, DtoB.java, " +
140 "DtoC.java, DynamicThreadPoolModule.java, DynamicThreadPoolModuleFactory.java, " +
141 "DynamicThreadPoolModuleMXBean.java, DynamicThreadPoolRuntimeMXBean.java, " +
142 "DynamicThreadPoolRuntimeRegistration.java, DynamicThreadPoolRuntimeRegistrator.java, " +
143 "EventBusModule.java, EventBusModuleFactory.java, EventBusModuleMXBean.java, " +
144 "EventBusServiceInterface.java, EventRuntimeMXBean.java, EventRuntimeRegistration.java, " +
145 "InnerStreamList.java, NamingThreadFactoryModule.java, NamingThreadFactoryModuleFactory.java, " +
146 "NamingThreadFactoryModuleMXBean.java, NamingThreadFactoryRuntimeMXBean.java, " +
147 "NamingThreadFactoryRuntimeRegistration.java, NamingThreadFactoryRuntimeRegistrator.java, " +
148 "NetconfTestFileImplModule.java, NetconfTestFileImplModuleFactory.java, " +
149 "NetconfTestFileImplModuleMXBean.java, NetconfTestFileImplRuntimeMXBean.java, " +
150 "NetconfTestFileImplRuntimeRegistration.java, NetconfTestFileImplRuntimeRegistrator.java, " +
151 "NetconfTestFiles1ImplModule.java, NetconfTestFiles1ImplModuleFactory.java, " +
152 "NetconfTestFiles1ImplModuleMXBean.java, NetconfTestFiles1ImplRuntimeMXBean.java, " +
153 "NetconfTestFiles1ImplRuntimeRegistration.java, NetconfTestFiles1ImplRuntimeRegistrator.java, NetconfTestImplModule.java, NetconfTestImplModuleFactory.java, NetconfTestImplModuleMXBean.java, NetconfTestImplRuntimeMXBean.java, NetconfTestImplRuntimeRegistration.java, NetconfTestImplRuntimeRegistrator.java, Peer.java, Peer.java, PeersRuntimeMXBean.java, PeersRuntimeRegistration.java, ScheduledThreadPoolServiceInterface.java, SimpleList.java, StreamRuntimeMXBean.java, StreamRuntimeRegistration.java, TestFileImplModule.java, TestFileImplModuleFactory.java, TestFileImplModuleMXBean.java, TestFileImplRuntimeMXBean.java, TestFileImplRuntimeRegistration.java, TestFileImplRuntimeRegistrator.java, TestFiles1ImplModule.java, TestFiles1ImplModuleFactory.java, TestFiles1ImplModuleMXBean.java, TestFiles1ImplRuntimeMXBean.java, TestFiles1ImplRuntimeRegistration.java, TestFiles1ImplRuntimeRegistrator.java, TestImplModule.java, TestImplModuleFactory.java, TestImplModuleMXBean.java, TestImplRuntimeMXBean.java, TestImplRuntimeRegistration.java, TestImplRuntimeRegistrator.java, ThreadFactoryServiceInterface.java, ThreadPoolServiceInterface.java, ThreadRuntimeMXBean.java, ThreadRuntimeRegistration.java, ThreadStreamRuntimeMXBean.java, ThreadStreamRuntimeRegistration.java]");
154 private static final List<String> expectedGenerateMBEsListNames = ServiceInterfaceEntryTest
155 .toFileNames("[AbstractBgpListenerImplModule.java, AbstractBgpListenerImplModuleFactory.java, BgpListenerImplModule.java, BgpListenerImplModuleFactory.java, BgpListenerImplModuleMXBean.java, BgpListenerImplRuntimeMXBean.java, BgpListenerImplRuntimeRegistration.java, BgpListenerImplRuntimeRegistrator.java, PeersRuntimeMXBean.java, PeersRuntimeRegistration.java]");
158 public void setUp() {
159 map.put(JMXGenerator.NAMESPACE_TO_PACKAGE_PREFIX + "1",
160 ConfigConstants.CONFIG_NAMESPACE
161 + JMXGenerator.NAMESPACE_TO_PACKAGE_DIVIDER
162 + PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX);
163 map.put(JMXGenerator.MODULE_FACTORY_FILE_BOOLEAN, "false");
164 jmxGenerator = new JMXGenerator(new FreeMarkerCodeWriterImpl());
165 jmxGenerator.setAdditionalConfig(map);
166 File targetDir = new File(generatorOutputPath, "target");
167 generatedResourcesDir = new File(targetDir, "generated-resources");
168 jmxGenerator.setResourceBaseDir(generatedResourcesDir);
169 Log mockedLog = mock(Log.class);
170 doReturn(false).when(mockedLog).isDebugEnabled();
171 doNothing().when(mockedLog).debug(any(CharSequence.class));
172 doNothing().when(mockedLog).info(any(CharSequence.class));
173 doNothing().when(mockedLog).error(any(CharSequence.class),
174 any(Throwable.class));
175 jmxGenerator.setLog(mockedLog);
176 MavenProject project = mock(MavenProject.class);
177 doReturn(generatorOutputPath).when(project).getBasedir();
178 jmxGenerator.setMavenProject(project);
179 outputBaseDir = JMXGenerator.concatFolders(targetDir,
180 "generated-sources", "config");
184 public void generateSIsMBsTest() {
185 Collection<File> files = jmxGenerator.generateSources(context,
186 outputBaseDir, context.getModules());
187 List<String> expectedFileNames = new ArrayList<>();
189 .addAll(ServiceInterfaceEntryTest.expectedSIEFileNames);
190 expectedFileNames.addAll(expectedModuleFileNames);
192 expectedFileNames.addAll(expectedBGPNames);
193 expectedFileNames.addAll(expectedNetconfNames);
194 expectedFileNames.addAll(expectedTestFiles);
195 Collections.sort(expectedFileNames);
196 // TODO: separate expectedAllFileNames into expectedBGPNames,
197 // expectedNetconfNames
198 assertEquals(expectedAllFileNames, toFileNames(files));
200 verifyModuleFactoryFile(false);
203 private void verifyModuleFactoryFile(boolean shouldBePresent) {
204 File factoryFile = new File(generatedResourcesDir, "META-INF"
205 + File.separator + "services" + File.separator
206 + ModuleFactory.class.getName());
207 if (!shouldBePresent)
208 assertFalse("Factory file should not be generated",
209 factoryFile.exists());
211 assertTrue("Factory file should be generated", factoryFile.exists());
214 public static List<String> toFileNames(Collection<File> files) {
215 List<String> result = new ArrayList<>();
216 for (File f : files) {
217 result.add(f.getName());
219 Collections.sort(result);
224 public void generateSIEsTest() throws IOException {
225 Collection<File> files = jmxGenerator.generateSources(context,
226 outputBaseDir, Sets.newHashSet(threadsModule));
227 assertEquals(ServiceInterfaceEntryTest.expectedSIEFileNames,
230 Map<String, ASTVisitor> verifiers = Maps.newHashMap();
232 for (File file : files) {
233 verifiers.put(file.getName(), new SieASTVisitor());
236 processGeneratedCode(files, verifiers);
238 for (File file : files) {
239 String fileName = file.getName();
240 SieASTVisitor verifier = (SieASTVisitor) verifiers.get(fileName);
242 assertEquals(fileName.substring(0, fileName.length() - 5),
246 containsString("org.opendaylight.controller.config.api.annotations.AbstractServiceInterface"));
247 assertEquals(PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
248 + ".threads", verifier.packageName);
249 assertNotNull(verifier.javadoc);
251 if ("ThreadPoolServiceInterface.java".equals(fileName)) {
252 assertContains(verifier.descriptionAnotValue,
253 "A simple pool of threads able to execute work.");
254 assertContains(verifier.sieAnnotValue, "threadpool");
255 assertContains(verifier.sieAnnotOsgiRegistrationType,
256 PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
257 + ".threadpool.ThreadPool.class");
258 } else if ("ScheduledThreadPoolServiceInterface.java"
260 assertContains(verifier.extnds,
261 PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
262 + ".threads.ThreadPoolServiceInterface");
264 verifier.descriptionAnotValue,
265 "An extension of the simple pool of threads able to schedule work to be executed at some point in time.");
266 assertContains(verifier.sieAnnotValue, "scheduled-threadpool");
267 assertContains(verifier.sieAnnotOsgiRegistrationType,
268 PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
269 + ".threadpool.ScheduledThreadPool.class");
270 } else if ("EventBusServiceInterface.java".equals(fileName)) {
272 verifier.descriptionAnotValue,
273 "Service representing an event bus. The service acts as message router between event producers and event consumers");
274 assertContains(verifier.sieAnnotValue, "eventbus");
275 assertContains(verifier.sieAnnotOsgiRegistrationType,
276 "com.google.common.eventbus.EventBus.class");
277 } else if ("ThreadFactoryServiceInterface.java".equals(fileName)) {
279 verifier.descriptionAnotValue,
280 "Service representing a ThreadFactory instance. It is directly useful in Java world, where various library pieces need to create threads and you may want to inject a customized thread implementation.");
281 assertContains(verifier.sieAnnotValue, "threadfactory");
282 assertContains(verifier.sieAnnotOsgiRegistrationType,
283 "java.util.concurrent.ThreadFactory.class");
285 } else if ("ScheduledExecutorServiceServiceInterface.java"
287 assertContains(verifier.sieAnnotOsgiRegistrationType,
288 "java.util.concurrent.ScheduledExecutorService.class");
290 fail("Unknown generated sie " + fileName);
296 public void generateMBEsListTest() throws Exception {
297 // default value for module factory file is true
298 map.put(JMXGenerator.MODULE_FACTORY_FILE_BOOLEAN, "randomValue");
299 jmxGenerator.setAdditionalConfig(map);
301 Collection<File> files = jmxGenerator.generateSources(context,
302 outputBaseDir, Sets.newHashSet(bgpListenerJavaModule));
304 assertEquals(expectedGenerateMBEsListNames, toFileNames(files));
308 public void generateMBEsTest() throws Exception {
309 // default value for module factory file is true
310 map.put(JMXGenerator.MODULE_FACTORY_FILE_BOOLEAN, "randomValue");
311 jmxGenerator.setAdditionalConfig(map);
313 Collection<File> files = jmxGenerator.generateSources(context,
314 outputBaseDir, Sets.newHashSet(threadsJavaModule));
316 assertEquals(expectedModuleFileNames, toFileNames(files));
318 Map<String, ASTVisitor> verifiers = Maps.newHashMap();
320 Collection<File> xmlFiles = Collections2.filter(files,
321 new Predicate<File>() {
324 public boolean apply(File input) {
325 return input.getName().endsWith("xml");
329 Collection<File> javaFiles = Collections2.filter(files,
330 new Predicate<File>() {
333 public boolean apply(File input) {
334 return input.getName().endsWith("java");
338 MbeASTVisitor abstractDynamicThreadPoolModuleVisitor = null;
339 MbeASTVisitor asyncEventBusModuleMXBeanVisitor = null;
340 MbeASTVisitor abstractNamingThreadFactoryModuleFactoryVisitor = null;
341 MbeASTVisitor asyncEventBusModuleVisitor = null;
342 MbeASTVisitor eventBusModuleFactoryVisitor = null;
344 for (File file : javaFiles) {
345 String name = file.getName();
346 MbeASTVisitor visitor = new MbeASTVisitor();
347 verifiers.put(name, visitor);
348 if (name.equals("AbstractDynamicThreadPoolModule.java"))
349 abstractDynamicThreadPoolModuleVisitor = visitor;
350 if (name.equals("AsyncEventBusModuleMXBean.java"))
351 asyncEventBusModuleMXBeanVisitor = visitor;
352 if (name.equals("AbstractNamingThreadFactoryModuleFactory.java"))
353 abstractNamingThreadFactoryModuleFactoryVisitor = visitor;
354 if (name.equals("AsyncEventBusModule.java"))
355 asyncEventBusModuleVisitor = visitor;
356 if (name.equals("EventBusModuleFactory.java"))
357 eventBusModuleFactoryVisitor = visitor;
360 processGeneratedCode(javaFiles, verifiers);
362 assertAbstractDynamicThreadPoolModule(abstractDynamicThreadPoolModuleVisitor);
363 assertAsyncEventBusModuleMXBean(asyncEventBusModuleMXBeanVisitor);
364 assertAbstractNamingThreadFactoryModuleFactory(abstractNamingThreadFactoryModuleFactoryVisitor);
365 assertAsyncEventBusModule(asyncEventBusModuleVisitor);
366 assertEventBusModuleFactory(eventBusModuleFactoryVisitor);
368 verifyXmlFiles(xmlFiles);
369 // verify ModuleFactory file
370 File moduleFactoryFile = JMXGenerator.concatFolders(
371 generatedResourcesDir, "META-INF", "services",
372 ModuleFactory.class.getName());
373 assertThat(moduleFactoryFile.exists(), is(true));
374 Set<String> lines = Sets.newHashSet(FileUtils
375 .readLines(moduleFactoryFile));
376 Set<String> expectedLines = Sets.newHashSet(//
377 PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
378 + ".threads.java.EventBusModuleFactory",//
379 PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
380 + ".threads.java.AsyncEventBusModuleFactory", //
381 PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
382 + ".threads.java.DynamicThreadPoolModuleFactory",//
383 PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
384 + ".threads.java.NamingThreadFactoryModuleFactory");
385 assertThat(lines, equalTo(expectedLines));
389 private void verifyXmlFiles(Collection<File> xmlFiles) throws Exception {
390 ErrorHandler errorHandler = new ErrorHandler() {
393 public void warning(SAXParseException exception)
394 throws SAXException {
395 fail("Generated blueprint xml is not well formed "
396 + exception.getMessage());
400 public void fatalError(SAXParseException exception)
401 throws SAXException {
402 fail("Generated blueprint xml is not well formed "
403 + exception.getMessage());
407 public void error(SAXParseException exception) throws SAXException {
408 fail("Generated blueprint xml is not well formed "
409 + exception.getMessage());
413 for (File file : xmlFiles) {
414 DocumentBuilderFactory factory = DocumentBuilderFactory
416 factory.setValidating(false);
417 factory.setNamespaceAware(true);
419 DocumentBuilder builder = factory.newDocumentBuilder();
421 builder.setErrorHandler(errorHandler);
422 builder.parse(new InputSource(file.getPath()));
427 private void assertEventBusModuleFactory(MbeASTVisitor visitor) {
428 assertEquals(PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
429 + ".threads.java", visitor.packageName);
430 assertEquals("EventBusModuleFactory", visitor.type);
431 assertContains(visitor.extnds,
432 PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
433 + ".threads.java.AbstractEventBusModuleFactory");
435 assertEquals(0, visitor.fieldDeclarations.size());
437 assertEquals("Incorrenct number of generated methods", 0,
438 visitor.methods.size());
439 assertEquals("Incorrenct number of generated constructors", 0,
440 visitor.constructors.size());
441 assertEquals("Incorrenct number of generated method descriptions", 0,
442 visitor.methodDescriptions.size());
443 assertEquals("Incorrenct number of generated method javadoc", 0,
444 visitor.methodJavadoc.size());
447 private void assertAsyncEventBusModule(MbeASTVisitor visitor) {
448 assertEquals(PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
449 + ".threads.java", visitor.packageName);
450 assertEquals("AsyncEventBusModule", visitor.type);
451 assertContains(visitor.extnds,
452 PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
453 + ".threads.java.AbstractAsyncEventBusModule");
455 assertEquals(0, visitor.fieldDeclarations.size());
457 assertEquals("Incorrenct number of generated methods", 2,
458 visitor.methods.size());
459 assertEquals("Incorrenct number of generated constructors", 2,
460 visitor.constructors.size());
461 assertEquals("Incorrenct number of generated method descriptions", 0,
462 visitor.methodDescriptions.size());
463 assertEquals("Incorrenct number of generated method javadoc", 0,
464 visitor.methodJavadoc.size());
467 private void assertAbstractNamingThreadFactoryModuleFactory(
468 MbeASTVisitor visitor) {
469 assertEquals(PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
470 + ".threads.java", visitor.packageName);
471 assertEquals("AbstractNamingThreadFactoryModuleFactory", visitor.type);
472 assertContains(visitor.implmts,
473 "org.opendaylight.controller.config.spi.ModuleFactory");
474 Set<String> fieldDeclarations = visitor.fieldDeclarations;
475 assertDeclaredField(fieldDeclarations,
476 "public static final java.lang.String NAME=\"threadfactory-naming\"");
479 "private static final java.util.Set<Class<? extends org.opendaylight.controller.config.api.annotations.AbstractServiceInterface>> serviceIfcs=new java.util.HashSet<Class<? extends org.opendaylight.controller.config.api.annotations.AbstractServiceInterface>>()");
481 assertEquals(2, fieldDeclarations.size());
483 assertFactoryMethods(visitor.methods, 8);
484 assertEquals("Incorrenct number of generated method descriptions", 0,
485 visitor.methodDescriptions.size());
486 assertEquals("Incorrenct number of generated method javadoc", 0,
487 visitor.methodJavadoc.size());
491 private void assertFactoryMethods(Set<String> methods, int expectedSize) {
493 List<ArgumentAssertion> args = Lists.newArrayList();
494 ArgumentAssertion oldInstanceArg = new ArgumentAssertion(DynamicMBeanWithInstance.class.getCanonicalName(), "old");
495 ArgumentAssertion instanceNameArg = new ArgumentAssertion(String.class.getSimpleName(), "instanceName");
496 ArgumentAssertion dependencyResolverArg = new ArgumentAssertion(DependencyResolver.class.getCanonicalName(), "dependencyResolver");
497 ArgumentAssertion bundleContextArg = new ArgumentAssertion(BundleContext.class.getCanonicalName(), "bundleContext");
499 assertMethodPresent(methods, new MethodAssertion(String.class.getSimpleName(), "getImplementationName"));
501 args.add(instanceNameArg);
502 args.add(dependencyResolverArg);
503 args.add(bundleContextArg);
504 assertMethodPresent(methods, new MethodAssertion(Module.class.getCanonicalName(), "createModule", args));
506 args.add(2, oldInstanceArg);
507 assertMethodPresent(methods, new MethodAssertion(Module.class.getCanonicalName(), "createModule", args));
510 args.add(oldInstanceArg);
511 assertMethodPresent(methods, new MethodAssertion("org.opendaylight.controller.config.threads.java.NamingThreadFactoryModule", "handleChangedClass", args));
514 args.add(instanceNameArg);
515 args.add(dependencyResolverArg);
516 args.add(bundleContextArg);
517 assertMethodPresent(methods, new MethodAssertion("org.opendaylight.controller.config.threads.java.NamingThreadFactoryModule", "instantiateModule", args));
520 args.add(2, new ArgumentAssertion("org.opendaylight.controller.config.threads.java.NamingThreadFactoryModule", "oldModule"));
521 args.add(3, new ArgumentAssertion(AutoCloseable.class.getCanonicalName(), "oldInstance"));
522 assertMethodPresent(methods, new MethodAssertion("org.opendaylight.controller.config.threads.java.NamingThreadFactoryModule", "instantiateModule", args));
525 args.add(new ArgumentAssertion(DependencyResolverFactory.class.getCanonicalName(), "dependencyResolverFactory"));
526 args.add(bundleContextArg);
527 assertMethodPresent(methods, new MethodAssertion("java.util.Set<org.opendaylight.controller.config.threads.java.NamingThreadFactoryModule>", "getDefaultModules", args));
530 args.add(new ArgumentAssertion("Class<? extends org.opendaylight.controller.config.api.annotations.AbstractServiceInterface>", "serviceInterface"));
531 assertMethodPresent(methods, new MethodAssertion("boolean", "isModuleImplementingServiceInterface", args));
533 assertEquals(methods.size(), expectedSize);
537 private void assertMethodPresent(Set<String> methods, MethodAssertion methodAssertion) {
538 assertTrue(String.format("Generated methods did not contain %s, generated methods: %s",
539 methodAssertion.toString(), methods), methods.contains(methodAssertion.toString()));
542 private void assertAsyncEventBusModuleMXBean(MbeASTVisitor visitor) {
543 assertEquals(PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
544 + ".threads.java", visitor.packageName);
545 assertEquals("AsyncEventBusModuleMXBean", visitor.type);
547 assertEquals("Incorrenct number of generated methods", 2,
548 visitor.methods.size());
551 private void assertAbstractDynamicThreadPoolModule(MbeASTVisitor visitor) {
552 assertEquals(PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
553 + ".threads.java", visitor.packageName);
554 assertNotNull(visitor.javadoc);
555 assertContains(visitor.descriptionAnotValue,
556 "threadpool-dynamic description");
557 assertEquals("AbstractDynamicThreadPoolModule", visitor.type);
558 assertContains(visitor.implmts,
559 PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
560 + ".threads.java.DynamicThreadPoolModuleMXBean",
561 Module.class.getCanonicalName(),
562 PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
563 + ".threads.ScheduledThreadPoolServiceInterface",
564 PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
565 + ".threads.ThreadPoolServiceInterface");
566 assertEquals(2, visitor.constructors.size());
567 Set<String> fieldDeclarations = visitor.fieldDeclarations;
568 assertDeclaredField(fieldDeclarations,
569 "private java.lang.Long maximumSize");
570 assertDeclaredField(fieldDeclarations,
571 "private javax.management.ObjectName threadfactory");
572 assertDeclaredField(fieldDeclarations,
573 "private java.util.concurrent.ThreadFactory threadfactoryDependency");
574 assertDeclaredField(fieldDeclarations,
575 "private java.lang.Long keepAlive=10");
576 assertDeclaredField(fieldDeclarations,
577 "private java.lang.Long coreSize");
578 assertDeclaredField(fieldDeclarations, "private byte[] binary");
579 assertEquals(22, fieldDeclarations.size());
581 assertEquals(1, visitor.requireIfc.size());
582 String reqIfc = visitor.requireIfc.get("setThreadfactory");
583 assertNotNull("Missing generated setter for threadfactory", reqIfc);
584 assertContains(reqIfc, PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
585 + ".threads.ThreadFactoryServiceInterface");
587 assertEquals("Incorrenct number of generated methods", 27,
588 visitor.methods.size());
589 assertEquals("Incorrenct number of generated method descriptions", 3,
590 visitor.methodDescriptions.size());
591 assertEquals("Incorrenct number of generated method javadoc", 3,
592 visitor.methodJavadoc.size());
593 assertNotNull("Missing javadoc for setMaximumSize method " + visitor.methodJavadoc,
594 visitor.methodJavadoc.get("void setMaximumSize(java.lang.Long maximumSize)"));
597 private void assertDeclaredField(Set<String> fieldDeclarations,
598 String declaration) {
599 assertTrue("Missing field " + declaration + ", got: "
601 fieldDeclarations.contains(declaration + ";\n"));
604 private static class SieASTVisitor extends ASTVisitor {
605 protected String packageName, descriptionAnotValue, sieAnnotValue,
606 sieAnnotOsgiRegistrationType, type, extnds, javadoc;
607 protected Map<String, String> methodDescriptions = Maps.newHashMap();
610 public boolean visit(PackageDeclaration node) {
611 packageName = node.getName().toString();
612 return super.visit(node);
616 public boolean visit(NormalAnnotation node) {
617 if (node.getTypeName().toString()
618 .equals(Description.class.getCanonicalName())) {
619 if (node.getParent() instanceof TypeDeclaration) {
620 descriptionAnotValue = node.values().get(0).toString();
621 } else if (node.getParent() instanceof MethodDeclaration) {
622 String descr = node.values().get(0).toString();
623 methodDescriptions.put(((MethodDeclaration) node
624 .getParent()).getName().toString(), descr);
629 .equals(ServiceInterfaceAnnotation.class.getCanonicalName())) {
630 String text1 = node.values().get(0).toString();
631 String text2 = node.values().get(1).toString();
632 if (text1.contains("value")) {
633 sieAnnotValue = text1;
634 sieAnnotOsgiRegistrationType = text2;
636 sieAnnotValue = text2;
637 sieAnnotOsgiRegistrationType = text1;
640 return super.visit(node);
644 public boolean visit(TypeDeclaration node) {
645 javadoc = node.getJavadoc() == null ? null : node.getJavadoc()
647 type = node.getName().toString();
648 List<?> superIfcs = node.superInterfaceTypes();
649 extnds = superIfcs != null && !superIfcs.isEmpty() ? superIfcs
651 return super.visit(node);
655 private static class MbeASTVisitor extends SieASTVisitor {
656 private String implmts;
657 private final Set<String> fieldDeclarations = Sets.newHashSet();
658 private final Set<String> constructors = Sets.newHashSet();
659 private final Set<String> methods = new HashSet<String>();
660 private final Map<String, String> requireIfc = Maps.newHashMap();
661 private final Map<String, String> methodJavadoc = Maps.newHashMap();
664 public boolean visit(NormalAnnotation node) {
665 boolean result = super.visit(node);
666 if (node.getTypeName().toString()
667 .equals(RequireInterface.class.getCanonicalName())
668 && node.getParent() instanceof MethodDeclaration) {
669 // remember only top level description annotation
670 String reqVal = node.values().get(0).toString();
671 requireIfc.put(((MethodDeclaration) node.getParent()).getName()
672 .toString(), reqVal);
678 public boolean visit(FieldDeclaration node) {
679 fieldDeclarations.add(node.toString());
680 return super.visit(node);
684 public boolean visit(MethodDeclaration node) {
685 if (node.isConstructor())
686 constructors.add(node.toString());
688 String methodSignature = node.getReturnType2() + " " + node.getName() + "(";
689 boolean first = true;
690 for (Object o : node.parameters()) {
694 methodSignature += ",";
696 methodSignature += o.toString();
698 methodSignature += ")";
699 methods.add(methodSignature);
700 if (node.getJavadoc() != null) {
701 methodJavadoc.put(methodSignature, node.getJavadoc().toString());
704 return super.visit(node);
708 public boolean visit(TypeDeclaration node) {
709 boolean visit = super.visit(node);
710 List<?> superIfcs = node.superInterfaceTypes();
711 implmts = superIfcs != null && !superIfcs.isEmpty() ? superIfcs
713 extnds = node.getSuperclassType() == null ? null : node
714 .getSuperclassType().toString();
720 private void assertContains(String source, String... contained) {
721 for (String string : contained) {
722 assertThat(source, containsString(string));
726 private void processGeneratedCode(Collection<File> files,
727 Map<String, ASTVisitor> verifiers) throws IOException {
728 ASTParser parser = ASTParser.newParser(AST.JLS3);
729 Map<?, ?> options = JavaCore.getOptions();
730 JavaCore.setComplianceOptions(JavaCore.VERSION_1_7, options);
731 parser.setCompilerOptions(options);
733 parser.setKind(ASTParser.K_COMPILATION_UNIT);
735 for (File file : files) {
736 char[] source = readFileAsChars(file);
737 parser.setSource(source);
738 parser.setResolveBindings(true);
740 CompilationUnit cu = (CompilationUnit) parser.createAST(null);
741 // Check for compilation problems in generated file
742 for (IProblem c : cu.getProblems()) {
743 // 1610613332 = Syntax error, annotations are only available if
744 // source level is 5.0
745 if (c.getID() == 1610613332)
747 // 1610613332 = Syntax error, parameterized types are only
748 // available if source level is 5.0
749 if (c.getID() == 1610613329)
751 if (c.getID() == 1610613328) // 'for each' statements are only available if source level is 5.0
753 fail("Error in generated source code " + file + ":"
754 + c.getSourceLineNumber() + " id: " + c.getID() + " message:" + c.toString());
757 ASTVisitor visitor = verifiers.get(file.getName());
759 fail("Unknown generated file " + file.getName());
765 public static char[] readFileAsChars(File file) throws IOException {
766 List<String> readLines = Files
767 .readLines(file, Charset.forName("utf-8"));
768 char[] retVal = new char[0];
769 for (String string : readLines) {
770 char[] line = string.toCharArray();
771 int beforeLength = retVal.length;
772 retVal = Arrays.copyOf(retVal, retVal.length + line.length + 1);
773 System.arraycopy(line, 0, retVal, beforeLength, line.length);
774 retVal[retVal.length - 1] = '\n';
779 private static class MethodAssertion extends ArgumentAssertion{
781 private List<ArgumentAssertion> arguments;
784 MethodAssertion(String type, String name, List<ArgumentAssertion> arguments) {
786 this.arguments = arguments;
789 MethodAssertion(String type, String name) {
790 this(type, name, Collections.<ArgumentAssertion>emptyList());
794 public String toString() {
795 final StringBuffer sb = new StringBuffer();
796 sb.append(type).append(' ');
797 sb.append(name).append('(');
800 for (ArgumentAssertion argument : arguments) {
801 sb.append(argument.type).append(' ');
802 sb.append(argument.name);
803 if(++i != arguments.size())
807 return sb.toString();
811 private static class ArgumentAssertion {
813 protected final String type, name;
815 private ArgumentAssertion(String type, String name) {
821 public String toString() {
822 final StringBuffer sb = new StringBuffer();
823 sb.append(type).append(' ');
825 return sb.toString();