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