2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.controller.config.yangjmxgenerator.plugin;
10 import com.google.common.base.Predicate;
11 import com.google.common.collect.Collections2;
12 import com.google.common.collect.Lists;
13 import com.google.common.collect.Maps;
14 import com.google.common.collect.Sets;
15 import com.google.common.io.Files;
16 import org.apache.commons.io.FileUtils;
17 import org.apache.maven.plugin.logging.Log;
18 import org.apache.maven.project.MavenProject;
19 import org.eclipse.jdt.core.JavaCore;
20 import org.eclipse.jdt.core.compiler.IProblem;
21 import org.eclipse.jdt.core.dom.AST;
22 import org.eclipse.jdt.core.dom.ASTParser;
23 import org.eclipse.jdt.core.dom.ASTVisitor;
24 import org.eclipse.jdt.core.dom.CompilationUnit;
25 import org.eclipse.jdt.core.dom.FieldDeclaration;
26 import org.eclipse.jdt.core.dom.MethodDeclaration;
27 import org.eclipse.jdt.core.dom.NormalAnnotation;
28 import org.eclipse.jdt.core.dom.PackageDeclaration;
29 import org.eclipse.jdt.core.dom.TypeDeclaration;
30 import org.junit.Before;
31 import org.junit.Test;
32 import org.opendaylight.controller.config.api.DependencyResolver;
33 import org.opendaylight.controller.config.api.DependencyResolverFactory;
34 import org.opendaylight.controller.config.api.DynamicMBeanWithInstance;
35 import org.opendaylight.controller.config.api.annotations.Description;
36 import org.opendaylight.controller.config.api.annotations.RequireInterface;
37 import org.opendaylight.controller.config.api.annotations.ServiceInterfaceAnnotation;
38 import org.opendaylight.controller.config.spi.Module;
39 import org.opendaylight.controller.config.spi.ModuleFactory;
40 import org.opendaylight.controller.config.yangjmxgenerator.ConfigConstants;
41 import org.opendaylight.controller.config.yangjmxgenerator.PackageTranslatorTest;
42 import org.opendaylight.controller.config.yangjmxgenerator.ServiceInterfaceEntryTest;
43 import org.osgi.framework.BundleContext;
44 import org.xml.sax.ErrorHandler;
45 import org.xml.sax.InputSource;
46 import org.xml.sax.SAXException;
47 import org.xml.sax.SAXParseException;
49 import javax.xml.parsers.DocumentBuilder;
50 import javax.xml.parsers.DocumentBuilderFactory;
52 import java.io.IOException;
53 import java.nio.charset.Charset;
54 import java.util.ArrayList;
55 import java.util.Arrays;
56 import java.util.Collection;
57 import java.util.Collections;
58 import java.util.HashMap;
59 import java.util.HashSet;
60 import java.util.List;
64 import static org.hamcrest.CoreMatchers.equalTo;
65 import static org.hamcrest.CoreMatchers.is;
66 import static org.junit.Assert.*;
67 import static org.junit.matchers.JUnitMatchers.containsString;
68 import static org.mockito.Matchers.any;
69 import static org.mockito.Mockito.*;
71 public class JMXGeneratorTest extends AbstractGeneratorTest {
73 JMXGenerator jmxGenerator;
75 protected final HashMap<String, String> map = Maps.newHashMap();
76 protected File outputBaseDir;
77 File generatedResourcesDir;
79 private static final List<String> expectedModuleFileNames = ServiceInterfaceEntryTest
80 .toFileNames("[AbstractAsyncEventBusModule.java, AbstractAsyncEventBusModuleFactory.java, " +
81 "AbstractDynamicThreadPoolModule.java, AbstractDynamicThreadPoolModuleFactory.java, " +
82 "AbstractEventBusModule.java, AbstractEventBusModuleFactory.java, " +
83 "AbstractNamingThreadFactoryModule.java, AbstractNamingThreadFactoryModuleFactory.java, " +
84 "AsyncEventBusModule.java, AsyncEventBusModuleFactory.java, AsyncEventBusModuleMXBean.java, " +
85 "AsyncEventBusRuntimeMXBean.java, AsyncEventBusRuntimeRegistration.java, " +
86 "AsyncEventBusRuntimeRegistrator.java, DynamicThreadPoolModule.java, " +
87 "DynamicThreadPoolModuleFactory.java, DynamicThreadPoolModuleMXBean.java, " +
88 "DynamicThreadPoolRuntimeMXBean.java, DynamicThreadPoolRuntimeRegistration.java, " +
89 "DynamicThreadPoolRuntimeRegistrator.java, EventBusModule.java, EventBusModuleFactory.java, " +
90 "EventBusModuleMXBean.java, EventRuntimeMXBean.java, EventRuntimeRegistration.java, " +
91 "InnerStreamList.java, NamingThreadFactoryModule.java, NamingThreadFactoryModuleFactory.java, " +
92 "NamingThreadFactoryModuleMXBean.java, NamingThreadFactoryRuntimeMXBean.java, NamingThreadFactoryRuntimeRegistration.java, NamingThreadFactoryRuntimeRegistrator.java, Peer.java, StreamRuntimeMXBean.java, StreamRuntimeRegistration.java, ThreadRuntimeMXBean.java, ThreadRuntimeRegistration.java, ThreadStreamRuntimeMXBean.java, ThreadStreamRuntimeRegistration.java]");
94 private static final List<String> expectedBGPNames = ServiceInterfaceEntryTest
95 .toFileNames("[AbstractBgpListenerImplModule.java, " + "AbstractBgpListenerImplModuleFactory.java, " +
96 "BgpListenerImplModule.java, " + "BgpListenerImplModuleFactory.java, " +
97 "BgpListenerImplModuleMXBean.java, Peers.java]");
99 private static final List<String> expectedNetconfNames = ServiceInterfaceEntryTest
100 .toFileNames("[AbstractNetconfTestImplModule.java, " + "AbstractNetconfTestImplModuleFactory.java, " +
101 "AbstractTestImplModule.java, " + "AbstractTestImplModuleFactory.java, " +
102 "AutoCloseableServiceInterface.java, " + "ComplexDtoBInner.java, ComplexList.java, Deep.java, " +
103 "DtoA.java, DtoA1.java, DtoAInner.java, DtoAInnerInner.java, DtoB.java, DtoC.java," + "NetconfTestImplModule.java, NetconfTestImplModuleFactory.java," + "NetconfTestImplModuleMXBean.java, Peer.java, SimpleList.java, TestImplModule.java, " + "TestImplModuleFactory.java," + " TestImplModuleMXBean.java" + "]");
104 private static final List<String> expectedTestFiles = ServiceInterfaceEntryTest
105 .toFileNames("[AbstractNetconfTestFileImplModule.java, AbstractNetconfTestFileImplModuleFactory.java, " +
106 "AbstractNetconfTestFiles1ImplModule.java, AbstractNetconfTestFiles1ImplModuleFactory.java, " +
107 "AbstractTestFileImplModule.java, AbstractTestFileImplModuleFactory.java, " +
108 "AbstractTestFiles1ImplModule.java, AbstractTestFiles1ImplModuleFactory.java, DtoA.java, " +
109 "DtoA.java, NetconfTestFileImplModuleMXBean.java, NetconfTestFileImplRuntimeMXBean.java, " +
110 "NetconfTestFileImplRuntimeRegistration.java, NetconfTestFileImplRuntimeRegistrator.java, " +
111 "NetconfTestFiles1ImplModule.java, NetconfTestFiles1ImplModuleFactory.java, " +
112 "NetconfTestFiles1ImplModuleMXBean.java, NetconfTestFiles1ImplRuntimeMXBean.java, " +
113 "NetconfTestFiles1ImplRuntimeRegistration.java, NetconfTestFiles1ImplRuntimeRegistrator.java, TestFileImplModule.java, TestFileImplModuleFactory.java, TestFileImplModuleMXBean.java, TestFileImplRuntimeMXBean.java, TestFileImplRuntimeRegistration.java, TestFileImplRuntimeRegistrator.java, TestFiles1ImplModule.java, TestFiles1ImplModuleFactory.java, TestFiles1ImplModuleMXBean.java, TestFiles1ImplRuntimeMXBean.java, TestFiles1ImplRuntimeRegistration.java, TestFiles1ImplRuntimeRegistrator.java]");
114 private static final List<String> expectedAllFileNames = ServiceInterfaceEntryTest
115 .toFileNames("[AbstractAsyncEventBusModule.java, AbstractAsyncEventBusModuleFactory.java, " +
116 "AbstractBgpListenerImplModule.java, AbstractBgpListenerImplModuleFactory.java, " +
117 "AbstractDynamicThreadPoolModule.java, AbstractDynamicThreadPoolModuleFactory.java, " +
118 "AbstractEventBusModule.java, AbstractEventBusModuleFactory.java, " +
119 "AbstractNamingThreadFactoryModule.java, AbstractNamingThreadFactoryModuleFactory.java, " +
120 "AbstractNetconfTestFileImplModule.java, AbstractNetconfTestFileImplModuleFactory.java, " +
121 "AbstractNetconfTestFiles1ImplModule.java, AbstractNetconfTestFiles1ImplModuleFactory.java, " +
122 "AbstractNetconfTestImplModule.java, AbstractNetconfTestImplModuleFactory.java, " +
123 "AbstractTestFileImplModule.java, AbstractTestFileImplModuleFactory.java, " +
124 "AbstractTestFiles1ImplModule.java, AbstractTestFiles1ImplModuleFactory.java, " +
125 "AbstractTestImplModule.java, AbstractTestImplModuleFactory.java, AsyncEventBusModule.java, " +
126 "AsyncEventBusModuleFactory.java, AsyncEventBusModuleMXBean.java, " +
127 "AsyncEventBusRuntimeMXBean.java, AsyncEventBusRuntimeRegistration.java, " +
128 "AsyncEventBusRuntimeRegistrator.java, AutoCloseableServiceInterface.java, " +
129 "BgpListenerImplModule.java, BgpListenerImplModuleFactory.java, BgpListenerImplModuleMXBean.java," +
130 " BgpListenerImplRuntimeMXBean.java, BgpListenerImplRuntimeRegistration.java, " +
131 "BgpListenerImplRuntimeRegistrator.java, ComplexDtoBInner.java, ComplexList.java, Deep.java, " +
132 "DtoA.java, DtoA.java, DtoA.java, DtoA1.java, DtoAInner.java, DtoAInnerInner.java, DtoB.java, " +
133 "DtoC.java, DynamicThreadPoolModule.java, DynamicThreadPoolModuleFactory.java, " +
134 "DynamicThreadPoolModuleMXBean.java, DynamicThreadPoolRuntimeMXBean.java, " +
135 "DynamicThreadPoolRuntimeRegistration.java, DynamicThreadPoolRuntimeRegistrator.java, " +
136 "EventBusModule.java, EventBusModuleFactory.java, EventBusModuleMXBean.java, " +
137 "EventBusServiceInterface.java, EventRuntimeMXBean.java, EventRuntimeRegistration.java, " +
138 "InnerStreamList.java, NamingThreadFactoryModule.java, NamingThreadFactoryModuleFactory.java, " +
139 "NamingThreadFactoryModuleMXBean.java, NamingThreadFactoryRuntimeMXBean.java, " +
140 "NamingThreadFactoryRuntimeRegistration.java, NamingThreadFactoryRuntimeRegistrator.java, " +
141 "NetconfTestFileImplModule.java, NetconfTestFileImplModuleFactory.java, " +
142 "NetconfTestFileImplModuleMXBean.java, NetconfTestFileImplRuntimeMXBean.java, " +
143 "NetconfTestFileImplRuntimeRegistration.java, NetconfTestFileImplRuntimeRegistrator.java, " +
144 "NetconfTestFiles1ImplModule.java, NetconfTestFiles1ImplModuleFactory.java, " +
145 "NetconfTestFiles1ImplModuleMXBean.java, NetconfTestFiles1ImplRuntimeMXBean.java, " +
146 "NetconfTestFiles1ImplRuntimeRegistration.java, NetconfTestFiles1ImplRuntimeRegistrator.java, NetconfTestImplModule.java, NetconfTestImplModuleFactory.java, NetconfTestImplModuleMXBean.java, NetconfTestImplRuntimeMXBean.java, NetconfTestImplRuntimeRegistration.java, NetconfTestImplRuntimeRegistrator.java, Peer.java, Peer.java, PeersRuntimeMXBean.java, PeersRuntimeRegistration.java, ScheduledThreadPoolServiceInterface.java, SimpleList.java, StreamRuntimeMXBean.java, StreamRuntimeRegistration.java, TestFileImplModule.java, TestFileImplModuleFactory.java, TestFileImplModuleMXBean.java, TestFileImplRuntimeMXBean.java, TestFileImplRuntimeRegistration.java, TestFileImplRuntimeRegistrator.java, TestFiles1ImplModule.java, TestFiles1ImplModuleFactory.java, TestFiles1ImplModuleMXBean.java, TestFiles1ImplRuntimeMXBean.java, TestFiles1ImplRuntimeRegistration.java, TestFiles1ImplRuntimeRegistrator.java, TestImplModule.java, TestImplModuleFactory.java, TestImplModuleMXBean.java, TestImplRuntimeMXBean.java, TestImplRuntimeRegistration.java, TestImplRuntimeRegistrator.java, ThreadFactoryServiceInterface.java, ThreadPoolServiceInterface.java, ThreadRuntimeMXBean.java, ThreadRuntimeRegistration.java, ThreadStreamRuntimeMXBean.java, ThreadStreamRuntimeRegistration.java]");
147 private static final List<String> expectedGenerateMBEsListNames = ServiceInterfaceEntryTest
148 .toFileNames("[AbstractBgpListenerImplModule.java, AbstractBgpListenerImplModuleFactory.java, BgpListenerImplModule.java, BgpListenerImplModuleFactory.java, BgpListenerImplModuleMXBean.java, BgpListenerImplRuntimeMXBean.java, BgpListenerImplRuntimeRegistration.java, BgpListenerImplRuntimeRegistrator.java, PeersRuntimeMXBean.java, PeersRuntimeRegistration.java]");
151 public void setUp() {
152 map.put(JMXGenerator.NAMESPACE_TO_PACKAGE_PREFIX + "1",
153 ConfigConstants.CONFIG_NAMESPACE
154 + JMXGenerator.NAMESPACE_TO_PACKAGE_DIVIDER
155 + PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX);
156 map.put(JMXGenerator.MODULE_FACTORY_FILE_BOOLEAN, "false");
157 jmxGenerator = new JMXGenerator(new FreeMarkerCodeWriterImpl());
158 jmxGenerator.setAdditionalConfig(map);
159 File targetDir = new File(generatorOutputPath, "target");
160 generatedResourcesDir = new File(targetDir, "generated-resources");
161 jmxGenerator.setResourceBaseDir(generatedResourcesDir);
162 Log mockedLog = mock(Log.class);
163 doReturn(false).when(mockedLog).isDebugEnabled();
164 doNothing().when(mockedLog).debug(any(CharSequence.class));
165 doNothing().when(mockedLog).info(any(CharSequence.class));
166 doNothing().when(mockedLog).error(any(CharSequence.class),
167 any(Throwable.class));
168 jmxGenerator.setLog(mockedLog);
169 MavenProject project = mock(MavenProject.class);
170 doReturn(generatorOutputPath).when(project).getBasedir();
171 jmxGenerator.setMavenProject(project);
172 outputBaseDir = JMXGenerator.concatFolders(targetDir,
173 "generated-sources", "config");
177 public void generateSIsMBsTest() {
178 Collection<File> files = jmxGenerator.generateSources(context,
179 outputBaseDir, context.getModules());
180 List<String> expectedFileNames = new ArrayList<>();
182 .addAll(ServiceInterfaceEntryTest.expectedSIEFileNames);
183 expectedFileNames.addAll(expectedModuleFileNames);
185 expectedFileNames.addAll(expectedBGPNames);
186 expectedFileNames.addAll(expectedNetconfNames);
187 expectedFileNames.addAll(expectedTestFiles);
188 Collections.sort(expectedFileNames);
189 // TODO: separate expectedAllFileNames into expectedBGPNames,
190 // expectedNetconfNames
191 assertEquals(expectedAllFileNames, toFileNames(files));
193 verifyModuleFactoryFile(false);
196 private void verifyModuleFactoryFile(boolean shouldBePresent) {
197 File factoryFile = new File(generatedResourcesDir, "META-INF"
198 + File.separator + "services" + File.separator
199 + ModuleFactory.class.getName());
200 if (!shouldBePresent)
201 assertFalse("Factory file should not be generated",
202 factoryFile.exists());
204 assertTrue("Factory file should be generated", factoryFile.exists());
207 public static List<String> toFileNames(Collection<File> files) {
208 List<String> result = new ArrayList<>();
209 for (File f : files) {
210 result.add(f.getName());
212 Collections.sort(result);
217 public void generateSIEsTest() throws IOException {
218 Collection<File> files = jmxGenerator.generateSources(context,
219 outputBaseDir, Sets.newHashSet(threadsModule));
220 assertEquals(ServiceInterfaceEntryTest.expectedSIEFileNames,
223 Map<String, ASTVisitor> verifiers = Maps.newHashMap();
225 for (File file : files) {
226 verifiers.put(file.getName(), new SieASTVisitor());
229 processGeneratedCode(files, verifiers);
231 for (File file : files) {
232 String fileName = file.getName();
233 SieASTVisitor verifier = (SieASTVisitor) verifiers.get(fileName);
235 assertEquals(fileName.substring(0, fileName.length() - 5),
239 containsString("org.opendaylight.controller.config.api.annotations.AbstractServiceInterface"));
240 assertEquals(PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
241 + ".threads", verifier.packageName);
242 assertNotNull(verifier.javadoc);
244 if ("ThreadPoolServiceInterface.java".equals(fileName)) {
245 assertContains(verifier.descriptionAnotValue,
246 "A simple pool of threads able to execute work.");
247 assertContains(verifier.sieAnnotValue, "threadpool");
248 assertContains(verifier.sieAnnotOsgiRegistrationType,
249 PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
250 + ".threadpool.ThreadPool.class");
251 } else if ("ScheduledThreadPoolServiceInterface.java"
253 assertContains(verifier.extnds,
254 PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
255 + ".threads.ThreadPoolServiceInterface");
257 verifier.descriptionAnotValue,
258 "An extension of the simple pool of threads able to schedule work to be executed at some point in time.");
259 assertContains(verifier.sieAnnotValue, "scheduled-threadpool");
260 assertContains(verifier.sieAnnotOsgiRegistrationType,
261 PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
262 + ".threadpool.ScheduledThreadPool.class");
263 } else if ("EventBusServiceInterface.java".equals(fileName)) {
265 verifier.descriptionAnotValue,
266 "Service representing an event bus. The service acts as message router between event producers and event consumers");
267 assertContains(verifier.sieAnnotValue, "eventbus");
268 assertContains(verifier.sieAnnotOsgiRegistrationType,
269 "com.google.common.eventbus.EventBus.class");
270 } else if ("ThreadFactoryServiceInterface.java".equals(fileName)) {
272 verifier.descriptionAnotValue,
273 "Service representing a ThreadFactory instance. It is directly useful in Java world, where various library pieces need to create threads and you may want to inject a customized thread implementation.");
274 assertContains(verifier.sieAnnotValue, "threadfactory");
275 assertContains(verifier.sieAnnotOsgiRegistrationType,
276 "java.util.concurrent.ThreadFactory.class");
278 } else if ("ScheduledExecutorServiceServiceInterface.java"
280 assertContains(verifier.sieAnnotOsgiRegistrationType,
281 "java.util.concurrent.ScheduledExecutorService.class");
283 fail("Unknown generated sie " + fileName);
289 public void generateMBEsListTest() throws Exception {
290 // default value for module factory file is true
291 map.put(JMXGenerator.MODULE_FACTORY_FILE_BOOLEAN, "randomValue");
292 jmxGenerator.setAdditionalConfig(map);
294 Collection<File> files = jmxGenerator.generateSources(context,
295 outputBaseDir, Sets.newHashSet(bgpListenerJavaModule));
297 assertEquals(expectedGenerateMBEsListNames, toFileNames(files));
301 public void generateMBEsTest() throws Exception {
302 // default value for module factory file is true
303 map.put(JMXGenerator.MODULE_FACTORY_FILE_BOOLEAN, "randomValue");
304 jmxGenerator.setAdditionalConfig(map);
306 Collection<File> files = jmxGenerator.generateSources(context,
307 outputBaseDir, Sets.newHashSet(threadsJavaModule));
309 assertEquals(expectedModuleFileNames, toFileNames(files));
311 Map<String, ASTVisitor> verifiers = Maps.newHashMap();
313 Collection<File> xmlFiles = Collections2.filter(files,
314 new Predicate<File>() {
317 public boolean apply(File input) {
318 return input.getName().endsWith("xml");
322 Collection<File> javaFiles = Collections2.filter(files,
323 new Predicate<File>() {
326 public boolean apply(File input) {
327 return input.getName().endsWith("java");
331 MbeASTVisitor abstractDynamicThreadPoolModuleVisitor = null;
332 MbeASTVisitor asyncEventBusModuleMXBeanVisitor = null;
333 MbeASTVisitor abstractNamingThreadFactoryModuleFactoryVisitor = null;
334 MbeASTVisitor asyncEventBusModuleVisitor = null;
335 MbeASTVisitor eventBusModuleFactoryVisitor = null;
337 for (File file : javaFiles) {
338 String name = file.getName();
339 MbeASTVisitor visitor = new MbeASTVisitor();
340 verifiers.put(name, visitor);
341 if (name.equals("AbstractDynamicThreadPoolModule.java"))
342 abstractDynamicThreadPoolModuleVisitor = visitor;
343 if (name.equals("AsyncEventBusModuleMXBean.java"))
344 asyncEventBusModuleMXBeanVisitor = visitor;
345 if (name.equals("AbstractNamingThreadFactoryModuleFactory.java"))
346 abstractNamingThreadFactoryModuleFactoryVisitor = visitor;
347 if (name.equals("AsyncEventBusModule.java"))
348 asyncEventBusModuleVisitor = visitor;
349 if (name.equals("EventBusModuleFactory.java"))
350 eventBusModuleFactoryVisitor = visitor;
353 processGeneratedCode(javaFiles, verifiers);
355 assertAbstractDynamicThreadPoolModule(abstractDynamicThreadPoolModuleVisitor);
356 assertAsyncEventBusModuleMXBean(asyncEventBusModuleMXBeanVisitor);
357 assertAbstractNamingThreadFactoryModuleFactory(abstractNamingThreadFactoryModuleFactoryVisitor);
358 assertAsyncEventBusModule(asyncEventBusModuleVisitor);
359 assertEventBusModuleFactory(eventBusModuleFactoryVisitor);
361 verifyXmlFiles(xmlFiles);
362 // verify ModuleFactory file
363 File moduleFactoryFile = JMXGenerator.concatFolders(
364 generatedResourcesDir, "META-INF", "services",
365 ModuleFactory.class.getName());
366 assertThat(moduleFactoryFile.exists(), is(true));
367 Set<String> lines = Sets.newHashSet(FileUtils
368 .readLines(moduleFactoryFile));
369 Set<String> expectedLines = Sets.newHashSet(//
370 PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
371 + ".threads.java.EventBusModuleFactory",//
372 PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
373 + ".threads.java.AsyncEventBusModuleFactory", //
374 PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
375 + ".threads.java.DynamicThreadPoolModuleFactory",//
376 PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
377 + ".threads.java.NamingThreadFactoryModuleFactory");
378 assertThat(lines, equalTo(expectedLines));
382 private void verifyXmlFiles(Collection<File> xmlFiles) throws Exception {
383 ErrorHandler errorHandler = new ErrorHandler() {
386 public void warning(SAXParseException exception)
387 throws SAXException {
388 fail("Generated blueprint xml is not well formed "
389 + exception.getMessage());
393 public void fatalError(SAXParseException exception)
394 throws SAXException {
395 fail("Generated blueprint xml is not well formed "
396 + exception.getMessage());
400 public void error(SAXParseException exception) throws SAXException {
401 fail("Generated blueprint xml is not well formed "
402 + exception.getMessage());
406 for (File file : xmlFiles) {
407 DocumentBuilderFactory factory = DocumentBuilderFactory
409 factory.setValidating(false);
410 factory.setNamespaceAware(true);
412 DocumentBuilder builder = factory.newDocumentBuilder();
414 builder.setErrorHandler(errorHandler);
415 builder.parse(new InputSource(file.getPath()));
420 private void assertEventBusModuleFactory(MbeASTVisitor visitor) {
421 assertEquals(PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
422 + ".threads.java", visitor.packageName);
423 assertEquals("EventBusModuleFactory", visitor.type);
424 assertContains(visitor.extnds,
425 PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
426 + ".threads.java.AbstractEventBusModuleFactory");
428 assertEquals(0, visitor.fieldDeclarations.size());
430 assertEquals("Incorrenct number of generated methods", 0,
431 visitor.methods.size());
432 assertEquals("Incorrenct number of generated constructors", 0,
433 visitor.constructors.size());
434 assertEquals("Incorrenct number of generated method descriptions", 0,
435 visitor.methodDescriptions.size());
436 assertEquals("Incorrenct number of generated method javadoc", 0,
437 visitor.methodJavadoc.size());
440 private void assertAsyncEventBusModule(MbeASTVisitor visitor) {
441 assertEquals(PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
442 + ".threads.java", visitor.packageName);
443 assertEquals("AsyncEventBusModule", visitor.type);
444 assertContains(visitor.extnds,
445 PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
446 + ".threads.java.AbstractAsyncEventBusModule");
448 assertEquals(0, visitor.fieldDeclarations.size());
450 assertEquals("Incorrenct number of generated methods", 2,
451 visitor.methods.size());
452 assertEquals("Incorrenct number of generated constructors", 2,
453 visitor.constructors.size());
454 assertEquals("Incorrenct number of generated method descriptions", 0,
455 visitor.methodDescriptions.size());
456 assertEquals("Incorrenct number of generated method javadoc", 0,
457 visitor.methodJavadoc.size());
460 private void assertAbstractNamingThreadFactoryModuleFactory(
461 MbeASTVisitor visitor) {
462 assertEquals(PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
463 + ".threads.java", visitor.packageName);
464 assertEquals("AbstractNamingThreadFactoryModuleFactory", visitor.type);
465 assertContains(visitor.implmts,
466 "org.opendaylight.controller.config.spi.ModuleFactory");
467 Set<String> fieldDeclarations = visitor.fieldDeclarations;
468 assertDeclaredField(fieldDeclarations,
469 "public static final java.lang.String NAME=\"threadfactory-naming\"");
472 "private static final java.util.Set<Class<? extends org.opendaylight.controller.config.api.annotations.AbstractServiceInterface>> serviceIfcs=new java.util.HashSet<Class<? extends org.opendaylight.controller.config.api.annotations.AbstractServiceInterface>>()");
474 assertEquals(2, fieldDeclarations.size());
476 assertFactoryMethods(visitor.methods, 8);
477 assertEquals("Incorrenct number of generated method descriptions", 0,
478 visitor.methodDescriptions.size());
479 assertEquals("Incorrenct number of generated method javadoc", 0,
480 visitor.methodJavadoc.size());
484 private void assertFactoryMethods(Set<String> methods, int expectedSize) {
486 List<ArgumentAssertion> args = Lists.newArrayList();
487 ArgumentAssertion oldInstanceArg = new ArgumentAssertion(DynamicMBeanWithInstance.class.getCanonicalName(), "old");
488 ArgumentAssertion instanceNameArg = new ArgumentAssertion(String.class.getSimpleName(), "instanceName");
489 ArgumentAssertion dependencyResolverArg = new ArgumentAssertion(DependencyResolver.class.getCanonicalName(), "dependencyResolver");
490 ArgumentAssertion bundleContextArg = new ArgumentAssertion(BundleContext.class.getCanonicalName(), "bundleContext");
492 assertMethodPresent(methods, new MethodAssertion(String.class.getSimpleName(), "getImplementationName"));
494 args.add(instanceNameArg);
495 args.add(dependencyResolverArg);
496 args.add(bundleContextArg);
497 assertMethodPresent(methods, new MethodAssertion(Module.class.getCanonicalName(), "createModule", args));
499 args.add(2, oldInstanceArg);
500 assertMethodPresent(methods, new MethodAssertion(Module.class.getCanonicalName(), "createModule", args));
503 args.add(oldInstanceArg);
504 assertMethodPresent(methods, new MethodAssertion("org.opendaylight.controller.config.threads.java.NamingThreadFactoryModule", "handleChangedClass", args));
507 args.add(instanceNameArg);
508 args.add(dependencyResolverArg);
509 args.add(bundleContextArg);
510 assertMethodPresent(methods, new MethodAssertion("org.opendaylight.controller.config.threads.java.NamingThreadFactoryModule", "instantiateModule", args));
513 args.add(2, new ArgumentAssertion("org.opendaylight.controller.config.threads.java.NamingThreadFactoryModule", "oldModule"));
514 args.add(3, new ArgumentAssertion(AutoCloseable.class.getCanonicalName(), "oldInstance"));
515 assertMethodPresent(methods, new MethodAssertion("org.opendaylight.controller.config.threads.java.NamingThreadFactoryModule", "instantiateModule", args));
518 args.add(new ArgumentAssertion(DependencyResolverFactory.class.getCanonicalName(), "dependencyResolverFactory"));
519 args.add(bundleContextArg);
520 assertMethodPresent(methods, new MethodAssertion("java.util.Set<org.opendaylight.controller.config.threads.java.NamingThreadFactoryModule>", "getDefaultModules", args));
523 args.add(new ArgumentAssertion("Class<? extends org.opendaylight.controller.config.api.annotations.AbstractServiceInterface>", "serviceInterface"));
524 assertMethodPresent(methods, new MethodAssertion("boolean", "isModuleImplementingServiceInterface", args));
526 assertEquals(methods.size(), expectedSize);
530 private void assertMethodPresent(Set<String> methods, MethodAssertion methodAssertion) {
531 assertTrue(String.format("Generated methods did not contain %s, generated methods: %s",
532 methodAssertion.toString(), methods), methods.contains(methodAssertion.toString()));
535 private void assertAsyncEventBusModuleMXBean(MbeASTVisitor visitor) {
536 assertEquals(PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
537 + ".threads.java", visitor.packageName);
538 assertEquals("AsyncEventBusModuleMXBean", visitor.type);
540 assertEquals("Incorrenct number of generated methods", 2,
541 visitor.methods.size());
544 private void assertAbstractDynamicThreadPoolModule(MbeASTVisitor visitor) {
545 assertEquals(PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
546 + ".threads.java", visitor.packageName);
547 assertNotNull(visitor.javadoc);
548 assertContains(visitor.descriptionAnotValue,
549 "threadpool-dynamic description");
550 assertEquals("AbstractDynamicThreadPoolModule", visitor.type);
551 assertContains(visitor.implmts,
552 PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
553 + ".threads.java.DynamicThreadPoolModuleMXBean",
554 Module.class.getCanonicalName(),
555 PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
556 + ".threads.ScheduledThreadPoolServiceInterface",
557 PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
558 + ".threads.ThreadPoolServiceInterface");
559 assertEquals(2, visitor.constructors.size());
560 Set<String> fieldDeclarations = visitor.fieldDeclarations;
561 assertDeclaredField(fieldDeclarations,
562 "private java.lang.Long maximumSize");
563 assertDeclaredField(fieldDeclarations,
564 "private javax.management.ObjectName threadfactory");
565 assertDeclaredField(fieldDeclarations,
566 "private java.util.concurrent.ThreadFactory threadfactoryDependency");
567 assertDeclaredField(fieldDeclarations,
568 "private java.lang.Long keepAlive=10");
569 assertDeclaredField(fieldDeclarations,
570 "private java.lang.Long coreSize");
571 assertDeclaredField(fieldDeclarations, "private byte[] binary");
572 assertEquals(22, fieldDeclarations.size());
574 assertEquals(1, visitor.requireIfc.size());
575 String reqIfc = visitor.requireIfc.get("setThreadfactory");
576 assertNotNull("Missing generated setter for threadfactory", reqIfc);
577 assertContains(reqIfc, PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
578 + ".threads.ThreadFactoryServiceInterface");
580 assertEquals("Incorrenct number of generated methods", 24,
581 visitor.methods.size());
582 assertEquals("Incorrenct number of generated method descriptions", 3,
583 visitor.methodDescriptions.size());
584 assertEquals("Incorrenct number of generated method javadoc", 3,
585 visitor.methodJavadoc.size());
586 assertNotNull("Missing javadoc for setMaximumSize method " + visitor.methodJavadoc,
587 visitor.methodJavadoc.get("void setMaximumSize(java.lang.Long maximumSize)"));
590 private void assertDeclaredField(Set<String> fieldDeclarations,
591 String declaration) {
592 assertTrue("Missing field " + declaration + ", got: "
594 fieldDeclarations.contains(declaration + ";\n"));
597 private static class SieASTVisitor extends ASTVisitor {
598 protected String packageName, descriptionAnotValue, sieAnnotValue,
599 sieAnnotOsgiRegistrationType, type, extnds, javadoc;
600 protected Map<String, String> methodDescriptions = Maps.newHashMap();
603 public boolean visit(PackageDeclaration node) {
604 packageName = node.getName().toString();
605 return super.visit(node);
609 public boolean visit(NormalAnnotation node) {
610 if (node.getTypeName().toString()
611 .equals(Description.class.getCanonicalName())) {
612 if (node.getParent() instanceof TypeDeclaration) {
613 descriptionAnotValue = node.values().get(0).toString();
614 } else if (node.getParent() instanceof MethodDeclaration) {
615 String descr = node.values().get(0).toString();
616 methodDescriptions.put(((MethodDeclaration) node
617 .getParent()).getName().toString(), descr);
622 .equals(ServiceInterfaceAnnotation.class.getCanonicalName())) {
623 String text1 = node.values().get(0).toString();
624 String text2 = node.values().get(1).toString();
625 if (text1.contains("value")) {
626 sieAnnotValue = text1;
627 sieAnnotOsgiRegistrationType = text2;
629 sieAnnotValue = text2;
630 sieAnnotOsgiRegistrationType = text1;
633 return super.visit(node);
637 public boolean visit(TypeDeclaration node) {
638 javadoc = node.getJavadoc() == null ? null : node.getJavadoc()
640 type = node.getName().toString();
641 List<?> superIfcs = node.superInterfaceTypes();
642 extnds = superIfcs != null && !superIfcs.isEmpty() ? superIfcs
644 return super.visit(node);
648 private static class MbeASTVisitor extends SieASTVisitor {
649 private String implmts;
650 private final Set<String> fieldDeclarations = Sets.newHashSet();
651 private final Set<String> constructors = Sets.newHashSet();
652 private final Set<String> methods = new HashSet<String>();
653 private final Map<String, String> requireIfc = Maps.newHashMap();
654 private final Map<String, String> methodJavadoc = Maps.newHashMap();
657 public boolean visit(NormalAnnotation node) {
658 boolean result = super.visit(node);
659 if (node.getTypeName().toString()
660 .equals(RequireInterface.class.getCanonicalName())
661 && node.getParent() instanceof MethodDeclaration) {
662 // remember only top level description annotation
663 String reqVal = node.values().get(0).toString();
664 requireIfc.put(((MethodDeclaration) node.getParent()).getName()
665 .toString(), reqVal);
671 public boolean visit(FieldDeclaration node) {
672 fieldDeclarations.add(node.toString());
673 return super.visit(node);
677 public boolean visit(MethodDeclaration node) {
678 if (node.isConstructor())
679 constructors.add(node.toString());
681 String methodSignature = node.getReturnType2() + " " + node.getName() + "(";
682 boolean first = true;
683 for (Object o : node.parameters()) {
687 methodSignature += ",";
689 methodSignature += o.toString();
691 methodSignature += ")";
692 methods.add(methodSignature);
693 if (node.getJavadoc() != null) {
694 methodJavadoc.put(methodSignature, node.getJavadoc().toString());
697 return super.visit(node);
701 public boolean visit(TypeDeclaration node) {
702 boolean visit = super.visit(node);
703 List<?> superIfcs = node.superInterfaceTypes();
704 implmts = superIfcs != null && !superIfcs.isEmpty() ? superIfcs
706 extnds = node.getSuperclassType() == null ? null : node
707 .getSuperclassType().toString();
713 private void assertContains(String source, String... contained) {
714 for (String string : contained) {
715 assertThat(source, containsString(string));
719 private void processGeneratedCode(Collection<File> files,
720 Map<String, ASTVisitor> verifiers) throws IOException {
721 ASTParser parser = ASTParser.newParser(AST.JLS3);
722 Map<?, ?> options = JavaCore.getOptions();
723 JavaCore.setComplianceOptions(JavaCore.VERSION_1_7, options);
724 parser.setCompilerOptions(options);
726 parser.setKind(ASTParser.K_COMPILATION_UNIT);
728 for (File file : files) {
729 char[] source = readFileAsChars(file);
730 parser.setSource(source);
731 parser.setResolveBindings(true);
733 CompilationUnit cu = (CompilationUnit) parser.createAST(null);
734 // Check for compilation problems in generated file
735 for (IProblem c : cu.getProblems()) {
736 // 1610613332 = Syntax error, annotations are only available if
737 // source level is 5.0
738 if (c.getID() == 1610613332)
740 // 1610613332 = Syntax error, parameterized types are only
741 // available if source level is 5.0
742 if (c.getID() == 1610613329)
744 fail("Error in generated source code " + file + ":"
745 + c.getSourceLineNumber() + " " + c.toString());
748 ASTVisitor visitor = verifiers.get(file.getName());
750 fail("Unknown generated file " + file.getName());
756 public static char[] readFileAsChars(File file) throws IOException {
757 List<String> readLines = Files
758 .readLines(file, Charset.forName("utf-8"));
759 char[] retVal = new char[0];
760 for (String string : readLines) {
761 char[] line = string.toCharArray();
762 int beforeLength = retVal.length;
763 retVal = Arrays.copyOf(retVal, retVal.length + line.length + 1);
764 System.arraycopy(line, 0, retVal, beforeLength, line.length);
765 retVal[retVal.length - 1] = '\n';
770 private static class MethodAssertion extends ArgumentAssertion{
772 private List<ArgumentAssertion> arguments;
775 MethodAssertion(String type, String name, List<ArgumentAssertion> arguments) {
777 this.arguments = arguments;
780 MethodAssertion(String type, String name) {
781 this(type, name, Collections.<ArgumentAssertion>emptyList());
785 public String toString() {
786 final StringBuffer sb = new StringBuffer();
787 sb.append(type).append(' ');
788 sb.append(name).append('(');
791 for (ArgumentAssertion argument : arguments) {
792 sb.append(argument.type).append(' ');
793 sb.append(argument.name);
794 if(++i != arguments.size())
798 return sb.toString();
802 private static class ArgumentAssertion {
804 protected final String type, name;
806 private ArgumentAssertion(String type, String name) {
812 public String toString() {
813 final StringBuffer sb = new StringBuffer();
814 sb.append(type).append(' ');
816 return sb.toString();