Merge "BUG 3057 - notify added event source by topics created before"
[controller.git] / opendaylight / config / yang-jmx-generator-plugin / src / test / java / org / opendaylight / controller / config / yangjmxgenerator / plugin / JMXGeneratorTest.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.controller.config.yangjmxgenerator.plugin;
9
10 import static org.hamcrest.CoreMatchers.containsString;
11 import static org.hamcrest.CoreMatchers.equalTo;
12 import static org.hamcrest.CoreMatchers.is;
13 import static org.junit.Assert.assertEquals;
14 import static org.junit.Assert.assertFalse;
15 import static org.junit.Assert.assertNotNull;
16 import static org.junit.Assert.assertThat;
17 import static org.junit.Assert.assertTrue;
18 import static org.junit.Assert.fail;
19 import static org.mockito.Mockito.doReturn;
20 import static org.mockito.Mockito.mock;
21 import com.google.common.base.Predicate;
22 import com.google.common.collect.Collections2;
23 import com.google.common.collect.Lists;
24 import com.google.common.collect.Maps;
25 import com.google.common.collect.Sets;
26 import com.google.common.io.Files;
27 import java.io.File;
28 import java.io.IOException;
29 import java.nio.charset.Charset;
30 import java.util.ArrayList;
31 import java.util.Arrays;
32 import java.util.Collection;
33 import java.util.Collections;
34 import java.util.HashMap;
35 import java.util.HashSet;
36 import java.util.List;
37 import java.util.Map;
38 import java.util.Set;
39 import javax.xml.parsers.DocumentBuilder;
40 import javax.xml.parsers.DocumentBuilderFactory;
41 import org.apache.commons.io.FileUtils;
42 import org.apache.maven.project.MavenProject;
43 import org.eclipse.jdt.core.JavaCore;
44 import org.eclipse.jdt.core.compiler.IProblem;
45 import org.eclipse.jdt.core.dom.AST;
46 import org.eclipse.jdt.core.dom.ASTParser;
47 import org.eclipse.jdt.core.dom.ASTVisitor;
48 import org.eclipse.jdt.core.dom.CompilationUnit;
49 import org.eclipse.jdt.core.dom.FieldDeclaration;
50 import org.eclipse.jdt.core.dom.MethodDeclaration;
51 import org.eclipse.jdt.core.dom.NormalAnnotation;
52 import org.eclipse.jdt.core.dom.PackageDeclaration;
53 import org.eclipse.jdt.core.dom.TypeDeclaration;
54 import org.junit.Before;
55 import org.junit.Test;
56 import org.opendaylight.controller.config.api.DependencyResolver;
57 import org.opendaylight.controller.config.api.DependencyResolverFactory;
58 import org.opendaylight.controller.config.api.DynamicMBeanWithInstance;
59 import org.opendaylight.controller.config.api.annotations.Description;
60 import org.opendaylight.controller.config.api.annotations.RequireInterface;
61 import org.opendaylight.controller.config.api.annotations.ServiceInterfaceAnnotation;
62 import org.opendaylight.controller.config.spi.AbstractModule;
63 import org.opendaylight.controller.config.spi.Module;
64 import org.opendaylight.controller.config.spi.ModuleFactory;
65 import org.opendaylight.controller.config.yangjmxgenerator.ConfigConstants;
66 import org.opendaylight.controller.config.yangjmxgenerator.PackageTranslatorTest;
67 import org.opendaylight.controller.config.yangjmxgenerator.ServiceInterfaceEntryTest;
68 import org.osgi.framework.BundleContext;
69 import org.xml.sax.ErrorHandler;
70 import org.xml.sax.InputSource;
71 import org.xml.sax.SAXException;
72 import org.xml.sax.SAXParseException;
73
74 //TODO: refactor
75 public class JMXGeneratorTest extends AbstractGeneratorTest {
76
77     JMXGenerator jmxGenerator;
78
79     protected final HashMap<String, String> map = Maps.newHashMap();
80     protected File outputBaseDir;
81     File generatedResourcesDir;
82
83     private static final List<String> expectedModuleFileNames = ServiceInterfaceEntryTest
84             .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, FromGrouping.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]");
85
86     private static final List<String> expectedBGPNames = ServiceInterfaceEntryTest
87             .toFileNames("[AbstractBgpListenerImplModule.java, " + "AbstractBgpListenerImplModuleFactory.java, " +
88                     "BgpListenerImplModule.java, " + "BgpListenerImplModuleFactory.java, " +
89                     "BgpListenerImplModuleMXBean.java, Peers.java]");
90
91     private static final List<String> expectedNetconfNames = ServiceInterfaceEntryTest
92             .toFileNames("[AbstractNetconfTestImplModule.java, " + "AbstractNetconfTestImplModuleFactory.java, " +
93                     "AbstractTestImplModule.java, " + "AbstractTestImplModuleFactory.java, " +
94                     "AutoCloseableServiceInterface.java, " + "ComplexDtoBInner.java, ComplexList.java, Deep.java, " +
95                     "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" + "]");
96     private static final List<String> expectedTestFiles = ServiceInterfaceEntryTest
97             .toFileNames("[AbstractNetconfTestFileImplModule.java, AbstractNetconfTestFileImplModuleFactory.java, " +
98                     "AbstractNetconfTestFiles1ImplModule.java, AbstractNetconfTestFiles1ImplModuleFactory.java, " +
99                     "AbstractTestFileImplModule.java, AbstractTestFileImplModuleFactory.java, " +
100                     "AbstractTestFiles1ImplModule.java, AbstractTestFiles1ImplModuleFactory.java, DtoA.java, " +
101                     "DtoA.java, NetconfTestFileImplModuleMXBean.java, NetconfTestFileImplRuntimeMXBean.java, " +
102                     "NetconfTestFileImplRuntimeRegistration.java, NetconfTestFileImplRuntimeRegistrator.java, " +
103                     "NetconfTestFiles1ImplModule.java, NetconfTestFiles1ImplModuleFactory.java, " +
104                     "NetconfTestFiles1ImplModuleMXBean.java, NetconfTestFiles1ImplRuntimeMXBean.java, " +
105                     "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]");
106     private static final List<String> expectedAllFileNames = ServiceInterfaceEntryTest
107             .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, FromGrouping.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]");
108     private static final List<String> expectedGenerateMBEsListNames = ServiceInterfaceEntryTest
109             .toFileNames("[AbstractBgpListenerImplModule.java, AbstractBgpListenerImplModuleFactory.java, BgpListenerImplModule.java, BgpListenerImplModuleFactory.java, BgpListenerImplModuleMXBean.java, BgpListenerImplRuntimeMXBean.java, BgpListenerImplRuntimeRegistration.java, BgpListenerImplRuntimeRegistrator.java, PeersRuntimeMXBean.java, PeersRuntimeRegistration.java]");
110
111     @Before
112     public void setUp() {
113         map.put(JMXGenerator.NAMESPACE_TO_PACKAGE_PREFIX + "1",
114                 ConfigConstants.CONFIG_NAMESPACE
115                         + JMXGenerator.NAMESPACE_TO_PACKAGE_DIVIDER
116                         + PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX);
117         map.put(JMXGenerator.MODULE_FACTORY_FILE_BOOLEAN, "false");
118         jmxGenerator = new JMXGenerator(new CodeWriter());
119         jmxGenerator.setAdditionalConfig(map);
120         File targetDir = new File(generatorOutputPath, "target");
121         generatedResourcesDir = new File(targetDir, "generated-resources");
122         jmxGenerator.setResourceBaseDir(generatedResourcesDir);
123         MavenProject project = mock(MavenProject.class);
124         doReturn(generatorOutputPath).when(project).getBasedir();
125         jmxGenerator.setMavenProject(project);
126         outputBaseDir = JMXGenerator.concatFolders(targetDir,
127                 "generated-sources", "config");
128     }
129
130     @Test
131     public void generateSIsMBsTest() {
132         Collection<File> files = jmxGenerator.generateSources(context,
133                 outputBaseDir, context.getModules());
134         List<String> expectedFileNames = new ArrayList<>();
135         expectedFileNames
136                 .addAll(ServiceInterfaceEntryTest.expectedSIEFileNames);
137         expectedFileNames.addAll(expectedModuleFileNames);
138
139         expectedFileNames.addAll(expectedBGPNames);
140         expectedFileNames.addAll(expectedNetconfNames);
141         expectedFileNames.addAll(expectedTestFiles);
142         Collections.sort(expectedFileNames);
143         // TODO: separate expectedAllFileNames into expectedBGPNames,
144         // expectedNetconfNames
145         assertEquals(expectedAllFileNames, toFileNames(files));
146
147         verifyModuleFactoryFile(false);
148     }
149
150     private void verifyModuleFactoryFile(final boolean shouldBePresent) {
151         File factoryFile = new File(generatedResourcesDir, "META-INF"
152                 + File.separator + "services" + File.separator
153                 + ModuleFactory.class.getName());
154         if (!shouldBePresent) {
155             assertFalse("Factory file should not be generated",
156                     factoryFile.exists());
157         } else {
158             assertTrue("Factory file should be generated", factoryFile.exists());
159         }
160     }
161
162     public static List<String> toFileNames(final Collection<File> files) {
163         List<String> result = new ArrayList<>();
164         for (File f : files) {
165             result.add(f.getName());
166         }
167         Collections.sort(result);
168         return result;
169     }
170
171     @Test
172     public void generateSIEsTest() throws IOException {
173         Collection<File> files = jmxGenerator.generateSources(context,
174                 outputBaseDir, Sets.newHashSet(threadsModule));
175         assertEquals(ServiceInterfaceEntryTest.expectedSIEFileNames,
176                 toFileNames(files));
177
178         Map<String, ASTVisitor> verifiers = Maps.newHashMap();
179
180         for (File file : files) {
181             verifiers.put(file.getName(), new SieASTVisitor());
182         }
183
184         processGeneratedCode(files, verifiers);
185
186         for (File file : files) {
187             String fileName = file.getName();
188             SieASTVisitor verifier = (SieASTVisitor) verifiers.get(fileName);
189
190             assertEquals(fileName.substring(0, fileName.length() - 5),
191                     verifier.type);
192             assertThat(
193                     verifier.extnds,
194                     containsString("org.opendaylight.controller.config.api.annotations.AbstractServiceInterface"));
195             assertEquals(PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
196                     + ".threads", verifier.packageName);
197             assertNotNull(verifier.javadoc);
198
199             if ("ThreadPoolServiceInterface.java".equals(fileName)) {
200                 assertContains(verifier.descriptionAnotValue,
201                         "A simple pool of threads able to execute work.");
202                 assertContains(verifier.sieAnnotValue, "threadpool");
203                 assertContains(verifier.sieAnnotOsgiRegistrationType,
204                         PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
205                                 + ".threadpool.ThreadPool.class");
206             } else if ("ScheduledThreadPoolServiceInterface.java"
207                     .equals(fileName)) {
208                 assertContains(verifier.extnds,
209                         PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
210                                 + ".threads.ThreadPoolServiceInterface");
211                 assertContains(
212                         verifier.descriptionAnotValue,
213                         "An extension of the simple pool of threads able to schedule work to be executed at some point in time.");
214                 assertContains(verifier.sieAnnotValue, "scheduled-threadpool");
215                 assertContains(verifier.sieAnnotOsgiRegistrationType,
216                         PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
217                                 + ".threadpool.ScheduledThreadPool.class");
218             } else if ("EventBusServiceInterface.java".equals(fileName)) {
219                 assertContains(
220                         verifier.descriptionAnotValue,
221                         "Service representing an event bus. The service acts as message router between event producers and event consumers");
222                 assertContains(verifier.sieAnnotValue, "eventbus");
223                 assertContains(verifier.sieAnnotOsgiRegistrationType,
224                         "com.google.common.eventbus.EventBus.class");
225             } else if ("ThreadFactoryServiceInterface.java".equals(fileName)) {
226                 assertContains(
227                         verifier.descriptionAnotValue,
228                         "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.");
229                 assertContains(verifier.sieAnnotValue, "threadfactory");
230                 assertContains(verifier.sieAnnotOsgiRegistrationType,
231                         "java.util.concurrent.ThreadFactory.class");
232
233             } else if ("ScheduledExecutorServiceServiceInterface.java"
234                     .equals(fileName)) {
235                 assertContains(verifier.sieAnnotOsgiRegistrationType,
236                         "java.util.concurrent.ScheduledExecutorService.class");
237             } else {
238                 fail("Unknown generated sie " + fileName);
239             }
240         }
241     }
242
243     @Test
244     public void generateMBEsListTest() throws Exception {
245         // default value for module factory file is true
246         map.put(JMXGenerator.MODULE_FACTORY_FILE_BOOLEAN, "randomValue");
247         jmxGenerator.setAdditionalConfig(map);
248
249         Collection<File> files = jmxGenerator.generateSources(context,
250                 outputBaseDir, Sets.newHashSet(bgpListenerJavaModule));
251
252         assertEquals(expectedGenerateMBEsListNames, toFileNames(files));
253     }
254
255     @Test
256     public void generateMBEsTest() throws Exception {
257         // default value for module factory file is true
258         map.put(JMXGenerator.MODULE_FACTORY_FILE_BOOLEAN, "randomValue");
259         jmxGenerator.setAdditionalConfig(map);
260
261         Collection<File> files = jmxGenerator.generateSources(context,
262                 outputBaseDir, Sets.newHashSet(threadsJavaModule));
263
264         assertEquals(expectedModuleFileNames, toFileNames(files));
265
266         Map<String, ASTVisitor> verifiers = Maps.newHashMap();
267
268         Collection<File> xmlFiles = Collections2.filter(files,
269                 new Predicate<File>() {
270
271                     @Override
272                     public boolean apply(final File input) {
273                         return input.getName().endsWith("xml");
274                     }
275                 });
276
277         Collection<File> javaFiles = Collections2.filter(files,
278                 new Predicate<File>() {
279
280                     @Override
281                     public boolean apply(final File input) {
282                         return input.getName().endsWith("java");
283                     }
284                 });
285
286         MbeASTVisitor abstractDynamicThreadPoolModuleVisitor = null;
287         MbeASTVisitor asyncEventBusModuleMXBeanVisitor = null;
288         MbeASTVisitor abstractNamingThreadFactoryModuleFactoryVisitor = null;
289         MbeASTVisitor asyncEventBusModuleVisitor = null;
290         MbeASTVisitor eventBusModuleFactoryVisitor = null;
291
292         for (File file : javaFiles) {
293             String name = file.getName();
294             MbeASTVisitor visitor = new MbeASTVisitor();
295             verifiers.put(name, visitor);
296             if (name.equals("AbstractDynamicThreadPoolModule.java")) {
297                 abstractDynamicThreadPoolModuleVisitor = visitor;
298             }
299             if (name.equals("AsyncEventBusModuleMXBean.java")) {
300                 asyncEventBusModuleMXBeanVisitor = visitor;
301             }
302             if (name.equals("AbstractNamingThreadFactoryModuleFactory.java")) {
303                 abstractNamingThreadFactoryModuleFactoryVisitor = visitor;
304             }
305             if (name.equals("AsyncEventBusModule.java")) {
306                 asyncEventBusModuleVisitor = visitor;
307             }
308             if (name.equals("EventBusModuleFactory.java")) {
309                 eventBusModuleFactoryVisitor = visitor;
310             }
311         }
312
313         processGeneratedCode(javaFiles, verifiers);
314
315         assertAbstractDynamicThreadPoolModule(abstractDynamicThreadPoolModuleVisitor);
316         assertAsyncEventBusModuleMXBean(asyncEventBusModuleMXBeanVisitor);
317         assertAbstractNamingThreadFactoryModuleFactory(abstractNamingThreadFactoryModuleFactoryVisitor);
318         assertAsyncEventBusModule(asyncEventBusModuleVisitor);
319         assertEventBusModuleFactory(eventBusModuleFactoryVisitor);
320
321         verifyXmlFiles(xmlFiles);
322         // verify ModuleFactory file
323         File moduleFactoryFile = JMXGenerator.concatFolders(
324                 generatedResourcesDir, "META-INF", "services",
325                 ModuleFactory.class.getName());
326         assertThat(moduleFactoryFile.exists(), is(true));
327         Set<String> lines = Sets.newHashSet(FileUtils
328                 .readLines(moduleFactoryFile));
329         Set<String> expectedLines = Sets.newHashSet(//
330                 PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
331                         + ".threads.java.EventBusModuleFactory",//
332                 PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
333                         + ".threads.java.AsyncEventBusModuleFactory", //
334                 PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
335                         + ".threads.java.DynamicThreadPoolModuleFactory",//
336                 PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
337                         + ".threads.java.NamingThreadFactoryModuleFactory", //
338                 PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
339                         + ".threads.java.ThreadPoolRegistryImplModuleFactory");
340
341
342         assertThat(lines, equalTo(expectedLines));
343
344     }
345
346     private void verifyXmlFiles(final Collection<File> xmlFiles) throws Exception {
347         ErrorHandler errorHandler = new ErrorHandler() {
348
349             @Override
350             public void warning(final SAXParseException exception)
351                     throws SAXException {
352                 fail("Generated blueprint xml is not well formed "
353                         + exception.getMessage());
354             }
355
356             @Override
357             public void fatalError(final SAXParseException exception)
358                     throws SAXException {
359                 fail("Generated blueprint xml is not well formed "
360                         + exception.getMessage());
361             }
362
363             @Override
364             public void error(final SAXParseException exception) throws SAXException {
365                 fail("Generated blueprint xml is not well formed "
366                         + exception.getMessage());
367             }
368         };
369
370         for (File file : xmlFiles) {
371             DocumentBuilderFactory factory = DocumentBuilderFactory
372                     .newInstance();
373             factory.setValidating(false);
374             factory.setNamespaceAware(true);
375
376             DocumentBuilder builder = factory.newDocumentBuilder();
377
378             builder.setErrorHandler(errorHandler);
379             builder.parse(new InputSource(file.getPath()));
380         }
381
382     }
383
384     private void assertEventBusModuleFactory(final MbeASTVisitor visitor) {
385         assertEquals(PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
386                 + ".threads.java", visitor.packageName);
387         assertEquals("EventBusModuleFactory", visitor.type);
388         assertContains(visitor.extnds,
389                 PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
390                         + ".threads.java.AbstractEventBusModuleFactory");
391
392         assertEquals(0, visitor.fieldDeclarations.size());
393
394         assertEquals("Incorrenct number of generated methods", 0,
395                 visitor.methods.size());
396         assertEquals("Incorrenct number of generated constructors", 0,
397                 visitor.constructors.size());
398         assertEquals("Incorrenct number of generated method descriptions", 0,
399                 visitor.methodDescriptions.size());
400         assertEquals("Incorrenct number of generated method javadoc", 0,
401                 visitor.methodJavadoc.size());
402     }
403
404     private void assertAsyncEventBusModule(final MbeASTVisitor visitor) {
405         assertEquals(PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
406                 + ".threads.java", visitor.packageName);
407         assertEquals("AsyncEventBusModule", visitor.type);
408         assertContains(visitor.extnds,
409                 PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
410                         + ".threads.java.AbstractAsyncEventBusModule");
411
412         assertEquals(0, visitor.fieldDeclarations.size());
413
414         assertEquals("Incorrenct number of generated methods", 2,
415                 visitor.methods.size());
416         assertEquals("Incorrenct number of generated constructors", 2,
417                 visitor.constructors.size());
418         assertEquals("Incorrenct number of generated method descriptions", 0,
419                 visitor.methodDescriptions.size());
420         assertEquals("Incorrenct number of generated method javadoc", 0,
421                 visitor.methodJavadoc.size());
422     }
423
424     private void assertAbstractNamingThreadFactoryModuleFactory(
425             final MbeASTVisitor visitor) {
426         assertEquals(PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
427                 + ".threads.java", visitor.packageName);
428         assertEquals("AbstractNamingThreadFactoryModuleFactory", visitor.type);
429         assertContains(visitor.implmts,
430                 "org.opendaylight.controller.config.spi.ModuleFactory");
431         Set<String> fieldDeclarations = visitor.fieldDeclarations;
432         assertDeclaredField(fieldDeclarations,
433                 "public static final java.lang.String NAME=\"threadfactory-naming\"");
434         assertDeclaredField(
435                 fieldDeclarations,
436                 "private static final java.util.Set<Class<? extends org.opendaylight.controller.config.api.annotations.AbstractServiceInterface>> serviceIfcs");
437
438         assertEquals(2, fieldDeclarations.size());
439
440         assertFactoryMethods(visitor.methods, 9);
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());
445
446     }
447
448     private void assertFactoryMethods(final Set<String> methods, final int expectedSize) {
449
450         List<ArgumentAssertion> args = Lists.newArrayList();
451         ArgumentAssertion oldInstanceArg = new ArgumentAssertion(DynamicMBeanWithInstance.class.getCanonicalName(), "old");
452         ArgumentAssertion instanceNameArg = new ArgumentAssertion(String.class.getSimpleName(), "instanceName");
453         ArgumentAssertion dependencyResolverArg = new ArgumentAssertion(DependencyResolver.class.getCanonicalName(), "dependencyResolver");
454         ArgumentAssertion bundleContextArg = new ArgumentAssertion(BundleContext.class.getCanonicalName(), "bundleContext");
455
456         assertMethodPresent(methods, new MethodAssertion(String.class.getSimpleName(), "getImplementationName"));
457
458         args.add(instanceNameArg);
459         args.add(dependencyResolverArg);
460         args.add(bundleContextArg);
461         assertMethodPresent(methods, new MethodAssertion(Module.class.getCanonicalName(), "createModule", args));
462
463         args.add(2, oldInstanceArg);
464         assertMethodPresent(methods, new MethodAssertion(Module.class.getCanonicalName(), "createModule", args));
465
466         args.clear();
467         args.add(oldInstanceArg);
468         assertMethodPresent(methods, new MethodAssertion("org.opendaylight.controller.config.threads.java.NamingThreadFactoryModule", "handleChangedClass", args));
469
470         args.clear();
471         args.add(instanceNameArg);
472         args.add(dependencyResolverArg);
473         args.add(bundleContextArg);
474         assertMethodPresent(methods, new MethodAssertion("org.opendaylight.controller.config.threads.java.NamingThreadFactoryModule", "instantiateModule", args));
475
476
477         args.add(2, new ArgumentAssertion("org.opendaylight.controller.config.threads.java.NamingThreadFactoryModule", "oldModule"));
478         args.add(3, new ArgumentAssertion(AutoCloseable.class.getCanonicalName(), "oldInstance"));
479         assertMethodPresent(methods, new MethodAssertion("org.opendaylight.controller.config.threads.java.NamingThreadFactoryModule", "instantiateModule", args));
480
481         args.clear();
482         args.add(new ArgumentAssertion(DependencyResolverFactory.class.getCanonicalName(), "dependencyResolverFactory"));
483         args.add(bundleContextArg);
484         assertMethodPresent(methods, new MethodAssertion("java.util.Set<org.opendaylight.controller.config.threads.java.NamingThreadFactoryModule>", "getDefaultModules", args));
485
486         args.clear();
487         args.add(new ArgumentAssertion("Class<? extends org.opendaylight.controller.config.api.annotations.AbstractServiceInterface>", "serviceInterface"));
488         assertMethodPresent(methods, new MethodAssertion("boolean", "isModuleImplementingServiceInterface", args));
489
490         assertEquals(methods.size(), expectedSize);
491
492     }
493
494     private void assertMethodPresent(final Set<String> methods, final MethodAssertion methodAssertion) {
495         assertTrue(String.format("Generated methods did not contain %s, generated methods: %s",
496                 methodAssertion.toString(), methods), methods.contains(methodAssertion.toString()));
497     }
498
499     private void assertAsyncEventBusModuleMXBean(final MbeASTVisitor visitor) {
500         assertEquals(PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
501                 + ".threads.java", visitor.packageName);
502         assertEquals("AsyncEventBusModuleMXBean", visitor.type);
503
504         assertEquals("Incorrenct number of generated methods", 4,
505                 visitor.methods.size());
506
507     }
508
509     private void assertAbstractDynamicThreadPoolModule(final MbeASTVisitor visitor) {
510         assertEquals(PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
511                 + ".threads.java", visitor.packageName);
512         assertNotNull(visitor.javadoc);
513         assertContains(visitor.descriptionAnotValue,
514                 "threadpool-dynamic description");
515         assertEquals("AbstractDynamicThreadPoolModule", visitor.type);
516         assertContains(visitor.implmts,
517                 PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
518                         + ".threads.java.DynamicThreadPoolModuleMXBean",
519                 PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
520                         + ".threads.ScheduledThreadPoolServiceInterface",
521                 PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
522                         + ".threads.ThreadPoolServiceInterface");
523         assertContains(visitor.extnds, AbstractModule.class.getCanonicalName());
524         assertEquals(2, visitor.constructors.size());
525         Set<String> fieldDeclarations = visitor.fieldDeclarations;
526         assertDeclaredField(fieldDeclarations,
527                 "private java.lang.Long maximumSize");
528         assertDeclaredField(fieldDeclarations,
529                 "private javax.management.ObjectName threadfactory");
530         assertDeclaredField(fieldDeclarations,
531                 "private java.util.concurrent.ThreadFactory threadfactoryDependency");
532         assertDeclaredField(fieldDeclarations,
533                 "private java.lang.Long keepAlive=new java.lang.Long(\"10\")");
534         assertDeclaredField(fieldDeclarations,
535                 "private java.lang.Long coreSize");
536         assertDeclaredField(fieldDeclarations, "private byte[] binary");
537         assertEquals(17, fieldDeclarations.size());
538
539         assertEquals(1, visitor.requireIfc.size());
540         String reqIfc = visitor.requireIfc.get("setThreadfactory");
541         assertNotNull("Missing generated setter for threadfactory", reqIfc);
542         assertContains(reqIfc, PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
543                 + ".threads.ThreadFactoryServiceInterface");
544
545         assertEquals("Incorrenct number of generated methods", 26,
546                 visitor.methods.size());
547         assertEquals("Incorrenct number of generated method descriptions", 3,
548                 visitor.methodDescriptions.size());
549         assertEquals("Incorrenct number of generated method javadoc", 3,
550                 visitor.methodJavadoc.size());
551         assertNotNull("Missing javadoc for setMaximumSize method " + visitor.methodJavadoc,
552                 visitor.methodJavadoc.get("void setMaximumSize(java.lang.Long maximumSize)"));
553     }
554
555     private void assertDeclaredField(final Set<String> fieldDeclarations,
556             final String declaration) {
557         assertTrue("Missing field " + declaration + ", got: "
558                 + fieldDeclarations,
559                 fieldDeclarations.contains(declaration + ";\n"));
560     }
561
562     private static class SieASTVisitor extends ASTVisitor {
563         protected String packageName, descriptionAnotValue, sieAnnotValue,
564                 sieAnnotOsgiRegistrationType, type, extnds, javadoc;
565         protected Map<String, String> methodDescriptions = Maps.newHashMap();
566
567         @Override
568         public boolean visit(final PackageDeclaration node) {
569             packageName = node.getName().toString();
570             return super.visit(node);
571         }
572
573         @Override
574         public boolean visit(final NormalAnnotation node) {
575             if (node.getTypeName().toString()
576                     .equals(Description.class.getCanonicalName())) {
577                 if (node.getParent() instanceof TypeDeclaration) {
578                     descriptionAnotValue = node.values().get(0).toString();
579                 } else if (node.getParent() instanceof MethodDeclaration) {
580                     String descr = node.values().get(0).toString();
581                     methodDescriptions.put(((MethodDeclaration) node
582                             .getParent()).getName().toString(), descr);
583                 }
584             } else if (node
585                     .getTypeName()
586                     .toString()
587                     .equals(ServiceInterfaceAnnotation.class.getCanonicalName())) {
588                 String text1 = node.values().get(0).toString();
589                 String text2 = node.values().get(1).toString();
590                 if (text1.contains("value")) {
591                     sieAnnotValue = text1;
592                     sieAnnotOsgiRegistrationType = text2;
593                 } else {
594                     sieAnnotValue = text2;
595                     sieAnnotOsgiRegistrationType = text1;
596                 }
597             }
598             return super.visit(node);
599         }
600
601         @Override
602         public boolean visit(final TypeDeclaration node) {
603             javadoc = node.getJavadoc() == null ? null : node.getJavadoc()
604                     .toString();
605             type = node.getName().toString();
606             List<?> superIfcs = node.superInterfaceTypes();
607             extnds = superIfcs != null && !superIfcs.isEmpty() ? superIfcs
608                     .toString() : null;
609             return super.visit(node);
610         }
611     }
612
613     private static class MbeASTVisitor extends SieASTVisitor {
614         private String implmts;
615         private final Set<String> fieldDeclarations = Sets.newHashSet();
616         private final Set<String> constructors = Sets.newHashSet();
617         private final Set<String> methods = new HashSet<String>();
618         private final Map<String, String> requireIfc = Maps.newHashMap();
619         private final Map<String, String> methodJavadoc = Maps.newHashMap();
620
621         @Override
622         public boolean visit(final NormalAnnotation node) {
623             boolean result = super.visit(node);
624             if (node.getTypeName().toString()
625                     .equals(RequireInterface.class.getCanonicalName())
626                     && node.getParent() instanceof MethodDeclaration) {
627                 // remember only top level description annotation
628                 String reqVal = node.values().get(0).toString();
629                 requireIfc.put(((MethodDeclaration) node.getParent()).getName()
630                         .toString(), reqVal);
631             }
632             return result;
633         }
634
635         @Override
636         public boolean visit(final FieldDeclaration node) {
637             fieldDeclarations.add(node.toString());
638             return super.visit(node);
639         }
640
641         @Override
642         public boolean visit(final MethodDeclaration node) {
643             if (node.isConstructor()) {
644                 constructors.add(node.toString());
645             } else {
646                 String methodSignature = node.getReturnType2() + " " + node.getName() + "(";
647                 boolean first = true;
648                 for (Object o : node.parameters()) {
649                     if (first){
650                         first = false;
651                     } else {
652                         methodSignature += ",";
653                     }
654                     methodSignature += o.toString();
655                 }
656                 methodSignature += ")";
657                 methods.add(methodSignature);
658                 if (node.getJavadoc() != null) {
659                     methodJavadoc.put(methodSignature, node.getJavadoc().toString());
660                 }
661             }
662             return super.visit(node);
663         }
664
665         @Override
666         public boolean visit(final TypeDeclaration node) {
667             boolean visit = super.visit(node);
668             List<?> superIfcs = node.superInterfaceTypes();
669             implmts = superIfcs != null && !superIfcs.isEmpty() ? superIfcs
670                     .toString() : null;
671             extnds = node.getSuperclassType() == null ? null : node
672                     .getSuperclassType().toString();
673             return visit;
674         }
675
676     }
677
678     private void assertContains(final String source, final String... contained) {
679         for (String string : contained) {
680             assertThat(source, containsString(string));
681         }
682     }
683
684     private void processGeneratedCode(final Collection<File> files,
685             final Map<String, ASTVisitor> verifiers) throws IOException {
686         ASTParser parser = ASTParser.newParser(AST.JLS3);
687         Map<?, ?> options = JavaCore.getOptions();
688         JavaCore.setComplianceOptions(JavaCore.VERSION_1_7, options);
689         parser.setCompilerOptions(options);
690
691         parser.setKind(ASTParser.K_COMPILATION_UNIT);
692
693         for (File file : files) {
694             char[] source = readFileAsChars(file);
695             parser.setSource(source);
696             parser.setResolveBindings(true);
697
698             CompilationUnit cu = (CompilationUnit) parser.createAST(null);
699             // Check for compilation problems in generated file
700             for (IProblem c : cu.getProblems()) {
701                 // 1610613332 = Syntax error, annotations are only available if
702                 // source level is 5.0
703                 if (c.getID() == 1610613332) {
704                     continue;
705                 }
706                 // 1610613332 = Syntax error, parameterized types are only
707                 // available if source level is 5.0
708                 if (c.getID() == 1610613329) {
709                     continue;
710                 }
711                 if (c.getID() == 1610613328) {
712                     continue;
713                 }
714                 fail("Error in generated source code " + file + ":"
715                         + c.getSourceLineNumber() + " id: " + c.getID() + " message:"  + c.toString());
716             }
717
718             ASTVisitor visitor = verifiers.get(file.getName());
719             if (visitor == null) {
720                 fail("Unknown generated file " + file.getName());
721             }
722             cu.accept(visitor);
723
724         }
725     }
726
727     public static char[] readFileAsChars(final 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';
737         }
738         return retVal;
739     }
740
741     private static class MethodAssertion extends ArgumentAssertion{
742
743         private final List<ArgumentAssertion> arguments;
744
745
746         MethodAssertion(final String type, final String name, final List<ArgumentAssertion> arguments) {
747             super(type, name);
748             this.arguments = arguments;
749         }
750
751         MethodAssertion(final String type, final String name) {
752             this(type, name, Collections.<ArgumentAssertion>emptyList());
753         }
754
755         @Override
756         public String toString() {
757             final StringBuffer sb = new StringBuffer();
758             sb.append(type).append(' ');
759             sb.append(name).append('(');
760
761             int i = 0;
762             for (ArgumentAssertion argument : arguments) {
763                 sb.append(argument.type).append(' ');
764                 sb.append(argument.name);
765                 if(++i != arguments.size()) {
766                     sb.append(',');
767                 }
768             }
769             sb.append(')');
770             return sb.toString();
771         }
772     }
773
774     private static class ArgumentAssertion {
775
776         protected final String type, name;
777
778         private ArgumentAssertion(final String type, final String name) {
779             this.type = type;
780             this.name = name;
781         }
782
783         @Override
784         public String toString() {
785             final StringBuffer sb = new StringBuffer();
786             sb.append(type).append(' ');
787             sb.append(name);
788             return sb.toString();
789         }
790     }
791 }