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