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;
79 public class JMXGeneratorTest extends AbstractGeneratorTest {
81 JMXGenerator jmxGenerator;
83 protected final HashMap<String, String> map = Maps.newHashMap();
84 protected File outputBaseDir;
85 File generatedResourcesDir;
87 private static final List<String> expectedModuleFileNames = ServiceInterfaceEntryTest
88 .toFileNames("[AbstractAsyncEventBusModule.java, AbstractAsyncEventBusModuleFactory.java, AbstractDynamicThreadPoolModule.java, AbstractDynamicThreadPoolModuleFactory.java, AbstractEventBusModule.java, AbstractEventBusModuleFactory.java, AbstractNamingThreadFactoryModule.java, AbstractNamingThreadFactoryModuleFactory.java, AbstractThreadPoolRegistryImplModule.java, AbstractThreadPoolRegistryImplModuleFactory.java, AsyncEventBusModule.java, AsyncEventBusModuleFactory.java, AsyncEventBusModuleMXBean.java, AsyncEventBusRuntimeMXBean.java, AsyncEventBusRuntimeRegistration.java, AsyncEventBusRuntimeRegistrator.java, DynamicThreadPoolModule.java, DynamicThreadPoolModuleFactory.java, DynamicThreadPoolModuleMXBean.java, DynamicThreadPoolRuntimeMXBean.java, DynamicThreadPoolRuntimeRegistration.java, DynamicThreadPoolRuntimeRegistrator.java, EventBusModule.java, EventBusModuleFactory.java, EventBusModuleMXBean.java, EventRuntimeMXBean.java, EventRuntimeRegistration.java, InnerStreamList.java, NamingThreadFactoryModule.java, NamingThreadFactoryModuleFactory.java, NamingThreadFactoryModuleMXBean.java, NamingThreadFactoryRuntimeMXBean.java, NamingThreadFactoryRuntimeRegistration.java, NamingThreadFactoryRuntimeRegistrator.java, Peer.java, StreamRuntimeMXBean.java, StreamRuntimeRegistration.java, ThreadPoolRegistryImplModule.java, ThreadPoolRegistryImplModuleFactory.java, ThreadPoolRegistryImplModuleMXBean.java, ThreadRuntimeMXBean.java, ThreadRuntimeRegistration.java, ThreadStreamRuntimeMXBean.java, ThreadStreamRuntimeRegistration.java]");
90 private static final List<String> expectedBGPNames = ServiceInterfaceEntryTest
91 .toFileNames("[AbstractBgpListenerImplModule.java, " + "AbstractBgpListenerImplModuleFactory.java, " +
92 "BgpListenerImplModule.java, " + "BgpListenerImplModuleFactory.java, " +
93 "BgpListenerImplModuleMXBean.java, Peers.java]");
95 private static final List<String> expectedNetconfNames = ServiceInterfaceEntryTest
96 .toFileNames("[AbstractNetconfTestImplModule.java, " + "AbstractNetconfTestImplModuleFactory.java, " +
97 "AbstractTestImplModule.java, " + "AbstractTestImplModuleFactory.java, " +
98 "AutoCloseableServiceInterface.java, " + "ComplexDtoBInner.java, ComplexList.java, Deep.java, " +
99 "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" + "]");
100 private static final List<String> expectedTestFiles = ServiceInterfaceEntryTest
101 .toFileNames("[AbstractNetconfTestFileImplModule.java, AbstractNetconfTestFileImplModuleFactory.java, " +
102 "AbstractNetconfTestFiles1ImplModule.java, AbstractNetconfTestFiles1ImplModuleFactory.java, " +
103 "AbstractTestFileImplModule.java, AbstractTestFileImplModuleFactory.java, " +
104 "AbstractTestFiles1ImplModule.java, AbstractTestFiles1ImplModuleFactory.java, DtoA.java, " +
105 "DtoA.java, NetconfTestFileImplModuleMXBean.java, NetconfTestFileImplRuntimeMXBean.java, " +
106 "NetconfTestFileImplRuntimeRegistration.java, NetconfTestFileImplRuntimeRegistrator.java, " +
107 "NetconfTestFiles1ImplModule.java, NetconfTestFiles1ImplModuleFactory.java, " +
108 "NetconfTestFiles1ImplModuleMXBean.java, NetconfTestFiles1ImplRuntimeMXBean.java, " +
109 "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]");
110 private static final List<String> expectedAllFileNames = ServiceInterfaceEntryTest
111 .toFileNames("[AbstractAsyncEventBusModule.java, AbstractAsyncEventBusModuleFactory.java, AbstractBgpListenerImplModule.java, AbstractBgpListenerImplModuleFactory.java, AbstractDynamicThreadPoolModule.java, AbstractDynamicThreadPoolModuleFactory.java, AbstractEventBusModule.java, AbstractEventBusModuleFactory.java, AbstractNamingThreadFactoryModule.java, AbstractNamingThreadFactoryModuleFactory.java, AbstractNetconfTestFileImplModule.java, AbstractNetconfTestFileImplModuleFactory.java, AbstractNetconfTestFiles1ImplModule.java, AbstractNetconfTestFiles1ImplModuleFactory.java, AbstractNetconfTestImplModule.java, AbstractNetconfTestImplModuleFactory.java, AbstractTestFileImplModule.java, AbstractTestFileImplModuleFactory.java, AbstractTestFiles1ImplModule.java, AbstractTestFiles1ImplModuleFactory.java, AbstractTestImplModule.java, AbstractTestImplModuleFactory.java, AbstractThreadPoolRegistryImplModule.java, AbstractThreadPoolRegistryImplModuleFactory.java, AsyncEventBusModule.java, AsyncEventBusModuleFactory.java, AsyncEventBusModuleMXBean.java, AsyncEventBusRuntimeMXBean.java, AsyncEventBusRuntimeRegistration.java, AsyncEventBusRuntimeRegistrator.java, AutoCloseableServiceInterface.java, BgpListenerImplModule.java, BgpListenerImplModuleFactory.java, BgpListenerImplModuleMXBean.java, BgpListenerImplRuntimeMXBean.java, BgpListenerImplRuntimeRegistration.java, BgpListenerImplRuntimeRegistrator.java, ComplexDtoBInner.java, ComplexList.java, Deep.java, DtoA.java, DtoA.java, DtoA.java, DtoA1.java, DtoAInner.java, DtoAInnerInner.java, DtoB.java, DtoC.java, DynamicThreadPoolModule.java, DynamicThreadPoolModuleFactory.java, DynamicThreadPoolModuleMXBean.java, DynamicThreadPoolRuntimeMXBean.java, DynamicThreadPoolRuntimeRegistration.java, DynamicThreadPoolRuntimeRegistrator.java, EventBusModule.java, EventBusModuleFactory.java, EventBusModuleMXBean.java, EventBusServiceInterface.java, EventRuntimeMXBean.java, EventRuntimeRegistration.java, InnerStreamList.java, NamingThreadFactoryModule.java, NamingThreadFactoryModuleFactory.java, NamingThreadFactoryModuleMXBean.java, NamingThreadFactoryRuntimeMXBean.java, NamingThreadFactoryRuntimeRegistration.java, NamingThreadFactoryRuntimeRegistrator.java, NetconfTestFileImplModule.java, NetconfTestFileImplModuleFactory.java, NetconfTestFileImplModuleMXBean.java, NetconfTestFileImplRuntimeMXBean.java, NetconfTestFileImplRuntimeRegistration.java, NetconfTestFileImplRuntimeRegistrator.java, NetconfTestFiles1ImplModule.java, NetconfTestFiles1ImplModuleFactory.java, NetconfTestFiles1ImplModuleMXBean.java, NetconfTestFiles1ImplRuntimeMXBean.java, 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, ThreadPoolRegistryImplModule.java, ThreadPoolRegistryImplModuleFactory.java, ThreadPoolRegistryImplModuleMXBean.java, ThreadPoolServiceInterface.java, ThreadRuntimeMXBean.java, ThreadRuntimeRegistration.java, ThreadStreamRuntimeMXBean.java, ThreadStreamRuntimeRegistration.java]");
112 private static final List<String> expectedGenerateMBEsListNames = ServiceInterfaceEntryTest
113 .toFileNames("[AbstractBgpListenerImplModule.java, AbstractBgpListenerImplModuleFactory.java, BgpListenerImplModule.java, BgpListenerImplModuleFactory.java, BgpListenerImplModuleMXBean.java, BgpListenerImplRuntimeMXBean.java, BgpListenerImplRuntimeRegistration.java, BgpListenerImplRuntimeRegistrator.java, PeersRuntimeMXBean.java, PeersRuntimeRegistration.java]");
116 public void setUp() {
117 map.put(JMXGenerator.NAMESPACE_TO_PACKAGE_PREFIX + "1",
118 ConfigConstants.CONFIG_NAMESPACE
119 + JMXGenerator.NAMESPACE_TO_PACKAGE_DIVIDER
120 + PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX);
121 map.put(JMXGenerator.MODULE_FACTORY_FILE_BOOLEAN, "false");
122 jmxGenerator = new JMXGenerator(new FreeMarkerCodeWriterImpl());
123 jmxGenerator.setAdditionalConfig(map);
124 File targetDir = new File(generatorOutputPath, "target");
125 generatedResourcesDir = new File(targetDir, "generated-resources");
126 jmxGenerator.setResourceBaseDir(generatedResourcesDir);
127 Log mockedLog = mock(Log.class);
128 doReturn(false).when(mockedLog).isDebugEnabled();
129 doNothing().when(mockedLog).debug(any(CharSequence.class));
130 doNothing().when(mockedLog).info(any(CharSequence.class));
131 doNothing().when(mockedLog).error(any(CharSequence.class),
132 any(Throwable.class));
133 jmxGenerator.setLog(mockedLog);
134 MavenProject project = mock(MavenProject.class);
135 doReturn(generatorOutputPath).when(project).getBasedir();
136 jmxGenerator.setMavenProject(project);
137 outputBaseDir = JMXGenerator.concatFolders(targetDir,
138 "generated-sources", "config");
142 public void generateSIsMBsTest() {
143 Collection<File> files = jmxGenerator.generateSources(context,
144 outputBaseDir, context.getModules());
145 List<String> expectedFileNames = new ArrayList<>();
147 .addAll(ServiceInterfaceEntryTest.expectedSIEFileNames);
148 expectedFileNames.addAll(expectedModuleFileNames);
150 expectedFileNames.addAll(expectedBGPNames);
151 expectedFileNames.addAll(expectedNetconfNames);
152 expectedFileNames.addAll(expectedTestFiles);
153 Collections.sort(expectedFileNames);
154 // TODO: separate expectedAllFileNames into expectedBGPNames,
155 // expectedNetconfNames
156 assertEquals(expectedAllFileNames, toFileNames(files));
158 verifyModuleFactoryFile(false);
161 private void verifyModuleFactoryFile(boolean shouldBePresent) {
162 File factoryFile = new File(generatedResourcesDir, "META-INF"
163 + File.separator + "services" + File.separator
164 + ModuleFactory.class.getName());
165 if (!shouldBePresent)
166 assertFalse("Factory file should not be generated",
167 factoryFile.exists());
169 assertTrue("Factory file should be generated", factoryFile.exists());
172 public static List<String> toFileNames(Collection<File> files) {
173 List<String> result = new ArrayList<>();
174 for (File f : files) {
175 result.add(f.getName());
177 Collections.sort(result);
182 public void generateSIEsTest() throws IOException {
183 Collection<File> files = jmxGenerator.generateSources(context,
184 outputBaseDir, Sets.newHashSet(threadsModule));
185 assertEquals(ServiceInterfaceEntryTest.expectedSIEFileNames,
188 Map<String, ASTVisitor> verifiers = Maps.newHashMap();
190 for (File file : files) {
191 verifiers.put(file.getName(), new SieASTVisitor());
194 processGeneratedCode(files, verifiers);
196 for (File file : files) {
197 String fileName = file.getName();
198 SieASTVisitor verifier = (SieASTVisitor) verifiers.get(fileName);
200 assertEquals(fileName.substring(0, fileName.length() - 5),
204 containsString("org.opendaylight.controller.config.api.annotations.AbstractServiceInterface"));
205 assertEquals(PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
206 + ".threads", verifier.packageName);
207 assertNotNull(verifier.javadoc);
209 if ("ThreadPoolServiceInterface.java".equals(fileName)) {
210 assertContains(verifier.descriptionAnotValue,
211 "A simple pool of threads able to execute work.");
212 assertContains(verifier.sieAnnotValue, "threadpool");
213 assertContains(verifier.sieAnnotOsgiRegistrationType,
214 PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
215 + ".threadpool.ThreadPool.class");
216 } else if ("ScheduledThreadPoolServiceInterface.java"
218 assertContains(verifier.extnds,
219 PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
220 + ".threads.ThreadPoolServiceInterface");
222 verifier.descriptionAnotValue,
223 "An extension of the simple pool of threads able to schedule work to be executed at some point in time.");
224 assertContains(verifier.sieAnnotValue, "scheduled-threadpool");
225 assertContains(verifier.sieAnnotOsgiRegistrationType,
226 PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
227 + ".threadpool.ScheduledThreadPool.class");
228 } else if ("EventBusServiceInterface.java".equals(fileName)) {
230 verifier.descriptionAnotValue,
231 "Service representing an event bus. The service acts as message router between event producers and event consumers");
232 assertContains(verifier.sieAnnotValue, "eventbus");
233 assertContains(verifier.sieAnnotOsgiRegistrationType,
234 "com.google.common.eventbus.EventBus.class");
235 } else if ("ThreadFactoryServiceInterface.java".equals(fileName)) {
237 verifier.descriptionAnotValue,
238 "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.");
239 assertContains(verifier.sieAnnotValue, "threadfactory");
240 assertContains(verifier.sieAnnotOsgiRegistrationType,
241 "java.util.concurrent.ThreadFactory.class");
243 } else if ("ScheduledExecutorServiceServiceInterface.java"
245 assertContains(verifier.sieAnnotOsgiRegistrationType,
246 "java.util.concurrent.ScheduledExecutorService.class");
248 fail("Unknown generated sie " + fileName);
254 public void generateMBEsListTest() throws Exception {
255 // default value for module factory file is true
256 map.put(JMXGenerator.MODULE_FACTORY_FILE_BOOLEAN, "randomValue");
257 jmxGenerator.setAdditionalConfig(map);
259 Collection<File> files = jmxGenerator.generateSources(context,
260 outputBaseDir, Sets.newHashSet(bgpListenerJavaModule));
262 assertEquals(expectedGenerateMBEsListNames, toFileNames(files));
266 public void generateMBEsTest() throws Exception {
267 // default value for module factory file is true
268 map.put(JMXGenerator.MODULE_FACTORY_FILE_BOOLEAN, "randomValue");
269 jmxGenerator.setAdditionalConfig(map);
271 Collection<File> files = jmxGenerator.generateSources(context,
272 outputBaseDir, Sets.newHashSet(threadsJavaModule));
274 assertEquals(expectedModuleFileNames, toFileNames(files));
276 Map<String, ASTVisitor> verifiers = Maps.newHashMap();
278 Collection<File> xmlFiles = Collections2.filter(files,
279 new Predicate<File>() {
282 public boolean apply(File input) {
283 return input.getName().endsWith("xml");
287 Collection<File> javaFiles = Collections2.filter(files,
288 new Predicate<File>() {
291 public boolean apply(File input) {
292 return input.getName().endsWith("java");
296 MbeASTVisitor abstractDynamicThreadPoolModuleVisitor = null;
297 MbeASTVisitor asyncEventBusModuleMXBeanVisitor = null;
298 MbeASTVisitor abstractNamingThreadFactoryModuleFactoryVisitor = null;
299 MbeASTVisitor asyncEventBusModuleVisitor = null;
300 MbeASTVisitor eventBusModuleFactoryVisitor = null;
302 for (File file : javaFiles) {
303 String name = file.getName();
304 MbeASTVisitor visitor = new MbeASTVisitor();
305 verifiers.put(name, visitor);
306 if (name.equals("AbstractDynamicThreadPoolModule.java"))
307 abstractDynamicThreadPoolModuleVisitor = visitor;
308 if (name.equals("AsyncEventBusModuleMXBean.java"))
309 asyncEventBusModuleMXBeanVisitor = visitor;
310 if (name.equals("AbstractNamingThreadFactoryModuleFactory.java"))
311 abstractNamingThreadFactoryModuleFactoryVisitor = visitor;
312 if (name.equals("AsyncEventBusModule.java"))
313 asyncEventBusModuleVisitor = visitor;
314 if (name.equals("EventBusModuleFactory.java"))
315 eventBusModuleFactoryVisitor = visitor;
318 processGeneratedCode(javaFiles, verifiers);
320 assertAbstractDynamicThreadPoolModule(abstractDynamicThreadPoolModuleVisitor);
321 assertAsyncEventBusModuleMXBean(asyncEventBusModuleMXBeanVisitor);
322 assertAbstractNamingThreadFactoryModuleFactory(abstractNamingThreadFactoryModuleFactoryVisitor);
323 assertAsyncEventBusModule(asyncEventBusModuleVisitor);
324 assertEventBusModuleFactory(eventBusModuleFactoryVisitor);
326 verifyXmlFiles(xmlFiles);
327 // verify ModuleFactory file
328 File moduleFactoryFile = JMXGenerator.concatFolders(
329 generatedResourcesDir, "META-INF", "services",
330 ModuleFactory.class.getName());
331 assertThat(moduleFactoryFile.exists(), is(true));
332 Set<String> lines = Sets.newHashSet(FileUtils
333 .readLines(moduleFactoryFile));
334 Set<String> expectedLines = Sets.newHashSet(//
335 PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
336 + ".threads.java.EventBusModuleFactory",//
337 PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
338 + ".threads.java.AsyncEventBusModuleFactory", //
339 PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
340 + ".threads.java.DynamicThreadPoolModuleFactory",//
341 PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
342 + ".threads.java.NamingThreadFactoryModuleFactory", //
343 PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
344 + ".threads.java.ThreadPoolRegistryImplModuleFactory");
347 assertThat(lines, equalTo(expectedLines));
351 private void verifyXmlFiles(Collection<File> xmlFiles) throws Exception {
352 ErrorHandler errorHandler = new ErrorHandler() {
355 public void warning(SAXParseException exception)
356 throws SAXException {
357 fail("Generated blueprint xml is not well formed "
358 + exception.getMessage());
362 public void fatalError(SAXParseException exception)
363 throws SAXException {
364 fail("Generated blueprint xml is not well formed "
365 + exception.getMessage());
369 public void error(SAXParseException exception) throws SAXException {
370 fail("Generated blueprint xml is not well formed "
371 + exception.getMessage());
375 for (File file : xmlFiles) {
376 DocumentBuilderFactory factory = DocumentBuilderFactory
378 factory.setValidating(false);
379 factory.setNamespaceAware(true);
381 DocumentBuilder builder = factory.newDocumentBuilder();
383 builder.setErrorHandler(errorHandler);
384 builder.parse(new InputSource(file.getPath()));
389 private void assertEventBusModuleFactory(MbeASTVisitor visitor) {
390 assertEquals(PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
391 + ".threads.java", visitor.packageName);
392 assertEquals("EventBusModuleFactory", visitor.type);
393 assertContains(visitor.extnds,
394 PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
395 + ".threads.java.AbstractEventBusModuleFactory");
397 assertEquals(0, visitor.fieldDeclarations.size());
399 assertEquals("Incorrenct number of generated methods", 0,
400 visitor.methods.size());
401 assertEquals("Incorrenct number of generated constructors", 0,
402 visitor.constructors.size());
403 assertEquals("Incorrenct number of generated method descriptions", 0,
404 visitor.methodDescriptions.size());
405 assertEquals("Incorrenct number of generated method javadoc", 0,
406 visitor.methodJavadoc.size());
409 private void assertAsyncEventBusModule(MbeASTVisitor visitor) {
410 assertEquals(PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
411 + ".threads.java", visitor.packageName);
412 assertEquals("AsyncEventBusModule", visitor.type);
413 assertContains(visitor.extnds,
414 PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
415 + ".threads.java.AbstractAsyncEventBusModule");
417 assertEquals(0, visitor.fieldDeclarations.size());
419 assertEquals("Incorrenct number of generated methods", 2,
420 visitor.methods.size());
421 assertEquals("Incorrenct number of generated constructors", 2,
422 visitor.constructors.size());
423 assertEquals("Incorrenct number of generated method descriptions", 0,
424 visitor.methodDescriptions.size());
425 assertEquals("Incorrenct number of generated method javadoc", 0,
426 visitor.methodJavadoc.size());
429 private void assertAbstractNamingThreadFactoryModuleFactory(
430 MbeASTVisitor visitor) {
431 assertEquals(PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
432 + ".threads.java", visitor.packageName);
433 assertEquals("AbstractNamingThreadFactoryModuleFactory", visitor.type);
434 assertContains(visitor.implmts,
435 "org.opendaylight.controller.config.spi.ModuleFactory");
436 Set<String> fieldDeclarations = visitor.fieldDeclarations;
437 assertDeclaredField(fieldDeclarations,
438 "public static final java.lang.String NAME=\"threadfactory-naming\"");
441 "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>>()");
443 assertEquals(2, fieldDeclarations.size());
445 assertFactoryMethods(visitor.methods, 8);
446 assertEquals("Incorrenct number of generated method descriptions", 0,
447 visitor.methodDescriptions.size());
448 assertEquals("Incorrenct number of generated method javadoc", 0,
449 visitor.methodJavadoc.size());
453 private void assertFactoryMethods(Set<String> methods, int expectedSize) {
455 List<ArgumentAssertion> args = Lists.newArrayList();
456 ArgumentAssertion oldInstanceArg = new ArgumentAssertion(DynamicMBeanWithInstance.class.getCanonicalName(), "old");
457 ArgumentAssertion instanceNameArg = new ArgumentAssertion(String.class.getSimpleName(), "instanceName");
458 ArgumentAssertion dependencyResolverArg = new ArgumentAssertion(DependencyResolver.class.getCanonicalName(), "dependencyResolver");
459 ArgumentAssertion bundleContextArg = new ArgumentAssertion(BundleContext.class.getCanonicalName(), "bundleContext");
461 assertMethodPresent(methods, new MethodAssertion(String.class.getSimpleName(), "getImplementationName"));
463 args.add(instanceNameArg);
464 args.add(dependencyResolverArg);
465 args.add(bundleContextArg);
466 assertMethodPresent(methods, new MethodAssertion(Module.class.getCanonicalName(), "createModule", args));
468 args.add(2, oldInstanceArg);
469 assertMethodPresent(methods, new MethodAssertion(Module.class.getCanonicalName(), "createModule", args));
472 args.add(oldInstanceArg);
473 assertMethodPresent(methods, new MethodAssertion("org.opendaylight.controller.config.threads.java.NamingThreadFactoryModule", "handleChangedClass", args));
476 args.add(instanceNameArg);
477 args.add(dependencyResolverArg);
478 args.add(bundleContextArg);
479 assertMethodPresent(methods, new MethodAssertion("org.opendaylight.controller.config.threads.java.NamingThreadFactoryModule", "instantiateModule", args));
482 args.add(2, new ArgumentAssertion("org.opendaylight.controller.config.threads.java.NamingThreadFactoryModule", "oldModule"));
483 args.add(3, new ArgumentAssertion(AutoCloseable.class.getCanonicalName(), "oldInstance"));
484 assertMethodPresent(methods, new MethodAssertion("org.opendaylight.controller.config.threads.java.NamingThreadFactoryModule", "instantiateModule", args));
487 args.add(new ArgumentAssertion(DependencyResolverFactory.class.getCanonicalName(), "dependencyResolverFactory"));
488 args.add(bundleContextArg);
489 assertMethodPresent(methods, new MethodAssertion("java.util.Set<org.opendaylight.controller.config.threads.java.NamingThreadFactoryModule>", "getDefaultModules", args));
492 args.add(new ArgumentAssertion("Class<? extends org.opendaylight.controller.config.api.annotations.AbstractServiceInterface>", "serviceInterface"));
493 assertMethodPresent(methods, new MethodAssertion("boolean", "isModuleImplementingServiceInterface", args));
495 assertEquals(methods.size(), expectedSize);
499 private void assertMethodPresent(Set<String> methods, MethodAssertion methodAssertion) {
500 assertTrue(String.format("Generated methods did not contain %s, generated methods: %s",
501 methodAssertion.toString(), methods), methods.contains(methodAssertion.toString()));
504 private void assertAsyncEventBusModuleMXBean(MbeASTVisitor visitor) {
505 assertEquals(PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
506 + ".threads.java", visitor.packageName);
507 assertEquals("AsyncEventBusModuleMXBean", visitor.type);
509 assertEquals("Incorrenct number of generated methods", 2,
510 visitor.methods.size());
513 private void assertAbstractDynamicThreadPoolModule(MbeASTVisitor visitor) {
514 assertEquals(PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
515 + ".threads.java", visitor.packageName);
516 assertNotNull(visitor.javadoc);
517 assertContains(visitor.descriptionAnotValue,
518 "threadpool-dynamic description");
519 assertEquals("AbstractDynamicThreadPoolModule", visitor.type);
520 assertContains(visitor.implmts,
521 PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
522 + ".threads.java.DynamicThreadPoolModuleMXBean",
523 Module.class.getCanonicalName(),
524 PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
525 + ".threads.ScheduledThreadPoolServiceInterface",
526 PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
527 + ".threads.ThreadPoolServiceInterface");
528 assertEquals(2, visitor.constructors.size());
529 Set<String> fieldDeclarations = visitor.fieldDeclarations;
530 assertDeclaredField(fieldDeclarations,
531 "private java.lang.Long maximumSize");
532 assertDeclaredField(fieldDeclarations,
533 "private javax.management.ObjectName threadfactory");
534 assertDeclaredField(fieldDeclarations,
535 "private java.util.concurrent.ThreadFactory threadfactoryDependency");
536 assertDeclaredField(fieldDeclarations,
537 "private java.lang.Long keepAlive=new java.lang.Long(\"10\")");
538 assertDeclaredField(fieldDeclarations,
539 "private java.lang.Long coreSize");
540 assertDeclaredField(fieldDeclarations, "private byte[] binary");
541 assertEquals(22, fieldDeclarations.size());
543 assertEquals(1, visitor.requireIfc.size());
544 String reqIfc = visitor.requireIfc.get("setThreadfactory");
545 assertNotNull("Missing generated setter for threadfactory", reqIfc);
546 assertContains(reqIfc, PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
547 + ".threads.ThreadFactoryServiceInterface");
549 assertEquals("Incorrenct number of generated methods", 27,
550 visitor.methods.size());
551 assertEquals("Incorrenct number of generated method descriptions", 3,
552 visitor.methodDescriptions.size());
553 assertEquals("Incorrenct number of generated method javadoc", 3,
554 visitor.methodJavadoc.size());
555 assertNotNull("Missing javadoc for setMaximumSize method " + visitor.methodJavadoc,
556 visitor.methodJavadoc.get("void setMaximumSize(java.lang.Long maximumSize)"));
559 private void assertDeclaredField(Set<String> fieldDeclarations,
560 String declaration) {
561 assertTrue("Missing field " + declaration + ", got: "
563 fieldDeclarations.contains(declaration + ";\n"));
566 private static class SieASTVisitor extends ASTVisitor {
567 protected String packageName, descriptionAnotValue, sieAnnotValue,
568 sieAnnotOsgiRegistrationType, type, extnds, javadoc;
569 protected Map<String, String> methodDescriptions = Maps.newHashMap();
572 public boolean visit(PackageDeclaration node) {
573 packageName = node.getName().toString();
574 return super.visit(node);
578 public boolean visit(NormalAnnotation node) {
579 if (node.getTypeName().toString()
580 .equals(Description.class.getCanonicalName())) {
581 if (node.getParent() instanceof TypeDeclaration) {
582 descriptionAnotValue = node.values().get(0).toString();
583 } else if (node.getParent() instanceof MethodDeclaration) {
584 String descr = node.values().get(0).toString();
585 methodDescriptions.put(((MethodDeclaration) node
586 .getParent()).getName().toString(), descr);
591 .equals(ServiceInterfaceAnnotation.class.getCanonicalName())) {
592 String text1 = node.values().get(0).toString();
593 String text2 = node.values().get(1).toString();
594 if (text1.contains("value")) {
595 sieAnnotValue = text1;
596 sieAnnotOsgiRegistrationType = text2;
598 sieAnnotValue = text2;
599 sieAnnotOsgiRegistrationType = text1;
602 return super.visit(node);
606 public boolean visit(TypeDeclaration node) {
607 javadoc = node.getJavadoc() == null ? null : node.getJavadoc()
609 type = node.getName().toString();
610 List<?> superIfcs = node.superInterfaceTypes();
611 extnds = superIfcs != null && !superIfcs.isEmpty() ? superIfcs
613 return super.visit(node);
617 private static class MbeASTVisitor extends SieASTVisitor {
618 private String implmts;
619 private final Set<String> fieldDeclarations = Sets.newHashSet();
620 private final Set<String> constructors = Sets.newHashSet();
621 private final Set<String> methods = new HashSet<String>();
622 private final Map<String, String> requireIfc = Maps.newHashMap();
623 private final Map<String, String> methodJavadoc = Maps.newHashMap();
626 public boolean visit(NormalAnnotation node) {
627 boolean result = super.visit(node);
628 if (node.getTypeName().toString()
629 .equals(RequireInterface.class.getCanonicalName())
630 && node.getParent() instanceof MethodDeclaration) {
631 // remember only top level description annotation
632 String reqVal = node.values().get(0).toString();
633 requireIfc.put(((MethodDeclaration) node.getParent()).getName()
634 .toString(), reqVal);
640 public boolean visit(FieldDeclaration node) {
641 fieldDeclarations.add(node.toString());
642 return super.visit(node);
646 public boolean visit(MethodDeclaration node) {
647 if (node.isConstructor())
648 constructors.add(node.toString());
650 String methodSignature = node.getReturnType2() + " " + node.getName() + "(";
651 boolean first = true;
652 for (Object o : node.parameters()) {
656 methodSignature += ",";
658 methodSignature += o.toString();
660 methodSignature += ")";
661 methods.add(methodSignature);
662 if (node.getJavadoc() != null) {
663 methodJavadoc.put(methodSignature, node.getJavadoc().toString());
666 return super.visit(node);
670 public boolean visit(TypeDeclaration node) {
671 boolean visit = super.visit(node);
672 List<?> superIfcs = node.superInterfaceTypes();
673 implmts = superIfcs != null && !superIfcs.isEmpty() ? superIfcs
675 extnds = node.getSuperclassType() == null ? null : node
676 .getSuperclassType().toString();
682 private void assertContains(String source, String... contained) {
683 for (String string : contained) {
684 assertThat(source, containsString(string));
688 private void processGeneratedCode(Collection<File> files,
689 Map<String, ASTVisitor> verifiers) throws IOException {
690 ASTParser parser = ASTParser.newParser(AST.JLS3);
691 Map<?, ?> options = JavaCore.getOptions();
692 JavaCore.setComplianceOptions(JavaCore.VERSION_1_7, options);
693 parser.setCompilerOptions(options);
695 parser.setKind(ASTParser.K_COMPILATION_UNIT);
697 for (File file : files) {
698 char[] source = readFileAsChars(file);
699 parser.setSource(source);
700 parser.setResolveBindings(true);
702 CompilationUnit cu = (CompilationUnit) parser.createAST(null);
703 // Check for compilation problems in generated file
704 for (IProblem c : cu.getProblems()) {
705 // 1610613332 = Syntax error, annotations are only available if
706 // source level is 5.0
707 if (c.getID() == 1610613332)
709 // 1610613332 = Syntax error, parameterized types are only
710 // available if source level is 5.0
711 if (c.getID() == 1610613329)
713 if (c.getID() == 1610613328) // 'for each' statements are only available if source level is 5.0
715 fail("Error in generated source code " + file + ":"
716 + c.getSourceLineNumber() + " id: " + c.getID() + " message:" + c.toString());
719 ASTVisitor visitor = verifiers.get(file.getName());
721 fail("Unknown generated file " + file.getName());
727 public static char[] readFileAsChars(File file) throws IOException {
728 List<String> readLines = Files
729 .readLines(file, Charset.forName("utf-8"));
730 char[] retVal = new char[0];
731 for (String string : readLines) {
732 char[] line = string.toCharArray();
733 int beforeLength = retVal.length;
734 retVal = Arrays.copyOf(retVal, retVal.length + line.length + 1);
735 System.arraycopy(line, 0, retVal, beforeLength, line.length);
736 retVal[retVal.length - 1] = '\n';
741 private static class MethodAssertion extends ArgumentAssertion{
743 private List<ArgumentAssertion> arguments;
746 MethodAssertion(String type, String name, List<ArgumentAssertion> arguments) {
748 this.arguments = arguments;
751 MethodAssertion(String type, String name) {
752 this(type, name, Collections.<ArgumentAssertion>emptyList());
756 public String toString() {
757 final StringBuffer sb = new StringBuffer();
758 sb.append(type).append(' ');
759 sb.append(name).append('(');
762 for (ArgumentAssertion argument : arguments) {
763 sb.append(argument.type).append(' ');
764 sb.append(argument.name);
765 if(++i != arguments.size())
769 return sb.toString();
773 private static class ArgumentAssertion {
775 protected final String type, name;
777 private ArgumentAssertion(String type, String name) {
783 public String toString() {
784 final StringBuffer sb = new StringBuffer();
785 sb.append(type).append(' ');
787 return sb.toString();