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