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