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