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