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